From 08dcc57fcd240922347c8a9f14d18e67a3f9f1a9 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Fri, 2 Jan 2015 23:43:19 +0200 Subject: drm/radeon: Initialize compute vmid This patch moves to radeon the initialization of compute vmid. That initializations was done in kfd-->kgd interface, but doing it in radeon as part of radeon's H/W initialization routines is more appropriate. In addition, this simplifies the kfd-->kgd interface. The patch removes the function from the interface file and from the interface declaration file. The function initializes memory apertures to fixed base/limit address and non cached memory types. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index cd3878f..8834997 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -129,9 +129,6 @@ struct kgd2kfd_calls { * @set_pasid_vmid_mapping: Exposes pasid/vmid pair to the H/W for no cp * scheduling mode. Only used for no cp scheduling mode. * - * @init_memory: Initializes memory apertures to fixed base/limit address - * and non cached memory types. - * * @init_pipeline: Initialized the compute pipelines. * * @hqd_load: Loads the mqd structure to a H/W hqd slot. used only for no cp @@ -175,7 +172,6 @@ struct kfd2kgd_calls { int (*set_pasid_vmid_mapping)(struct kgd_dev *kgd, unsigned int pasid, unsigned int vmid); - int (*init_memory)(struct kgd_dev *kgd); int (*init_pipeline)(struct kgd_dev *kgd, uint32_t pipe_id, uint32_t hpd_size, uint64_t hpd_gpu_addr); diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 6dcde37..14d173e 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -5707,6 +5707,28 @@ void cik_pcie_gart_tlb_flush(struct radeon_device *rdev) WREG32(VM_INVALIDATE_REQUEST, 0x1); } +static void cik_pcie_init_compute_vmid(struct radeon_device *rdev) +{ + int i; + uint32_t sh_mem_bases, sh_mem_config; + + sh_mem_bases = 0x6000 | 0x6000 << 16; + sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED); + sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED); + + mutex_lock(&rdev->srbm_mutex); + for (i = 8; i < 16; i++) { + cik_srbm_select(rdev, 0, 0, 0, i); + /* CP and shaders */ + WREG32(SH_MEM_CONFIG, sh_mem_config); + WREG32(SH_MEM_APE1_BASE, 1); + WREG32(SH_MEM_APE1_LIMIT, 0); + WREG32(SH_MEM_BASES, sh_mem_bases); + } + cik_srbm_select(rdev, 0, 0, 0, 0); + mutex_unlock(&rdev->srbm_mutex); +} + /** * cik_pcie_gart_enable - gart enable * @@ -5820,6 +5842,8 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) cik_srbm_select(rdev, 0, 0, 0, 0); mutex_unlock(&rdev->srbm_mutex); + cik_pcie_init_compute_vmid(rdev); + cik_pcie_gart_tlb_flush(rdev); DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", (unsigned)(rdev->mc.gtt_size >> 20), diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c index cae11ee..13e8066 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.c +++ b/drivers/gpu/drm/radeon/radeon_kfd.c @@ -63,8 +63,6 @@ static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, unsigned int vmid); -static int kgd_init_memory(struct kgd_dev *kgd); - static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, uint32_t hpd_size, uint64_t hpd_gpu_addr); @@ -89,7 +87,6 @@ static const struct kfd2kgd_calls kfd2kgd = { .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, .program_sh_mem_settings = kgd_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, - .init_memory = kgd_init_memory, .init_pipeline = kgd_init_pipeline, .hqd_load = kgd_hqd_load, .hqd_sdma_load = kgd_hqd_sdma_load, @@ -375,42 +372,6 @@ static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, return 0; } -static int kgd_init_memory(struct kgd_dev *kgd) -{ - /* - * Configure apertures: - * LDS: 0x60000000'00000000 - 0x60000001'00000000 (4GB) - * Scratch: 0x60000001'00000000 - 0x60000002'00000000 (4GB) - * GPUVM: 0x60010000'00000000 - 0x60020000'00000000 (1TB) - */ - int i; - uint32_t sh_mem_bases = PRIVATE_BASE(0x6000) | SHARED_BASE(0x6000); - - for (i = 8; i < 16; i++) { - uint32_t sh_mem_config; - - lock_srbm(kgd, 0, 0, 0, i); - - sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED); - sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED); - - write_register(kgd, SH_MEM_CONFIG, sh_mem_config); - - write_register(kgd, SH_MEM_BASES, sh_mem_bases); - - /* Scratch aperture is not supported for now. */ - write_register(kgd, SH_STATIC_MEM_CONFIG, 0); - - /* APE1 disabled for now. */ - write_register(kgd, SH_MEM_APE1_BASE, 1); - write_register(kgd, SH_MEM_APE1_LIMIT, 0); - - unlock_srbm(kgd); - } - - return 0; -} - static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, uint32_t hpd_size, uint64_t hpd_gpu_addr) { -- cgit v0.10.2 From fe502804205e4103bdff4854bb41cd78fa82b099 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Sun, 26 Oct 2014 18:07:34 +0200 Subject: drm/amdkfd: Remove call to deprecated init_memory interface This patch removes a call to kfd-->kgd interface function that is doing H/W initialization. That function is moved into radeon to be part of the common H/W initialization sequence. The interface function will be deleted. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 6806e64..60f4ccb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -37,9 +37,6 @@ #define CIK_HPD_EOP_BYTES_LOG2 11 #define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2) -static bool is_mem_initialized; - -static int init_memory(struct device_queue_manager *dqm); static int set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid, unsigned int vmid); @@ -486,20 +483,6 @@ static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble) SHARED_BASE(top_address_nybble << 12); } -static int init_memory(struct device_queue_manager *dqm) -{ - int i, retval; - - for (i = 8; i < 16; i++) - set_pasid_vmid_mapping(dqm, 0, i); - - retval = kfd2kgd->init_memory(dqm->dev->kgd); - if (retval == 0) - is_mem_initialized = true; - return retval; -} - - static int init_pipelines(struct device_queue_manager *dqm, unsigned int pipes_num, unsigned int first_pipe) { @@ -560,10 +543,6 @@ static int init_scheduler(struct device_queue_manager *dqm) pr_debug("kfd: In %s\n", __func__); retval = init_pipelines(dqm, get_pipes_num(dqm), KFD_DQM_FIRST_PIPE); - if (retval != 0) - return retval; - - retval = init_memory(dqm); return retval; } -- cgit v0.10.2 From 23d6cbe616b66ef85cee2ad8b9d9e7873bb81ed3 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 2 Jan 2015 23:32:49 +0200 Subject: drm/radeon: Don't use relative paths in #include Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 12bc212..c58cfd3 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -2,7 +2,7 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -ccflags-y := -Iinclude/drm +ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include hostprogs-y := mkregtable clean-files := rn50_reg_safe.h r100_reg_safe.h r200_reg_safe.h rv515_reg_safe.h r300_reg_safe.h r420_reg_safe.h rs600_reg_safe.h r600_reg_safe.h evergreen_reg_safe.h cayman_reg_safe.h diff --git a/drivers/gpu/drm/radeon/radeon_kfd.h b/drivers/gpu/drm/radeon/radeon_kfd.h index f90e161..1103f90 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.h +++ b/drivers/gpu/drm/radeon/radeon_kfd.h @@ -29,7 +29,7 @@ #define RADEON_KFD_H_INCLUDED #include -#include "../amd/include/kgd_kfd_interface.h" +#include "kgd_kfd_interface.h" struct radeon_device; -- cgit v0.10.2 From bd7fbd38e58046d8b2e37003e01b9fa0f545e5ae Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Fri, 2 Jan 2015 23:18:39 +0200 Subject: drm/amd: Put cik structures in a common place This patch creates a new file, cik_structs.h, and puts the cik_mqd and cik_sdma_rlc_registers structures in that file. The new file is placed in a common include folder under the drm/amd folder, so it will be shared among all amd drm drivers. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/include/cik_structs.h b/drivers/gpu/drm/amd/include/cik_structs.h new file mode 100644 index 0000000..749eab9 --- /dev/null +++ b/drivers/gpu/drm/amd/include/cik_structs.h @@ -0,0 +1,293 @@ +/* + * Copyright 2012 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. + * + */ + +#ifndef CIK_STRUCTS_H_ +#define CIK_STRUCTS_H_ + +struct cik_mqd { + uint32_t header; + uint32_t compute_dispatch_initiator; + uint32_t compute_dim_x; + uint32_t compute_dim_y; + uint32_t compute_dim_z; + uint32_t compute_start_x; + uint32_t compute_start_y; + uint32_t compute_start_z; + uint32_t compute_num_thread_x; + uint32_t compute_num_thread_y; + uint32_t compute_num_thread_z; + uint32_t compute_pipelinestat_enable; + uint32_t compute_perfcount_enable; + uint32_t compute_pgm_lo; + uint32_t compute_pgm_hi; + uint32_t compute_tba_lo; + uint32_t compute_tba_hi; + uint32_t compute_tma_lo; + uint32_t compute_tma_hi; + uint32_t compute_pgm_rsrc1; + uint32_t compute_pgm_rsrc2; + uint32_t compute_vmid; + uint32_t compute_resource_limits; + uint32_t compute_static_thread_mgmt_se0; + uint32_t compute_static_thread_mgmt_se1; + uint32_t compute_tmpring_size; + uint32_t compute_static_thread_mgmt_se2; + uint32_t compute_static_thread_mgmt_se3; + uint32_t compute_restart_x; + uint32_t compute_restart_y; + uint32_t compute_restart_z; + uint32_t compute_thread_trace_enable; + uint32_t compute_misc_reserved; + uint32_t compute_user_data_0; + uint32_t compute_user_data_1; + uint32_t compute_user_data_2; + uint32_t compute_user_data_3; + uint32_t compute_user_data_4; + uint32_t compute_user_data_5; + uint32_t compute_user_data_6; + uint32_t compute_user_data_7; + uint32_t compute_user_data_8; + uint32_t compute_user_data_9; + uint32_t compute_user_data_10; + uint32_t compute_user_data_11; + uint32_t compute_user_data_12; + uint32_t compute_user_data_13; + uint32_t compute_user_data_14; + uint32_t compute_user_data_15; + uint32_t cp_compute_csinvoc_count_lo; + uint32_t cp_compute_csinvoc_count_hi; + uint32_t cp_mqd_base_addr_lo; + uint32_t cp_mqd_base_addr_hi; + uint32_t cp_hqd_active; + uint32_t cp_hqd_vmid; + uint32_t cp_hqd_persistent_state; + uint32_t cp_hqd_pipe_priority; + uint32_t cp_hqd_queue_priority; + uint32_t cp_hqd_quantum; + uint32_t cp_hqd_pq_base_lo; + uint32_t cp_hqd_pq_base_hi; + uint32_t cp_hqd_pq_rptr; + uint32_t cp_hqd_pq_rptr_report_addr_lo; + uint32_t cp_hqd_pq_rptr_report_addr_hi; + uint32_t cp_hqd_pq_wptr_poll_addr_lo; + uint32_t cp_hqd_pq_wptr_poll_addr_hi; + uint32_t cp_hqd_pq_doorbell_control; + uint32_t cp_hqd_pq_wptr; + uint32_t cp_hqd_pq_control; + uint32_t cp_hqd_ib_base_addr_lo; + uint32_t cp_hqd_ib_base_addr_hi; + uint32_t cp_hqd_ib_rptr; + uint32_t cp_hqd_ib_control; + uint32_t cp_hqd_iq_timer; + uint32_t cp_hqd_iq_rptr; + uint32_t cp_hqd_dequeue_request; + uint32_t cp_hqd_dma_offload; + uint32_t cp_hqd_sema_cmd; + uint32_t cp_hqd_msg_type; + uint32_t cp_hqd_atomic0_preop_lo; + uint32_t cp_hqd_atomic0_preop_hi; + uint32_t cp_hqd_atomic1_preop_lo; + uint32_t cp_hqd_atomic1_preop_hi; + uint32_t cp_hqd_hq_status0; + uint32_t cp_hqd_hq_control0; + uint32_t cp_mqd_control; + uint32_t cp_mqd_query_time_lo; + uint32_t cp_mqd_query_time_hi; + uint32_t cp_mqd_connect_start_time_lo; + uint32_t cp_mqd_connect_start_time_hi; + uint32_t cp_mqd_connect_end_time_lo; + uint32_t cp_mqd_connect_end_time_hi; + uint32_t cp_mqd_connect_end_wf_count; + uint32_t cp_mqd_connect_end_pq_rptr; + uint32_t cp_mqd_connect_end_pq_wptr; + uint32_t cp_mqd_connect_end_ib_rptr; + uint32_t reserved_96; + uint32_t reserved_97; + uint32_t reserved_98; + uint32_t reserved_99; + uint32_t iqtimer_pkt_header; + uint32_t iqtimer_pkt_dw0; + uint32_t iqtimer_pkt_dw1; + uint32_t iqtimer_pkt_dw2; + uint32_t iqtimer_pkt_dw3; + uint32_t iqtimer_pkt_dw4; + uint32_t iqtimer_pkt_dw5; + uint32_t iqtimer_pkt_dw6; + uint32_t reserved_108; + uint32_t reserved_109; + uint32_t reserved_110; + uint32_t reserved_111; + uint32_t queue_doorbell_id0; + uint32_t queue_doorbell_id1; + uint32_t queue_doorbell_id2; + uint32_t queue_doorbell_id3; + uint32_t queue_doorbell_id4; + uint32_t queue_doorbell_id5; + uint32_t queue_doorbell_id6; + uint32_t queue_doorbell_id7; + uint32_t queue_doorbell_id8; + uint32_t queue_doorbell_id9; + uint32_t queue_doorbell_id10; + uint32_t queue_doorbell_id11; + uint32_t queue_doorbell_id12; + uint32_t queue_doorbell_id13; + uint32_t queue_doorbell_id14; + uint32_t queue_doorbell_id15; +}; + +struct cik_sdma_rlc_registers { + uint32_t sdma_rlc_rb_cntl; + uint32_t sdma_rlc_rb_base; + uint32_t sdma_rlc_rb_base_hi; + uint32_t sdma_rlc_rb_rptr; + uint32_t sdma_rlc_rb_wptr; + uint32_t sdma_rlc_rb_wptr_poll_cntl; + uint32_t sdma_rlc_rb_wptr_poll_addr_hi; + uint32_t sdma_rlc_rb_wptr_poll_addr_lo; + uint32_t sdma_rlc_rb_rptr_addr_hi; + uint32_t sdma_rlc_rb_rptr_addr_lo; + uint32_t sdma_rlc_ib_cntl; + uint32_t sdma_rlc_ib_rptr; + uint32_t sdma_rlc_ib_offset; + uint32_t sdma_rlc_ib_base_lo; + uint32_t sdma_rlc_ib_base_hi; + uint32_t sdma_rlc_ib_size; + uint32_t sdma_rlc_skip_cntl; + uint32_t sdma_rlc_context_status; + uint32_t sdma_rlc_doorbell; + uint32_t sdma_rlc_virtual_addr; + uint32_t sdma_rlc_ape1_cntl; + uint32_t sdma_rlc_doorbell_log; + uint32_t reserved_22; + uint32_t reserved_23; + uint32_t reserved_24; + uint32_t reserved_25; + uint32_t reserved_26; + uint32_t reserved_27; + uint32_t reserved_28; + uint32_t reserved_29; + uint32_t reserved_30; + uint32_t reserved_31; + uint32_t reserved_32; + uint32_t reserved_33; + uint32_t reserved_34; + uint32_t reserved_35; + uint32_t reserved_36; + uint32_t reserved_37; + uint32_t reserved_38; + uint32_t reserved_39; + uint32_t reserved_40; + uint32_t reserved_41; + uint32_t reserved_42; + uint32_t reserved_43; + uint32_t reserved_44; + uint32_t reserved_45; + uint32_t reserved_46; + uint32_t reserved_47; + uint32_t reserved_48; + uint32_t reserved_49; + uint32_t reserved_50; + uint32_t reserved_51; + uint32_t reserved_52; + uint32_t reserved_53; + uint32_t reserved_54; + uint32_t reserved_55; + uint32_t reserved_56; + uint32_t reserved_57; + uint32_t reserved_58; + uint32_t reserved_59; + uint32_t reserved_60; + uint32_t reserved_61; + uint32_t reserved_62; + uint32_t reserved_63; + uint32_t reserved_64; + uint32_t reserved_65; + uint32_t reserved_66; + uint32_t reserved_67; + uint32_t reserved_68; + uint32_t reserved_69; + uint32_t reserved_70; + uint32_t reserved_71; + uint32_t reserved_72; + uint32_t reserved_73; + uint32_t reserved_74; + uint32_t reserved_75; + uint32_t reserved_76; + uint32_t reserved_77; + uint32_t reserved_78; + uint32_t reserved_79; + uint32_t reserved_80; + uint32_t reserved_81; + uint32_t reserved_82; + uint32_t reserved_83; + uint32_t reserved_84; + uint32_t reserved_85; + uint32_t reserved_86; + uint32_t reserved_87; + uint32_t reserved_88; + uint32_t reserved_89; + uint32_t reserved_90; + uint32_t reserved_91; + uint32_t reserved_92; + uint32_t reserved_93; + uint32_t reserved_94; + uint32_t reserved_95; + uint32_t reserved_96; + uint32_t reserved_97; + uint32_t reserved_98; + uint32_t reserved_99; + uint32_t reserved_100; + uint32_t reserved_101; + uint32_t reserved_102; + uint32_t reserved_103; + uint32_t reserved_104; + uint32_t reserved_105; + uint32_t reserved_106; + uint32_t reserved_107; + uint32_t reserved_108; + uint32_t reserved_109; + uint32_t reserved_110; + uint32_t reserved_111; + uint32_t reserved_112; + uint32_t reserved_113; + uint32_t reserved_114; + uint32_t reserved_115; + uint32_t reserved_116; + uint32_t reserved_117; + uint32_t reserved_118; + uint32_t reserved_119; + uint32_t reserved_120; + uint32_t reserved_121; + uint32_t reserved_122; + uint32_t reserved_123; + uint32_t reserved_124; + uint32_t reserved_125; + uint32_t reserved_126; + uint32_t reserved_127; + uint32_t sdma_engine_id; + uint32_t sdma_queue_id; +}; + + + +#endif /* CIK_STRUCTS_H_ */ -- cgit v0.10.2 From 71273adc52fafcda181e62cef64ddffd76d91944 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 2 Jan 2015 23:18:54 +0200 Subject: drm/amdkfd: Don't include header files from radeon Because amdkfd will need to work both with radeon and amdgpu, don't include header files that are in radeon's folder. Instead, use the common amd include folder and move amdkfd specific defines to amdkfd header files. Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/cik_regs.h b/drivers/gpu/drm/amd/amdkfd/cik_regs.h index 607fc5c..01ff332 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_regs.h +++ b/drivers/gpu/drm/amd/amdkfd/cik_regs.h @@ -168,6 +168,8 @@ #define IB_ATC_EN (1U << 23) #define DEFAULT_MIN_IB_AVAIL_SIZE (3U << 20) +#define AQL_ENABLE 1 + #define CP_HQD_DEQUEUE_REQUEST 0xC974 #define DEQUEUE_REQUEST_DRAIN 1 #define DEQUEUE_REQUEST_RESET 2 @@ -188,6 +190,17 @@ #define MQD_VMID_MASK (0xf << 0) #define MQD_CONTROL_PRIV_STATE_EN (1U << 8) +#define SDMA_RB_VMID(x) (x << 24) +#define SDMA_RB_ENABLE (1 << 0) +#define SDMA_RB_SIZE(x) ((x) << 1) /* log2 */ +#define SDMA_RPTR_WRITEBACK_ENABLE (1 << 12) +#define SDMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */ +#define SDMA_OFFSET(x) (x << 0) +#define SDMA_DB_ENABLE (1 << 28) +#define SDMA_ATC (1 << 0) +#define SDMA_VA_PTR32 (1 << 4) +#define SDMA_VA_SHARED_BASE(x) (x << 8) + #define GRBM_GFX_INDEX 0x30800 #define INSTANCE_INDEX(x) ((x) << 0) #define SH_INDEX(x) ((x) << 8) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 60f4ccb..fead2d7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -31,7 +31,6 @@ #include "kfd_mqd_manager.h" #include "cik_regs.h" #include "kfd_kernel_queue.h" -#include "../../radeon/cik_reg.h" /* Size of the per-pipe EOP queue */ #define CIK_HPD_EOP_BYTES_LOG2 11 diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index 678c33f..155e33c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -26,8 +26,7 @@ #include "kfd_priv.h" #include "kfd_mqd_manager.h" #include "cik_regs.h" -#include "../../radeon/cikd.h" -#include "../../radeon/cik_reg.h" +#include "cik_structs.h" inline void busy_wait(unsigned long ms) { -- cgit v0.10.2 From 836aabc0d4e2a5c5c375c3f44da4096b1073a525 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 2 Jan 2015 23:33:20 +0200 Subject: drm/radeon: Use new cik_structs.h file Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/cik_reg.h b/drivers/gpu/drm/radeon/cik_reg.h index bbb8f2e..f667347 100644 --- a/drivers/gpu/drm/radeon/cik_reg.h +++ b/drivers/gpu/drm/radeon/cik_reg.h @@ -184,268 +184,4 @@ #define SDMA0_CNTL 0xD010 #define SDMA1_CNTL 0xD810 -struct cik_mqd { - uint32_t header; - uint32_t compute_dispatch_initiator; - uint32_t compute_dim_x; - uint32_t compute_dim_y; - uint32_t compute_dim_z; - uint32_t compute_start_x; - uint32_t compute_start_y; - uint32_t compute_start_z; - uint32_t compute_num_thread_x; - uint32_t compute_num_thread_y; - uint32_t compute_num_thread_z; - uint32_t compute_pipelinestat_enable; - uint32_t compute_perfcount_enable; - uint32_t compute_pgm_lo; - uint32_t compute_pgm_hi; - uint32_t compute_tba_lo; - uint32_t compute_tba_hi; - uint32_t compute_tma_lo; - uint32_t compute_tma_hi; - uint32_t compute_pgm_rsrc1; - uint32_t compute_pgm_rsrc2; - uint32_t compute_vmid; - uint32_t compute_resource_limits; - uint32_t compute_static_thread_mgmt_se0; - uint32_t compute_static_thread_mgmt_se1; - uint32_t compute_tmpring_size; - uint32_t compute_static_thread_mgmt_se2; - uint32_t compute_static_thread_mgmt_se3; - uint32_t compute_restart_x; - uint32_t compute_restart_y; - uint32_t compute_restart_z; - uint32_t compute_thread_trace_enable; - uint32_t compute_misc_reserved; - uint32_t compute_user_data_0; - uint32_t compute_user_data_1; - uint32_t compute_user_data_2; - uint32_t compute_user_data_3; - uint32_t compute_user_data_4; - uint32_t compute_user_data_5; - uint32_t compute_user_data_6; - uint32_t compute_user_data_7; - uint32_t compute_user_data_8; - uint32_t compute_user_data_9; - uint32_t compute_user_data_10; - uint32_t compute_user_data_11; - uint32_t compute_user_data_12; - uint32_t compute_user_data_13; - uint32_t compute_user_data_14; - uint32_t compute_user_data_15; - uint32_t cp_compute_csinvoc_count_lo; - uint32_t cp_compute_csinvoc_count_hi; - uint32_t cp_mqd_base_addr_lo; - uint32_t cp_mqd_base_addr_hi; - uint32_t cp_hqd_active; - uint32_t cp_hqd_vmid; - uint32_t cp_hqd_persistent_state; - uint32_t cp_hqd_pipe_priority; - uint32_t cp_hqd_queue_priority; - uint32_t cp_hqd_quantum; - uint32_t cp_hqd_pq_base_lo; - uint32_t cp_hqd_pq_base_hi; - uint32_t cp_hqd_pq_rptr; - uint32_t cp_hqd_pq_rptr_report_addr_lo; - uint32_t cp_hqd_pq_rptr_report_addr_hi; - uint32_t cp_hqd_pq_wptr_poll_addr_lo; - uint32_t cp_hqd_pq_wptr_poll_addr_hi; - uint32_t cp_hqd_pq_doorbell_control; - uint32_t cp_hqd_pq_wptr; - uint32_t cp_hqd_pq_control; - uint32_t cp_hqd_ib_base_addr_lo; - uint32_t cp_hqd_ib_base_addr_hi; - uint32_t cp_hqd_ib_rptr; - uint32_t cp_hqd_ib_control; - uint32_t cp_hqd_iq_timer; - uint32_t cp_hqd_iq_rptr; - uint32_t cp_hqd_dequeue_request; - uint32_t cp_hqd_dma_offload; - uint32_t cp_hqd_sema_cmd; - uint32_t cp_hqd_msg_type; - uint32_t cp_hqd_atomic0_preop_lo; - uint32_t cp_hqd_atomic0_preop_hi; - uint32_t cp_hqd_atomic1_preop_lo; - uint32_t cp_hqd_atomic1_preop_hi; - uint32_t cp_hqd_hq_status0; - uint32_t cp_hqd_hq_control0; - uint32_t cp_mqd_control; - uint32_t cp_mqd_query_time_lo; - uint32_t cp_mqd_query_time_hi; - uint32_t cp_mqd_connect_start_time_lo; - uint32_t cp_mqd_connect_start_time_hi; - uint32_t cp_mqd_connect_end_time_lo; - uint32_t cp_mqd_connect_end_time_hi; - uint32_t cp_mqd_connect_end_wf_count; - uint32_t cp_mqd_connect_end_pq_rptr; - uint32_t cp_mqd_connect_end_pq_wptr; - uint32_t cp_mqd_connect_end_ib_rptr; - uint32_t reserved_96; - uint32_t reserved_97; - uint32_t reserved_98; - uint32_t reserved_99; - uint32_t iqtimer_pkt_header; - uint32_t iqtimer_pkt_dw0; - uint32_t iqtimer_pkt_dw1; - uint32_t iqtimer_pkt_dw2; - uint32_t iqtimer_pkt_dw3; - uint32_t iqtimer_pkt_dw4; - uint32_t iqtimer_pkt_dw5; - uint32_t iqtimer_pkt_dw6; - uint32_t reserved_108; - uint32_t reserved_109; - uint32_t reserved_110; - uint32_t reserved_111; - uint32_t queue_doorbell_id0; - uint32_t queue_doorbell_id1; - uint32_t queue_doorbell_id2; - uint32_t queue_doorbell_id3; - uint32_t queue_doorbell_id4; - uint32_t queue_doorbell_id5; - uint32_t queue_doorbell_id6; - uint32_t queue_doorbell_id7; - uint32_t queue_doorbell_id8; - uint32_t queue_doorbell_id9; - uint32_t queue_doorbell_id10; - uint32_t queue_doorbell_id11; - uint32_t queue_doorbell_id12; - uint32_t queue_doorbell_id13; - uint32_t queue_doorbell_id14; - uint32_t queue_doorbell_id15; -}; - -struct cik_sdma_rlc_registers { - uint32_t sdma_rlc_rb_cntl; - uint32_t sdma_rlc_rb_base; - uint32_t sdma_rlc_rb_base_hi; - uint32_t sdma_rlc_rb_rptr; - uint32_t sdma_rlc_rb_wptr; - uint32_t sdma_rlc_rb_wptr_poll_cntl; - uint32_t sdma_rlc_rb_wptr_poll_addr_hi; - uint32_t sdma_rlc_rb_wptr_poll_addr_lo; - uint32_t sdma_rlc_rb_rptr_addr_hi; - uint32_t sdma_rlc_rb_rptr_addr_lo; - uint32_t sdma_rlc_ib_cntl; - uint32_t sdma_rlc_ib_rptr; - uint32_t sdma_rlc_ib_offset; - uint32_t sdma_rlc_ib_base_lo; - uint32_t sdma_rlc_ib_base_hi; - uint32_t sdma_rlc_ib_size; - uint32_t sdma_rlc_skip_cntl; - uint32_t sdma_rlc_context_status; - uint32_t sdma_rlc_doorbell; - uint32_t sdma_rlc_virtual_addr; - uint32_t sdma_rlc_ape1_cntl; - uint32_t sdma_rlc_doorbell_log; - uint32_t reserved_22; - uint32_t reserved_23; - uint32_t reserved_24; - uint32_t reserved_25; - uint32_t reserved_26; - uint32_t reserved_27; - uint32_t reserved_28; - uint32_t reserved_29; - uint32_t reserved_30; - uint32_t reserved_31; - uint32_t reserved_32; - uint32_t reserved_33; - uint32_t reserved_34; - uint32_t reserved_35; - uint32_t reserved_36; - uint32_t reserved_37; - uint32_t reserved_38; - uint32_t reserved_39; - uint32_t reserved_40; - uint32_t reserved_41; - uint32_t reserved_42; - uint32_t reserved_43; - uint32_t reserved_44; - uint32_t reserved_45; - uint32_t reserved_46; - uint32_t reserved_47; - uint32_t reserved_48; - uint32_t reserved_49; - uint32_t reserved_50; - uint32_t reserved_51; - uint32_t reserved_52; - uint32_t reserved_53; - uint32_t reserved_54; - uint32_t reserved_55; - uint32_t reserved_56; - uint32_t reserved_57; - uint32_t reserved_58; - uint32_t reserved_59; - uint32_t reserved_60; - uint32_t reserved_61; - uint32_t reserved_62; - uint32_t reserved_63; - uint32_t reserved_64; - uint32_t reserved_65; - uint32_t reserved_66; - uint32_t reserved_67; - uint32_t reserved_68; - uint32_t reserved_69; - uint32_t reserved_70; - uint32_t reserved_71; - uint32_t reserved_72; - uint32_t reserved_73; - uint32_t reserved_74; - uint32_t reserved_75; - uint32_t reserved_76; - uint32_t reserved_77; - uint32_t reserved_78; - uint32_t reserved_79; - uint32_t reserved_80; - uint32_t reserved_81; - uint32_t reserved_82; - uint32_t reserved_83; - uint32_t reserved_84; - uint32_t reserved_85; - uint32_t reserved_86; - uint32_t reserved_87; - uint32_t reserved_88; - uint32_t reserved_89; - uint32_t reserved_90; - uint32_t reserved_91; - uint32_t reserved_92; - uint32_t reserved_93; - uint32_t reserved_94; - uint32_t reserved_95; - uint32_t reserved_96; - uint32_t reserved_97; - uint32_t reserved_98; - uint32_t reserved_99; - uint32_t reserved_100; - uint32_t reserved_101; - uint32_t reserved_102; - uint32_t reserved_103; - uint32_t reserved_104; - uint32_t reserved_105; - uint32_t reserved_106; - uint32_t reserved_107; - uint32_t reserved_108; - uint32_t reserved_109; - uint32_t reserved_110; - uint32_t reserved_111; - uint32_t reserved_112; - uint32_t reserved_113; - uint32_t reserved_114; - uint32_t reserved_115; - uint32_t reserved_116; - uint32_t reserved_117; - uint32_t reserved_118; - uint32_t reserved_119; - uint32_t reserved_120; - uint32_t reserved_121; - uint32_t reserved_122; - uint32_t reserved_123; - uint32_t reserved_124; - uint32_t reserved_125; - uint32_t reserved_126; - uint32_t reserved_127; - uint32_t sdma_engine_id; - uint32_t sdma_queue_id; -}; - #endif diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c index 13e8066..ddbabab 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.c +++ b/drivers/gpu/drm/radeon/radeon_kfd.c @@ -30,6 +30,7 @@ #include "radeon_kfd.h" #include "radeon_ucode.h" #include +#include "cik_structs.h" #define CIK_PIPE_PER_MEC (4) -- cgit v0.10.2 From ff3d04a17117ed0825076c0e9edd0fe232daec9f Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Sun, 4 Jan 2015 10:37:18 +0200 Subject: drm/amdkfd: Add new VI-specific queue properties This patch adds new fields to the queue_properties structure. The new fields are relevant only for queues running on AMD GPU VI architecture. The eop_ring_buffer_address and eop_ring_buffer_size describe an end-of-pipe queue which is assigned to the MQD. In CI, the EOP queue was per pipeline and in VI it is per queue. The ctx_save_restore_area_address and ctx_save_restore_area_size describe a memory area that is designated to allow the CP to do context save/restore in mid-wave state. This patch also modifies the set_queue_properties_from_user() (called from kfd_ioctl_create_queue()) to check and copy those new parameters. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 4c0b1e4..b008fd6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -145,6 +145,8 @@ static long kfd_ioctl_get_version(struct file *filep, struct kfd_process *p, static int set_queue_properties_from_user(struct queue_properties *q_properties, struct kfd_ioctl_create_queue_args *args) { + void *tmp; + if (args->queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) { pr_err("kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE\n"); return -EINVAL; @@ -182,6 +184,20 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties, return -EFAULT; } + tmp = (void *)(uintptr_t)args->eop_buffer_address; + if (tmp != NULL && + !access_ok(VERIFY_WRITE, tmp, sizeof(uint32_t))) { + pr_debug("kfd: can't access eop buffer"); + return -EFAULT; + } + + tmp = (void *)(uintptr_t)args->ctx_save_restore_address; + if (tmp != NULL && + !access_ok(VERIFY_WRITE, tmp, sizeof(uint32_t))) { + pr_debug("kfd: can't access ctx save restore buffer"); + return -EFAULT; + } + q_properties->is_interop = false; q_properties->queue_percent = args->queue_percentage; q_properties->priority = args->queue_priority; @@ -189,6 +205,11 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties, q_properties->queue_size = args->ring_size; q_properties->read_ptr = (uint32_t *) args->read_pointer_address; q_properties->write_ptr = (uint32_t *) args->write_pointer_address; + q_properties->eop_ring_buffer_address = args->eop_buffer_address; + q_properties->eop_ring_buffer_size = args->eop_buffer_size; + q_properties->ctx_save_restore_area_address = + args->ctx_save_restore_address; + q_properties->ctx_save_restore_area_size = args->ctx_save_restore_size; if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE || args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL) q_properties->type = KFD_QUEUE_TYPE_COMPUTE; @@ -220,6 +241,11 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties, pr_debug("Queue Format (%d)\n", q_properties->format); + pr_debug("Queue EOP (0x%llX)\n", q_properties->eop_ring_buffer_address); + + pr_debug("Queue CTX save arex (0x%llX)\n", + q_properties->ctx_save_restore_area_address); + return 0; } @@ -244,9 +270,12 @@ static long kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, if (err) return err; + pr_debug("kfd: looking for gpu id 0x%x\n", args.gpu_id); dev = kfd_device_by_id(args.gpu_id); - if (dev == NULL) + if (dev == NULL) { + pr_debug("kfd: gpu id 0x%x was not found\n", args.gpu_id); return -EINVAL; + } mutex_lock(&p->mutex); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index a79c217..3ba34b7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -299,6 +299,11 @@ struct queue_properties { uint32_t sdma_engine_id; uint32_t sdma_queue_id; uint32_t sdma_vm_addr; + /* Relevant only for VI */ + uint64_t eop_ring_buffer_address; + uint32_t eop_ring_buffer_size; + uint64_t ctx_save_restore_area_address; + uint32_t ctx_save_restore_area_size; }; /** -- cgit v0.10.2 From 85d258f9a7e827dc321d54d15ce1c6d5b0048a17 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Sun, 4 Jan 2015 10:36:30 +0200 Subject: drm/amdkfd: Make KFD_MQD_TYPE enum types H/W agnostic As the MQD types are common across all AMD GPUs/APUs, let's remove the CIK part from the name. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index fead2d7..3d5f71a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -57,8 +57,8 @@ static inline enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type) { if (type == KFD_QUEUE_TYPE_SDMA) - return KFD_MQD_TYPE_CIK_SDMA; - return KFD_MQD_TYPE_CIK_CP; + return KFD_MQD_TYPE_SDMA; + return KFD_MQD_TYPE_CP; } static inline unsigned int get_pipes_num(struct device_queue_manager *dqm) @@ -271,7 +271,7 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm, BUG_ON(!dqm || !q || !qpd); - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE); + mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); if (mqd == NULL) return -ENOMEM; @@ -302,13 +302,13 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, pr_debug("kfd: In Func %s\n", __func__); mutex_lock(&dqm->lock); - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE); + mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); if (mqd == NULL) { retval = -ENOMEM; goto out; } - mqd_sdma = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_SDMA); + mqd_sdma = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); if (mqd_sdma == NULL) { mutex_unlock(&dqm->lock); return -ENOMEM; @@ -515,7 +515,7 @@ static int init_pipelines(struct device_queue_manager *dqm, memset(hpdptr, 0, CIK_HPD_EOP_BYTES * pipes_num); - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE); + mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); if (mqd == NULL) { kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem); return -ENOMEM; @@ -646,7 +646,7 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, struct mqd_manager *mqd; int retval; - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_SDMA); + mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); if (!mqd) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 0fd8bb7..773c213 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -57,7 +57,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, case KFD_QUEUE_TYPE_DIQ: case KFD_QUEUE_TYPE_HIQ: kq->mqd = dev->dqm->get_mqd_manager(dev->dqm, - KFD_MQD_TYPE_CIK_HIQ); + KFD_MQD_TYPE_HIQ); break; default: BUG(); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index 155e33c..be989fb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -423,8 +423,8 @@ struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, mqd->dev = dev; switch (type) { - case KFD_MQD_TYPE_CIK_CP: - case KFD_MQD_TYPE_CIK_COMPUTE: + case KFD_MQD_TYPE_CP: + case KFD_MQD_TYPE_COMPUTE: mqd->init_mqd = init_mqd; mqd->uninit_mqd = uninit_mqd; mqd->load_mqd = load_mqd; @@ -432,7 +432,7 @@ struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, mqd->destroy_mqd = destroy_mqd; mqd->is_occupied = is_occupied; break; - case KFD_MQD_TYPE_CIK_HIQ: + case KFD_MQD_TYPE_HIQ: mqd->init_mqd = init_mqd_hiq; mqd->uninit_mqd = uninit_mqd; mqd->load_mqd = load_mqd; @@ -440,7 +440,7 @@ struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, mqd->destroy_mqd = destroy_mqd; mqd->is_occupied = is_occupied; break; - case KFD_MQD_TYPE_CIK_SDMA: + case KFD_MQD_TYPE_SDMA: mqd->init_mqd = init_mqd_sdma; mqd->uninit_mqd = uninit_mqd_sdma; mqd->load_mqd = load_mqd_sdma; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 3ba34b7..a4e0ddd 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -356,10 +356,10 @@ struct queue { * Please read the kfd_mqd_manager.h description. */ enum KFD_MQD_TYPE { - KFD_MQD_TYPE_CIK_COMPUTE = 0, /* for no cp scheduling */ - KFD_MQD_TYPE_CIK_HIQ, /* for hiq */ - KFD_MQD_TYPE_CIK_CP, /* for cp queues and diq */ - KFD_MQD_TYPE_CIK_SDMA, /* for sdma queues */ + KFD_MQD_TYPE_COMPUTE = 0, /* for no cp scheduling */ + KFD_MQD_TYPE_HIQ, /* for hiq */ + KFD_MQD_TYPE_CP, /* for cp queues and diq */ + KFD_MQD_TYPE_SDMA, /* for sdma queues */ KFD_MQD_TYPE_MAX }; -- cgit v0.10.2 From 0da7558c690708259617417d3ddc5b5042f1cca4 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Thu, 1 Jan 2015 17:10:01 +0200 Subject: drm/amdkfd: Add asic property to kfd_device_info This patch adds a new property to kfd_device_info structure. That structure holds information that is H/W specific. The new property is called asic_family and its purpose is to distinguish between different asic families in amdkfd operations, mainly in QCM (queue control & management) This patch also adds a new enum, to select different ASICs. We set the current kfd_device_info instance as Kaveri and create a new instance which describes the new AMD APU, codenamed 'Carrizo'. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 994a9c1..24b37ff 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -31,6 +31,14 @@ #define MQD_SIZE_ALIGNED 768 static const struct kfd_device_info kaveri_device_info = { + .asic_family = CHIP_KAVERI, + .max_pasid_bits = 16, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .mqd_size_aligned = MQD_SIZE_ALIGNED +}; + +static const struct kfd_device_info carrizo_device_info = { + .asic_family = CHIP_CARRIZO, .max_pasid_bits = 16, .ih_ring_entry_size = 4 * sizeof(uint32_t), .num_of_watch_points = 4, @@ -65,7 +73,7 @@ static const struct kfd_deviceid supported_devices[] = { { 0x1318, &kaveri_device_info }, /* Kaveri */ { 0x131B, &kaveri_device_info }, /* Kaveri */ { 0x131C, &kaveri_device_info }, /* Kaveri */ - { 0x131D, &kaveri_device_info }, /* Kaveri */ + { 0x131D, &kaveri_device_info } /* Kaveri */ }; static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index a4e0ddd..872a1da 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -104,7 +104,13 @@ enum cache_policy { cache_policy_noncoherent }; +enum asic_family_type { + CHIP_KAVERI = 0, + CHIP_CARRIZO +}; + struct kfd_device_info { + unsigned int asic_family; unsigned int max_pasid_bits; size_t ih_ring_entry_size; uint8_t num_of_watch_points; -- cgit v0.10.2 From 4b8f589b052fe800e36f11eb2d29d4cf364bbed0 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Sun, 4 Jan 2015 11:24:25 +0200 Subject: drm/amdkfd: Change MQD manager to be H/W specific The MQDs for CI and VI are different. Therefore, the MQD manager module need to be H/W specific. This patch splits the current MQD manager into three files: - kfd_mqd_manager.c, which contains common functions and initializes the specific mqd manager module according to the H/W - kfd_mqd_manager_cik.c, which contains Kaveri specific functions. This is basically the old kfd_mqd_manager.c - kfd_mqd_manager_vi.c, which will contain VI specific functions. Currently it is not implemented except for returning NULL on initialization. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile index be6246d..bc6053f 100644 --- a/drivers/gpu/drm/amd/amdkfd/Makefile +++ b/drivers/gpu/drm/amd/amdkfd/Makefile @@ -7,6 +7,7 @@ ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/ amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \ kfd_process.o kfd_queue.o kfd_mqd_manager.o \ + kfd_mqd_manager_cik.o kfd_mqd_manager_vi.o \ kfd_kernel_queue.o kfd_packet_manager.o \ kfd_process_queue_manager.o kfd_device_queue_manager.o \ kfd_interrupt.o diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index be989fb..b1ef136 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -21,439 +21,17 @@ * */ -#include -#include #include "kfd_priv.h" -#include "kfd_mqd_manager.h" -#include "cik_regs.h" -#include "cik_structs.h" - -inline void busy_wait(unsigned long ms) -{ - while (time_before(jiffies, ms)) - cpu_relax(); -} - -static inline struct cik_mqd *get_mqd(void *mqd) -{ - return (struct cik_mqd *)mqd; -} - -static int init_mqd(struct mqd_manager *mm, void **mqd, - struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, - struct queue_properties *q) -{ - uint64_t addr; - struct cik_mqd *m; - int retval; - - BUG_ON(!mm || !q || !mqd); - - pr_debug("kfd: In func %s\n", __func__); - - retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd), - mqd_mem_obj); - - if (retval != 0) - return -ENOMEM; - - m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr; - addr = (*mqd_mem_obj)->gpu_addr; - - memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256)); - - m->header = 0xC0310800; - m->compute_pipelinestat_enable = 1; - m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF; - m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF; - m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF; - m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF; - - /* - * Make sure to use the last queue state saved on mqd when the cp - * reassigns the queue, so when queue is switched on/off (e.g over - * subscription or quantum timeout) the context will be consistent - */ - m->cp_hqd_persistent_state = - DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ; - - m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN; - m->cp_mqd_base_addr_lo = lower_32_bits(addr); - m->cp_mqd_base_addr_hi = upper_32_bits(addr); - - m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN; - /* Although WinKFD writes this, I suspect it should not be necessary */ - m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE; - - m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS | - QUANTUM_DURATION(10); - - /* - * Pipe Priority - * Identifies the pipe relative priority when this queue is connected - * to the pipeline. The pipe priority is against the GFX pipe and HP3D. - * In KFD we are using a fixed pipe priority set to CS_MEDIUM. - * 0 = CS_LOW (typically below GFX) - * 1 = CS_MEDIUM (typically between HP3D and GFX - * 2 = CS_HIGH (typically above HP3D) - */ - m->cp_hqd_pipe_priority = 1; - m->cp_hqd_queue_priority = 15; - - *mqd = m; - if (gart_addr != NULL) - *gart_addr = addr; - retval = mm->update_mqd(mm, m, q); - - return retval; -} - -static int init_mqd_sdma(struct mqd_manager *mm, void **mqd, - struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, - struct queue_properties *q) -{ - int retval; - struct cik_sdma_rlc_registers *m; - - BUG_ON(!mm || !mqd || !mqd_mem_obj); - - retval = kfd_gtt_sa_allocate(mm->dev, - sizeof(struct cik_sdma_rlc_registers), - mqd_mem_obj); - - if (retval != 0) - return -ENOMEM; - - m = (struct cik_sdma_rlc_registers *) (*mqd_mem_obj)->cpu_ptr; - - memset(m, 0, sizeof(struct cik_sdma_rlc_registers)); - - *mqd = m; - if (gart_addr != NULL) - *gart_addr = (*mqd_mem_obj)->gpu_addr; - - retval = mm->update_mqd(mm, m, q); - - return retval; -} - -static void uninit_mqd(struct mqd_manager *mm, void *mqd, - struct kfd_mem_obj *mqd_mem_obj) -{ - BUG_ON(!mm || !mqd); - kfd_gtt_sa_free(mm->dev, mqd_mem_obj); -} - -static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd, - struct kfd_mem_obj *mqd_mem_obj) -{ - BUG_ON(!mm || !mqd); - kfd_gtt_sa_free(mm->dev, mqd_mem_obj); -} - -static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id, - uint32_t queue_id, uint32_t __user *wptr) -{ - return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr); -} - -static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, - uint32_t pipe_id, uint32_t queue_id, - uint32_t __user *wptr) -{ - return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd); -} - -static int update_mqd(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) -{ - struct cik_mqd *m; - - BUG_ON(!mm || !q || !mqd); - - pr_debug("kfd: In func %s\n", __func__); - - m = get_mqd(mqd); - m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE | - DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN; - - /* - * Calculating queue size which is log base 2 of actual queue size -1 - * dwords and another -1 for ffs - */ - m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int)) - - 1 - 1; - m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); - m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8); - m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr); - m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr); - m->cp_hqd_pq_doorbell_control = DOORBELL_EN | - DOORBELL_OFFSET(q->doorbell_off); - - m->cp_hqd_vmid = q->vmid; - - if (q->format == KFD_QUEUE_FORMAT_AQL) { - m->cp_hqd_iq_rptr = AQL_ENABLE; - m->cp_hqd_pq_control |= NO_UPDATE_RPTR; - } - - m->cp_hqd_active = 0; - q->is_active = false; - if (q->queue_size > 0 && - q->queue_address != 0 && - q->queue_percent > 0) { - m->cp_hqd_active = 1; - q->is_active = true; - } - - return 0; -} - -static int update_mqd_sdma(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) -{ - struct cik_sdma_rlc_registers *m; - - BUG_ON(!mm || !mqd || !q); - - m = get_sdma_mqd(mqd); - m->sdma_rlc_rb_cntl = - SDMA_RB_SIZE((ffs(q->queue_size / sizeof(unsigned int)))) | - SDMA_RB_VMID(q->vmid) | - SDMA_RPTR_WRITEBACK_ENABLE | - SDMA_RPTR_WRITEBACK_TIMER(6); - - m->sdma_rlc_rb_base = lower_32_bits(q->queue_address >> 8); - m->sdma_rlc_rb_base_hi = upper_32_bits(q->queue_address >> 8); - m->sdma_rlc_rb_rptr_addr_lo = lower_32_bits((uint64_t)q->read_ptr); - m->sdma_rlc_rb_rptr_addr_hi = upper_32_bits((uint64_t)q->read_ptr); - m->sdma_rlc_doorbell = SDMA_OFFSET(q->doorbell_off) | SDMA_DB_ENABLE; - m->sdma_rlc_virtual_addr = q->sdma_vm_addr; - - m->sdma_engine_id = q->sdma_engine_id; - m->sdma_queue_id = q->sdma_queue_id; - - q->is_active = false; - if (q->queue_size > 0 && - q->queue_address != 0 && - q->queue_percent > 0) { - m->sdma_rlc_rb_cntl |= SDMA_RB_ENABLE; - q->is_active = true; - } - - return 0; -} - -static int destroy_mqd(struct mqd_manager *mm, void *mqd, - enum kfd_preempt_type type, - unsigned int timeout, uint32_t pipe_id, - uint32_t queue_id) -{ - return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout, - pipe_id, queue_id); -} - -/* - * preempt type here is ignored because there is only one way - * to preempt sdma queue - */ -static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd, - enum kfd_preempt_type type, - unsigned int timeout, uint32_t pipe_id, - uint32_t queue_id) -{ - return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout); -} - -static bool is_occupied(struct mqd_manager *mm, void *mqd, - uint64_t queue_address, uint32_t pipe_id, - uint32_t queue_id) -{ - - return kfd2kgd->hqd_is_occupies(mm->dev->kgd, queue_address, - pipe_id, queue_id); - -} - -static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd, - uint64_t queue_address, uint32_t pipe_id, - uint32_t queue_id) -{ - return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd); -} - -/* - * HIQ MQD Implementation, concrete implementation for HIQ MQD implementation. - * The HIQ queue in Kaveri is using the same MQD structure as all the user mode - * queues but with different initial values. - */ - -static int init_mqd_hiq(struct mqd_manager *mm, void **mqd, - struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, - struct queue_properties *q) -{ - uint64_t addr; - struct cik_mqd *m; - int retval; - - BUG_ON(!mm || !q || !mqd || !mqd_mem_obj); - - pr_debug("kfd: In func %s\n", __func__); - - retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd), - mqd_mem_obj); - - if (retval != 0) - return -ENOMEM; - - m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr; - addr = (*mqd_mem_obj)->gpu_addr; - - memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256)); - - m->header = 0xC0310800; - m->compute_pipelinestat_enable = 1; - m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF; - m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF; - m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF; - m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF; - - m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE | - PRELOAD_REQ; - m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS | - QUANTUM_DURATION(10); - - m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN; - m->cp_mqd_base_addr_lo = lower_32_bits(addr); - m->cp_mqd_base_addr_hi = upper_32_bits(addr); - - m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE; - - /* - * Pipe Priority - * Identifies the pipe relative priority when this queue is connected - * to the pipeline. The pipe priority is against the GFX pipe and HP3D. - * In KFD we are using a fixed pipe priority set to CS_MEDIUM. - * 0 = CS_LOW (typically below GFX) - * 1 = CS_MEDIUM (typically between HP3D and GFX - * 2 = CS_HIGH (typically above HP3D) - */ - m->cp_hqd_pipe_priority = 1; - m->cp_hqd_queue_priority = 15; - - *mqd = m; - if (gart_addr) - *gart_addr = addr; - retval = mm->update_mqd(mm, m, q); - - return retval; -} - -static int update_mqd_hiq(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) -{ - struct cik_mqd *m; - - BUG_ON(!mm || !q || !mqd); - - pr_debug("kfd: In func %s\n", __func__); - - m = get_mqd(mqd); - m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE | - DEFAULT_MIN_AVAIL_SIZE | - PRIV_STATE | - KMD_QUEUE; - - /* - * Calculating queue size which is log base 2 of actual queue - * size -1 dwords - */ - m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int)) - - 1 - 1; - m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); - m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8); - m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr); - m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr); - m->cp_hqd_pq_doorbell_control = DOORBELL_EN | - DOORBELL_OFFSET(q->doorbell_off); - - m->cp_hqd_vmid = q->vmid; - - m->cp_hqd_active = 0; - q->is_active = false; - if (q->queue_size > 0 && - q->queue_address != 0 && - q->queue_percent > 0) { - m->cp_hqd_active = 1; - q->is_active = true; - } - - return 0; -} - -/* - * SDMA MQD Implementation - */ - -struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd) -{ - struct cik_sdma_rlc_registers *m; - - BUG_ON(!mqd); - - m = (struct cik_sdma_rlc_registers *)mqd; - - return m; -} struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, struct kfd_dev *dev) { - struct mqd_manager *mqd; - - BUG_ON(!dev); - BUG_ON(type >= KFD_MQD_TYPE_MAX); - - pr_debug("kfd: In func %s\n", __func__); - - mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL); - if (!mqd) - return NULL; - - mqd->dev = dev; - - switch (type) { - case KFD_MQD_TYPE_CP: - case KFD_MQD_TYPE_COMPUTE: - mqd->init_mqd = init_mqd; - mqd->uninit_mqd = uninit_mqd; - mqd->load_mqd = load_mqd; - mqd->update_mqd = update_mqd; - mqd->destroy_mqd = destroy_mqd; - mqd->is_occupied = is_occupied; - break; - case KFD_MQD_TYPE_HIQ: - mqd->init_mqd = init_mqd_hiq; - mqd->uninit_mqd = uninit_mqd; - mqd->load_mqd = load_mqd; - mqd->update_mqd = update_mqd_hiq; - mqd->destroy_mqd = destroy_mqd; - mqd->is_occupied = is_occupied; - break; - case KFD_MQD_TYPE_SDMA: - mqd->init_mqd = init_mqd_sdma; - mqd->uninit_mqd = uninit_mqd_sdma; - mqd->load_mqd = load_mqd_sdma; - mqd->update_mqd = update_mqd_sdma; - mqd->destroy_mqd = destroy_mqd_sdma; - mqd->is_occupied = is_occupied_sdma; - break; - default: - kfree(mqd); - return NULL; + switch (dev->device_info->asic_family) { + case CHIP_KAVERI: + return mqd_manager_init_cik(type, dev); + case CHIP_CARRIZO: + return mqd_manager_init_vi(type, dev); } - return mqd; + return NULL; } - -/* SDMA queues should be implemented here when the cp will supports them */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c new file mode 100644 index 0000000..7b28f6e --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -0,0 +1,454 @@ +/* + * 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 +#include +#include "kfd_priv.h" +#include "kfd_mqd_manager.h" +#include "cik_regs.h" +#include "cik_structs.h" + +inline void busy_wait(unsigned long ms) +{ + while (time_before(jiffies, ms)) + cpu_relax(); +} + +static inline struct cik_mqd *get_mqd(void *mqd) +{ + return (struct cik_mqd *)mqd; +} + +static int init_mqd(struct mqd_manager *mm, void **mqd, + struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, + struct queue_properties *q) +{ + uint64_t addr; + struct cik_mqd *m; + int retval; + + BUG_ON(!mm || !q || !mqd); + + pr_debug("kfd: In func %s\n", __func__); + + retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd), + mqd_mem_obj); + + if (retval != 0) + return -ENOMEM; + + m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr; + addr = (*mqd_mem_obj)->gpu_addr; + + memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256)); + + m->header = 0xC0310800; + m->compute_pipelinestat_enable = 1; + m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF; + + /* + * Make sure to use the last queue state saved on mqd when the cp + * reassigns the queue, so when queue is switched on/off (e.g over + * subscription or quantum timeout) the context will be consistent + */ + m->cp_hqd_persistent_state = + DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ; + + m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN; + m->cp_mqd_base_addr_lo = lower_32_bits(addr); + m->cp_mqd_base_addr_hi = upper_32_bits(addr); + + m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN; + /* Although WinKFD writes this, I suspect it should not be necessary */ + m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE; + + m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS | + QUANTUM_DURATION(10); + + /* + * Pipe Priority + * Identifies the pipe relative priority when this queue is connected + * to the pipeline. The pipe priority is against the GFX pipe and HP3D. + * In KFD we are using a fixed pipe priority set to CS_MEDIUM. + * 0 = CS_LOW (typically below GFX) + * 1 = CS_MEDIUM (typically between HP3D and GFX + * 2 = CS_HIGH (typically above HP3D) + */ + m->cp_hqd_pipe_priority = 1; + m->cp_hqd_queue_priority = 15; + + *mqd = m; + if (gart_addr != NULL) + *gart_addr = addr; + retval = mm->update_mqd(mm, m, q); + + return retval; +} + +static int init_mqd_sdma(struct mqd_manager *mm, void **mqd, + struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, + struct queue_properties *q) +{ + int retval; + struct cik_sdma_rlc_registers *m; + + BUG_ON(!mm || !mqd || !mqd_mem_obj); + + retval = kfd_gtt_sa_allocate(mm->dev, + sizeof(struct cik_sdma_rlc_registers), + mqd_mem_obj); + + if (retval != 0) + return -ENOMEM; + + m = (struct cik_sdma_rlc_registers *) (*mqd_mem_obj)->cpu_ptr; + + memset(m, 0, sizeof(struct cik_sdma_rlc_registers)); + + *mqd = m; + if (gart_addr != NULL) + *gart_addr = (*mqd_mem_obj)->gpu_addr; + + retval = mm->update_mqd(mm, m, q); + + return retval; +} + +static void uninit_mqd(struct mqd_manager *mm, void *mqd, + struct kfd_mem_obj *mqd_mem_obj) +{ + BUG_ON(!mm || !mqd); + kfd_gtt_sa_free(mm->dev, mqd_mem_obj); +} + +static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd, + struct kfd_mem_obj *mqd_mem_obj) +{ + BUG_ON(!mm || !mqd); + kfd_gtt_sa_free(mm->dev, mqd_mem_obj); +} + +static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id, + uint32_t queue_id, uint32_t __user *wptr) +{ + return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr); +} + +static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, + uint32_t pipe_id, uint32_t queue_id, + uint32_t __user *wptr) +{ + return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd); +} + +static int update_mqd(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + struct cik_mqd *m; + + BUG_ON(!mm || !q || !mqd); + + pr_debug("kfd: In func %s\n", __func__); + + m = get_mqd(mqd); + m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE | + DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN; + + /* + * Calculating queue size which is log base 2 of actual queue size -1 + * dwords and another -1 for ffs + */ + m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int)) + - 1 - 1; + m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); + m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8); + m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr); + m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr); + m->cp_hqd_pq_doorbell_control = DOORBELL_EN | + DOORBELL_OFFSET(q->doorbell_off); + + m->cp_hqd_vmid = q->vmid; + + if (q->format == KFD_QUEUE_FORMAT_AQL) { + m->cp_hqd_iq_rptr = AQL_ENABLE; + m->cp_hqd_pq_control |= NO_UPDATE_RPTR; + } + + m->cp_hqd_active = 0; + q->is_active = false; + if (q->queue_size > 0 && + q->queue_address != 0 && + q->queue_percent > 0) { + m->cp_hqd_active = 1; + q->is_active = true; + } + + return 0; +} + +static int update_mqd_sdma(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + struct cik_sdma_rlc_registers *m; + + BUG_ON(!mm || !mqd || !q); + + m = get_sdma_mqd(mqd); + m->sdma_rlc_rb_cntl = + SDMA_RB_SIZE((ffs(q->queue_size / sizeof(unsigned int)))) | + SDMA_RB_VMID(q->vmid) | + SDMA_RPTR_WRITEBACK_ENABLE | + SDMA_RPTR_WRITEBACK_TIMER(6); + + m->sdma_rlc_rb_base = lower_32_bits(q->queue_address >> 8); + m->sdma_rlc_rb_base_hi = upper_32_bits(q->queue_address >> 8); + m->sdma_rlc_rb_rptr_addr_lo = lower_32_bits((uint64_t)q->read_ptr); + m->sdma_rlc_rb_rptr_addr_hi = upper_32_bits((uint64_t)q->read_ptr); + m->sdma_rlc_doorbell = SDMA_OFFSET(q->doorbell_off) | SDMA_DB_ENABLE; + m->sdma_rlc_virtual_addr = q->sdma_vm_addr; + + m->sdma_engine_id = q->sdma_engine_id; + m->sdma_queue_id = q->sdma_queue_id; + + q->is_active = false; + if (q->queue_size > 0 && + q->queue_address != 0 && + q->queue_percent > 0) { + m->sdma_rlc_rb_cntl |= SDMA_RB_ENABLE; + q->is_active = true; + } + + return 0; +} + +static int destroy_mqd(struct mqd_manager *mm, void *mqd, + enum kfd_preempt_type type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id) +{ + return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout, + pipe_id, queue_id); +} + +/* + * preempt type here is ignored because there is only one way + * to preempt sdma queue + */ +static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd, + enum kfd_preempt_type type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id) +{ + return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout); +} + +static bool is_occupied(struct mqd_manager *mm, void *mqd, + uint64_t queue_address, uint32_t pipe_id, + uint32_t queue_id) +{ + + return kfd2kgd->hqd_is_occupies(mm->dev->kgd, queue_address, + pipe_id, queue_id); + +} + +static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd, + uint64_t queue_address, uint32_t pipe_id, + uint32_t queue_id) +{ + return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd); +} + +/* + * HIQ MQD Implementation, concrete implementation for HIQ MQD implementation. + * The HIQ queue in Kaveri is using the same MQD structure as all the user mode + * queues but with different initial values. + */ + +static int init_mqd_hiq(struct mqd_manager *mm, void **mqd, + struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, + struct queue_properties *q) +{ + uint64_t addr; + struct cik_mqd *m; + int retval; + + BUG_ON(!mm || !q || !mqd || !mqd_mem_obj); + + pr_debug("kfd: In func %s\n", __func__); + + retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd), + mqd_mem_obj); + + if (retval != 0) + return -ENOMEM; + + m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr; + addr = (*mqd_mem_obj)->gpu_addr; + + memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256)); + + m->header = 0xC0310800; + m->compute_pipelinestat_enable = 1; + m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF; + + m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE | + PRELOAD_REQ; + m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS | + QUANTUM_DURATION(10); + + m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN; + m->cp_mqd_base_addr_lo = lower_32_bits(addr); + m->cp_mqd_base_addr_hi = upper_32_bits(addr); + + m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE; + + /* + * Pipe Priority + * Identifies the pipe relative priority when this queue is connected + * to the pipeline. The pipe priority is against the GFX pipe and HP3D. + * In KFD we are using a fixed pipe priority set to CS_MEDIUM. + * 0 = CS_LOW (typically below GFX) + * 1 = CS_MEDIUM (typically between HP3D and GFX + * 2 = CS_HIGH (typically above HP3D) + */ + m->cp_hqd_pipe_priority = 1; + m->cp_hqd_queue_priority = 15; + + *mqd = m; + if (gart_addr) + *gart_addr = addr; + retval = mm->update_mqd(mm, m, q); + + return retval; +} + +static int update_mqd_hiq(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + struct cik_mqd *m; + + BUG_ON(!mm || !q || !mqd); + + pr_debug("kfd: In func %s\n", __func__); + + m = get_mqd(mqd); + m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE | + DEFAULT_MIN_AVAIL_SIZE | + PRIV_STATE | + KMD_QUEUE; + + /* + * Calculating queue size which is log base 2 of actual queue + * size -1 dwords + */ + m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int)) + - 1 - 1; + m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); + m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8); + m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr); + m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr); + m->cp_hqd_pq_doorbell_control = DOORBELL_EN | + DOORBELL_OFFSET(q->doorbell_off); + + m->cp_hqd_vmid = q->vmid; + + m->cp_hqd_active = 0; + q->is_active = false; + if (q->queue_size > 0 && + q->queue_address != 0 && + q->queue_percent > 0) { + m->cp_hqd_active = 1; + q->is_active = true; + } + + return 0; +} + +struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd) +{ + struct cik_sdma_rlc_registers *m; + + BUG_ON(!mqd); + + m = (struct cik_sdma_rlc_registers *)mqd; + + return m; +} + +struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type, + struct kfd_dev *dev) +{ + struct mqd_manager *mqd; + + BUG_ON(!dev); + BUG_ON(type >= KFD_MQD_TYPE_MAX); + + pr_debug("kfd: In func %s\n", __func__); + + mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL); + if (!mqd) + return NULL; + + mqd->dev = dev; + + switch (type) { + case KFD_MQD_TYPE_CP: + case KFD_MQD_TYPE_COMPUTE: + mqd->init_mqd = init_mqd; + mqd->uninit_mqd = uninit_mqd; + mqd->load_mqd = load_mqd; + mqd->update_mqd = update_mqd; + mqd->destroy_mqd = destroy_mqd; + mqd->is_occupied = is_occupied; + break; + case KFD_MQD_TYPE_HIQ: + mqd->init_mqd = init_mqd_hiq; + mqd->uninit_mqd = uninit_mqd; + mqd->load_mqd = load_mqd; + mqd->update_mqd = update_mqd_hiq; + mqd->destroy_mqd = destroy_mqd; + mqd->is_occupied = is_occupied; + break; + case KFD_MQD_TYPE_SDMA: + mqd->init_mqd = init_mqd_sdma; + mqd->uninit_mqd = uninit_mqd_sdma; + mqd->load_mqd = load_mqd_sdma; + mqd->update_mqd = update_mqd_sdma; + mqd->destroy_mqd = destroy_mqd_sdma; + mqd->is_occupied = is_occupied_sdma; + break; + default: + kfree(mqd); + return NULL; + } + + return mqd; +} + diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c new file mode 100644 index 0000000..b3a7e3b --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -0,0 +1,33 @@ +/* + * 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 +#include "kfd_priv.h" +#include "kfd_mqd_manager.h" + +struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type, + struct kfd_dev *dev) +{ + pr_warn("amdkfd: VI MQD is not currently supported\n"); + return NULL; +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 872a1da..bfcf45f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -573,6 +573,10 @@ void print_queue(struct queue *q); struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, struct kfd_dev *dev); +struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type, + struct kfd_dev *dev); +struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type, + struct kfd_dev *dev); struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev); void device_queue_manager_uninit(struct device_queue_manager *dqm); struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, -- cgit v0.10.2 From 04df25d123945a2261a7755673962257241b1394 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 5 Jan 2015 18:15:45 +0200 Subject: MAINTAINERS: Update amdkfd files Add two files under amdkfd section. Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/MAINTAINERS b/MAINTAINERS index ddb9ac8..23fa31d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -624,6 +624,8 @@ L: dri-devel@lists.freedesktop.org T: git git://people.freedesktop.org/~gabbayo/linux.git S: Supported F: drivers/gpu/drm/amd/amdkfd/ +F: drivers/gpu/drm/amd/include/cik_structs.h +F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h F: drivers/gpu/drm/radeon/radeon_kfd.c F: drivers/gpu/drm/radeon/radeon_kfd.h F: include/uapi/linux/kfd_ioctl.h -- cgit v0.10.2 From c2e1b3a496332b90d073bc9dddd3324d660fca24 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Mon, 18 Aug 2014 14:55:59 +0300 Subject: drm/amdkfd: Fix logic of destroy_queue_nocpsch() This patch rewrites destroy_queue_nocpsch() as the current logic that is implemented in the function is completely flawed. This function is used only in non-HWS mode. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Acked-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 3d5f71a..c83f011 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -294,7 +294,8 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, struct queue *q) { int retval; - struct mqd_manager *mqd, *mqd_sdma; + struct mqd_manager *mqd; + BUG_ON(!dqm || !q || !q->mqd || !qpd); retval = 0; @@ -302,33 +303,32 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, pr_debug("kfd: In Func %s\n", __func__); mutex_lock(&dqm->lock); - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); - if (mqd == NULL) { - retval = -ENOMEM; - goto out; - } - mqd_sdma = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); - if (mqd_sdma == NULL) { - mutex_unlock(&dqm->lock); - return -ENOMEM; + if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) { + mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); + if (mqd == NULL) { + retval = -ENOMEM; + goto out; + } + deallocate_hqd(dqm, q); + } else if (q->properties.type == KFD_QUEUE_TYPE_SDMA) { + mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); + if (mqd == NULL) { + retval = -ENOMEM; + goto out; + } + dqm->sdma_queue_count--; + deallocate_sdma_queue(dqm, q->sdma_id); } retval = mqd->destroy_mqd(mqd, q->mqd, - KFD_PREEMPT_TYPE_WAVEFRONT, + KFD_PREEMPT_TYPE_WAVEFRONT_RESET, QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS, q->pipe, q->queue); if (retval != 0) goto out; - if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) - deallocate_hqd(dqm, q); - else if (q->properties.type == KFD_QUEUE_TYPE_SDMA) { - dqm->sdma_queue_count--; - deallocate_sdma_queue(dqm, q->sdma_id); - } - mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj); list_del(&q->list); -- cgit v0.10.2 From 9216ed294053be68a673754a0f8da88aa7fb7941 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 12 Jan 2015 22:34:21 +0200 Subject: drm/amdkfd: Don't BUG on freeing GART sub-allocation Instead of creating a BUG if trying to free a NULL GART sub-allocation object, just return 0 (success). This is done to mirror behavior of kfree. Signed-off-by: Oded Gabbay diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 24b37ff..a23ed24 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -511,7 +511,10 @@ int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj) unsigned int bit; BUG_ON(!kfd); - BUG_ON(!mem_obj); + + /* Act like kfree when trying to free a NULL object */ + if (!mem_obj) + return 0; pr_debug("kfd: free mem_obj = %p, range_start = %d, range_end = %d\n", mem_obj, mem_obj->range_start, mem_obj->range_end); -- cgit v0.10.2 From 45c9a5e4297b9a07d94ff8195ff6f21ba3581ad6 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 12 Jan 2015 14:26:10 +0200 Subject: drm/amdkfd: Encapsulate DQM functions in ops structure This patch does some re-org on the device_queue_manager structure. It takes out all the function pointers from the structure and puts them in a new structure, called device_queue_manager_ops. Then, it puts an instance of that structure inside device_queue_manager. This re-org is done to prepare the DQM module to support more than one AMD APU (Kaveri). Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index b008fd6..38b6150 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -439,7 +439,7 @@ static long kfd_ioctl_set_memory_policy(struct file *filep, (args.alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT) ? cache_policy_coherent : cache_policy_noncoherent; - if (!dev->dqm->set_cache_memory_policy(dev->dqm, + if (!dev->dqm->ops.set_cache_memory_policy(dev->dqm, &pdd->qpd, default_policy, alternate_policy, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index a23ed24..a770ec6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -253,7 +253,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, goto device_queue_manager_error; } - if (kfd->dqm->start(kfd->dqm) != 0) { + if (kfd->dqm->ops.start(kfd->dqm) != 0) { dev_err(kfd_device, "Error starting queuen manager for device (%x:%x)\n", kfd->pdev->vendor, kfd->pdev->device); @@ -307,7 +307,7 @@ void kgd2kfd_suspend(struct kfd_dev *kfd) BUG_ON(kfd == NULL); if (kfd->init_complete) { - kfd->dqm->stop(kfd->dqm); + kfd->dqm->ops.stop(kfd->dqm); amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL); amd_iommu_free_device(kfd->pdev); } @@ -328,7 +328,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd) return -ENXIO; amd_iommu_set_invalidate_ctx_cb(kfd->pdev, iommu_pasid_shutdown_callback); - kfd->dqm->start(kfd->dqm); + kfd->dqm->ops.start(kfd->dqm); } return 0; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index c83f011..12c8448 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -271,7 +271,7 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm, BUG_ON(!dqm || !q || !qpd); - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); + mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); if (mqd == NULL) return -ENOMEM; @@ -305,14 +305,14 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, mutex_lock(&dqm->lock); if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) { - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); + mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); if (mqd == NULL) { retval = -ENOMEM; goto out; } deallocate_hqd(dqm, q); } else if (q->properties.type == KFD_QUEUE_TYPE_SDMA) { - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); + mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); if (mqd == NULL) { retval = -ENOMEM; goto out; @@ -348,7 +348,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) BUG_ON(!dqm || !q || !q->mqd); mutex_lock(&dqm->lock); - mqd = dqm->get_mqd_manager(dqm, q->properties.type); + mqd = dqm->ops.get_mqd_manager(dqm, q->properties.type); if (mqd == NULL) { mutex_unlock(&dqm->lock); return -ENOMEM; @@ -515,7 +515,7 @@ static int init_pipelines(struct device_queue_manager *dqm, memset(hpdptr, 0, CIK_HPD_EOP_BYTES * pipes_num); - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); + mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); if (mqd == NULL) { kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem); return -ENOMEM; @@ -646,7 +646,7 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, struct mqd_manager *mqd; int retval; - mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); + mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); if (!mqd) return -ENOMEM; @@ -849,7 +849,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, if (q->properties.type == KFD_QUEUE_TYPE_SDMA) select_sdma_engine_id(q); - mqd = dqm->get_mqd_manager(dqm, + mqd = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); if (mqd == NULL) { @@ -994,7 +994,7 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, /* remove queue from list to prevent rescheduling after preemption */ mutex_lock(&dqm->lock); - mqd = dqm->get_mqd_manager(dqm, + mqd = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); if (!mqd) { retval = -ENOMEM; @@ -1116,40 +1116,40 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) case KFD_SCHED_POLICY_HWS: case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION: /* initialize dqm for cp scheduling */ - dqm->create_queue = create_queue_cpsch; - dqm->initialize = initialize_cpsch; - dqm->start = start_cpsch; - dqm->stop = stop_cpsch; - dqm->destroy_queue = destroy_queue_cpsch; - dqm->update_queue = update_queue; - dqm->get_mqd_manager = get_mqd_manager_nocpsch; - dqm->register_process = register_process_nocpsch; - dqm->unregister_process = unregister_process_nocpsch; - dqm->uninitialize = uninitialize_nocpsch; - dqm->create_kernel_queue = create_kernel_queue_cpsch; - dqm->destroy_kernel_queue = destroy_kernel_queue_cpsch; - dqm->set_cache_memory_policy = set_cache_memory_policy; + dqm->ops.create_queue = create_queue_cpsch; + dqm->ops.initialize = initialize_cpsch; + dqm->ops.start = start_cpsch; + dqm->ops.stop = stop_cpsch; + dqm->ops.destroy_queue = destroy_queue_cpsch; + dqm->ops.update_queue = update_queue; + dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch; + dqm->ops.register_process = register_process_nocpsch; + dqm->ops.unregister_process = unregister_process_nocpsch; + dqm->ops.uninitialize = uninitialize_nocpsch; + dqm->ops.create_kernel_queue = create_kernel_queue_cpsch; + dqm->ops.destroy_kernel_queue = destroy_kernel_queue_cpsch; + dqm->ops.set_cache_memory_policy = set_cache_memory_policy; break; case KFD_SCHED_POLICY_NO_HWS: /* initialize dqm for no cp scheduling */ - dqm->start = start_nocpsch; - dqm->stop = stop_nocpsch; - dqm->create_queue = create_queue_nocpsch; - dqm->destroy_queue = destroy_queue_nocpsch; - dqm->update_queue = update_queue; - dqm->get_mqd_manager = get_mqd_manager_nocpsch; - dqm->register_process = register_process_nocpsch; - dqm->unregister_process = unregister_process_nocpsch; - dqm->initialize = initialize_nocpsch; - dqm->uninitialize = uninitialize_nocpsch; - dqm->set_cache_memory_policy = set_cache_memory_policy; + dqm->ops.start = start_nocpsch; + dqm->ops.stop = stop_nocpsch; + dqm->ops.create_queue = create_queue_nocpsch; + dqm->ops.destroy_queue = destroy_queue_nocpsch; + dqm->ops.update_queue = update_queue; + dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch; + dqm->ops.register_process = register_process_nocpsch; + dqm->ops.unregister_process = unregister_process_nocpsch; + dqm->ops.initialize = initialize_nocpsch; + dqm->ops.uninitialize = uninitialize_nocpsch; + dqm->ops.set_cache_memory_policy = set_cache_memory_policy; break; default: BUG(); break; } - if (dqm->initialize(dqm) != 0) { + if (dqm->ops.initialize(dqm) != 0) { kfree(dqm); return NULL; } @@ -1161,7 +1161,7 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm) { BUG_ON(!dqm); - dqm->uninitialize(dqm); + dqm->ops.uninitialize(dqm); kfree(dqm); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 554c06e..72d2ca0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -46,7 +46,7 @@ struct device_process_node { }; /** - * struct device_queue_manager + * struct device_queue_manager_ops * * @create_queue: Queue creation routine. * @@ -81,15 +81,9 @@ struct device_process_node { * @set_cache_memory_policy: Sets memory policy (cached/ non cached) for the * memory apertures. * - * This struct is a base class for the kfd queues scheduler in the - * device level. The device base class should expose the basic operations - * for queue creation and queue destruction. This base class hides the - * scheduling mode of the driver and the specific implementation of the - * concrete device. This class is the only class in the queues scheduler - * that configures the H/W. */ -struct device_queue_manager { +struct device_queue_manager_ops { int (*create_queue)(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd, @@ -124,7 +118,22 @@ struct device_queue_manager { enum cache_policy alternate_policy, void __user *alternate_aperture_base, uint64_t alternate_aperture_size); +}; + +/** + * struct device_queue_manager + * + * This struct is a base class for the kfd queues scheduler in the + * device level. The device base class should expose the basic operations + * for queue creation and queue destruction. This base class hides the + * scheduling mode of the driver and the specific implementation of the + * concrete device. This class is the only class in the queues scheduler + * that configures the H/W. + * + */ +struct device_queue_manager { + struct device_queue_manager_ops ops; struct mqd_manager *mqds[KFD_MQD_TYPE_MAX]; struct packet_manager packets; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 773c213..add0fb4 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -56,7 +56,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, switch (type) { case KFD_QUEUE_TYPE_DIQ: case KFD_QUEUE_TYPE_HIQ: - kq->mqd = dev->dqm->get_mqd_manager(dev->dqm, + kq->mqd = dev->dqm->ops.get_mqd_manager(dev->dqm, KFD_MQD_TYPE_HIQ); break; default: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 948b1ca..513eeb6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -178,7 +178,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, if (list_empty(&pqm->queues)) { pdd->qpd.pqm = pqm; - dev->dqm->register_process(dev->dqm, &pdd->qpd); + dev->dqm->ops.register_process(dev->dqm, &pdd->qpd); } pqn = kzalloc(sizeof(struct process_queue_node), GFP_KERNEL); @@ -204,7 +204,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, goto err_create_queue; pqn->q = q; pqn->kq = NULL; - retval = dev->dqm->create_queue(dev->dqm, q, &pdd->qpd, + retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd, &q->properties.vmid); print_queue(q); break; @@ -217,7 +217,8 @@ int pqm_create_queue(struct process_queue_manager *pqm, kq->queue->properties.queue_id = *qid; pqn->kq = kq; pqn->q = NULL; - retval = dev->dqm->create_kernel_queue(dev->dqm, kq, &pdd->qpd); + retval = dev->dqm->ops.create_kernel_queue(dev->dqm, + kq, &pdd->qpd); break; default: BUG(); @@ -285,13 +286,13 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) if (pqn->kq) { /* destroy kernel queue (DIQ) */ dqm = pqn->kq->dev->dqm; - dqm->destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd); + dqm->ops.destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd); kernel_queue_uninit(pqn->kq); } if (pqn->q) { dqm = pqn->q->device->dqm; - retval = dqm->destroy_queue(dqm, &pdd->qpd, pqn->q); + retval = dqm->ops.destroy_queue(dqm, &pdd->qpd, pqn->q); if (retval != 0) return retval; @@ -303,7 +304,7 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) clear_bit(qid, pqm->queue_slot_bitmap); if (list_empty(&pqm->queues)) - dqm->unregister_process(dqm, &pdd->qpd); + dqm->ops.unregister_process(dqm, &pdd->qpd); return retval; } @@ -324,7 +325,8 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, pqn->q->properties.queue_percent = p->queue_percent; pqn->q->properties.priority = p->priority; - retval = pqn->q->device->dqm->update_queue(pqn->q->device->dqm, pqn->q); + retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm, + pqn->q); if (retval != 0) return retval; -- cgit v0.10.2 From a22fc85495575d81c36db24b12f66fd314b7ced1 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Mon, 12 Jan 2015 14:28:46 +0200 Subject: drm/amdkfd: Add initial VI support for DQM This patch starts to add support for the VI APU in the DQM module. Because most (more than 90%) of the DQM code is shared among AMD's APUs, we chose a design that performs most/all the code in the shared DQM file (kfd_device_queue_manager.c). If there is H/W specific code to be executed, than it is written in an asic-specific extension function for that H/W. That asic-specific extension function is called from the shared function at the appropriate time. This requires that for every asic-specific extension function that is implemented in a specific ASIC, there will be an equivalent implementation in ALL ASICs, even if those implementations are just stubs. That way we achieve: - Maintainability: by having one copy of most of the code, we only need to fix bugs at one locations - Readability: very clear what is the shared code and what is done per ASIC - Extensibility: very easy to add new H/W specific files/functions Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile index bc6053f..7558683 100644 --- a/drivers/gpu/drm/amd/amdkfd/Makefile +++ b/drivers/gpu/drm/amd/amdkfd/Makefile @@ -10,6 +10,7 @@ amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ kfd_mqd_manager_cik.o kfd_mqd_manager_vi.o \ kfd_kernel_queue.o kfd_packet_manager.o \ kfd_process_queue_manager.o kfd_device_queue_manager.o \ + kfd_device_queue_manager_cik.o kfd_device_queue_manager_vi.o \ kfd_interrupt.o obj-$(CONFIG_HSA_AMD) += amdkfd.o diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 12c8448..b201624 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -61,7 +61,7 @@ enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type) return KFD_MQD_TYPE_CP; } -static inline unsigned int get_pipes_num(struct device_queue_manager *dqm) +inline unsigned int get_pipes_num(struct device_queue_manager *dqm) { BUG_ON(!dqm || !dqm->dev); return dqm->dev->shared_resources.compute_pipe_count; @@ -78,7 +78,7 @@ static inline unsigned int get_pipes_num_cpsch(void) return PIPE_PER_ME_CP_SCHEDULING; } -static inline unsigned int +inline unsigned int get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd) { uint32_t nybble; @@ -88,7 +88,7 @@ get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd) return nybble; } -static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd) +inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd) { unsigned int shared_base; @@ -97,41 +97,7 @@ static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd) return shared_base; } -static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble); -static void init_process_memory(struct device_queue_manager *dqm, - struct qcm_process_device *qpd) -{ - struct kfd_process_device *pdd; - unsigned int temp; - - BUG_ON(!dqm || !qpd); - - pdd = qpd_to_pdd(qpd); - - /* check if sh_mem_config register already configured */ - if (qpd->sh_mem_config == 0) { - qpd->sh_mem_config = - ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) | - DEFAULT_MTYPE(MTYPE_NONCACHED) | - APE1_MTYPE(MTYPE_NONCACHED); - qpd->sh_mem_ape1_limit = 0; - qpd->sh_mem_ape1_base = 0; - } - - if (qpd->pqm->process->is_32bit_user_mode) { - temp = get_sh_mem_bases_32(pdd); - qpd->sh_mem_bases = SHARED_BASE(temp); - qpd->sh_mem_config |= PTR32; - } else { - temp = get_sh_mem_bases_nybble_64(pdd); - qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); - } - - pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n", - qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases); -} - -static void program_sh_mem_settings(struct device_queue_manager *dqm, +void program_sh_mem_settings(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { return kfd2kgd->program_sh_mem_settings(dqm->dev->kgd, qpd->vmid, @@ -391,6 +357,7 @@ static int register_process_nocpsch(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { struct device_process_node *n; + int retval; BUG_ON(!dqm || !qpd); @@ -405,12 +372,13 @@ static int register_process_nocpsch(struct device_queue_manager *dqm, mutex_lock(&dqm->lock); list_add(&n->list, &dqm->queues); - init_process_memory(dqm, qpd); + retval = dqm->ops_asic_specific.register_process(dqm, qpd); + dqm->processes_count++; mutex_unlock(&dqm->lock); - return 0; + return retval; } static int unregister_process_nocpsch(struct device_queue_manager *dqm, @@ -455,34 +423,7 @@ set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid, vmid); } -static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble) -{ - /* In 64-bit mode, we can only control the top 3 bits of the LDS, - * scratch and GPUVM apertures. - * The hardware fills in the remaining 59 bits according to the - * following pattern: - * LDS: X0000000'00000000 - X0000001'00000000 (4GB) - * Scratch: X0000001'00000000 - X0000002'00000000 (4GB) - * GPUVM: Y0010000'00000000 - Y0020000'00000000 (1TB) - * - * (where X/Y is the configurable nybble with the low-bit 0) - * - * LDS and scratch will have the same top nybble programmed in the - * top 3 bits of SH_MEM_BASES.PRIVATE_BASE. - * GPUVM can have a different top nybble programmed in the - * top 3 bits of SH_MEM_BASES.SHARED_BASE. - * We don't bother to support different top nybbles - * for LDS/Scratch and GPUVM. - */ - - BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE || - top_address_nybble == 0); - - return PRIVATE_BASE(top_address_nybble << 12) | - SHARED_BASE(top_address_nybble << 12); -} - -static int init_pipelines(struct device_queue_manager *dqm, +int init_pipelines(struct device_queue_manager *dqm, unsigned int pipes_num, unsigned int first_pipe) { void *hpdptr; @@ -715,7 +656,7 @@ static int initialize_cpsch(struct device_queue_manager *dqm) dqm->queue_count = dqm->processes_count = 0; dqm->sdma_queue_count = 0; dqm->active_runlist = false; - retval = init_pipelines(dqm, get_pipes_num(dqm), 0); + retval = dqm->ops_asic_specific.initialize(dqm); if (retval != 0) goto fail_init_pipelines; @@ -1035,8 +976,7 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, void __user *alternate_aperture_base, uint64_t alternate_aperture_size) { - uint32_t default_mtype; - uint32_t ape1_mtype; + bool retval; pr_debug("kfd: In func %s\n", __func__); @@ -1073,18 +1013,13 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, qpd->sh_mem_ape1_limit = limit >> 16; } - default_mtype = (default_policy == cache_policy_coherent) ? - MTYPE_NONCACHED : - MTYPE_CACHED; - - ape1_mtype = (alternate_policy == cache_policy_coherent) ? - MTYPE_NONCACHED : - MTYPE_CACHED; - - qpd->sh_mem_config = (qpd->sh_mem_config & PTR32) - | ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) - | DEFAULT_MTYPE(default_mtype) - | APE1_MTYPE(ape1_mtype); + retval = dqm->ops_asic_specific.set_cache_memory_policy( + dqm, + qpd, + default_policy, + alternate_policy, + alternate_aperture_base, + alternate_aperture_size); if ((sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0)) program_sh_mem_settings(dqm, qpd); @@ -1094,7 +1029,7 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, qpd->sh_mem_ape1_limit); mutex_unlock(&dqm->lock); - return true; + return retval; out: mutex_unlock(&dqm->lock); @@ -1107,6 +1042,8 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) BUG_ON(!dev); + pr_debug("kfd: loading device queue manager\n"); + dqm = kzalloc(sizeof(struct device_queue_manager), GFP_KERNEL); if (!dqm) return NULL; @@ -1149,6 +1086,13 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) break; } + switch (dev->device_info->asic_family) { + case CHIP_CARRIZO: + device_queue_manager_init_vi(&dqm->ops_asic_specific); + case CHIP_KAVERI: + device_queue_manager_init_cik(&dqm->ops_asic_specific); + } + if (dqm->ops.initialize(dqm) != 0) { kfree(dqm); return NULL; @@ -1164,4 +1108,3 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm) dqm->ops.uninitialize(dqm); kfree(dqm); } - diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 72d2ca0..1934795 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -134,6 +134,7 @@ struct device_queue_manager_ops { struct device_queue_manager { struct device_queue_manager_ops ops; + struct device_queue_manager_ops ops_asic_specific; struct mqd_manager *mqds[KFD_MQD_TYPE_MAX]; struct packet_manager packets; @@ -155,6 +156,14 @@ struct device_queue_manager { bool active_runlist; }; - +void device_queue_manager_init_cik(struct device_queue_manager_ops *ops); +void device_queue_manager_init_vi(struct device_queue_manager_ops *ops); +void program_sh_mem_settings(struct device_queue_manager *dqm, + struct qcm_process_device *qpd); +inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *qpd); +inline unsigned int get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd); +int init_pipelines(struct device_queue_manager *dqm, + unsigned int pipes_num, unsigned int first_pipe); +inline unsigned int get_pipes_num(struct device_queue_manager *dqm); #endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c new file mode 100644 index 0000000..6b07246 --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c @@ -0,0 +1,135 @@ +/* + * 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 "kfd_device_queue_manager.h" +#include "cik_regs.h" + +static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, + enum cache_policy alternate_policy, + void __user *alternate_aperture_base, + uint64_t alternate_aperture_size); +static int register_process_cik(struct device_queue_manager *dqm, + struct qcm_process_device *qpd); +static int initialize_cpsch_cik(struct device_queue_manager *dqm); + +void device_queue_manager_init_cik(struct device_queue_manager_ops *ops) +{ + ops->set_cache_memory_policy = set_cache_memory_policy_cik; + ops->register_process = register_process_cik; + ops->initialize = initialize_cpsch_cik; +} + +static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble) +{ + /* In 64-bit mode, we can only control the top 3 bits of the LDS, + * scratch and GPUVM apertures. + * The hardware fills in the remaining 59 bits according to the + * following pattern: + * LDS: X0000000'00000000 - X0000001'00000000 (4GB) + * Scratch: X0000001'00000000 - X0000002'00000000 (4GB) + * GPUVM: Y0010000'00000000 - Y0020000'00000000 (1TB) + * + * (where X/Y is the configurable nybble with the low-bit 0) + * + * LDS and scratch will have the same top nybble programmed in the + * top 3 bits of SH_MEM_BASES.PRIVATE_BASE. + * GPUVM can have a different top nybble programmed in the + * top 3 bits of SH_MEM_BASES.SHARED_BASE. + * We don't bother to support different top nybbles + * for LDS/Scratch and GPUVM. + */ + + BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE || + top_address_nybble == 0); + + return PRIVATE_BASE(top_address_nybble << 12) | + SHARED_BASE(top_address_nybble << 12); +} + +static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, + enum cache_policy alternate_policy, + void __user *alternate_aperture_base, + uint64_t alternate_aperture_size) +{ + uint32_t default_mtype; + uint32_t ape1_mtype; + + default_mtype = (default_policy == cache_policy_coherent) ? + MTYPE_NONCACHED : + MTYPE_CACHED; + + ape1_mtype = (alternate_policy == cache_policy_coherent) ? + MTYPE_NONCACHED : + MTYPE_CACHED; + + qpd->sh_mem_config = (qpd->sh_mem_config & PTR32) + | ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) + | DEFAULT_MTYPE(default_mtype) + | APE1_MTYPE(ape1_mtype); + + return true; +} + +static int register_process_cik(struct device_queue_manager *dqm, + struct qcm_process_device *qpd) +{ + struct kfd_process_device *pdd; + unsigned int temp; + + BUG_ON(!dqm || !qpd); + + pdd = qpd_to_pdd(qpd); + + /* check if sh_mem_config register already configured */ + if (qpd->sh_mem_config == 0) { + qpd->sh_mem_config = + ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) | + DEFAULT_MTYPE(MTYPE_NONCACHED) | + APE1_MTYPE(MTYPE_NONCACHED); + qpd->sh_mem_ape1_limit = 0; + qpd->sh_mem_ape1_base = 0; + } + + if (qpd->pqm->process->is_32bit_user_mode) { + temp = get_sh_mem_bases_32(pdd); + qpd->sh_mem_bases = SHARED_BASE(temp); + qpd->sh_mem_config |= PTR32; + } else { + temp = get_sh_mem_bases_nybble_64(pdd); + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); + } + + pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n", + qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases); + + return 0; +} + +static int initialize_cpsch_cik(struct device_queue_manager *dqm) +{ + return init_pipelines(dqm, get_pipes_num(dqm), 0); +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c new file mode 100644 index 0000000..20553dc --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c @@ -0,0 +1,64 @@ +/* + * 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 "kfd_device_queue_manager.h" + +static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, + enum cache_policy alternate_policy, + void __user *alternate_aperture_base, + uint64_t alternate_aperture_size); +static int register_process_vi(struct device_queue_manager *dqm, + struct qcm_process_device *qpd); +static int initialize_cpsch_vi(struct device_queue_manager *dqm); + +void device_queue_manager_init_vi(struct device_queue_manager_ops *ops) +{ + pr_warn("amdkfd: VI DQM is not currently supported\n"); + + ops->set_cache_memory_policy = set_cache_memory_policy_vi; + ops->register_process = register_process_vi; + ops->initialize = initialize_cpsch_vi; +} + +static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, + enum cache_policy alternate_policy, + void __user *alternate_aperture_base, + uint64_t alternate_aperture_size) +{ + return false; +} + +static int register_process_vi(struct device_queue_manager *dqm, + struct qcm_process_device *qpd) +{ + return -1; +} + +static int initialize_cpsch_vi(struct device_queue_manager *dqm) +{ + return 0; +} -- cgit v0.10.2 From 443fbd5f115feba160a8d7ed6ac708cb91e3b955 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 12 Jan 2015 15:53:44 +0200 Subject: drm/amdkfd: Encapsulate KQ functions in ops structure This patch does some re-org on the kernel_queue structure. It takes out all the function pointers from the structure and puts them in a new structure, called kernel_queue_ops. Then, it puts an instance of that structure inside kernel_queue. This re-org is done to prepare the KQ module to support more than one AMD APU (Kaveri). Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index add0fb4..731635d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -293,14 +293,14 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, if (!kq) return NULL; - kq->initialize = initialize; - kq->uninitialize = uninitialize; - kq->acquire_packet_buffer = acquire_packet_buffer; - kq->submit_packet = submit_packet; - kq->sync_with_hw = sync_with_hw; - kq->rollback_packet = rollback_packet; - - if (kq->initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) { + kq->ops.initialize = initialize; + kq->ops.uninitialize = uninitialize; + kq->ops.acquire_packet_buffer = acquire_packet_buffer; + kq->ops.submit_packet = submit_packet; + kq->ops.sync_with_hw = sync_with_hw; + kq->ops.rollback_packet = rollback_packet; + + if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) { pr_err("kfd: failed to init kernel queue\n"); kfree(kq); return NULL; @@ -312,7 +312,7 @@ void kernel_queue_uninit(struct kernel_queue *kq) { BUG_ON(!kq); - kq->uninitialize(kq); + kq->ops.uninitialize(kq); kfree(kq); } @@ -329,12 +329,12 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev) kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ); BUG_ON(!kq); - retval = kq->acquire_packet_buffer(kq, 5, &buffer); + retval = kq->ops.acquire_packet_buffer(kq, 5, &buffer); BUG_ON(retval != 0); for (i = 0; i < 5; i++) buffer[i] = kq->nop_packet; - kq->submit_packet(kq); - kq->sync_with_hw(kq, 1000); + kq->ops.submit_packet(kq); + kq->ops.sync_with_hw(kq, 1000); pr_debug("kfd: ending kernel queue test\n"); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h index dcd2bdb..e01b77b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h @@ -28,8 +28,31 @@ #include #include "kfd_priv.h" -struct kernel_queue { - /* interface */ +/** + * struct kernel_queue_ops + * + * @initialize: Initialize a kernel queue, including allocations of GART memory + * needed for the queue. + * + * @uninitialize: Uninitialize a kernel queue and free all its memory usages. + * + * @acquire_packet_buffer: Returns a pointer to the location in the kernel + * queue ring buffer where the calling function can write its packet. It is + * Guaranteed that there is enough space for that packet. It also updates the + * pending write pointer to that location so subsequent calls to + * acquire_packet_buffer will get a correct write pointer + * + * @submit_packet: Update the write pointer and doorbell of a kernel queue. + * + * @sync_with_hw: Wait until the write pointer and the read pointer of a kernel + * queue are equal, which means the CP has read all the submitted packets. + * + * @rollback_packet: This routine is called if we failed to build an acquired + * packet for some reason. It just overwrites the pending wptr with the current + * one + * + */ +struct kernel_queue_ops { bool (*initialize)(struct kernel_queue *kq, struct kfd_dev *dev, enum kfd_queue_type type, unsigned int queue_size); void (*uninitialize)(struct kernel_queue *kq); @@ -41,6 +64,10 @@ struct kernel_queue { int (*sync_with_hw)(struct kernel_queue *kq, unsigned long timeout_ms); void (*rollback_packet)(struct kernel_queue *kq); +}; + +struct kernel_queue { + struct kernel_queue_ops ops; /* data */ struct kfd_dev *dev; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c index 3cda952..5fb5c03 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c @@ -348,7 +348,7 @@ int pm_send_set_resources(struct packet_manager *pm, pr_debug("kfd: In func %s\n", __func__); mutex_lock(&pm->lock); - pm->priv_queue->acquire_packet_buffer(pm->priv_queue, + pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue, sizeof(*packet) / sizeof(uint32_t), (unsigned int **)&packet); if (packet == NULL) { @@ -375,8 +375,8 @@ int pm_send_set_resources(struct packet_manager *pm, packet->queue_mask_lo = lower_32_bits(res->queue_mask); packet->queue_mask_hi = upper_32_bits(res->queue_mask); - pm->priv_queue->submit_packet(pm->priv_queue); - pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT); + pm->priv_queue->ops.submit_packet(pm->priv_queue); + pm->priv_queue->ops.sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT); mutex_unlock(&pm->lock); @@ -402,7 +402,7 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues) packet_size_dwords = sizeof(struct pm4_runlist) / sizeof(uint32_t); mutex_lock(&pm->lock); - retval = pm->priv_queue->acquire_packet_buffer(pm->priv_queue, + retval = pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue, packet_size_dwords, &rl_buffer); if (retval != 0) goto fail_acquire_packet_buffer; @@ -412,15 +412,15 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues) if (retval != 0) goto fail_create_runlist; - pm->priv_queue->submit_packet(pm->priv_queue); - pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT); + pm->priv_queue->ops.submit_packet(pm->priv_queue); + pm->priv_queue->ops.sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT); mutex_unlock(&pm->lock); return retval; fail_create_runlist: - pm->priv_queue->rollback_packet(pm->priv_queue); + pm->priv_queue->ops.rollback_packet(pm->priv_queue); fail_acquire_packet_buffer: mutex_unlock(&pm->lock); fail_create_runlist_ib: @@ -438,7 +438,7 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address, BUG_ON(!pm || !fence_address); mutex_lock(&pm->lock); - retval = pm->priv_queue->acquire_packet_buffer( + retval = pm->priv_queue->ops.acquire_packet_buffer( pm->priv_queue, sizeof(struct pm4_query_status) / sizeof(uint32_t), (unsigned int **)&packet); @@ -459,8 +459,8 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address, packet->data_hi = upper_32_bits((uint64_t)fence_value); packet->data_lo = lower_32_bits((uint64_t)fence_value); - pm->priv_queue->submit_packet(pm->priv_queue); - pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT); + pm->priv_queue->ops.submit_packet(pm->priv_queue); + pm->priv_queue->ops.sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT); mutex_unlock(&pm->lock); return 0; @@ -482,7 +482,7 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type, BUG_ON(!pm); mutex_lock(&pm->lock); - retval = pm->priv_queue->acquire_packet_buffer( + retval = pm->priv_queue->ops.acquire_packet_buffer( pm->priv_queue, sizeof(struct pm4_unmap_queues) / sizeof(uint32_t), &buffer); @@ -537,8 +537,8 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type, break; }; - pm->priv_queue->submit_packet(pm->priv_queue); - pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT); + pm->priv_queue->ops.submit_packet(pm->priv_queue); + pm->priv_queue->ops.sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT); mutex_unlock(&pm->lock); return 0; -- cgit v0.10.2 From 6898f0a568742b3d751e82899b8e1b0fe1b134f5 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Tue, 2 Dec 2014 16:38:57 +0200 Subject: drm/amdkfd: Add initial VI support for KQ This patch starts to add support for the VI APU in the KQ (kernel queue) module. Because most (more than 90%) of the KQ code is shared among AMD's APUs, we chose a design that performs most/all the code in the shared KQ file (kfd_kernel_queue.c). If there is H/W specific code to be executed, than it is written in an asic-specific extension function for that H/W. That asic-specific extension function is called from the shared function at the appropriate time. This requires that for every asic-specific extension function that is implemented in a specific ASIC, there will be an equivalent implementation in ALL ASICs, even if those implementations are just stubs. That way we achieve: - Maintainability: by having one copy of most of the code, we only need to fix bugs at one locations - Readability: very clear what is the shared code and what is done per ASIC - Extensibility: very easy to add new H/W specific files/functions Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile index 7558683..cd09c05 100644 --- a/drivers/gpu/drm/amd/amdkfd/Makefile +++ b/drivers/gpu/drm/amd/amdkfd/Makefile @@ -8,7 +8,8 @@ amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \ kfd_process.o kfd_queue.o kfd_mqd_manager.o \ kfd_mqd_manager_cik.o kfd_mqd_manager_vi.o \ - kfd_kernel_queue.o kfd_packet_manager.o \ + kfd_kernel_queue.o kfd_kernel_queue_cik.o \ + kfd_kernel_queue_vi.o kfd_packet_manager.o \ kfd_process_queue_manager.o kfd_device_queue_manager.o \ kfd_device_queue_manager_cik.o kfd_device_queue_manager_vi.o \ kfd_interrupt.o diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 731635d..75950ed 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -73,13 +73,16 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, goto err_get_kernel_doorbell; retval = kfd_gtt_sa_allocate(dev, queue_size, &kq->pq); - if (retval != 0) goto err_pq_allocate_vidmem; kq->pq_kernel_addr = kq->pq->cpu_ptr; kq->pq_gpu_addr = kq->pq->gpu_addr; + retval = kq->ops_asic_specific.initialize(kq, dev, type, queue_size); + if (retval == false) + goto err_eop_allocate_vidmem; + retval = kfd_gtt_sa_allocate(dev, sizeof(*kq->rptr_kernel), &kq->rptr_mem); @@ -111,6 +114,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, prop.queue_address = kq->pq_gpu_addr; prop.read_ptr = (uint32_t *) kq->rptr_gpu_addr; prop.write_ptr = (uint32_t *) kq->wptr_gpu_addr; + prop.eop_ring_buffer_address = kq->eop_gpu_addr; + prop.eop_ring_buffer_size = PAGE_SIZE; if (init_queue(&kq->queue, prop) != 0) goto err_init_queue; @@ -156,6 +161,8 @@ err_init_queue: err_wptr_allocate_vidmem: kfd_gtt_sa_free(dev, kq->rptr_mem); err_rptr_allocate_vidmem: + kfd_gtt_sa_free(dev, kq->eop_mem); +err_eop_allocate_vidmem: kfd_gtt_sa_free(dev, kq->pq); err_pq_allocate_vidmem: pr_err("kfd: error init pq\n"); @@ -182,6 +189,7 @@ static void uninitialize(struct kernel_queue *kq) kfd_gtt_sa_free(kq->dev, kq->rptr_mem); kfd_gtt_sa_free(kq->dev, kq->wptr_mem); + kq->ops_asic_specific.uninitialize(kq); kfd_gtt_sa_free(kq->dev, kq->pq); kfd_release_kernel_doorbell(kq->dev, kq->queue->properties.doorbell_ptr); @@ -300,6 +308,13 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, kq->ops.sync_with_hw = sync_with_hw; kq->ops.rollback_packet = rollback_packet; + switch (dev->device_info->asic_family) { + case CHIP_CARRIZO: + kernel_queue_init_vi(&kq->ops_asic_specific); + case CHIP_KAVERI: + kernel_queue_init_cik(&kq->ops_asic_specific); + } + if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) { pr_err("kfd: failed to init kernel queue\n"); kfree(kq); @@ -324,7 +339,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev) BUG_ON(!dev); - pr_debug("kfd: starting kernel queue test\n"); + pr_err("kfd: starting kernel queue test\n"); kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ); BUG_ON(!kq); @@ -336,7 +351,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev) kq->ops.submit_packet(kq); kq->ops.sync_with_hw(kq, 1000); - pr_debug("kfd: ending kernel queue test\n"); + pr_err("kfd: ending kernel queue test\n"); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h index e01b77b..2659d93 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h @@ -68,6 +68,7 @@ struct kernel_queue_ops { struct kernel_queue { struct kernel_queue_ops ops; + struct kernel_queue_ops ops_asic_specific; /* data */ struct kfd_dev *dev; @@ -85,6 +86,9 @@ struct kernel_queue { struct kfd_mem_obj *pq; uint64_t pq_gpu_addr; uint32_t *pq_kernel_addr; + struct kfd_mem_obj *eop_mem; + uint64_t eop_gpu_addr; + uint32_t *eop_kernel_addr; struct kfd_mem_obj *fence_mem_obj; uint64_t fence_gpu_addr; @@ -93,4 +97,7 @@ struct kernel_queue { struct list_head list; }; +void kernel_queue_init_cik(struct kernel_queue_ops *ops); +void kernel_queue_init_vi(struct kernel_queue_ops *ops); + #endif /* KFD_KERNEL_QUEUE_H_ */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c new file mode 100644 index 0000000..a90eb44 --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c @@ -0,0 +1,44 @@ +/* + * 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 "kfd_kernel_queue.h" + +static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev, + enum kfd_queue_type type, unsigned int queue_size); +static void uninitialize_cik(struct kernel_queue *kq); + +void kernel_queue_init_cik(struct kernel_queue_ops *ops) +{ + ops->initialize = initialize_cik; + ops->uninitialize = uninitialize_cik; +} + +static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev, + enum kfd_queue_type type, unsigned int queue_size) +{ + return true; +} + +static void uninitialize_cik(struct kernel_queue *kq) +{ +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c new file mode 100644 index 0000000..f1d4828 --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c @@ -0,0 +1,56 @@ +/* + * 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 "kfd_kernel_queue.h" + +static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev, + enum kfd_queue_type type, unsigned int queue_size); +static void uninitialize_vi(struct kernel_queue *kq); + +void kernel_queue_init_vi(struct kernel_queue_ops *ops) +{ + ops->initialize = initialize_vi; + ops->uninitialize = uninitialize_vi; +} + +static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev, + enum kfd_queue_type type, unsigned int queue_size) +{ + int retval; + + retval = kfd_gtt_sa_allocate(dev, PAGE_SIZE, &kq->eop_mem); + if (retval != 0) + return false; + + kq->eop_gpu_addr = kq->eop_mem->gpu_addr; + kq->eop_kernel_addr = kq->eop_mem->cpu_ptr; + + memset(kq->eop_kernel_addr, 0, PAGE_SIZE); + + return true; +} + +static void uninitialize_vi(struct kernel_queue *kq) +{ + kfd_gtt_sa_free(kq->dev, kq->eop_mem); +} -- cgit v0.10.2 From 3148ade72806e7bd1e4784798c2d5645dd13618a Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 21 Nov 2014 16:14:56 +0000 Subject: drm/i915/skl: Read out crtl1 for eDP/DPLL0 v2: Put the DPLL0 state readout in skylake_get_ddi_pll(), closer to where the PLL assignement read out is done rather than the frequency readout function. (Daniel) v3: Remove stray new line (Damien) Add Paulo's r-b tag for v1 Reviewed-by: Paulo Zanoni (v1) Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6289bab..9d38423 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8058,12 +8058,21 @@ static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, struct intel_crtc_config *pipe_config) { - u32 temp; + u32 temp, dpll_ctl1; temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port); pipe_config->ddi_pll_sel = temp >> (port * 3 + 1); switch (pipe_config->ddi_pll_sel) { + case SKL_DPLL0: + /* + * On SKL the eDP DPLL (DPLL0 as we don't use SSC) is not part + * of the shared DPLL framework and thus needs to be read out + * separately + */ + dpll_ctl1 = I915_READ(DPLL_CTRL1); + pipe_config->dpll_hw_state.ctrl1 = dpll_ctl1 & 0x3f; + break; case SKL_DPLL1: pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1; break; -- cgit v0.10.2 From ff94456453409e013aadf0fdaa38d6dd339456f4 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 20 Nov 2014 14:58:16 +0000 Subject: drm/i915/skl: Implement the skl version of MMIO flips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because the plane registers are different in Skylake we need to adapt the MMIO code as well. v2: Don't introduce yet another vfunc when the direction is do consolidate the plane updates to use the same code path (Daniel) v3: - Use enum pipe instead of int (Ville) - Also update PLANE_STRIDE when the tiling has changed (Ville) - Put intel_mark_page_flip_active() in the shared code (Damien) v4: - Remove unused variable v5: - Fix whitespace Vs tabs (Ville) Reviewed-by: Ville Syrjälä Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9d38423..d547166 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9526,22 +9526,50 @@ static bool use_mmio_flip(struct intel_engine_cs *ring, return ring != obj->ring; } -static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) +static void skl_do_mmio_flip(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = intel_crtc->base.primary->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + const enum pipe pipe = intel_crtc->pipe; + u32 ctl, stride; + + ctl = I915_READ(PLANE_CTL(pipe, 0)); + ctl &= ~PLANE_CTL_TILED_MASK; + if (obj->tiling_mode == I915_TILING_X) + ctl |= PLANE_CTL_TILED_X; + + /* + * The stride is either expressed as a multiple of 64 bytes chunks for + * linear buffers or in number of tiles for tiled buffers. + */ + stride = fb->pitches[0] >> 6; + if (obj->tiling_mode == I915_TILING_X) + stride = fb->pitches[0] >> 9; /* X tiles are 512 bytes wide */ + + /* + * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on + * PLANE_SURF updates, the update is then guaranteed to be atomic. + */ + I915_WRITE(PLANE_CTL(pipe, 0), ctl); + I915_WRITE(PLANE_STRIDE(pipe, 0), stride); + + I915_WRITE(PLANE_SURF(pipe, 0), intel_crtc->unpin_work->gtt_offset); + POSTING_READ(PLANE_SURF(pipe, 0)); +} + +static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc) { struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_framebuffer *intel_fb = to_intel_framebuffer(intel_crtc->base.primary->fb); struct drm_i915_gem_object *obj = intel_fb->obj; - bool atomic_update; - u32 start_vbl_count; u32 dspcntr; u32 reg; - intel_mark_page_flip_active(intel_crtc); - - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); - reg = DSPCNTR(intel_crtc->plane); dspcntr = I915_READ(reg); @@ -9556,6 +9584,28 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) intel_crtc->unpin_work->gtt_offset); POSTING_READ(DSPSURF(intel_crtc->plane)); +} + +/* + * XXX: This is the temporary way to update the plane registers until we get + * around to using the usual plane update functions for MMIO flips + */ +static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + bool atomic_update; + u32 start_vbl_count; + + intel_mark_page_flip_active(intel_crtc); + + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + + if (INTEL_INFO(dev)->gen >= 9) + skl_do_mmio_flip(intel_crtc); + else + /* use_mmio_flip() retricts MMIO flips to ilk+ */ + ilk_do_mmio_flip(intel_crtc); + if (atomic_update) intel_pipe_update_end(intel_crtc, start_vbl_count); } -- cgit v0.10.2 From bfd7ebdac3c303ea2ee1abd781ee3fda82321a92 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 14 Nov 2014 08:52:30 -0800 Subject: drm/i915: Parse VBT PSR block. PSR (aka SRD) block is defined at VBT and currently being used. Mainly/At-least to configure the amount of idle_frames require to get back to PSR Entry. Signed-off-by: Rodrigo Vivi Reviewed-by: Durgadoss R Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bb1892d..c7f00a4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1306,6 +1306,13 @@ enum drrs_support_type { SEAMLESS_DRRS_SUPPORT = 2 }; +enum psr_lines_to_wait { + PSR_0_LINES_TO_WAIT = 0, + PSR_1_LINE_TO_WAIT, + PSR_4_LINES_TO_WAIT, + PSR_8_LINES_TO_WAIT +}; + struct intel_vbt_data { struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ @@ -1335,6 +1342,15 @@ struct intel_vbt_data { struct edp_power_seq edp_pps; struct { + bool full_link; + bool require_aux_wakeup; + int idle_frames; + enum psr_lines_to_wait lines_to_wait; + int tp1_wakeup_time; + int tp2_tp3_wakeup_time; + } psr; + + struct { u16 pwm_freq_hz; bool present; bool active_low_pwm; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index a4bd90f..3f17825 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -664,6 +664,50 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) } } +static void +parse_psr(struct drm_i915_private *dev_priv, struct bdb_header *bdb) +{ + struct bdb_psr *psr; + struct psr_table *psr_table; + + psr = find_section(bdb, BDB_PSR); + if (!psr) { + DRM_DEBUG_KMS("No PSR BDB found.\n"); + return; + } + + psr_table = &psr->psr_table[panel_type]; + + dev_priv->vbt.psr.full_link = psr_table->full_link; + dev_priv->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup; + + /* Allowed VBT values goes from 0 to 15 */ + dev_priv->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 : + psr_table->idle_frames > 15 ? 15 : psr_table->idle_frames; + + switch (psr_table->lines_to_wait) { + case 0: + dev_priv->vbt.psr.lines_to_wait = PSR_0_LINES_TO_WAIT; + break; + case 1: + dev_priv->vbt.psr.lines_to_wait = PSR_1_LINE_TO_WAIT; + break; + case 2: + dev_priv->vbt.psr.lines_to_wait = PSR_4_LINES_TO_WAIT; + break; + case 3: + dev_priv->vbt.psr.lines_to_wait = PSR_8_LINES_TO_WAIT; + break; + default: + DRM_DEBUG_KMS("VBT has unknown PSR lines to wait %u\n", + psr_table->lines_to_wait); + break; + } + + dev_priv->vbt.psr.tp1_wakeup_time = psr_table->tp1_wakeup_time; + dev_priv->vbt.psr.tp2_tp3_wakeup_time = psr_table->tp2_tp3_wakeup_time; +} + static u8 *goto_next_sequence(u8 *data, int *size) { u16 len; @@ -1241,6 +1285,7 @@ intel_parse_bios(struct drm_device *dev) parse_device_mapping(dev_priv, bdb); parse_driver_features(dev_priv, bdb); parse_edp(dev_priv, bdb); + parse_psr(dev_priv, bdb); parse_mipi(dev_priv, bdb); parse_ddi_ports(dev_priv, bdb); diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 7603765..de01167 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -80,7 +80,7 @@ struct vbios_data { #define BDB_EXT_MMIO_REGS 6 #define BDB_SWF_IO 7 #define BDB_SWF_MMIO 8 -#define BDB_DOT_CLOCK_TABLE 9 +#define BDB_PSR 9 #define BDB_MODE_REMOVAL_TABLE 10 #define BDB_CHILD_DEVICE_TABLE 11 #define BDB_DRIVER_FEATURES 12 @@ -556,6 +556,26 @@ struct bdb_edp { u16 edp_t3_optimization; } __packed; +struct psr_table { + /* Feature bits */ + u8 full_link:1; + u8 require_aux_to_wakeup:1; + u8 feature_bits_rsvd:6; + + /* Wait times */ + u8 idle_frames:4; + u8 lines_to_wait:3; + u8 wait_times_rsvd:1; + + /* TP wake up time in multiple of 100 */ + u16 tp1_wakeup_time; + u16 tp2_tp3_wakeup_time; +} __packed; + +struct bdb_psr { + struct psr_table psr_table[16]; +} __packed; + void intel_setup_bios(struct drm_device *dev); int intel_parse_bios(struct drm_device *dev); -- cgit v0.10.2 From d44b4dcbd1b44737462b77971d216d21a9413341 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 14 Nov 2014 08:52:31 -0800 Subject: drm/i915: HSW/BDW PSR Set idle_frames = VBT + 1 Let's use VBT + 1 now we parse it. v2: fix subject v3: rebase over intel_psr and without counting on previous fix Cc: Arthur Runyan Signed-off-by: Rodrigo Vivi Reviewed-by: Durgadoss R Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 716b8a9..576568e 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -163,7 +163,12 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp) struct drm_device *dev = dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t max_sleep_time = 0x1f; - uint32_t idle_frames = 1; + /* Lately it was identified that depending on panel idle frame count + * calculated at HW can be off by 1. So let's use what came + * from VBT + 1 and at minimum 2 to be on the safe side. + */ + uint32_t idle_frames = dev_priv->vbt.psr.idle_frames ? + dev_priv->vbt.psr.idle_frames + 1 : 2; uint32_t val = 0x0; const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; bool only_standby = false; -- cgit v0.10.2 From 8cc726c9387e751d6081f1083c0ff1fde0ab6071 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 14 Nov 2014 08:52:32 -0800 Subject: drm/i915: PSR get full link off x standby from VBT OEMs can specify if full_link might be always enabled, i.e. only_standby over VBT. Signed-off-by: Rodrigo Vivi Reviewed-by: Durgadoss R Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 576568e..e706c9d 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -120,7 +120,7 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t aux_clock_divider; int precharge = 0x3; - bool only_standby = false; + bool only_standby = dev_priv->vbt.psr.full_link; static const uint8_t aux_msg[] = { [0] = DP_AUX_NATIVE_WRITE << 4, [1] = DP_SET_POWER >> 8, -- cgit v0.10.2 From d298ce5e25c1719cc32a2fd9373e1e72c50329f0 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 19 Nov 2014 07:34:04 -0800 Subject: drm/i915: remove PSR BDW single frame update. Single frame update is a feature available on BDW for PSR that allows Source to send Sink only one frame and get it updated. Usually useful when page flipping. However with our frontbuffer tracking where we force psr exit on flips we don't need this feature. Also after it got added here many workaround was added to documentation to mask some bits when using single frame update. So the safest thing is to just stop using it. v2: Rebase after removing skip aux one and fixing typo on commit message. Reviewed-by: Durgadoss R Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index e706c9d..843762a 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -181,7 +181,6 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp) val |= EDP_PSR_TP2_TP3_TIME_0us; val |= EDP_PSR_TP1_TIME_0us; val |= EDP_PSR_SKIP_AUX_EXIT; - val |= IS_BROADWELL(dev) ? BDW_PSR_SINGLE_FRAME : 0; } else val |= EDP_PSR_LINK_DISABLE; -- cgit v0.10.2 From e4d59f6b0f51d0c46fbd7e15a653045ad63161a8 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 20 Nov 2014 02:22:08 -0800 Subject: drm/i915: Remove intel_psr_is_enabled function. This function was in use to check if PSR feature got enabled. However on HSW and BDW we currently force psr exit by disabling EDP_PSR_ENABLE bit at EDP_PSR_CTL(dev). So this function was actually returning the active/inactive state that is different from the enable/disable meaning and had the risk of false negative. But anyway this check with DRRS was dangerous, since DRRS could try to get enabled before PSR gets there. So let's just remove it for now. A proper synchronization mechanism must be implemented later probably using pipe config. Cc: Daniel Vetter Reviewed-by: Durgadoss R Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5cecc20..fa509db 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4763,14 +4763,9 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate) } /* - * FIXME: This needs proper synchronization with psr state. But really - * hard to tell without seeing the user of this function of this code. - * Check locking and ordering once that lands. + * FIXME: This needs proper synchronization with psr state for some + * platforms that cannot have PSR and DRRS enabled at the same time. */ - if (INTEL_INFO(dev)->gen < 8 && intel_psr_is_enabled(dev)) { - DRM_DEBUG_KMS("DRRS is disabled as PSR is enabled\n"); - return; - } encoder = intel_attached_encoder(&intel_connector->base); intel_dp = enc_to_intel_dp(&encoder->base); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 25fdbb1..5e81f09 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1115,7 +1115,6 @@ void intel_backlight_unregister(struct drm_device *dev); /* intel_psr.c */ -bool intel_psr_is_enabled(struct drm_device *dev); void intel_psr_enable(struct intel_dp *intel_dp); void intel_psr_disable(struct intel_dp *intel_dp); void intel_psr_invalidate(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 843762a..576ad02 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -61,16 +61,6 @@ static bool is_edp_psr(struct intel_dp *intel_dp) return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED; } -bool intel_psr_is_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!HAS_PSR(dev)) - return false; - - return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE; -} - static void intel_psr_write_vsc(struct intel_dp *intel_dp, struct edp_vsc_psr *vsc_psr) { -- cgit v0.10.2 From c8f7df58f711e02b0788b75c054c6d32056ea170 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 14 Nov 2014 08:52:36 -0800 Subject: drm/i915: Add PSR registers for PSR VLV/CHV. Baytrail (Valleyview) and Braswell (Cherryview) uses a complete different implementation of PSR that we currently have supported for Haswell and Broadwell. So let's start by adding registers definitions. I usually don't like commit that adds just registers without using, but after I put all in one commit I realized that no one would want to take the AR to review it so I decided to split in order to make reviewer's life easier. Only last commit in this series will actually enable the PSR on intel enable panel path. But as it happens currently with HSW/BDW the plan is to let it disabled by default (protected by kernel parameter) while we are able to fully validate it. v2: Remove a unused bit definition that isn't used on vlv and reserved on chv as pointed out by Durgadoss. Cc: Durgadoss R Signed-off-by: Rodrigo Vivi Reviewed-by: Durgadoss R Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5446758..a965522 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2524,6 +2524,42 @@ enum punit_power_well { #define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC) #define PIPE_MULT(trans) _TRANSCODER2(trans, _PIPE_MULT_A) +/* VLV eDP PSR registers */ +#define _PSRCTLA (VLV_DISPLAY_BASE + 0x60090) +#define _PSRCTLB (VLV_DISPLAY_BASE + 0x61090) +#define VLV_EDP_PSR_ENABLE (1<<0) +#define VLV_EDP_PSR_RESET (1<<1) +#define VLV_EDP_PSR_MODE_MASK (7<<2) +#define VLV_EDP_PSR_MODE_HW_TIMER (1<<3) +#define VLV_EDP_PSR_MODE_SW_TIMER (1<<2) +#define VLV_EDP_PSR_SINGLE_FRAME_UPDATE (1<<7) +#define VLV_EDP_PSR_ACTIVE_ENTRY (1<<8) +#define VLV_EDP_PSR_SRC_TRANSMITTER_STATE (1<<9) +#define VLV_EDP_PSR_DBL_FRAME (1<<10) +#define VLV_EDP_PSR_FRAME_COUNT_MASK (0xff<<16) +#define VLV_EDP_PSR_IDLE_FRAME_SHIFT 16 +#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB) + +#define _VSCSDPA (VLV_DISPLAY_BASE + 0x600a0) +#define _VSCSDPB (VLV_DISPLAY_BASE + 0x610a0) +#define VLV_EDP_PSR_SDP_FREQ_MASK (3<<30) +#define VLV_EDP_PSR_SDP_FREQ_ONCE (1<<31) +#define VLV_EDP_PSR_SDP_FREQ_EVFRAME (1<<30) +#define VLV_VSCSDP(pipe) _PIPE(pipe, _VSCSDPA, _VSCSDPB) + +#define _PSRSTATA (VLV_DISPLAY_BASE + 0x60094) +#define _PSRSTATB (VLV_DISPLAY_BASE + 0x61094) +#define VLV_EDP_PSR_LAST_STATE_MASK (7<<3) +#define VLV_EDP_PSR_CURR_STATE_MASK 7 +#define VLV_EDP_PSR_DISABLED (0<<0) +#define VLV_EDP_PSR_INACTIVE (1<<0) +#define VLV_EDP_PSR_IN_TRANS_TO_ACTIVE (2<<0) +#define VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0) +#define VLV_EDP_PSR_ACTIVE_SF_UPDATE (4<<0) +#define VLV_EDP_PSR_EXIT (5<<0) +#define VLV_EDP_PSR_IN_TRANS (1<<7) +#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB) + /* HSW+ eDP PSR registers */ #define EDP_PSR_BASE(dev) (IS_HASWELL(dev) ? 0x64800 : 0x6f800) #define EDP_PSR_CTL(dev) (EDP_PSR_BASE(dev) + 0) -- cgit v0.10.2 From e2bbc343de8ea463af9da810b6e5e32dbd636b44 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 19 Nov 2014 07:37:00 -0800 Subject: drm/i915: PSR VLV/CHV: Introduce setup, enable and disable functions The biggest difference from HSW/BDW PSR here is that VLV enable_source function enables PSR but let it in Inactive state. So it might be called on early stage along with setup and enable_sink ones. v2: Rebase over intel_psr.c; Remove docs from static functions; Merge vlv_psr_active_on_pipe; Timeout for psr transition is 250us; Remove SRC_TRASMITTER_STATE; v3: Rebase after is_psr_enabled function got removed; Get SRC_TRANSMITTER_STATE back to be on the safe side since default for panels is to require link training on exit when main link off; As pointed out by Durgadoss msecs_to_jiffies used on wait_for only uses int, so let's use 1 instead. Althought the 1/4 of this is needed for the transition let's use 1 for simplicity; Cc: Durgadoss R Signed-off-by: Rodrigo Vivi Reviewed-by: Durgadoss R Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 576ad02..30f341a 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -61,6 +61,17 @@ static bool is_edp_psr(struct intel_dp *intel_dp) return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED; } +static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val; + + val = I915_READ(VLV_PSRSTAT(pipe)) & + VLV_EDP_PSR_CURR_STATE_MASK; + return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) || + (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE); +} + static void intel_psr_write_vsc(struct intel_dp *intel_dp, struct edp_vsc_psr *vsc_psr) { @@ -90,7 +101,23 @@ static void intel_psr_write_vsc(struct intel_dp *intel_dp, POSTING_READ(ctl_reg); } -static void intel_psr_setup_vsc(struct intel_dp *intel_dp) +static void vlv_psr_setup_vsc(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = intel_dig_port->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + uint32_t val; + + /* VLV auto-generate VSC package as per EDP 1.3 spec, Table 3.10 */ + val = I915_READ(VLV_VSCSDP(pipe)); + val &= ~VLV_EDP_PSR_SDP_FREQ_MASK; + val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME; + I915_WRITE(VLV_VSCSDP(pipe), val); +} + +static void hsw_psr_setup_vsc(struct intel_dp *intel_dp) { struct edp_vsc_psr psr_vsc; @@ -103,7 +130,13 @@ static void intel_psr_setup_vsc(struct intel_dp *intel_dp) intel_psr_write_vsc(intel_dp, &psr_vsc); } -static void intel_psr_enable_sink(struct intel_dp *intel_dp) +static void vlv_psr_enable_sink(struct intel_dp *intel_dp) +{ + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, + DP_PSR_ENABLE); +} + +static void hsw_psr_enable_sink(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; @@ -147,7 +180,22 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT)); } -static void intel_psr_enable_source(struct intel_dp *intel_dp) +static void vlv_psr_enable_source(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dig_port->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + + /* Transition from PSR_state 0 to PSR_state 1, i.e. PSR Inactive */ + I915_WRITE(VLV_PSRCTL(pipe), + VLV_EDP_PSR_MODE_SW_TIMER | + VLV_EDP_PSR_SRC_TRANSMITTER_STATE | + VLV_EDP_PSR_ENABLE); +} + +static void hsw_psr_enable_source(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; @@ -225,7 +273,7 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp) return true; } -static void intel_psr_do_enable(struct intel_dp *intel_dp) +static void intel_psr_activate(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; @@ -235,9 +283,12 @@ static void intel_psr_do_enable(struct intel_dp *intel_dp) WARN_ON(dev_priv->psr.active); lockdep_assert_held(&dev_priv->psr.lock); - /* Enable/Re-enable PSR on the host */ - intel_psr_enable_source(intel_dp); - + /* Enable/Re-enable PSR on the host + * On HSW+ after we enable PSR on source it will activate it + * as soon as it match configure idle_frame count. So + * we just actually enable it here on activation time. + */ + hsw_psr_enable_source(intel_dp); dev_priv->psr.active = true; } @@ -274,37 +325,67 @@ void intel_psr_enable(struct intel_dp *intel_dp) dev_priv->psr.busy_frontbuffer_bits = 0; - intel_psr_setup_vsc(intel_dp); + if (HAS_DDI(dev)) { + hsw_psr_setup_vsc(intel_dp); - /* Avoid continuous PSR exit by masking memup and hpd */ - I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP | - EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP); + /* Avoid continuous PSR exit by masking memup and hpd */ + I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP | + EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP); - /* Enable PSR on the panel */ - intel_psr_enable_sink(intel_dp); + /* Enable PSR on the panel */ + hsw_psr_enable_sink(intel_dp); + } else { + vlv_psr_setup_vsc(intel_dp); + + /* Enable PSR on the panel */ + vlv_psr_enable_sink(intel_dp); + + /* On HSW+ enable_source also means go to PSR entry/active + * state as soon as idle_frame achieved and here would be + * to soon. However on VLV enable_source just enable PSR + * but let it on inactive state. So we might do this prior + * to active transition, i.e. here. + */ + vlv_psr_enable_source(intel_dp); + } dev_priv->psr.enabled = intel_dp; unlock: mutex_unlock(&dev_priv->psr.lock); } -/** - * intel_psr_disable - Disable PSR - * @intel_dp: Intel DP - * - * This function needs to be called before disabling pipe. - */ -void intel_psr_disable(struct intel_dp *intel_dp) +static void vlv_psr_disable(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = + to_intel_crtc(intel_dig_port->base.base.crtc); + uint32_t val; - mutex_lock(&dev_priv->psr.lock); - if (!dev_priv->psr.enabled) { - mutex_unlock(&dev_priv->psr.lock); - return; + if (dev_priv->psr.active) { + /* Put VLV PSR back to PSR_state 0 that is PSR Disabled. */ + if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) & + VLV_EDP_PSR_IN_TRANS) == 0, 1)) + WARN(1, "PSR transition took longer than expected\n"); + + val = I915_READ(VLV_PSRCTL(intel_crtc->pipe)); + val &= ~VLV_EDP_PSR_ACTIVE_ENTRY; + val &= ~VLV_EDP_PSR_ENABLE; + val &= ~VLV_EDP_PSR_MODE_MASK; + I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val); + + dev_priv->psr.active = false; + } else { + WARN_ON(vlv_is_psr_active_on_pipe(dev, intel_crtc->pipe)); } +} + +static void hsw_psr_disable(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->psr.active) { I915_WRITE(EDP_PSR_CTL(dev), @@ -319,6 +400,30 @@ void intel_psr_disable(struct intel_dp *intel_dp) } else { WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE); } +} + +/** + * intel_psr_disable - Disable PSR + * @intel_dp: Intel DP + * + * This function needs to be called before disabling pipe. + */ +void intel_psr_disable(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev_priv->psr.lock); + if (!dev_priv->psr.enabled) { + mutex_unlock(&dev_priv->psr.lock); + return; + } + + if (HAS_DDI(dev)) + hsw_psr_disable(intel_dp); + else + vlv_psr_disable(intel_dp); dev_priv->psr.enabled = NULL; mutex_unlock(&dev_priv->psr.lock); @@ -357,7 +462,7 @@ static void intel_psr_work(struct work_struct *work) if (dev_priv->psr.busy_frontbuffer_bits) goto unlock; - intel_psr_do_enable(intel_dp); + intel_psr_activate(intel_dp); unlock: mutex_unlock(&dev_priv->psr.lock); } -- cgit v0.10.2 From 995d304774966bf1e3013b5bf7df554b3d807b17 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 19 Nov 2014 07:37:47 -0800 Subject: drm/i915: VLV/CHV PSR Software timer mode This patch introduces exit/activate functions for PSR on VLV+. Since on VLV+ HW cannot track frame updates and force PSR exit let's use fully SW tracking available. v2: Rebase over intel_psr.c; Remove Single Frame update transitioning from state 3 to 5 directly; Fake a software invalidation for sprites and cursor so we don't miss any screen update; v3: As pointed out by Durgadoss msecs_to_jiffies used on wait_for only uses int, so let's use 1 instead. Althought the 1/4 of this is needed for the transition let's use 1 for simplicity; Also fix comments as suggested by Durgadoss Cc: Durgadoss R Signed-off-by: Rodrigo Vivi Reviewed-by: Durgadoss R Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 30f341a..dd0e6e0 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -195,6 +195,23 @@ static void vlv_psr_enable_source(struct intel_dp *intel_dp) VLV_EDP_PSR_ENABLE); } +static void vlv_psr_activate(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dig_port->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + + /* Let's do the transition from PSR_state 1 to PSR_state 2 + * that is PSR transition to active - static frame transmission. + * Then Hardware is responsible for the transition to PSR_state 3 + * that is PSR active - no Remote Frame Buffer (RFB) update. + */ + I915_WRITE(VLV_PSRCTL(pipe), I915_READ(VLV_PSRCTL(pipe)) | + VLV_EDP_PSR_ACTIVE_ENTRY); +} + static void hsw_psr_enable_source(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); @@ -283,12 +300,16 @@ static void intel_psr_activate(struct intel_dp *intel_dp) WARN_ON(dev_priv->psr.active); lockdep_assert_held(&dev_priv->psr.lock); - /* Enable/Re-enable PSR on the host - * On HSW+ after we enable PSR on source it will activate it - * as soon as it match configure idle_frame count. So - * we just actually enable it here on activation time. - */ - hsw_psr_enable_source(intel_dp); + /* Enable/Re-enable PSR on the host */ + if (HAS_DDI(dev)) + /* On HSW+ after we enable PSR on source it will activate it + * as soon as it match configure idle_frame count. So + * we just actually enable it here on activation time. + */ + hsw_psr_enable_source(intel_dp); + else + vlv_psr_activate(intel_dp); + dev_priv->psr.active = true; } @@ -436,18 +457,27 @@ static void intel_psr_work(struct work_struct *work) struct drm_i915_private *dev_priv = container_of(work, typeof(*dev_priv), psr.work.work); struct intel_dp *intel_dp = dev_priv->psr.enabled; + struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; /* We have to make sure PSR is ready for re-enable * otherwise it keeps disabled until next full enable/disable cycle. * PSR might take some time to get fully disabled * and be ready for re-enable. */ - if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) & - EDP_PSR_STATUS_STATE_MASK) == 0, 50)) { - DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); - return; + if (HAS_DDI(dev_priv->dev)) { + if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) & + EDP_PSR_STATUS_STATE_MASK) == 0, 50)) { + DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); + return; + } + } else { + if (wait_for((I915_READ(VLV_PSRSTAT(pipe)) & + VLV_EDP_PSR_IN_TRANS) == 0, 1)) { + DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); + return; + } } - mutex_lock(&dev_priv->psr.lock); intel_dp = dev_priv->psr.enabled; @@ -470,17 +500,47 @@ unlock: static void intel_psr_exit(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp *intel_dp = dev_priv->psr.enabled; + struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + u32 val; - if (dev_priv->psr.active) { - u32 val = I915_READ(EDP_PSR_CTL(dev)); + if (!dev_priv->psr.active) + return; + + if (HAS_DDI(dev)) { + val = I915_READ(EDP_PSR_CTL(dev)); WARN_ON(!(val & EDP_PSR_ENABLE)); I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE); dev_priv->psr.active = false; + } else { + val = I915_READ(VLV_PSRCTL(pipe)); + + /* Here we do the transition from PSR_state 3 to PSR_state 5 + * directly once PSR State 4 that is active with single frame + * update can be skipped. PSR_state 5 that is PSR exit then + * Hardware is responsible to transition back to PSR_state 1 + * that is PSR inactive. Same state after + * vlv_edp_psr_enable_source. + */ + val &= ~VLV_EDP_PSR_ACTIVE_ENTRY; + I915_WRITE(VLV_PSRCTL(pipe), val); + + /* Send AUX wake up - Spec says after transitioning to PSR + * active we have to send AUX wake up by writing 01h in DPCD + * 600h of sink device. + * XXX: This might slow down the transition, but without this + * HW doesn't complete the transition to PSR_state 1 and we + * never get the screen updated. + */ + drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, + DP_SET_POWER_D0); } + dev_priv->psr.active = false; } /** @@ -558,6 +618,17 @@ void intel_psr_flush(struct drm_device *dev, (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe))) intel_psr_exit(dev); + /* + * On Valleyview and Cherryview we don't use hardware tracking so + * sprite plane updates or cursor moves don't result in a PSR + * invalidating. Which means we need to manually fake this in + * software for all flushes, not just when we've seen a preceding + * invalidation through frontbuffer rendering. */ + if (!HAS_DDI(dev) && + ((frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)) || + (frontbuffer_bits & INTEL_FRONTBUFFER_CURSOR(pipe)))) + intel_psr_exit(dev); + if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) schedule_delayed_work(&dev_priv->psr.work, msecs_to_jiffies(100)); -- cgit v0.10.2 From a6cbdb8e37d65bbf827fc31ee68b50b1e562a8ba Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 14 Nov 2014 08:52:40 -0800 Subject: drm/i915: VLV/CHV PSR debugfs. Add debugfs support for Valleyview and Cherryview considering that we have PSR per pipe and we don't have any kind of performance counter as we have on other platforms that support PSR. Signed-off-by: Rodrigo Vivi Reviewed-by: Durgadoss R Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 779a275..eed7402 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2155,6 +2155,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 psrperf = 0; + u32 stat[3]; + enum pipe pipe; bool enabled = false; intel_runtime_pm_get(dev_priv); @@ -2169,14 +2171,36 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) seq_printf(m, "Re-enable work scheduled: %s\n", yesno(work_busy(&dev_priv->psr.work.work))); - enabled = HAS_PSR(dev) && - I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE; - seq_printf(m, "HW Enabled & Active bit: %s\n", yesno(enabled)); + if (HAS_PSR(dev)) { + if (HAS_DDI(dev)) + enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE; + else { + for_each_pipe(dev_priv, pipe) { + stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) & + VLV_EDP_PSR_CURR_STATE_MASK; + if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) || + (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE)) + enabled = true; + } + } + } + seq_printf(m, "HW Enabled & Active bit: %s", yesno(enabled)); - if (HAS_PSR(dev)) + if (!HAS_DDI(dev)) + for_each_pipe(dev_priv, pipe) { + if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) || + (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE)) + seq_printf(m, " pipe %c", pipe_name(pipe)); + } + seq_puts(m, "\n"); + + /* CHV PSR has no kind of performance counter */ + if (HAS_PSR(dev) && HAS_DDI(dev)) { psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) & EDP_PSR_PERF_CNT_MASK; - seq_printf(m, "Performance_Counter: %u\n", psrperf); + + seq_printf(m, "Performance_Counter: %u\n", psrperf); + } mutex_unlock(&dev_priv->psr.lock); intel_runtime_pm_put(dev_priv); -- cgit v0.10.2 From b32c6f482dc56c52169cad7c9d35908c020dd22d Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 20 Nov 2014 03:44:37 -0800 Subject: drm/i915: Enable PSR for Baytrail and Braswell. This patch is the last in series of VLV/CHV PSR, that finally enable PSR by adding it to HAS_PSR and calling the proper enable and disable functions on the right places. Although it is still disabled by default. v2: Rebase over intel_psr and merge Durgadoss's fixes. v3: Fix typo. Signed-off-by: Rodrigo Vivi Reviewed-by: Durgadoss R Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c7f00a4..f6f92f1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2257,7 +2257,8 @@ struct drm_i915_cmd_table { #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) -#define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) +#define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev) || \ + IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) #define HAS_RUNTIME_PM(dev) (IS_GEN6(dev) || IS_HASWELL(dev) || \ IS_BROADWELL(dev) || IS_VALLEYVIEW(dev)) #define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fa509db..3fc3296 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2105,6 +2105,9 @@ static void intel_disable_dp(struct intel_encoder *encoder) if (crtc->config.has_audio) intel_audio_codec_disable(encoder); + if (HAS_PSR(dev) && !HAS_DDI(dev)) + intel_psr_disable(intel_dp); + /* Make sure the panel is off before trying to change the mode. But also * ensure that we have vdd while we switch off the panel. */ intel_edp_panel_vdd_on(intel_dp); @@ -2329,6 +2332,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder) struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); intel_edp_backlight_on(intel_dp); + intel_psr_enable(intel_dp); } static void g4x_pre_enable_dp(struct intel_encoder *encoder) -- cgit v0.10.2 From 57e215135f8ad7519fb079a0234e91a94bddd2f9 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Tue, 18 Nov 2014 20:07:20 +0000 Subject: drm/i915: Check for matching ringbuffer in logical_ring_wait_request() The request queue is per-engine, and may therefore contain requests from several different contexts/ringbuffers. In determining which request to wait for, this function should only consider requests from the ringbuffer that it's checking for space, and ignore any that it finds that belong to other contexts. Signed-off-by: Dave Gordon Reviewed-by: Deepak S Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index e588376..047d8f0 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -930,6 +930,16 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, } list_for_each_entry(request, &ring->request_list, list) { + /* + * The request queue is per-engine, so can contain requests + * from multiple ringbuffers. Here, we must ignore any that + * aren't from the ringbuffer we're considering. + */ + struct intel_context *ctx = request->ctx; + if (ctx->engine[ring->id].ringbuf != ringbuf) + continue; + + /* Would completion of this request free enough space? */ if (__intel_ring_space(request->tail, ringbuf->tail, ringbuf->size) >= bytes) { seqno = request->seqno; -- cgit v0.10.2 From d65621c496a2afe6c6724cbd7150e2ec60b42f13 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Tue, 18 Nov 2014 20:07:21 +0000 Subject: drm/i915: Don't read 'HEAD' MMIO register in LRC mode The logical ring code was updating the software ring 'head' value by reading the hardware 'HEAD' register. In LRC mode, this is not valid as the hardware is not necessarily executing the same context that is being processed by the software. Thus reading the h/w HEAD could put an unrelated (undefined, effectively random) value into the s/w 'head' -- A Bad Thing for the free space calculations. Signed-off-by: Dave Gordon Reviewed-by: Deepak S Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 047d8f0..03b5c04 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -986,7 +986,6 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, end = jiffies + 60 * HZ; do { - ringbuf->head = I915_READ_HEAD(ring); ringbuf->space = intel_ring_space(ringbuf); if (ringbuf->space >= bytes) { ret = 0; -- cgit v0.10.2 From 4feb765943c42dbc706dac348e8a893325b1153f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 24 Nov 2014 11:21:52 +0100 Subject: drm/i915: Remove user pinning code Now unused. Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index eed7402..a47fc25 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -96,9 +96,7 @@ static int i915_capabilities(struct seq_file *m, void *data) static const char *get_pin_flag(struct drm_i915_gem_object *obj) { - if (obj->user_pin_count > 0) - return "P"; - else if (i915_gem_obj_is_pinned(obj)) + if (i915_gem_obj_is_pinned(obj)) return "p"; else return " "; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ecee3bc..887d88f 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1004,6 +1004,13 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) kfree(file_priv); } +static int +i915_gem_reject_pin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + return -ENODEV; +} + const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF_DRV(I915_FLUSH, drm_noop, DRM_AUTH), @@ -1025,8 +1032,8 @@ const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f6f92f1..7a81ae2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1958,10 +1958,6 @@ struct drm_i915_gem_object { /** Record of address bit 17 of each page at last unbind. */ unsigned long *bit_17; - /** User space pin count and filp owning the pin */ - unsigned long user_pin_count; - struct drm_file *pin_filp; - union { /** for phy allocated objects */ struct drm_dma_handle *phys_handle; @@ -2428,10 +2424,6 @@ int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_execbuffer2(struct drm_device *dev, void *data, struct drm_file *file_priv); -int i915_gem_pin_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int i915_gem_unpin_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); int i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d2ba315..c630d49 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3903,18 +3903,14 @@ static bool is_pin_display(struct drm_i915_gem_object *obj) if (!vma) return false; - /* There are 3 sources that pin objects: + /* There are 2 sources that pin objects: * 1. The display engine (scanouts, sprites, cursors); * 2. Reservations for execbuffer; - * 3. The user. * * We can ignore reservations as we hold the struct_mutex and - * are only called outside of the reservation path. The user - * can only increment pin_count once, and so if after - * subtracting the potential reference by the user, any pin_count - * remains, it must be due to another use by the display engine. + * are only called outside of the reservation path. */ - return vma->pin_count - !!obj->user_pin_count; + return vma->pin_count; } /* @@ -4258,102 +4254,6 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) } int -i915_gem_pin_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_i915_gem_pin *args = data; - struct drm_i915_gem_object *obj; - int ret; - - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return -ENODEV; - - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ret; - - obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (&obj->base == NULL) { - ret = -ENOENT; - goto unlock; - } - - if (obj->madv != I915_MADV_WILLNEED) { - DRM_DEBUG("Attempting to pin a purgeable buffer\n"); - ret = -EFAULT; - goto out; - } - - if (obj->pin_filp != NULL && obj->pin_filp != file) { - DRM_DEBUG("Already pinned in i915_gem_pin_ioctl(): %d\n", - args->handle); - ret = -EINVAL; - goto out; - } - - if (obj->user_pin_count == ULONG_MAX) { - ret = -EBUSY; - goto out; - } - - if (obj->user_pin_count == 0) { - ret = i915_gem_obj_ggtt_pin(obj, args->alignment, PIN_MAPPABLE); - if (ret) - goto out; - } - - obj->user_pin_count++; - obj->pin_filp = file; - - args->offset = i915_gem_obj_ggtt_offset(obj); -out: - drm_gem_object_unreference(&obj->base); -unlock: - mutex_unlock(&dev->struct_mutex); - return ret; -} - -int -i915_gem_unpin_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_i915_gem_pin *args = data; - struct drm_i915_gem_object *obj; - int ret; - - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return -ENODEV; - - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ret; - - obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (&obj->base == NULL) { - ret = -ENOENT; - goto unlock; - } - - if (obj->pin_filp != file) { - DRM_DEBUG("Not pinned by caller in i915_gem_pin_ioctl(): %d\n", - args->handle); - ret = -EINVAL; - goto out; - } - obj->user_pin_count--; - if (obj->user_pin_count == 0) { - obj->pin_filp = NULL; - i915_gem_object_ggtt_unpin(obj); - } - -out: - drm_gem_object_unreference(&obj->base); -unlock: - mutex_unlock(&dev->struct_mutex); - return ret; -} - -int i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index beaf4bc..92db665 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -146,11 +146,10 @@ struct i915_vma { /** * How many users have pinned this object in GTT space. The following - * users can each hold at most one reference: pwrite/pread, pin_ioctl - * (via user_pin_count), execbuffer (objects are not allowed multiple - * times for the same batchbuffer), and the framebuffer code. When - * switching/pageflipping, the framebuffer code has at most two buffers - * pinned per crtc. + * users can each hold at most one reference: pwrite/pread, execbuffer + * (objects are not allowed multiple times for the same batchbuffer), + * and the framebuffer code. When switching/pageflipping, the + * framebuffer code has at most two buffers pinned per crtc. * * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 * bits with absolutely no headroom. So use 4 bits. */ diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index cdaee6c..eea98d5 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -679,8 +679,6 @@ static void capture_bo(struct drm_i915_error_buffer *err, err->pinned = 0; if (i915_gem_obj_is_pinned(obj)) err->pinned = 1; - if (obj->user_pin_count > 0) - err->pinned = -1; err->tiling = obj->tiling_mode; err->dirty = obj->dirty; err->purgeable = obj->madv != I915_MADV_WILLNEED; -- cgit v0.10.2 From bdcf120bfcb7e3b9356e96cdd7a6ac3c28062ffc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Nov 2014 11:56:33 +0000 Subject: drm/i915: Assert that we successfully downclock the GPU before suspend Before suspending, we wait upon the outstanding GPU requests and flush our pending idle handlers. This should downclock the GPU to its lowest power state. Add a WARN to check that the delayed tasks were run and did their job properly. Suggested-by: Akash Goel Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c630d49..fa3f907 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4581,6 +4581,11 @@ i915_gem_suspend(struct drm_device *dev) cancel_delayed_work_sync(&dev_priv->mm.retire_work); flush_delayed_work(&dev_priv->mm.idle_work); + /* Assert that we sucessfully flushed all the work and + * reset the GPU back to its idle, low power state. + */ + WARN_ON(dev_priv->mm.busy); + return 0; err: -- cgit v0.10.2 From f61ccae333c6f523adf75aa61605c14a275d2aca Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 25 Nov 2014 13:45:41 +0000 Subject: drm/i915: Fix short description of intel_display_power_is_enabled() That's the version actually taking the dev_priv->power_domains lock. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index f5a78d5..8a2bd18 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -118,7 +118,7 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv, } /** - * intel_display_power_is_enabled - unlocked check for a power domain + * intel_display_power_is_enabled - check for a power domain * @dev_priv: i915 device instance * @domain: power domain to check * -- cgit v0.10.2 From 9eba5d4a1d79d5094321469479b4dbe418f60110 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:23 +0000 Subject: drm/i915: Ensure OLS & PLR are always in sync The aim is to replace seqno values with request structures. A step along the way is to switch to using the PLR in preference to the OLS. That requires the PLR to only be valid when and only when the OLS is also valid. I.e., the two must be kept in lock step. Then, code which was using the OLS can be safely switched over to using the PLR instead. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 03b5c04..cc49b84 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -879,37 +879,48 @@ void intel_lr_context_unpin(struct intel_engine_cs *ring, static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, struct intel_context *ctx) { + struct drm_i915_gem_request *request; int ret; - if (ring->outstanding_lazy_seqno) - return 0; + /* XXX: The aim is to replace seqno values with request structures. + * A step along the way is to switch to using the PLR in preference + * to the OLS. That requires the PLR to only be valid when the OLS is + * also valid. I.e., the two must be kept in step. */ - if (ring->preallocated_lazy_request == NULL) { - struct drm_i915_gem_request *request; + if (ring->outstanding_lazy_seqno) { + WARN_ON(ring->preallocated_lazy_request == NULL); + return 0; + } + WARN_ON(ring->preallocated_lazy_request != NULL); - request = kmalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return -ENOMEM; + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; - if (ctx != ring->default_context) { - ret = intel_lr_context_pin(ring, ctx); - if (ret) { - kfree(request); - return ret; - } + if (ctx != ring->default_context) { + ret = intel_lr_context_pin(ring, ctx); + if (ret) { + kfree(request); + return ret; } + } - /* Hold a reference to the context this request belongs to - * (we will need it when the time comes to emit/retire the - * request). - */ - request->ctx = ctx; - i915_gem_context_reference(request->ctx); - - ring->preallocated_lazy_request = request; + ret = i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); + if (ret) { + intel_lr_context_unpin(ring, ctx); + kfree(request); + return ret; } - return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); + /* Hold a reference to the context this request belongs to + * (we will need it when the time comes to emit/retire the + * request). + */ + request->ctx = ctx; + i915_gem_context_reference(request->ctx); + + ring->preallocated_lazy_request = request; + return 0; } static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1d01b51..9fe1307 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2024,20 +2024,33 @@ int intel_ring_idle(struct intel_engine_cs *ring) static int intel_ring_alloc_seqno(struct intel_engine_cs *ring) { - if (ring->outstanding_lazy_seqno) + int ret; + struct drm_i915_gem_request *request; + + /* XXX: The aim is to replace seqno values with request structures. + * A step along the way is to switch to using the PLR in preference + * to the OLS. That requires the PLR to only be valid when the OLS + * is also valid. I.e., the two must be kept in step. */ + + if (ring->outstanding_lazy_seqno) { + WARN_ON(ring->preallocated_lazy_request == NULL); return 0; + } - if (ring->preallocated_lazy_request == NULL) { - struct drm_i915_gem_request *request; + WARN_ON(ring->preallocated_lazy_request != NULL); - request = kmalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return -ENOMEM; + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; - ring->preallocated_lazy_request = request; + ret = i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); + if (ret) { + kfree(request); + return ret; } - return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); + ring->preallocated_lazy_request = request; + return 0; } static int __intel_ring_prepare(struct intel_engine_cs *ring, -- cgit v0.10.2 From abfe262ae76246434fc427db855d716e575d0c1f Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:24 +0000 Subject: drm/i915: Add reference count to request structure The plan is to use request structures everywhere that seqno values were previously used. This means saving pointers to structures in places that used to be simple integers. In turn, that means that the target structure now needs much more stringent lifetime tracking. That is, it must not be freed while some other random object still holds a pointer to it. To achieve this tracking, a reference count needs to be added. Whenever a pointer to the structure is saved away, the count must be incremented and the free must only occur when all references have been released. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7a81ae2..36d4078 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1991,6 +1991,8 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old, * an emission time with seqnos for tracking how far ahead of the GPU we are. */ struct drm_i915_gem_request { + struct kref ref; + /** On Which ring this request was generated */ struct intel_engine_cs *ring; @@ -2020,6 +2022,32 @@ struct drm_i915_gem_request { struct list_head client_list; }; +void i915_gem_request_free(struct kref *req_ref); + +static inline void +i915_gem_request_reference(struct drm_i915_gem_request *req) +{ + kref_get(&req->ref); +} + +static inline void +i915_gem_request_unreference(struct drm_i915_gem_request *req) +{ + kref_put(&req->ref, i915_gem_request_free); +} + +static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst, + struct drm_i915_gem_request *src) +{ + if (src) + i915_gem_request_reference(src); + + if (*pdst) + i915_gem_request_unreference(*pdst); + + *pdst = src; +} + struct drm_i915_file_private { struct drm_i915_private *dev_priv; struct drm_file *file; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fa3f907..ef45e2e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2569,21 +2569,30 @@ static void i915_set_reset_status(struct drm_i915_private *dev_priv, static void i915_gem_free_request(struct drm_i915_gem_request *request) { - struct intel_context *ctx = request->ctx; - list_del(&request->list); i915_gem_request_remove_from_client(request); + i915_gem_request_unreference(request); +} + +void i915_gem_request_free(struct kref *req_ref) +{ + struct drm_i915_gem_request *req = container_of(req_ref, + typeof(*req), ref); + struct intel_context *ctx = req->ctx; + if (ctx) { if (i915.enable_execlists) { - struct intel_engine_cs *ring = request->ring; + struct intel_engine_cs *ring = req->ring; if (ctx != ring->default_context) intel_lr_context_unpin(ring, ctx); } + i915_gem_context_unreference(ctx); } - kfree(request); + + kfree(req); } struct drm_i915_gem_request * @@ -2671,8 +2680,7 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, } /* These may not have been flush before the reset, do so now */ - kfree(ring->preallocated_lazy_request); - ring->preallocated_lazy_request = NULL; + i915_gem_request_assign(&ring->preallocated_lazy_request, NULL); ring->outstanding_lazy_seqno = 0; } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index cc49b84..56c275d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -905,6 +905,8 @@ static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, } } + kref_init(&request->ref); + ret = i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); if (ret) { intel_lr_context_unpin(ring, ctx); @@ -1374,7 +1376,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring) intel_logical_ring_stop(ring); WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); - ring->preallocated_lazy_request = NULL; + i915_gem_request_assign(&ring->preallocated_lazy_request, NULL); ring->outstanding_lazy_seqno = 0; if (ring->cleanup) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9fe1307..fbeaa3ad 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1870,7 +1870,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring) intel_unpin_ringbuffer_obj(ringbuf); intel_destroy_ringbuffer_obj(ringbuf); - ring->preallocated_lazy_request = NULL; + i915_gem_request_assign(&ring->preallocated_lazy_request, NULL); ring->outstanding_lazy_seqno = 0; if (ring->cleanup) @@ -2043,6 +2043,8 @@ intel_ring_alloc_seqno(struct intel_engine_cs *ring) if (request == NULL) return -ENOMEM; + kref_init(&request->ref); + ret = i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); if (ret) { kfree(request); -- cgit v0.10.2 From b793a00a57da8d5057168aace0695a823bbb6e02 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:25 +0000 Subject: drm/i915: Add helper functions to aid seqno -> request transition Added helper functions for retrieving the ring and seqno entries from a request structure. This allows the internal workings of the request structure to be hidden from code that is using these. It also allows for useful workarounds/debug code to be added as or when necessary. Note that it is intended that the majority (if not all) uses of the seqno accessor will disappear eventually as code is updated to use the request structure itself rather than working with seqno values. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 36d4078..48c0c4a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2024,6 +2024,18 @@ struct drm_i915_gem_request { void i915_gem_request_free(struct kref *req_ref); +static inline uint32_t +i915_gem_request_get_seqno(struct drm_i915_gem_request *req) +{ + return req ? req->seqno : 0; +} + +static inline struct intel_engine_cs * +i915_gem_request_get_ring(struct drm_i915_gem_request *req) +{ + return req ? req->ring : NULL; +} + static inline void i915_gem_request_reference(struct drm_i915_gem_request *req) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index fe426cf..20636e0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -442,6 +442,13 @@ static inline u32 intel_ring_get_seqno(struct intel_engine_cs *ring) return ring->outstanding_lazy_seqno; } +static inline struct drm_i915_gem_request * +intel_ring_get_request(struct intel_engine_cs *ring) +{ + BUG_ON(ring->preallocated_lazy_request == NULL); + return ring->preallocated_lazy_request; +} + static inline void i915_trace_irq_get(struct intel_engine_cs *ring, u32 seqno) { if (ring->trace_irq_seqno == 0 && ring->irq_get(ring)) -- cgit v0.10.2 From 97b2a6a10a1aef6f32832fcbc9d6a27650354904 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:26 +0000 Subject: drm/i915: Replace last_[rwf]_seqno with last_[rwf]_req The object structure contains the last read, write and fenced seqno values for use in syncrhonisation operations. These have now been replaced with their request structure counterparts. Note that to ensure that objects do not end up with dangling pointers, the assignments of last_*_req include reference count updates. Thus a request cannot be freed if an object is still hanging on to it for any reason. v2: Corrected 'last_rendering_' to 'last_read_' in a number of comments that did not get updated when 'last_rendering_seqno' became 'last_read|write_seqno' several millenia ago. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a47fc25..4619873 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -131,9 +131,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) obj->base.size / 1024, obj->base.read_domains, obj->base.write_domain, - obj->last_read_seqno, - obj->last_write_seqno, - obj->last_fenced_seqno, + i915_gem_request_get_seqno(obj->last_read_req), + i915_gem_request_get_seqno(obj->last_write_req), + i915_gem_request_get_seqno(obj->last_fenced_req), i915_cache_level_str(to_i915(obj->base.dev), obj->cache_level), obj->dirty ? " dirty" : "", obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 48c0c4a..4924f1d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1944,10 +1944,10 @@ struct drm_i915_gem_object { struct intel_engine_cs *ring; /** Breadcrumb of last rendering to the buffer. */ - uint32_t last_read_seqno; - uint32_t last_write_seqno; + struct drm_i915_gem_request *last_read_req; + struct drm_i915_gem_request *last_write_req; /** Breadcrumb of last fenced GPU access to the buffer. */ - uint32_t last_fenced_seqno; + struct drm_i915_gem_request *last_fenced_req; /** Current tiling stride for the object, if it's tiled. */ uint32_t stride; @@ -1986,9 +1986,10 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old, * The request queue allows us to note sequence numbers that have been emitted * and may be associated with active buffers to be retired. * - * By keeping this list, we can avoid having to do questionable - * sequence-number comparisons on buffer last_rendering_seqnos, and associate - * an emission time with seqnos for tracking how far ahead of the GPU we are. + * By keeping this list, we can avoid having to do questionable sequence + * number comparisons on buffer last_read|write_seqno. It also allows an + * emission time to be associated with the request for tracking how far ahead + * of the GPU the submission is. */ struct drm_i915_gem_request { struct kref ref; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ef45e2e..a1110fb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1346,11 +1346,11 @@ i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj) /* Manually manage the write flush as we may have not yet * retired the buffer. * - * Note that the last_write_seqno is always the earlier of - * the two (read/write) seqno, so if we haved successfully waited, + * Note that the last_write_req is always the earlier of + * the two (read/write) requests, so if we haved successfully waited, * we know we have passed the last write. */ - obj->last_write_seqno = 0; + i915_gem_request_assign(&obj->last_write_req, NULL); return 0; } @@ -1363,14 +1363,18 @@ static __must_check int i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, bool readonly) { + struct drm_i915_gem_request *req; struct intel_engine_cs *ring = obj->ring; u32 seqno; int ret; - seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno; - if (seqno == 0) + req = readonly ? obj->last_write_req : obj->last_read_req; + if (!req) return 0; + seqno = i915_gem_request_get_seqno(req); + WARN_ON(seqno == 0); + ret = i915_wait_seqno(ring, seqno); if (ret) return ret; @@ -1386,6 +1390,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, struct drm_i915_file_private *file_priv, bool readonly) { + struct drm_i915_gem_request *req; struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring = obj->ring; @@ -1396,10 +1401,13 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, BUG_ON(!mutex_is_locked(&dev->struct_mutex)); BUG_ON(!dev_priv->mm.interruptible); - seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno; - if (seqno == 0) + req = readonly ? obj->last_write_req : obj->last_read_req; + if (!req) return 0; + seqno = i915_gem_request_get_seqno(req); + WARN_ON(seqno == 0); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, true); if (ret) return ret; @@ -2257,12 +2265,12 @@ static void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_engine_cs *ring) { - u32 seqno = intel_ring_get_seqno(ring); + struct drm_i915_gem_request *req = intel_ring_get_request(ring); BUG_ON(ring == NULL); - if (obj->ring != ring && obj->last_write_seqno) { - /* Keep the seqno relative to the current ring */ - obj->last_write_seqno = seqno; + if (obj->ring != ring && obj->last_write_req) { + /* Keep the request relative to the current ring */ + i915_gem_request_assign(&obj->last_write_req, req); } obj->ring = ring; @@ -2274,7 +2282,7 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, list_move_tail(&obj->ring_list, &ring->active_list); - obj->last_read_seqno = seqno; + i915_gem_request_assign(&obj->last_read_req, req); } void i915_vma_move_to_active(struct i915_vma *vma, @@ -2305,11 +2313,11 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) list_del_init(&obj->ring_list); obj->ring = NULL; - obj->last_read_seqno = 0; - obj->last_write_seqno = 0; + i915_gem_request_assign(&obj->last_read_req, NULL); + i915_gem_request_assign(&obj->last_write_req, NULL); obj->base.write_domain = 0; - obj->last_fenced_seqno = 0; + i915_gem_request_assign(&obj->last_fenced_req, NULL); obj->active = 0; drm_gem_object_unreference(&obj->base); @@ -2326,7 +2334,7 @@ i915_gem_object_retire(struct drm_i915_gem_object *obj) return; if (i915_seqno_passed(ring->get_seqno(ring, true), - obj->last_read_seqno)) + i915_gem_request_get_seqno(obj->last_read_req))) i915_gem_object_move_to_inactive(obj); } @@ -2753,7 +2761,8 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) struct drm_i915_gem_object, ring_list); - if (!i915_seqno_passed(seqno, obj->last_read_seqno)) + if (!i915_seqno_passed(seqno, + i915_gem_request_get_seqno(obj->last_read_req))) break; i915_gem_object_move_to_inactive(obj); @@ -2872,7 +2881,8 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj) int ret; if (obj->active) { - ret = i915_gem_check_olr(obj->ring, obj->last_read_seqno); + ret = i915_gem_check_olr(obj->ring, + i915_gem_request_get_seqno(obj->last_read_req)); if (ret) return ret; @@ -2933,13 +2943,12 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (ret) goto out; - if (obj->active) { - seqno = obj->last_read_seqno; - ring = obj->ring; - } + if (!obj->active || !obj->last_read_req) + goto out; - if (seqno == 0) - goto out; + seqno = i915_gem_request_get_seqno(obj->last_read_req); + WARN_ON(seqno == 0); + ring = obj->ring; /* Do this after OLR check to make sure we make forward progress polling * on this IOCTL with a timeout <=0 (like busy ioctl) @@ -2990,7 +2999,7 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, idx = intel_ring_sync_index(from, to); - seqno = obj->last_read_seqno; + seqno = i915_gem_request_get_seqno(obj->last_read_req); /* Optimization: Avoid semaphore sync when we are sure we already * waited for an object with higher seqno */ if (seqno <= from->semaphore.sync_seqno[idx]) @@ -3003,11 +3012,12 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, trace_i915_gem_ring_sync_to(from, to, seqno); ret = to->semaphore.sync_to(to, from, seqno); if (!ret) - /* We use last_read_seqno because sync_to() + /* We use last_read_req because sync_to() * might have just caused seqno wrap under * the radar. */ - from->semaphore.sync_seqno[idx] = obj->last_read_seqno; + from->semaphore.sync_seqno[idx] = + i915_gem_request_get_seqno(obj->last_read_req); return ret; } @@ -3321,12 +3331,13 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, static int i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) { - if (obj->last_fenced_seqno) { - int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno); + if (obj->last_fenced_req) { + int ret = i915_wait_seqno(obj->ring, + i915_gem_request_get_seqno(obj->last_fenced_req)); if (ret) return ret; - obj->last_fenced_seqno = 0; + i915_gem_request_assign(&obj->last_fenced_req, NULL); } return 0; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f06027b..4d9baef 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -946,7 +946,7 @@ void i915_gem_execbuffer_move_to_active(struct list_head *vmas, struct intel_engine_cs *ring) { - u32 seqno = intel_ring_get_seqno(ring); + struct drm_i915_gem_request *req = intel_ring_get_request(ring); struct i915_vma *vma; list_for_each_entry(vma, vmas, exec_list) { @@ -963,7 +963,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, i915_vma_move_to_active(vma, ring); if (obj->base.write_domain) { obj->dirty = 1; - obj->last_write_seqno = seqno; + i915_gem_request_assign(&obj->last_write_req, req); intel_fb_obj_invalidate(obj, ring); @@ -971,7 +971,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; } if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) { - obj->last_fenced_seqno = seqno; + i915_gem_request_assign(&obj->last_fenced_req, req); if (entry->flags & __EXEC_OBJECT_HAS_FENCE) { struct drm_i915_private *dev_priv = to_i915(ring->dev); list_move_tail(&dev_priv->fence_regs[obj->fence_reg].lru_list, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 92db665..dd849df 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -181,7 +181,7 @@ struct i915_address_space { * List of objects currently involved in rendering. * * Includes buffers having the contents of their GPU caches - * flushed, not necessarily primitives. last_rendering_seqno + * flushed, not necessarily primitives. last_read_req * represents when the rendering involved will be completed. * * A reference is held on the buffer while on this list. @@ -192,7 +192,7 @@ struct i915_address_space { * LRU list of objects which are not in the ringbuffer and * are ready to unbind, but are still in the GTT. * - * last_rendering_seqno is 0 while an object is in this list. + * last_read_req is NULL while an object is in this list. * * A reference is not held on the buffer while on this list, * as merely being GTT-bound shouldn't prevent its being diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 4727a4e..7a24bd1 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -399,7 +399,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, } obj->fence_dirty = - obj->last_fenced_seqno || + obj->last_fenced_req || obj->fence_reg != I915_FENCE_REG_NONE; obj->tiling_mode = args->tiling_mode; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index eea98d5..af0ceee 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -670,8 +670,8 @@ static void capture_bo(struct drm_i915_error_buffer *err, err->size = obj->base.size; err->name = obj->base.name; - err->rseqno = obj->last_read_seqno; - err->wseqno = obj->last_write_seqno; + err->rseqno = i915_gem_request_get_seqno(obj->last_read_req); + err->wseqno = i915_gem_request_get_seqno(obj->last_write_req); err->gtt_offset = vma->node.start; err->read_domains = obj->base.read_domains; err->write_domain = obj->base.write_domain; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d547166..70e7580 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9637,7 +9637,8 @@ static int intel_queue_mmio_flip(struct drm_device *dev, { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_crtc->mmio_flip.seqno = obj->last_write_seqno; + intel_crtc->mmio_flip.seqno = + i915_gem_request_get_seqno(obj->last_write_req); intel_crtc->mmio_flip.ring = obj->ring; schedule_work(&intel_crtc->mmio_flip.work); @@ -9900,7 +9901,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (ret) goto cleanup_unpin; - work->flip_queued_seqno = obj->last_write_seqno; + work->flip_queued_seqno = + i915_gem_request_get_seqno(obj->last_write_req); work->flip_queued_ring = obj->ring; } else { ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 20636e0..dbac132 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -251,7 +251,7 @@ struct intel_engine_cs { * ringbuffer. * * Includes buffers having the contents of their GPU caches - * flushed, not necessarily primitives. last_rendering_seqno + * flushed, not necessarily primitives. last_read_req * represents when the rendering involved will be completed. * * A reference is held on the buffer while on this list. -- cgit v0.10.2 From 54fb2411dd0b4d7d91e9d77536ac84295607a93b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:27 +0000 Subject: drm/i915: Convert i915_gem_ring_throttle to use requests Convert the throttle code to use the request structure rather than extracting a ring/seqno pair from it and using those. This is in preparation for __wait_seqno() becoming __wait_request(). For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a1110fb..bf01358 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4098,10 +4098,8 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_file_private *file_priv = file->driver_priv; unsigned long recent_enough = jiffies - msecs_to_jiffies(20); - struct drm_i915_gem_request *request; - struct intel_engine_cs *ring = NULL; + struct drm_i915_gem_request *request, *target = NULL; unsigned reset_counter; - u32 seqno = 0; int ret; ret = i915_gem_wait_for_error(&dev_priv->gpu_error); @@ -4117,16 +4115,17 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) if (time_after_eq(request->emitted_jiffies, recent_enough)) break; - ring = request->ring; - seqno = request->seqno; + target = request; } reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); spin_unlock(&file_priv->mm.lock); - if (seqno == 0) + if (target == NULL) return 0; - ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL, NULL); + ret = __i915_wait_seqno(i915_gem_request_get_ring(target), + i915_gem_request_get_seqno(target), + reset_counter, true, NULL, NULL); if (ret == 0) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); -- cgit v0.10.2 From ff8658850aa9bdb5bc308ff8cce60c2558c58566 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:28 +0000 Subject: drm/i915: Ensure requests stick around during waits Added reference counting of the request structure around __wait_seqno() calls. This is a precursor to updating the wait code itself to take the request rather than a seqno. At that point, it would be a Bad Idea for a request object to be retired and freed while the wait code is still using it. v3: Note that even though the mutex lock is held during a call to i915_wait_seqno(), it is still necessary to explicitly bump the reference count. It appears that the shrinker can asynchronously retire items even though the mutex is locked. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel [danvet: Remove wrongly squashed hunk which breaks the build.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bf01358..8ec0785 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1417,10 +1417,12 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, return ret; reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + i915_gem_request_reference(req); mutex_unlock(&dev->struct_mutex); ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL, file_priv); mutex_lock(&dev->struct_mutex); + i915_gem_request_unreference(req); if (ret) return ret; @@ -2920,6 +2922,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_wait *args = data; struct drm_i915_gem_object *obj; + struct drm_i915_gem_request *req; struct intel_engine_cs *ring = NULL; unsigned reset_counter; u32 seqno = 0; @@ -2946,7 +2949,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (!obj->active || !obj->last_read_req) goto out; - seqno = i915_gem_request_get_seqno(obj->last_read_req); + req = obj->last_read_req; + seqno = i915_gem_request_get_seqno(req); WARN_ON(seqno == 0); ring = obj->ring; @@ -2960,10 +2964,15 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) drm_gem_object_unreference(&obj->base); reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + i915_gem_request_reference(req); mutex_unlock(&dev->struct_mutex); - return __i915_wait_seqno(ring, seqno, reset_counter, true, - &args->timeout_ns, file->driver_priv); + ret = __i915_wait_seqno(ring, seqno, reset_counter, true, &args->timeout_ns, + file->driver_priv); + mutex_lock(&dev->struct_mutex); + i915_gem_request_unreference(req); + mutex_unlock(&dev->struct_mutex); + return ret; out: drm_gem_object_unreference(&obj->base); @@ -4118,6 +4127,8 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) target = request; } reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + if (target) + i915_gem_request_reference(target); spin_unlock(&file_priv->mm.lock); if (target == NULL) @@ -4129,6 +4140,10 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) if (ret == 0) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); + mutex_lock(&dev->struct_mutex); + i915_gem_request_unreference(target); + mutex_unlock(&dev->struct_mutex); + return ret; } -- cgit v0.10.2 From 6259cead57ebc19325183f8fd9968e19fc2fbe53 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:29 +0000 Subject: drm/i915: Remove 'outstanding_lazy_seqno' The OLS value is now obsolete. Exactly the same value is guarateed to be always available as PLR->seqno. Thus it is safe to remove the OLS completely. And also to rename the PLR to OLR to keep the 'outstanding lazy ...' naming convention valid. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8ec0785..fba22a5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1164,7 +1164,7 @@ i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno) BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex)); ret = 0; - if (seqno == ring->outstanding_lazy_seqno) + if (seqno == i915_gem_request_get_seqno(ring->outstanding_lazy_request)) ret = i915_add_request(ring, NULL); return ret; @@ -2421,7 +2421,7 @@ int __i915_add_request(struct intel_engine_cs *ring, u32 request_ring_position, request_start; int ret; - request = ring->preallocated_lazy_request; + request = ring->outstanding_lazy_request; if (WARN_ON(request == NULL)) return -ENOMEM; @@ -2466,7 +2466,6 @@ int __i915_add_request(struct intel_engine_cs *ring, return ret; } - request->seqno = intel_ring_get_seqno(ring); request->ring = ring; request->head = request_start; request->tail = request_ring_position; @@ -2503,8 +2502,7 @@ int __i915_add_request(struct intel_engine_cs *ring, } trace_i915_gem_request_add(ring, request->seqno); - ring->outstanding_lazy_seqno = 0; - ring->preallocated_lazy_request = NULL; + ring->outstanding_lazy_request = NULL; i915_queue_hangcheck(ring->dev); @@ -2689,9 +2687,8 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, i915_gem_free_request(request); } - /* These may not have been flush before the reset, do so now */ - i915_gem_request_assign(&ring->preallocated_lazy_request, NULL); - ring->outstanding_lazy_seqno = 0; + /* This may not have been flushed before the reset, so clean it now */ + i915_gem_request_assign(&ring->outstanding_lazy_request, NULL); } void i915_gem_restore_fences(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 4d9baef..7ecfa91 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1211,7 +1211,9 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, return ret; } - trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags); + trace_i915_gem_ring_dispatch(ring, + i915_gem_request_get_seqno(intel_ring_get_request(ring)), + flags); i915_gem_execbuffer_move_to_active(vmas, ring); i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 70e7580..3085731 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9910,7 +9910,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (ret) goto cleanup_unpin; - work->flip_queued_seqno = intel_ring_get_seqno(ring); + work->flip_queued_seqno = + i915_gem_request_get_seqno(intel_ring_get_request(ring)); work->flip_queued_ring = ring; } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 56c275d..2f944c4 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -876,22 +876,14 @@ void intel_lr_context_unpin(struct intel_engine_cs *ring, } } -static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int logical_ring_alloc_request(struct intel_engine_cs *ring, + struct intel_context *ctx) { struct drm_i915_gem_request *request; int ret; - /* XXX: The aim is to replace seqno values with request structures. - * A step along the way is to switch to using the PLR in preference - * to the OLS. That requires the PLR to only be valid when the OLS is - * also valid. I.e., the two must be kept in step. */ - - if (ring->outstanding_lazy_seqno) { - WARN_ON(ring->preallocated_lazy_request == NULL); + if (ring->outstanding_lazy_request) return 0; - } - WARN_ON(ring->preallocated_lazy_request != NULL); request = kmalloc(sizeof(*request), GFP_KERNEL); if (request == NULL) @@ -907,7 +899,7 @@ static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, kref_init(&request->ref); - ret = i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); + ret = i915_gem_get_seqno(ring->dev, &request->seqno); if (ret) { intel_lr_context_unpin(ring, ctx); kfree(request); @@ -921,7 +913,7 @@ static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, request->ctx = ctx; i915_gem_context_reference(request->ctx); - ring->preallocated_lazy_request = request; + ring->outstanding_lazy_request = request; return 0; } @@ -1098,7 +1090,7 @@ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords) return ret; /* Preallocate the olr before touching the ring */ - ret = logical_ring_alloc_seqno(ring, ringbuf->FIXME_lrc_ctx); + ret = logical_ring_alloc_request(ring, ringbuf->FIXME_lrc_ctx); if (ret) return ret; @@ -1351,7 +1343,8 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf) (ring->status_page.gfx_addr + (I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT))); intel_logical_ring_emit(ringbuf, 0); - intel_logical_ring_emit(ringbuf, ring->outstanding_lazy_seqno); + intel_logical_ring_emit(ringbuf, + i915_gem_request_get_seqno(ring->outstanding_lazy_request)); intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT); intel_logical_ring_emit(ringbuf, MI_NOOP); intel_logical_ring_advance_and_submit(ringbuf); @@ -1376,8 +1369,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring) intel_logical_ring_stop(ring); WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); - i915_gem_request_assign(&ring->preallocated_lazy_request, NULL); - ring->outstanding_lazy_seqno = 0; + i915_gem_request_assign(&ring->outstanding_lazy_request, NULL); if (ring->cleanup) ring->cleanup(ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index fbeaa3ad..accfc89 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -911,17 +911,20 @@ static int gen8_rcs_signal(struct intel_engine_cs *signaller, return ret; for_each_ring(waiter, dev_priv, i) { + u32 seqno; u64 gtt_offset = signaller->semaphore.signal_ggtt[i]; if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID) continue; + seqno = i915_gem_request_get_seqno( + signaller->outstanding_lazy_request); intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6)); intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB | PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_FLUSH_ENABLE); intel_ring_emit(signaller, lower_32_bits(gtt_offset)); intel_ring_emit(signaller, upper_32_bits(gtt_offset)); - intel_ring_emit(signaller, signaller->outstanding_lazy_seqno); + intel_ring_emit(signaller, seqno); intel_ring_emit(signaller, 0); intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL | MI_SEMAPHORE_TARGET(waiter->id)); @@ -949,16 +952,19 @@ static int gen8_xcs_signal(struct intel_engine_cs *signaller, return ret; for_each_ring(waiter, dev_priv, i) { + u32 seqno; u64 gtt_offset = signaller->semaphore.signal_ggtt[i]; if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID) continue; + seqno = i915_gem_request_get_seqno( + signaller->outstanding_lazy_request); intel_ring_emit(signaller, (MI_FLUSH_DW + 1) | MI_FLUSH_DW_OP_STOREDW); intel_ring_emit(signaller, lower_32_bits(gtt_offset) | MI_FLUSH_DW_USE_GTT); intel_ring_emit(signaller, upper_32_bits(gtt_offset)); - intel_ring_emit(signaller, signaller->outstanding_lazy_seqno); + intel_ring_emit(signaller, seqno); intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL | MI_SEMAPHORE_TARGET(waiter->id)); intel_ring_emit(signaller, 0); @@ -987,9 +993,11 @@ static int gen6_signal(struct intel_engine_cs *signaller, for_each_ring(useless, dev_priv, i) { u32 mbox_reg = signaller->semaphore.mbox.signal[i]; if (mbox_reg != GEN6_NOSYNC) { + u32 seqno = i915_gem_request_get_seqno( + signaller->outstanding_lazy_request); intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(signaller, mbox_reg); - intel_ring_emit(signaller, signaller->outstanding_lazy_seqno); + intel_ring_emit(signaller, seqno); } } @@ -1024,7 +1032,8 @@ gen6_add_request(struct intel_engine_cs *ring) intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, ring->outstanding_lazy_seqno); + intel_ring_emit(ring, + i915_gem_request_get_seqno(ring->outstanding_lazy_request)); intel_ring_emit(ring, MI_USER_INTERRUPT); __intel_ring_advance(ring); @@ -1142,7 +1151,8 @@ pc_render_add_request(struct intel_engine_cs *ring) PIPE_CONTROL_WRITE_FLUSH | PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE); intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, ring->outstanding_lazy_seqno); + intel_ring_emit(ring, + i915_gem_request_get_seqno(ring->outstanding_lazy_request)); intel_ring_emit(ring, 0); PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */ @@ -1161,7 +1171,8 @@ pc_render_add_request(struct intel_engine_cs *ring) PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | PIPE_CONTROL_NOTIFY); intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, ring->outstanding_lazy_seqno); + intel_ring_emit(ring, + i915_gem_request_get_seqno(ring->outstanding_lazy_request)); intel_ring_emit(ring, 0); __intel_ring_advance(ring); @@ -1401,7 +1412,8 @@ i9xx_add_request(struct intel_engine_cs *ring) intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, ring->outstanding_lazy_seqno); + intel_ring_emit(ring, + i915_gem_request_get_seqno(ring->outstanding_lazy_request)); intel_ring_emit(ring, MI_USER_INTERRUPT); __intel_ring_advance(ring); @@ -1870,8 +1882,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring) intel_unpin_ringbuffer_obj(ringbuf); intel_destroy_ringbuffer_obj(ringbuf); - i915_gem_request_assign(&ring->preallocated_lazy_request, NULL); - ring->outstanding_lazy_seqno = 0; + i915_gem_request_assign(&ring->outstanding_lazy_request, NULL); if (ring->cleanup) ring->cleanup(ring); @@ -2004,7 +2015,7 @@ int intel_ring_idle(struct intel_engine_cs *ring) int ret; /* We need to add any requests required to flush the objects and ring */ - if (ring->outstanding_lazy_seqno) { + if (ring->outstanding_lazy_request) { ret = i915_add_request(ring, NULL); if (ret) return ret; @@ -2022,22 +2033,13 @@ int intel_ring_idle(struct intel_engine_cs *ring) } static int -intel_ring_alloc_seqno(struct intel_engine_cs *ring) +intel_ring_alloc_request(struct intel_engine_cs *ring) { int ret; struct drm_i915_gem_request *request; - /* XXX: The aim is to replace seqno values with request structures. - * A step along the way is to switch to using the PLR in preference - * to the OLS. That requires the PLR to only be valid when the OLS - * is also valid. I.e., the two must be kept in step. */ - - if (ring->outstanding_lazy_seqno) { - WARN_ON(ring->preallocated_lazy_request == NULL); + if (ring->outstanding_lazy_request) return 0; - } - - WARN_ON(ring->preallocated_lazy_request != NULL); request = kmalloc(sizeof(*request), GFP_KERNEL); if (request == NULL) @@ -2045,13 +2047,13 @@ intel_ring_alloc_seqno(struct intel_engine_cs *ring) kref_init(&request->ref); - ret = i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); + ret = i915_gem_get_seqno(ring->dev, &request->seqno); if (ret) { kfree(request); return ret; } - ring->preallocated_lazy_request = request; + ring->outstanding_lazy_request = request; return 0; } @@ -2092,7 +2094,7 @@ int intel_ring_begin(struct intel_engine_cs *ring, return ret; /* Preallocate the olr before touching the ring */ - ret = intel_ring_alloc_seqno(ring); + ret = intel_ring_alloc_request(ring); if (ret) return ret; @@ -2127,7 +2129,7 @@ void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - BUG_ON(ring->outstanding_lazy_seqno); + BUG_ON(ring->outstanding_lazy_request); if (INTEL_INFO(dev)->gen == 6 || INTEL_INFO(dev)->gen == 7) { I915_WRITE(RING_SYNC_0(ring->mmio_base), 0); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index dbac132..2a84bd9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -267,8 +267,7 @@ struct intel_engine_cs { /** * Do we have some not yet emitted requests outstanding? */ - struct drm_i915_gem_request *preallocated_lazy_request; - u32 outstanding_lazy_seqno; + struct drm_i915_gem_request *outstanding_lazy_request; bool gpu_caches_dirty; bool fbc_dirty; @@ -436,17 +435,11 @@ static inline u32 intel_ring_get_tail(struct intel_ringbuffer *ringbuf) return ringbuf->tail; } -static inline u32 intel_ring_get_seqno(struct intel_engine_cs *ring) -{ - BUG_ON(ring->outstanding_lazy_seqno == 0); - return ring->outstanding_lazy_seqno; -} - static inline struct drm_i915_gem_request * intel_ring_get_request(struct intel_engine_cs *ring) { - BUG_ON(ring->preallocated_lazy_request == NULL); - return ring->preallocated_lazy_request; + BUG_ON(ring->outstanding_lazy_request == NULL); + return ring->outstanding_lazy_request; } static inline void i915_trace_irq_get(struct intel_engine_cs *ring, u32 seqno) -- cgit v0.10.2 From b6660d59f66835e4e99eaa772ea4cb74f96f4de3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:30 +0000 Subject: drm/i915: Make 'i915_gem_check_olr' actually check by request not seqno Updated the _check_olr() function to actually take a request object and compare it to the OLR rather than extracting seqnos and comparing those. Note that there is one use case where the request object being processed is no longer available at that point in the call stack. Hence a temporary copy of the original function is still present (but called _check_ols() instead). This will be removed in a subsequent patch. Also, downgraded a BUG_ON to a WARN_ON as apparently the former is frowned upon for shipping code. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4924f1d..e6a997c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2577,7 +2577,7 @@ bool i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_requests_ring(struct intel_engine_cs *ring); int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible); -int __must_check i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno); +int __must_check i915_gem_check_olr(struct drm_i915_gem_request *req); static inline bool i915_reset_in_progress(struct i915_gpu_error *error) { @@ -3117,4 +3117,20 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) } } +/* XXX: Temporary solution to be removed later in patch series. */ +static inline int __must_check i915_gem_check_ols( + struct intel_engine_cs *ring, u32 seqno) +{ + int ret; + + WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex)); + + ret = 0; + if (seqno == i915_gem_request_get_seqno(ring->outstanding_lazy_request)) + ret = i915_add_request(ring, NULL); + + return ret; +} +/* XXX: Temporary solution to be removed later in patch series. */ + #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fba22a5..7d6f9bc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1153,19 +1153,18 @@ i915_gem_check_wedge(struct i915_gpu_error *error, } /* - * Compare seqno against outstanding lazy request. Emit a request if they are - * equal. + * Compare arbitrary request against outstanding lazy request. Emit on match. */ int -i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno) +i915_gem_check_olr(struct drm_i915_gem_request *req) { int ret; - BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); ret = 0; - if (seqno == i915_gem_request_get_seqno(ring->outstanding_lazy_request)) - ret = i915_add_request(ring, NULL); + if (req == req->ring->outstanding_lazy_request) + ret = i915_add_request(req->ring, NULL); return ret; } @@ -1328,7 +1327,7 @@ i915_wait_seqno(struct intel_engine_cs *ring, uint32_t seqno) if (ret) return ret; - ret = i915_gem_check_olr(ring, seqno); + ret = i915_gem_check_ols(ring, seqno); if (ret) return ret; @@ -1395,7 +1394,6 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring = obj->ring; unsigned reset_counter; - u32 seqno; int ret; BUG_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -1405,22 +1403,19 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (!req) return 0; - seqno = i915_gem_request_get_seqno(req); - WARN_ON(seqno == 0); - ret = i915_gem_check_wedge(&dev_priv->gpu_error, true); if (ret) return ret; - ret = i915_gem_check_olr(ring, seqno); + ret = i915_gem_check_olr(req); if (ret) return ret; reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); i915_gem_request_reference(req); mutex_unlock(&dev->struct_mutex); - ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL, - file_priv); + ret = __i915_wait_seqno(ring, i915_gem_request_get_seqno(req), + reset_counter, true, NULL, file_priv); mutex_lock(&dev->struct_mutex); i915_gem_request_unreference(req); if (ret) @@ -2880,8 +2875,7 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj) int ret; if (obj->active) { - ret = i915_gem_check_olr(obj->ring, - i915_gem_request_get_seqno(obj->last_read_req)); + ret = i915_gem_check_olr(obj->last_read_req); if (ret) return ret; @@ -3011,7 +3005,7 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, if (seqno <= from->semaphore.sync_seqno[idx]) return 0; - ret = i915_gem_check_olr(obj->ring, seqno); + ret = i915_gem_check_olr(obj->last_read_req); if (ret) return ret; -- cgit v0.10.2 From 9bfc01a29b7d4d6b965a596b047b405bf6f58be1 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:31 +0000 Subject: drm/i915: Convert 'last_flip_req' to be a request not a seqno Converted 'last_flip_req' to be an actual request rather than a seqno value as part of the on going seqno to request changes. This includes reference counting the request being saved away to ensure it can not be retired and freed while the overlay code is still waiting on it. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index dc2f4f26..5defc37 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -182,7 +182,7 @@ struct intel_overlay { u32 flip_addr; struct drm_i915_gem_object *reg_bo; /* flip handling */ - uint32_t last_flip_req; + struct drm_i915_gem_request *last_flip_req; void (*flip_tail)(struct intel_overlay *); }; @@ -217,17 +217,20 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, int ret; BUG_ON(overlay->last_flip_req); - ret = i915_add_request(ring, &overlay->last_flip_req); + i915_gem_request_assign(&overlay->last_flip_req, + ring->outstanding_lazy_request); + ret = i915_add_request(ring, NULL); if (ret) return ret; overlay->flip_tail = tail; - ret = i915_wait_seqno(ring, overlay->last_flip_req); + ret = i915_wait_seqno(ring, + i915_gem_request_get_seqno(overlay->last_flip_req)); if (ret) return ret; i915_gem_retire_requests(dev); - overlay->last_flip_req = 0; + i915_gem_request_assign(&overlay->last_flip_req, NULL); return 0; } @@ -286,7 +289,10 @@ static int intel_overlay_continue(struct intel_overlay *overlay, intel_ring_emit(ring, flip_addr); intel_ring_advance(ring); - return i915_add_request(ring, &overlay->last_flip_req); + WARN_ON(overlay->last_flip_req); + i915_gem_request_assign(&overlay->last_flip_req, + ring->outstanding_lazy_request); + return i915_add_request(ring, NULL); } static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) @@ -366,10 +372,11 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) struct intel_engine_cs *ring = &dev_priv->ring[RCS]; int ret; - if (overlay->last_flip_req == 0) + if (overlay->last_flip_req == NULL) return 0; - ret = i915_wait_seqno(ring, overlay->last_flip_req); + ret = i915_wait_seqno(ring, + i915_gem_request_get_seqno(overlay->last_flip_req)); if (ret) return ret; i915_gem_retire_requests(dev); @@ -377,7 +384,7 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) if (overlay->flip_tail) overlay->flip_tail(overlay); - overlay->last_flip_req = 0; + i915_gem_request_assign(&overlay->last_flip_req, NULL); return 0; } -- cgit v0.10.2 From a4b3a5713d9f1ca94762b468117f918d3b15e5c4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 26 Nov 2014 14:17:05 +0100 Subject: drm/i915: Convert i915_wait_seqno to i915_wait_request Updated i915_wait_seqno() to take a request structure instead of a seqno value and renamed it accordingly. Internally, it just pulls the seqno out of the request and calls on to __wait_seqno() as before. However, all the code further up the stack is now simplified as it can just pass the request object straight through without having to peek inside. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel [danvet: Squash in hunk from an earlier patch which was rebased wrongly.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e6a997c..23a1afd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2629,8 +2629,7 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, bool interruptible, s64 *timeout, struct drm_i915_file_private *file_priv); -int __must_check i915_wait_seqno(struct intel_engine_cs *ring, - uint32_t seqno); +int __must_check i915_wait_request(struct drm_i915_gem_request *req); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int __must_check i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, @@ -3117,20 +3116,4 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) } } -/* XXX: Temporary solution to be removed later in patch series. */ -static inline int __must_check i915_gem_check_ols( - struct intel_engine_cs *ring, u32 seqno) -{ - int ret; - - WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex)); - - ret = 0; - if (seqno == i915_gem_request_get_seqno(ring->outstanding_lazy_request)) - ret = i915_add_request(ring, NULL); - - return ret; -} -/* XXX: Temporary solution to be removed later in patch series. */ - #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7d6f9bc..1089f0f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1308,32 +1308,40 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, } /** - * Waits for a sequence number to be signaled, and cleans up the + * Waits for a request to be signaled, and cleans up the * request and object lists appropriately for that event. */ int -i915_wait_seqno(struct intel_engine_cs *ring, uint32_t seqno) +i915_wait_request(struct drm_i915_gem_request *req) { - struct drm_device *dev = ring->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - bool interruptible = dev_priv->mm.interruptible; + struct drm_device *dev; + struct drm_i915_private *dev_priv; + bool interruptible; unsigned reset_counter; int ret; + BUG_ON(req == NULL); + + dev = req->ring->dev; + dev_priv = dev->dev_private; + interruptible = dev_priv->mm.interruptible; + BUG_ON(!mutex_is_locked(&dev->struct_mutex)); - BUG_ON(seqno == 0); ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); if (ret) return ret; - ret = i915_gem_check_ols(ring, seqno); + ret = i915_gem_check_olr(req); if (ret) return ret; reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); - return __i915_wait_seqno(ring, seqno, reset_counter, interruptible, - NULL, NULL); + i915_gem_request_reference(req); + ret = __i915_wait_seqno(req->ring, i915_gem_request_get_seqno(req), + reset_counter, interruptible, NULL, NULL); + i915_gem_request_unreference(req); + return ret; } static int @@ -1363,18 +1371,13 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, bool readonly) { struct drm_i915_gem_request *req; - struct intel_engine_cs *ring = obj->ring; - u32 seqno; int ret; req = readonly ? obj->last_write_req : obj->last_read_req; if (!req) return 0; - seqno = i915_gem_request_get_seqno(req); - WARN_ON(seqno == 0); - - ret = i915_wait_seqno(ring, seqno); + ret = i915_wait_request(req); if (ret) return ret; @@ -3332,8 +3335,7 @@ static int i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) { if (obj->last_fenced_req) { - int ret = i915_wait_seqno(obj->ring, - i915_gem_request_get_seqno(obj->last_fenced_req)); + int ret = i915_wait_request(obj->last_fenced_req); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 2f944c4..8d0b8ac 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -922,7 +922,6 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, { struct intel_engine_cs *ring = ringbuf->ring; struct drm_i915_gem_request *request; - u32 seqno = 0; int ret; if (ringbuf->last_retired_head != -1) { @@ -947,15 +946,14 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, /* Would completion of this request free enough space? */ if (__intel_ring_space(request->tail, ringbuf->tail, ringbuf->size) >= bytes) { - seqno = request->seqno; break; } } - if (seqno == 0) + if (&request->list == &ring->request_list) return -ENOSPC; - ret = i915_wait_seqno(ring, seqno); + ret = i915_wait_request(request); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 5defc37..6c530e2 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -224,8 +224,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, return ret; overlay->flip_tail = tail; - ret = i915_wait_seqno(ring, - i915_gem_request_get_seqno(overlay->last_flip_req)); + ret = i915_wait_request(overlay->last_flip_req); if (ret) return ret; i915_gem_retire_requests(dev); @@ -367,19 +366,15 @@ static int intel_overlay_off(struct intel_overlay *overlay) * We have to be careful not to repeat work forever an make forward progess. */ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) { - struct drm_device *dev = overlay->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_engine_cs *ring = &dev_priv->ring[RCS]; int ret; if (overlay->last_flip_req == NULL) return 0; - ret = i915_wait_seqno(ring, - i915_gem_request_get_seqno(overlay->last_flip_req)); + ret = i915_wait_request(overlay->last_flip_req); if (ret) return ret; - i915_gem_retire_requests(dev); + i915_gem_retire_requests(overlay->dev); if (overlay->flip_tail) overlay->flip_tail(overlay); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index accfc89..b9d0d29 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1899,7 +1899,6 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n) { struct intel_ringbuffer *ringbuf = ring->buffer; struct drm_i915_gem_request *request; - u32 seqno = 0; int ret; if (ringbuf->last_retired_head != -1) { @@ -1914,15 +1913,14 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n) list_for_each_entry(request, &ring->request_list, list) { if (__intel_ring_space(request->tail, ringbuf->tail, ringbuf->size) >= n) { - seqno = request->seqno; break; } } - if (seqno == 0) + if (&request->list == &ring->request_list) return -ENOSPC; - ret = i915_wait_seqno(ring, seqno); + ret = i915_wait_request(request); if (ret) return ret; @@ -2011,7 +2009,7 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) int intel_ring_idle(struct intel_engine_cs *ring) { - u32 seqno; + struct drm_i915_gem_request *req; int ret; /* We need to add any requests required to flush the objects and ring */ @@ -2025,11 +2023,11 @@ int intel_ring_idle(struct intel_engine_cs *ring) if (list_empty(&ring->request_list)) return 0; - seqno = list_entry(ring->request_list.prev, + req = list_entry(ring->request_list.prev, struct drm_i915_gem_request, - list)->seqno; + list); - return i915_wait_seqno(ring, seqno); + return i915_wait_request(req); } static int -- cgit v0.10.2 From f245860ece9b18394b679c2c55738babc904f506 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 26 Nov 2014 10:26:05 +0100 Subject: drm/i915: Check locking in i915_gem_request_unreference With refcounting it looks like you can just drop that refcount, but that's not really the case. So make sure no one forgets. Motivated by the unlocked call in the mmio flip code. Cc: John Harrison Cc: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 23a1afd..9a9372a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2046,6 +2046,7 @@ i915_gem_request_reference(struct drm_i915_gem_request *req) static inline void i915_gem_request_unreference(struct drm_i915_gem_request *req) { + WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); kref_put(&req->ref, i915_gem_request_free); } -- cgit v0.10.2 From cc8c4cc2a0cee06ecdd27aa654e26ec3b2b05048 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:34 +0000 Subject: drm/i915: Convert mmio_flip::seqno to struct request Converted the mmio_flip 'seqno' value to be a request structure as part of the on going seqno to request changes. This includes reference counting the request being saved away to ensure it can not be retired and freed while the flip code is still waiting on it. v2: Used the IRQ friendly request dereference call in the notify handler as that code is called asynchronously without holding any useful mutex locks. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel [danvet: Drop the _irq variant and use the normal reques unref, wrapped in dev->struct_mutex per the discussion on the m-l.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3085731..61c4024 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9612,20 +9612,24 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) static void intel_mmio_flip_work_func(struct work_struct *work) { - struct intel_crtc *intel_crtc = + struct intel_crtc *crtc = container_of(work, struct intel_crtc, mmio_flip.work); - struct intel_engine_cs *ring; - uint32_t seqno; + struct intel_mmio_flip *mmio_flip; - seqno = intel_crtc->mmio_flip.seqno; - ring = intel_crtc->mmio_flip.ring; - - if (seqno) - WARN_ON(__i915_wait_seqno(ring, seqno, - intel_crtc->reset_counter, + mmio_flip = &crtc->mmio_flip; + if (mmio_flip->req) + WARN_ON(__i915_wait_seqno(i915_gem_request_get_ring(mmio_flip->req), + i915_gem_request_get_seqno(mmio_flip->req), + crtc->reset_counter, false, NULL, NULL) != 0); - intel_do_mmio_flip(intel_crtc); + intel_do_mmio_flip(crtc); + if (mmio_flip->req) { + mutex_lock(&crtc->base.dev->struct_mutex); + i915_gem_request_unreference(mmio_flip->req); + mutex_unlock(&crtc->base.dev->struct_mutex); + } + mmio_flip->req = NULL; } static int intel_queue_mmio_flip(struct drm_device *dev, @@ -9637,9 +9641,8 @@ static int intel_queue_mmio_flip(struct drm_device *dev, { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_crtc->mmio_flip.seqno = - i915_gem_request_get_seqno(obj->last_write_req); - intel_crtc->mmio_flip.ring = obj->ring; + i915_gem_request_assign(&intel_crtc->mmio_flip.req, + obj->last_write_req); schedule_work(&intel_crtc->mmio_flip.work); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5e81f09..6f87e3c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -406,8 +406,7 @@ struct intel_pipe_wm { }; struct intel_mmio_flip { - u32 seqno; - struct intel_engine_cs *ring; + struct drm_i915_gem_request *req; struct work_struct work; }; -- cgit v0.10.2 From 9c654818295eee21720e62040e235e6951b05b40 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:35 +0000 Subject: drm/i915: Convert __wait_seqno() to __wait_request() Now that all code above is using request structures instead of seqno values, it is possible to convert __wait_seqno() itself. Internally, it is still calling i915_seqno_passed(), this will be updated later in the series. This step is just changing the parameter list and function name. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9a9372a..69a0e00 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2625,7 +2625,7 @@ int __i915_add_request(struct intel_engine_cs *ring, u32 *seqno); #define i915_add_request(ring, seqno) \ __i915_add_request(ring, NULL, NULL, seqno) -int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, +int __i915_wait_request(struct drm_i915_gem_request *req, unsigned reset_counter, bool interruptible, s64 *timeout, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1089f0f..3f56f50 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1189,10 +1189,9 @@ static bool can_wait_boost(struct drm_i915_file_private *file_priv) } /** - * __i915_wait_seqno - wait until execution of seqno has finished - * @ring: the ring expected to report seqno - * @seqno: duh! - * @reset_counter: reset sequence associated with the given seqno + * __i915_wait_request - wait until execution of request has finished + * @req: duh! + * @reset_counter: reset sequence associated with the given request * @interruptible: do an interruptible wait (normally yes) * @timeout: in - how long to wait (NULL forever); out - how much time remaining * @@ -1203,15 +1202,16 @@ static bool can_wait_boost(struct drm_i915_file_private *file_priv) * reset_counter _must_ be read before, and an appropriate smp_rmb must be * inserted. * - * Returns 0 if the seqno was found within the alloted time. Else returns the + * Returns 0 if the request was found within the alloted time. Else returns the * errno with remaining time filled in timeout argument. */ -int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, +int __i915_wait_request(struct drm_i915_gem_request *req, unsigned reset_counter, bool interruptible, s64 *timeout, struct drm_i915_file_private *file_priv) { + struct intel_engine_cs *ring = i915_gem_request_get_ring(req); struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; const bool irq_test_in_progress = @@ -1223,7 +1223,8 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, WARN(!intel_irqs_enabled(dev_priv), "IRQs disabled"); - if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) + if (i915_seqno_passed(ring->get_seqno(ring, true), + i915_gem_request_get_seqno(req))) return 0; timeout_expire = timeout ? jiffies + nsecs_to_jiffies((u64)*timeout) : 0; @@ -1240,7 +1241,8 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, return -ENODEV; /* Record current time in case interrupted by signal, or wedged */ - trace_i915_gem_request_wait_begin(ring, seqno); + trace_i915_gem_request_wait_begin(i915_gem_request_get_ring(req), + i915_gem_request_get_seqno(req)); before = ktime_get_raw_ns(); for (;;) { struct timer_list timer; @@ -1259,7 +1261,8 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, break; } - if (i915_seqno_passed(ring->get_seqno(ring, false), seqno)) { + if (i915_seqno_passed(ring->get_seqno(ring, false), + i915_gem_request_get_seqno(req))) { ret = 0; break; } @@ -1291,7 +1294,8 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno, } } now = ktime_get_raw_ns(); - trace_i915_gem_request_wait_end(ring, seqno); + trace_i915_gem_request_wait_end(i915_gem_request_get_ring(req), + i915_gem_request_get_seqno(req)); if (!irq_test_in_progress) ring->irq_put(ring); @@ -1338,8 +1342,8 @@ i915_wait_request(struct drm_i915_gem_request *req) reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); i915_gem_request_reference(req); - ret = __i915_wait_seqno(req->ring, i915_gem_request_get_seqno(req), - reset_counter, interruptible, NULL, NULL); + ret = __i915_wait_request(req, reset_counter, + interruptible, NULL, NULL); i915_gem_request_unreference(req); return ret; } @@ -1395,7 +1399,6 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, struct drm_i915_gem_request *req; struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_engine_cs *ring = obj->ring; unsigned reset_counter; int ret; @@ -1417,8 +1420,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); i915_gem_request_reference(req); mutex_unlock(&dev->struct_mutex); - ret = __i915_wait_seqno(ring, i915_gem_request_get_seqno(req), - reset_counter, true, NULL, file_priv); + ret = __i915_wait_request(req, reset_counter, true, NULL, file_priv); mutex_lock(&dev->struct_mutex); i915_gem_request_unreference(req); if (ret) @@ -2917,9 +2919,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) struct drm_i915_gem_wait *args = data; struct drm_i915_gem_object *obj; struct drm_i915_gem_request *req; - struct intel_engine_cs *ring = NULL; unsigned reset_counter; - u32 seqno = 0; int ret = 0; if (args->flags != 0) @@ -2944,9 +2944,6 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) goto out; req = obj->last_read_req; - seqno = i915_gem_request_get_seqno(req); - WARN_ON(seqno == 0); - ring = obj->ring; /* Do this after OLR check to make sure we make forward progress polling * on this IOCTL with a timeout <=0 (like busy ioctl) @@ -2961,8 +2958,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) i915_gem_request_reference(req); mutex_unlock(&dev->struct_mutex); - ret = __i915_wait_seqno(ring, seqno, reset_counter, true, &args->timeout_ns, - file->driver_priv); + ret = __i915_wait_request(req, reset_counter, true, &args->timeout_ns, + file->driver_priv); mutex_lock(&dev->struct_mutex); i915_gem_request_unreference(req); mutex_unlock(&dev->struct_mutex); @@ -4127,9 +4124,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) if (target == NULL) return 0; - ret = __i915_wait_seqno(i915_gem_request_get_ring(target), - i915_gem_request_get_seqno(target), - reset_counter, true, NULL, NULL); + ret = __i915_wait_request(target, reset_counter, true, NULL, NULL); if (ret == 0) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 61c4024..0eaa1f4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9618,10 +9618,9 @@ static void intel_mmio_flip_work_func(struct work_struct *work) mmio_flip = &crtc->mmio_flip; if (mmio_flip->req) - WARN_ON(__i915_wait_seqno(i915_gem_request_get_ring(mmio_flip->req), - i915_gem_request_get_seqno(mmio_flip->req), - crtc->reset_counter, - false, NULL, NULL) != 0); + WARN_ON(__i915_wait_request(mmio_flip->req, + crtc->reset_counter, + false, NULL, NULL) != 0); intel_do_mmio_flip(crtc); if (mmio_flip->req) { -- cgit v0.10.2 From 9400ae5c8248dd29c55f2c2355b71e55995774d3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:36 +0000 Subject: drm/i915: Remove obsolete seqno parameter from 'i915_add_request' There is no longer any need to retrieve a seqno value from an i915_add_request() call. The calling code already knows which request structure is being processed (it can only be ring->OLR). And as the request itself is now used in preference to the basic seqno value, the latter is now redundant in this situation. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 69a0e00..d4e1fa7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2621,10 +2621,9 @@ int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); int __i915_add_request(struct intel_engine_cs *ring, struct drm_file *file, - struct drm_i915_gem_object *batch_obj, - u32 *seqno); -#define i915_add_request(ring, seqno) \ - __i915_add_request(ring, NULL, NULL, seqno) + struct drm_i915_gem_object *batch_obj); +#define i915_add_request(ring) \ + __i915_add_request(ring, NULL, NULL) int __i915_wait_request(struct drm_i915_gem_request *req, unsigned reset_counter, bool interruptible, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3f56f50..c403bac 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1164,7 +1164,7 @@ i915_gem_check_olr(struct drm_i915_gem_request *req) ret = 0; if (req == req->ring->outstanding_lazy_request) - ret = i915_add_request(req->ring, NULL); + ret = i915_add_request(req->ring); return ret; } @@ -2412,8 +2412,7 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) int __i915_add_request(struct intel_engine_cs *ring, struct drm_file *file, - struct drm_i915_gem_object *obj, - u32 *out_seqno) + struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; @@ -2512,8 +2511,6 @@ int __i915_add_request(struct intel_engine_cs *ring, round_jiffies_up_relative(HZ)); intel_mark_busy(dev_priv->dev); - if (out_seqno) - *out_seqno = request->seqno; return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 7ecfa91..faada75 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -993,7 +993,7 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - (void)__i915_add_request(ring, file, obj, NULL); + (void)__i915_add_request(ring, file, obj); } static int diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index 98dcd94..521548a 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -173,7 +173,7 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring) i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - ret = __i915_add_request(ring, NULL, so.obj, NULL); + ret = __i915_add_request(ring, NULL, so.obj); /* __i915_add_request moves object to inactive if it fails */ out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8d0b8ac..1ed25a1 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1628,7 +1628,7 @@ int intel_lr_context_render_state_init(struct intel_engine_cs *ring, i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - ret = __i915_add_request(ring, file, so.obj, NULL); + ret = __i915_add_request(ring, file, so.obj); /* intel_logical_ring_add_request moves object to inactive if it * fails */ out: diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 6c530e2..c1abf49 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -219,7 +219,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, BUG_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, ring->outstanding_lazy_request); - ret = i915_add_request(ring, NULL); + ret = i915_add_request(ring); if (ret) return ret; @@ -291,7 +291,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, WARN_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, ring->outstanding_lazy_request); - return i915_add_request(ring, NULL); + return i915_add_request(ring); } static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b9d0d29..abdaafd 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2014,7 +2014,7 @@ int intel_ring_idle(struct intel_engine_cs *ring) /* We need to add any requests required to flush the objects and ring */ if (ring->outstanding_lazy_request) { - ret = i915_add_request(ring, NULL); + ret = i915_add_request(ring); if (ret) return ret; } -- cgit v0.10.2 From f06cc1b9401cf0b60f3cd30d8127a8a4f088d4c3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:37 +0000 Subject: drm/i915: Convert 'flip_queued_seqno' into 'flip_queued_request' Converted the flip_queued_seqno value to be a request structure as part of the on going seqno to request changes. This includes reference counting the request being saved away to ensure it can not be retired and freed while the flip code is still waiting on it. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel [danvet: Again get rid of the _irq request unref by simply moving that into the unpin worker. Doesn't matter when we hang onto the request for a bit longer, and in the unpin worker we already grab the dev->struct_mutex anyway.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4619873..3a25a7be 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -544,11 +544,11 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) if (work->flip_queued_ring) { seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n", work->flip_queued_ring->name, - work->flip_queued_seqno, + i915_gem_request_get_seqno(work->flip_queued_req), dev_priv->next_seqno, work->flip_queued_ring->get_seqno(work->flip_queued_ring, true), i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true), - work->flip_queued_seqno)); + i915_gem_request_get_seqno(work->flip_queued_req))); } else seq_printf(m, "Flip not associated with any ring\n"); seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n", diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0eaa1f4..766cea7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9128,6 +9128,11 @@ static void intel_unpin_work_fn(struct work_struct *__work) drm_gem_object_unreference(&work->old_fb_obj->base); intel_update_fbc(dev); + + if (work->flip_queued_req) + i915_gem_request_unreference(work->flip_queued_req); + work->flip_queued_req = NULL; + work->flip_queued_ring = NULL; mutex_unlock(&dev->struct_mutex); intel_frontbuffer_flip_complete(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); @@ -9736,10 +9741,14 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev, return false; if (work->flip_ready_vblank == 0) { - if (work->flip_queued_ring && - !i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true), - work->flip_queued_seqno)) - return false; + if (work->flip_queued_ring) { + uint32_t s1 = work->flip_queued_ring->get_seqno( + work->flip_queued_ring, true); + uint32_t s2 = i915_gem_request_get_seqno( + work->flip_queued_req); + if (!i915_seqno_passed(s1, s2)) + return false; + } work->flip_ready_vblank = drm_vblank_count(dev, intel_crtc->pipe); } @@ -9903,8 +9912,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (ret) goto cleanup_unpin; - work->flip_queued_seqno = - i915_gem_request_get_seqno(obj->last_write_req); + i915_gem_request_assign(&work->flip_queued_req, + obj->last_write_req); work->flip_queued_ring = obj->ring; } else { ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring, @@ -9912,8 +9921,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (ret) goto cleanup_unpin; - work->flip_queued_seqno = - i915_gem_request_get_seqno(intel_ring_get_request(ring)); + i915_gem_request_assign(&work->flip_queued_req, + intel_ring_get_request(ring)); work->flip_queued_ring = ring; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6f87e3c..a3c7e14f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -708,7 +708,7 @@ struct intel_unpin_work { u32 flip_count; u32 gtt_offset; struct intel_engine_cs *flip_queued_ring; - u32 flip_queued_seqno; + struct drm_i915_gem_request *flip_queued_req; int flip_queued_vblank; int flip_ready_vblank; bool enable_stall_check; -- cgit v0.10.2 From 74328ee51051e73e4952876cc9061ff01530267c Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:38 +0000 Subject: drm/i915: Convert trace functions from seqno to request All the code above is now using requests not seqnos so it is possible to convert the trace functions across. Note that rather than get into problematic reference counting issues, the trace code only saves the seqno and ring values from the request structure not the structure pointer itself. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c403bac..e798155 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1241,8 +1241,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req, return -ENODEV; /* Record current time in case interrupted by signal, or wedged */ - trace_i915_gem_request_wait_begin(i915_gem_request_get_ring(req), - i915_gem_request_get_seqno(req)); + trace_i915_gem_request_wait_begin(req); before = ktime_get_raw_ns(); for (;;) { struct timer_list timer; @@ -1294,8 +1293,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req, } } now = ktime_get_raw_ns(); - trace_i915_gem_request_wait_end(i915_gem_request_get_ring(req), - i915_gem_request_get_seqno(req)); + trace_i915_gem_request_wait_end(req); if (!irq_test_in_progress) ring->irq_put(ring); @@ -2500,7 +2498,7 @@ int __i915_add_request(struct intel_engine_cs *ring, spin_unlock(&file_priv->mm.lock); } - trace_i915_gem_request_add(ring, request->seqno); + trace_i915_gem_request_add(request); ring->outstanding_lazy_request = NULL; i915_queue_hangcheck(ring->dev); @@ -2776,7 +2774,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) if (!i915_seqno_passed(seqno, request->seqno)) break; - trace_i915_gem_request_retire(ring, request->seqno); + trace_i915_gem_request_retire(request); /* This is one of the few common intersection points * between legacy ringbuffer submission and execlists: @@ -3006,7 +3004,7 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, if (ret) return ret; - trace_i915_gem_ring_sync_to(from, to, seqno); + trace_i915_gem_ring_sync_to(from, to, obj->last_read_req); ret = to->semaphore.sync_to(to, from, seqno); if (!ret) /* We use last_read_req because sync_to() diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index faada75..0c25f62 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1211,9 +1211,7 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, return ret; } - trace_i915_gem_ring_dispatch(ring, - i915_gem_request_get_seqno(intel_ring_get_request(ring)), - flags); + trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), flags); i915_gem_execbuffer_move_to_active(vmas, ring); i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 751d4ad..2c0327b 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -328,8 +328,8 @@ TRACE_EVENT(i915_gem_evict_vm, TRACE_EVENT(i915_gem_ring_sync_to, TP_PROTO(struct intel_engine_cs *from, struct intel_engine_cs *to, - u32 seqno), - TP_ARGS(from, to, seqno), + struct drm_i915_gem_request *req), + TP_ARGS(from, to, req), TP_STRUCT__entry( __field(u32, dev) @@ -342,7 +342,7 @@ TRACE_EVENT(i915_gem_ring_sync_to, __entry->dev = from->dev->primary->index; __entry->sync_from = from->id; __entry->sync_to = to->id; - __entry->seqno = seqno; + __entry->seqno = i915_gem_request_get_seqno(req); ), TP_printk("dev=%u, sync-from=%u, sync-to=%u, seqno=%u", @@ -352,8 +352,8 @@ TRACE_EVENT(i915_gem_ring_sync_to, ); TRACE_EVENT(i915_gem_ring_dispatch, - TP_PROTO(struct intel_engine_cs *ring, u32 seqno, u32 flags), - TP_ARGS(ring, seqno, flags), + TP_PROTO(struct drm_i915_gem_request *req, u32 flags), + TP_ARGS(req, flags), TP_STRUCT__entry( __field(u32, dev) @@ -363,11 +363,13 @@ TRACE_EVENT(i915_gem_ring_dispatch, ), TP_fast_assign( + struct intel_engine_cs *ring = + i915_gem_request_get_ring(req); __entry->dev = ring->dev->primary->index; __entry->ring = ring->id; - __entry->seqno = seqno; + __entry->seqno = i915_gem_request_get_seqno(req); __entry->flags = flags; - i915_trace_irq_get(ring, seqno); + i915_trace_irq_get(ring, __entry->seqno); ), TP_printk("dev=%u, ring=%u, seqno=%u, flags=%x", @@ -398,8 +400,8 @@ TRACE_EVENT(i915_gem_ring_flush, ); DECLARE_EVENT_CLASS(i915_gem_request, - TP_PROTO(struct intel_engine_cs *ring, u32 seqno), - TP_ARGS(ring, seqno), + TP_PROTO(struct drm_i915_gem_request *req), + TP_ARGS(req), TP_STRUCT__entry( __field(u32, dev) @@ -408,9 +410,11 @@ DECLARE_EVENT_CLASS(i915_gem_request, ), TP_fast_assign( + struct intel_engine_cs *ring = + i915_gem_request_get_ring(req); __entry->dev = ring->dev->primary->index; __entry->ring = ring->id; - __entry->seqno = seqno; + __entry->seqno = i915_gem_request_get_seqno(req); ), TP_printk("dev=%u, ring=%u, seqno=%u", @@ -418,8 +422,8 @@ DECLARE_EVENT_CLASS(i915_gem_request, ); DEFINE_EVENT(i915_gem_request, i915_gem_request_add, - TP_PROTO(struct intel_engine_cs *ring, u32 seqno), - TP_ARGS(ring, seqno) + TP_PROTO(struct drm_i915_gem_request *req), + TP_ARGS(req) ); TRACE_EVENT(i915_gem_request_complete, @@ -443,13 +447,13 @@ TRACE_EVENT(i915_gem_request_complete, ); DEFINE_EVENT(i915_gem_request, i915_gem_request_retire, - TP_PROTO(struct intel_engine_cs *ring, u32 seqno), - TP_ARGS(ring, seqno) + TP_PROTO(struct drm_i915_gem_request *req), + TP_ARGS(req) ); TRACE_EVENT(i915_gem_request_wait_begin, - TP_PROTO(struct intel_engine_cs *ring, u32 seqno), - TP_ARGS(ring, seqno), + TP_PROTO(struct drm_i915_gem_request *req), + TP_ARGS(req), TP_STRUCT__entry( __field(u32, dev) @@ -465,10 +469,13 @@ TRACE_EVENT(i915_gem_request_wait_begin, * less desirable. */ TP_fast_assign( + struct intel_engine_cs *ring = + i915_gem_request_get_ring(req); __entry->dev = ring->dev->primary->index; __entry->ring = ring->id; - __entry->seqno = seqno; - __entry->blocking = mutex_is_locked(&ring->dev->struct_mutex); + __entry->seqno = i915_gem_request_get_seqno(req); + __entry->blocking = + mutex_is_locked(&ring->dev->struct_mutex); ), TP_printk("dev=%u, ring=%u, seqno=%u, blocking=%s", @@ -477,8 +484,8 @@ TRACE_EVENT(i915_gem_request_wait_begin, ); DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end, - TP_PROTO(struct intel_engine_cs *ring, u32 seqno), - TP_ARGS(ring, seqno) + TP_PROTO(struct drm_i915_gem_request *req), + TP_ARGS(req) ); DECLARE_EVENT_CLASS(i915_ring, -- cgit v0.10.2 From 44cdd6d219bc64f6810b8ed0023a4d4db9e0fe68 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:40 +0000 Subject: drm/i915: Convert 'ring_idle()' to use requests not seqnos More seqno value to request structure conversions. Note, this change temporarily moves the 'get_seqno()' call inside ring_idle() but this will disappear again in a later patch when i915_seqno_passed() itself is converted. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 981834b..1bb315a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2749,18 +2749,19 @@ static void gen8_disable_vblank(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } -static u32 -ring_last_seqno(struct intel_engine_cs *ring) +static struct drm_i915_gem_request * +ring_last_request(struct intel_engine_cs *ring) { return list_entry(ring->request_list.prev, - struct drm_i915_gem_request, list)->seqno; + struct drm_i915_gem_request, list); } static bool -ring_idle(struct intel_engine_cs *ring, u32 seqno) +ring_idle(struct intel_engine_cs *ring) { return (list_empty(&ring->request_list) || - i915_seqno_passed(seqno, ring_last_seqno(ring))); + i915_seqno_passed(ring->get_seqno(ring, false), + i915_gem_request_get_seqno(ring_last_request(ring)))); } static bool @@ -2980,7 +2981,7 @@ static void i915_hangcheck_elapsed(unsigned long data) acthd = intel_ring_get_active_head(ring); if (ring->hangcheck.seqno == seqno) { - if (ring_idle(ring, seqno)) { + if (ring_idle(ring)) { ring->hangcheck.action = HANGCHECK_IDLE; if (waitqueue_active(&ring->irq_queue)) { -- cgit v0.10.2 From ff79e857024143f54aff5257c14595e949f46d8a Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:41 +0000 Subject: drm/i915: Connect requests to rings at creation not submission It makes a lot more sense (and makes future seqno -> request conversion patches simpler) to fill in the 'ring' field of the request structure at the point of creation rather than submission. Given that the request structure is assigned by ring specific code and thus is locked to a ring from the start, there really is no reason to defer this assignment. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e798155..8285c08 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2463,7 +2463,6 @@ int __i915_add_request(struct intel_engine_cs *ring, return ret; } - request->ring = ring; request->head = request_start; request->tail = request_ring_position; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 1ed25a1..b13221b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -898,6 +898,7 @@ static int logical_ring_alloc_request(struct intel_engine_cs *ring, } kref_init(&request->ref); + request->ring = ring; ret = i915_gem_get_seqno(ring->dev, &request->seqno); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index abdaafd..788e1b6 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2044,6 +2044,7 @@ intel_ring_alloc_request(struct intel_engine_cs *ring) return -ENOMEM; kref_init(&request->ref); + request->ring = ring; ret = i915_gem_get_seqno(ring->dev, &request->seqno); if (ret) { -- cgit v0.10.2 From 1b5a433a4dd967b125131da42b89b5cc0d5b1f57 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:42 +0000 Subject: drm/i915: Convert 'i915_seqno_passed' calls into 'i915_gem_request_completed' Almost everywhere that caled i915_seqno_passed() was really asking 'has the given seqno popped out of the hardware yet?'. Thus it had to query the current hardware seqno and then do a signed delta comparison (which copes with wrapping around zero but not with seqno values more than 2GB apart, although the latter is unlikely!). Now that the majority of seqno instances have been replaced with request structures, it is possible to convert this test to be request based as well. There is now a 'i915_gem_request_completed()' function which takes a request and returns true or false as appropriate. Note that this currently just wraps up the original _passed() test but a later patch in the series will reduce this to simply returning a cached internal value, i.e.: _completed(req) { return req->completed; }' This checkin converts almost all _seqno_passed() calls. The only one left is in the semaphore code which still requires seqnos not request structures. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel [danvet: Drop hunk touching the trace_irq code since I've dropped the patch which converts that, and resolve resulting conflict.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3a25a7be..a76aa31 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -547,8 +547,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) i915_gem_request_get_seqno(work->flip_queued_req), dev_priv->next_seqno, work->flip_queued_ring->get_seqno(work->flip_queued_ring, true), - i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true), - i915_gem_request_get_seqno(work->flip_queued_req))); + i915_gem_request_completed(work->flip_queued_req, true)); } else seq_printf(m, "Flip not associated with any ring\n"); seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n", diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d4e1fa7..04fb96e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2062,6 +2062,12 @@ static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst, *pdst = src; } +/* + * XXX: i915_gem_request_completed should be here but currently needs the + * definition of i915_seqno_passed() which is below. It will be moved in + * a later patch when the call to i915_seqno_passed() is obsoleted... + */ + struct drm_i915_file_private { struct drm_i915_private *dev_priv; struct drm_file *file; @@ -2563,6 +2569,18 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) return (int32_t)(seq1 - seq2) >= 0; } +static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req, + bool lazy_coherency) +{ + u32 seqno; + + BUG_ON(req == NULL); + + seqno = req->ring->get_seqno(req->ring, lazy_coherency); + + return i915_seqno_passed(seqno, req->seqno); +} + int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno); int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno); int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8285c08..16a8445 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1223,8 +1223,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req, WARN(!intel_irqs_enabled(dev_priv), "IRQs disabled"); - if (i915_seqno_passed(ring->get_seqno(ring, true), - i915_gem_request_get_seqno(req))) + if (i915_gem_request_completed(req, true)) return 0; timeout_expire = timeout ? jiffies + nsecs_to_jiffies((u64)*timeout) : 0; @@ -1260,8 +1259,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req, break; } - if (i915_seqno_passed(ring->get_seqno(ring, false), - i915_gem_request_get_seqno(req))) { + if (i915_gem_request_completed(req, false)) { ret = 0; break; } @@ -2333,8 +2331,7 @@ i915_gem_object_retire(struct drm_i915_gem_object *obj) if (ring == NULL) return; - if (i915_seqno_passed(ring->get_seqno(ring, true), - i915_gem_request_get_seqno(obj->last_read_req))) + if (i915_gem_request_completed(obj->last_read_req, true)) i915_gem_object_move_to_inactive(obj); } @@ -2601,12 +2598,9 @@ struct drm_i915_gem_request * i915_gem_find_active_request(struct intel_engine_cs *ring) { struct drm_i915_gem_request *request; - u32 completed_seqno; - - completed_seqno = ring->get_seqno(ring, false); list_for_each_entry(request, &ring->request_list, list) { - if (i915_seqno_passed(completed_seqno, request->seqno)) + if (i915_gem_request_completed(request, false)) continue; return request; @@ -2734,15 +2728,11 @@ void i915_gem_reset(struct drm_device *dev) void i915_gem_retire_requests_ring(struct intel_engine_cs *ring) { - uint32_t seqno; - if (list_empty(&ring->request_list)) return; WARN_ON(i915_verify_lists(ring->dev)); - seqno = ring->get_seqno(ring, true); - /* Move any buffers on the active list that are no longer referenced * by the ringbuffer to the flushing/inactive lists as appropriate, * before we free the context associated with the requests. @@ -2754,8 +2744,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) struct drm_i915_gem_object, ring_list); - if (!i915_seqno_passed(seqno, - i915_gem_request_get_seqno(obj->last_read_req))) + if (!i915_gem_request_completed(obj->last_read_req, true)) break; i915_gem_object_move_to_inactive(obj); @@ -2770,7 +2759,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) struct drm_i915_gem_request, list); - if (!i915_seqno_passed(seqno, request->seqno)) + if (!i915_gem_request_completed(request, true)) break; trace_i915_gem_request_retire(request); @@ -2797,7 +2786,8 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) } if (unlikely(ring->trace_irq_seqno && - i915_seqno_passed(seqno, ring->trace_irq_seqno))) { + i915_seqno_passed(ring->get_seqno(ring, true), + ring->trace_irq_seqno))) { ring->irq_put(ring); ring->trace_irq_seqno = 0; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 1bb315a..7913a72 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2760,8 +2760,7 @@ static bool ring_idle(struct intel_engine_cs *ring) { return (list_empty(&ring->request_list) || - i915_seqno_passed(ring->get_seqno(ring, false), - i915_gem_request_get_seqno(ring_last_request(ring)))); + i915_gem_request_completed(ring_last_request(ring), false)); } static bool diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 766cea7..92a0350 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9742,11 +9742,7 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev, if (work->flip_ready_vblank == 0) { if (work->flip_queued_ring) { - uint32_t s1 = work->flip_queued_ring->get_seqno( - work->flip_queued_ring, true); - uint32_t s2 = i915_gem_request_get_seqno( - work->flip_queued_req); - if (!i915_seqno_passed(s1, s2)) + if (!i915_gem_request_completed(work->flip_queued_req, true)) return false; } -- cgit v0.10.2 From 41c5241555d762810f975d5d9d70143aa93834cd Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:43 +0000 Subject: drm/i915: Remove the now redundant 'obj->ring' The ring member of the object structure was always updated with the last_read_seqno member. Thus with the conversion to last_read_req, obj->ring is now a direct copy of obj->last_read_req->ring. This makes it somewhat redundant and potentially misleading (especially as there was no comment to explain its purpose). This checkin removes the redundant field. Many uses were simply testing for non-null to see if the object is active on the GPU. Some of these have been converted to check 'obj->active' instead. Others (where the last_read_req is about to be used anyway) have been changed to check obj->last_read_req. The rest simply pull the ring out from the request structure and proceed as before. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a76aa31..b2dca46 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -166,8 +166,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) *t = '\0'; seq_printf(m, " (%s mappable)", s); } - if (obj->ring != NULL) - seq_printf(m, " (%s)", obj->ring->name); + if (obj->last_read_req != NULL) + seq_printf(m, " (%s)", + i915_gem_request_get_ring(obj->last_read_req)->name); if (obj->frontbuffer_bits) seq_printf(m, " (frontbuffer: 0x%03x)", obj->frontbuffer_bits); } @@ -334,7 +335,7 @@ static int per_file_stats(int id, void *ptr, void *data) if (ppgtt->file_priv != stats->file_priv) continue; - if (obj->ring) /* XXX per-vma statistic */ + if (obj->active) /* XXX per-vma statistic */ stats->active += obj->base.size; else stats->inactive += obj->base.size; @@ -344,7 +345,7 @@ static int per_file_stats(int id, void *ptr, void *data) } else { if (i915_gem_obj_ggtt_bound(obj)) { stats->global += obj->base.size; - if (obj->ring) + if (obj->active) stats->active += obj->base.size; else stats->inactive += obj->base.size; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 04fb96e..97804a3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1941,8 +1941,6 @@ struct drm_i915_gem_object { void *dma_buf_vmapping; int vmapping_count; - struct intel_engine_cs *ring; - /** Breadcrumb of last rendering to the buffer. */ struct drm_i915_gem_request *last_read_req; struct drm_i915_gem_request *last_write_req; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 16a8445..b9222a7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2263,14 +2263,18 @@ static void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_engine_cs *ring) { - struct drm_i915_gem_request *req = intel_ring_get_request(ring); + struct drm_i915_gem_request *req; + struct intel_engine_cs *old_ring; BUG_ON(ring == NULL); - if (obj->ring != ring && obj->last_write_req) { + + req = intel_ring_get_request(ring); + old_ring = i915_gem_request_get_ring(obj->last_read_req); + + if (old_ring != ring && obj->last_write_req) { /* Keep the request relative to the current ring */ i915_gem_request_assign(&obj->last_write_req, req); } - obj->ring = ring; /* Add a reference if we're newly entering the active list. */ if (!obj->active) { @@ -2309,7 +2313,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) intel_fb_obj_flush(obj, true); list_del_init(&obj->ring_list); - obj->ring = NULL; i915_gem_request_assign(&obj->last_read_req, NULL); i915_gem_request_assign(&obj->last_write_req, NULL); @@ -2326,9 +2329,7 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) static void i915_gem_object_retire(struct drm_i915_gem_object *obj) { - struct intel_engine_cs *ring = obj->ring; - - if (ring == NULL) + if (obj->last_read_req == NULL) return; if (i915_gem_request_completed(obj->last_read_req, true)) @@ -2861,14 +2862,17 @@ i915_gem_idle_work_handler(struct work_struct *work) static int i915_gem_object_flush_active(struct drm_i915_gem_object *obj) { + struct intel_engine_cs *ring; int ret; if (obj->active) { + ring = i915_gem_request_get_ring(obj->last_read_req); + ret = i915_gem_check_olr(obj->last_read_req); if (ret) return ret; - i915_gem_retire_requests_ring(obj->ring); + i915_gem_retire_requests_ring(ring); } return 0; @@ -2971,10 +2975,12 @@ int i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_engine_cs *to) { - struct intel_engine_cs *from = obj->ring; + struct intel_engine_cs *from; u32 seqno; int ret, idx; + from = i915_gem_request_get_ring(obj->last_read_req); + if (from == NULL || to == from) return 0; @@ -3929,7 +3935,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, bool was_pin_display; int ret; - if (pipelined != obj->ring) { + if (pipelined != i915_gem_request_get_ring(obj->last_read_req)) { ret = i915_gem_object_sync(obj, pipelined); if (ret) return ret; @@ -4284,9 +4290,11 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, ret = i915_gem_object_flush_active(obj); args->busy = obj->active; - if (obj->ring) { + if (obj->last_read_req) { + struct intel_engine_cs *ring; BUILD_BUG_ON(I915_NUM_RINGS > 16); - args->busy |= intel_ring_flag(obj->ring) << 16; + ring = i915_gem_request_get_ring(obj->last_read_req); + args->busy |= intel_ring_flag(ring) << 16; } drm_gem_object_unreference(&obj->base); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index d17ff43..3c3a9ff 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -619,7 +619,8 @@ static int do_switch(struct intel_engine_cs *ring, * swapped, but there is no way to do that yet. */ from->legacy_hw_ctx.rcs_state->dirty = 1; - BUG_ON(from->legacy_hw_ctx.rcs_state->ring != ring); + BUG_ON(i915_gem_request_get_ring( + from->legacy_hw_ctx.rcs_state->last_read_req) != ring); /* obj is kept alive until the next request by its active ref */ i915_gem_object_ggtt_unpin(from->legacy_hw_ctx.rcs_state); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index af0ceee..c4536e1 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -683,7 +683,8 @@ static void capture_bo(struct drm_i915_error_buffer *err, err->dirty = obj->dirty; err->purgeable = obj->madv != I915_MADV_WILLNEED; err->userptr = obj->userptr.mm != NULL; - err->ring = obj->ring ? obj->ring->id : -1; + err->ring = obj->last_read_req ? + i915_gem_request_get_ring(obj->last_read_req)->id : -1; err->cache_level = obj->cache_level; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 92a0350..e216cb7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9528,7 +9528,7 @@ static bool use_mmio_flip(struct intel_engine_cs *ring, else if (i915.enable_execlists) return true; else - return ring != obj->ring; + return ring != i915_gem_request_get_ring(obj->last_read_req); } static void skl_do_mmio_flip(struct intel_crtc *intel_crtc) @@ -9888,7 +9888,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, } else if (IS_IVYBRIDGE(dev)) { ring = &dev_priv->ring[BCS]; } else if (INTEL_INFO(dev)->gen >= 7) { - ring = obj->ring; + ring = i915_gem_request_get_ring(obj->last_read_req); if (ring == NULL || ring->id != RCS) ring = &dev_priv->ring[BCS]; } else { @@ -9910,7 +9910,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, i915_gem_request_assign(&work->flip_queued_req, obj->last_write_req); - work->flip_queued_ring = obj->ring; + work->flip_queued_ring = + i915_gem_request_get_ring(obj->last_write_req); } else { ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring, page_flip_flags); -- cgit v0.10.2 From 3a8a946efbe0312f7a3d074163499f13d38dfb08 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 26 Nov 2014 14:39:48 +0100 Subject: drm/i915: Remove redundant flip_work->flip_queued_ring Similar to the patch from John which removed obj->ring. Cc: John Harrison Cc: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b2dca46..6c16939 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -542,12 +542,15 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n", pipe, plane); } - if (work->flip_queued_ring) { + if (work->flip_queued_req) { + struct intel_engine_cs *ring = + i915_gem_request_get_ring(work->flip_queued_req); + seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n", - work->flip_queued_ring->name, + ring->name, i915_gem_request_get_seqno(work->flip_queued_req), dev_priv->next_seqno, - work->flip_queued_ring->get_seqno(work->flip_queued_ring, true), + ring->get_seqno(ring, true), i915_gem_request_completed(work->flip_queued_req, true)); } else seq_printf(m, "Flip not associated with any ring\n"); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e216cb7..376ec89 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9132,7 +9132,6 @@ static void intel_unpin_work_fn(struct work_struct *__work) if (work->flip_queued_req) i915_gem_request_unreference(work->flip_queued_req); work->flip_queued_req = NULL; - work->flip_queued_ring = NULL; mutex_unlock(&dev->struct_mutex); intel_frontbuffer_flip_complete(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); @@ -9741,10 +9740,9 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev, return false; if (work->flip_ready_vblank == 0) { - if (work->flip_queued_ring) { - if (!i915_gem_request_completed(work->flip_queued_req, true)) - return false; - } + if (work->flip_queued_req && + !i915_gem_request_completed(work->flip_queued_req, true)) + return false; work->flip_ready_vblank = drm_vblank_count(dev, intel_crtc->pipe); } @@ -9910,8 +9908,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, i915_gem_request_assign(&work->flip_queued_req, obj->last_write_req); - work->flip_queued_ring = - i915_gem_request_get_ring(obj->last_write_req); } else { ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring, page_flip_flags); @@ -9920,7 +9916,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, i915_gem_request_assign(&work->flip_queued_req, intel_ring_get_request(ring)); - work->flip_queued_ring = ring; } work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a3c7e14f..1a9c70f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -707,7 +707,6 @@ struct intel_unpin_work { #define INTEL_FLIP_COMPLETE 2 u32 flip_count; u32 gtt_offset; - struct intel_engine_cs *flip_queued_ring; struct drm_i915_gem_request *flip_queued_req; int flip_queued_vblank; int flip_ready_vblank; -- cgit v0.10.2 From 581c26e8a26482eb9d8072a35978034e2dd16b9d Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 24 Nov 2014 18:49:39 +0000 Subject: drm/i915: Convert 'trace_irq' to use requests rather than seqnos Updated the trace_irq code to use requests instead of seqnos. This includes reference counting the request object to ensure it sticks around when required. Note that getting access to the reference counting functions means moving the inline i915_trace_irq_get() function from intel_ringbuffer.h to i915_drv.h. For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel [danvet: Resolve conflict due to shuffled merge order.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 97804a3..049482f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3132,4 +3132,11 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) } } +static inline void i915_trace_irq_get(struct intel_engine_cs *ring, + struct drm_i915_gem_request *req) +{ + if (ring->trace_irq_req == NULL && ring->irq_get(ring)) + i915_gem_request_assign(&ring->trace_irq_req, req); +} + #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b9222a7..0751ec9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2786,11 +2786,10 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) i915_gem_free_request(request); } - if (unlikely(ring->trace_irq_seqno && - i915_seqno_passed(ring->get_seqno(ring, true), - ring->trace_irq_seqno))) { + if (unlikely(ring->trace_irq_req && + i915_gem_request_completed(ring->trace_irq_req, true))) { ring->irq_put(ring); - ring->trace_irq_seqno = 0; + i915_gem_request_assign(&ring->trace_irq_req, NULL); } WARN_ON(i915_verify_lists(ring->dev)); diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 2c0327b..2ade958 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -369,7 +369,7 @@ TRACE_EVENT(i915_gem_ring_dispatch, __entry->ring = ring->id; __entry->seqno = i915_gem_request_get_seqno(req); __entry->flags = flags; - i915_trace_irq_get(ring, __entry->seqno); + i915_trace_irq_get(ring, req); ), TP_printk("dev=%u, ring=%u, seqno=%u, flags=%x", diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2a84bd9..39e303d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -142,7 +142,7 @@ struct intel_engine_cs { unsigned irq_refcount; /* protected by dev_priv->irq_lock */ u32 irq_enable_mask; /* bitmask to enable ring interrupt */ - u32 trace_irq_seqno; + struct drm_i915_gem_request *trace_irq_req; bool __must_check (*irq_get)(struct intel_engine_cs *ring); void (*irq_put)(struct intel_engine_cs *ring); @@ -442,10 +442,4 @@ intel_ring_get_request(struct intel_engine_cs *ring) return ring->outstanding_lazy_request; } -static inline void i915_trace_irq_get(struct intel_engine_cs *ring, u32 seqno) -{ - if (ring->trace_irq_seqno == 0 && ring->irq_get(ring)) - ring->trace_irq_seqno = seqno; -} - #endif /* _INTEL_RINGBUFFER_H_ */ -- cgit v0.10.2 From 1362b7764088d49cedf87cd9d0b6ac2f16306dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Nov 2014 17:07:29 +0200 Subject: drm/i915: Deal with video overlay on GPU reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clear the video overlay state on GPU reset. Any pending overlay request in the ring has been nuked, and the display itself gets reset. So we pretty much lose all state here. Adjust the software state to match so that the next "putimage" will restore things to working order. v2: Ass a locking check into intel_overlay_release_old_vid() (Daniel) Cc: Daniel Vetter Signed-off-by: Ville Syrjälä [danvet: s/0/NULL/ to appease sparse, reported by 0-day tester.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1e9c136..71be3c9 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -838,6 +838,8 @@ int i915_reset(struct drm_device *dev) return ret; } + intel_overlay_reset(dev_priv); + /* Ok, now get things going again... */ /* diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1a9c70f..abb2cf4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1081,6 +1081,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, struct drm_file *file_priv); int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); +void intel_overlay_reset(struct drm_i915_private *dev_priv); /* intel_panel.c */ diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index c1abf49..973c9de 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -394,6 +394,8 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) struct intel_engine_cs *ring = &dev_priv->ring[RCS]; int ret; + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + /* Only wait if there is actually an old frame to release to * guarantee forward progress. */ @@ -424,6 +426,22 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) return 0; } +void intel_overlay_reset(struct drm_i915_private *dev_priv) +{ + struct intel_overlay *overlay = dev_priv->overlay; + + if (!overlay) + return; + + intel_overlay_release_old_vid(overlay); + + overlay->last_flip_req = NULL; + overlay->old_xscale = 0; + overlay->old_yscale = 0; + overlay->crtc = NULL; + overlay->active = false; +} + struct put_image_params { int format; short dst_x; -- cgit v0.10.2 From e7d7cad08d35329a5a783a0aa620560223fe0eb8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 14 Nov 2014 16:54:21 +0200 Subject: drm/i915/dsi: clean up MIPI DSI pipe vs. port usage MIPI DSI works on ports A and C, which map to pipes A and B, respectively. Things are going to get more complicated with the introduction of dual link DSI support, so clean up the register defines and code to match reality. Signed-off-by: Jani Nikula Reviewed-by: Gaurav K Singh Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a965522..dc03fac 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -31,6 +31,8 @@ #define _PORT(port, a, b) ((a) + (port)*((b)-(a))) #define _PIPE3(pipe, a, b, c) ((pipe) == PIPE_A ? (a) : \ (pipe) == PIPE_B ? (b) : (c)) +#define _PORT3(port, a, b, c) ((port) == PORT_A ? (a) : \ + (port) == PORT_B ? (b) : (c)) #define _MASKED_BIT_ENABLE(a) (((a) << 16) | (a)) #define _MASKED_BIT_DISABLE(a) ((a) << 16) @@ -1494,7 +1496,7 @@ enum punit_power_well { #define I915_ISP_INTERRUPT (1<<22) #define I915_LPE_PIPE_B_INTERRUPT (1<<21) #define I915_LPE_PIPE_A_INTERRUPT (1<<20) -#define I915_MIPIB_INTERRUPT (1<<19) +#define I915_MIPIC_INTERRUPT (1<<19) #define I915_MIPIA_INTERRUPT (1<<18) #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) #define I915_DISPLAY_PORT_INTERRUPT (1<<17) @@ -6652,29 +6654,30 @@ enum punit_power_well { #define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) #define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) -/* VLV MIPI registers */ +/* MIPI DSI registers */ + +#define _MIPI_PORT(port, a, c) _PORT3(port, a, 0, c) /* ports A and C only */ #define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190) -#define _MIPIB_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700) -#define MIPI_PORT_CTRL(tc) _TRANSCODER(tc, _MIPIA_PORT_CTRL, \ - _MIPIB_PORT_CTRL) -#define DPI_ENABLE (1 << 31) /* A + B */ +#define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700) +#define MIPI_PORT_CTRL(port) _MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL) +#define DPI_ENABLE (1 << 31) /* A + C */ #define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27 #define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27) #define DUAL_LINK_MODE_MASK (1 << 26) #define DUAL_LINK_MODE_FRONT_BACK (0 << 26) #define DUAL_LINK_MODE_PIXEL_ALTERNATIVE (1 << 26) -#define DITHERING_ENABLE (1 << 25) /* A + B */ +#define DITHERING_ENABLE (1 << 25) /* A + C */ #define FLOPPED_HSTX (1 << 23) #define DE_INVERT (1 << 19) /* XXX */ #define MIPIA_FLISDSI_DELAY_COUNT_SHIFT 18 #define MIPIA_FLISDSI_DELAY_COUNT_MASK (0xf << 18) #define AFE_LATCHOUT (1 << 17) #define LP_OUTPUT_HOLD (1 << 16) -#define MIPIB_FLISDSI_DELAY_COUNT_HIGH_SHIFT 15 -#define MIPIB_FLISDSI_DELAY_COUNT_HIGH_MASK (1 << 15) -#define MIPIB_MIPI4DPHY_DELAY_COUNT_SHIFT 11 -#define MIPIB_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 11) +#define MIPIC_FLISDSI_DELAY_COUNT_HIGH_SHIFT 15 +#define MIPIC_FLISDSI_DELAY_COUNT_HIGH_MASK (1 << 15) +#define MIPIC_MIPI4DPHY_DELAY_COUNT_SHIFT 11 +#define MIPIC_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 11) #define CSB_SHIFT 9 #define CSB_MASK (3 << 9) #define CSB_20MHZ (0 << 9) @@ -6683,10 +6686,10 @@ enum punit_power_well { #define BANDGAP_MASK (1 << 8) #define BANDGAP_PNW_CIRCUIT (0 << 8) #define BANDGAP_LNC_CIRCUIT (1 << 8) -#define MIPIB_FLISDSI_DELAY_COUNT_LOW_SHIFT 5 -#define MIPIB_FLISDSI_DELAY_COUNT_LOW_MASK (7 << 5) -#define TEARING_EFFECT_DELAY (1 << 4) /* A + B */ -#define TEARING_EFFECT_SHIFT 2 /* A + B */ +#define MIPIC_FLISDSI_DELAY_COUNT_LOW_SHIFT 5 +#define MIPIC_FLISDSI_DELAY_COUNT_LOW_MASK (7 << 5) +#define TEARING_EFFECT_DELAY (1 << 4) /* A + C */ +#define TEARING_EFFECT_SHIFT 2 /* A + C */ #define TEARING_EFFECT_MASK (3 << 2) #define TEARING_EFFECT_OFF (0 << 2) #define TEARING_EFFECT_DSI (1 << 2) @@ -6698,9 +6701,9 @@ enum punit_power_well { #define LANE_CONFIGURATION_DUAL_LINK_B (2 << 0) #define _MIPIA_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61194) -#define _MIPIB_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61704) -#define MIPI_TEARING_CTRL(tc) _TRANSCODER(tc, \ - _MIPIA_TEARING_CTRL, _MIPIB_TEARING_CTRL) +#define _MIPIC_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61704) +#define MIPI_TEARING_CTRL(port) _MIPI_PORT(port, \ + _MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL) #define TEARING_EFFECT_DELAY_SHIFT 0 #define TEARING_EFFECT_DELAY_MASK (0xffff << 0) @@ -6710,9 +6713,9 @@ enum punit_power_well { /* MIPI DSI Controller and D-PHY registers */ #define _MIPIA_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb000) -#define _MIPIB_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb800) -#define MIPI_DEVICE_READY(tc) _TRANSCODER(tc, _MIPIA_DEVICE_READY, \ - _MIPIB_DEVICE_READY) +#define _MIPIC_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb800) +#define MIPI_DEVICE_READY(port) _MIPI_PORT(port, _MIPIA_DEVICE_READY, \ + _MIPIC_DEVICE_READY) #define BUS_POSSESSION (1 << 3) /* set to give bus to receiver */ #define ULPS_STATE_MASK (3 << 1) #define ULPS_STATE_ENTER (2 << 1) @@ -6721,13 +6724,13 @@ enum punit_power_well { #define DEVICE_READY (1 << 0) #define _MIPIA_INTR_STAT (dev_priv->mipi_mmio_base + 0xb004) -#define _MIPIB_INTR_STAT (dev_priv->mipi_mmio_base + 0xb804) -#define MIPI_INTR_STAT(tc) _TRANSCODER(tc, _MIPIA_INTR_STAT, \ - _MIPIB_INTR_STAT) +#define _MIPIC_INTR_STAT (dev_priv->mipi_mmio_base + 0xb804) +#define MIPI_INTR_STAT(port) _MIPI_PORT(port, _MIPIA_INTR_STAT, \ + _MIPIC_INTR_STAT) #define _MIPIA_INTR_EN (dev_priv->mipi_mmio_base + 0xb008) -#define _MIPIB_INTR_EN (dev_priv->mipi_mmio_base + 0xb808) -#define MIPI_INTR_EN(tc) _TRANSCODER(tc, _MIPIA_INTR_EN, \ - _MIPIB_INTR_EN) +#define _MIPIC_INTR_EN (dev_priv->mipi_mmio_base + 0xb808) +#define MIPI_INTR_EN(port) _MIPI_PORT(port, _MIPIA_INTR_EN, \ + _MIPIC_INTR_EN) #define TEARING_EFFECT (1 << 31) #define SPL_PKT_SENT_INTERRUPT (1 << 30) #define GEN_READ_DATA_AVAIL (1 << 29) @@ -6762,9 +6765,9 @@ enum punit_power_well { #define RXSOT_ERROR (1 << 0) #define _MIPIA_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb00c) -#define _MIPIB_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb80c) -#define MIPI_DSI_FUNC_PRG(tc) _TRANSCODER(tc, _MIPIA_DSI_FUNC_PRG, \ - _MIPIB_DSI_FUNC_PRG) +#define _MIPIC_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb80c) +#define MIPI_DSI_FUNC_PRG(port) _MIPI_PORT(port, _MIPIA_DSI_FUNC_PRG, \ + _MIPIC_DSI_FUNC_PRG) #define CMD_MODE_DATA_WIDTH_MASK (7 << 13) #define CMD_MODE_NOT_SUPPORTED (0 << 13) #define CMD_MODE_DATA_WIDTH_16_BIT (1 << 13) @@ -6786,93 +6789,93 @@ enum punit_power_well { #define DATA_LANES_PRG_REG_MASK (7 << 0) #define _MIPIA_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb010) -#define _MIPIB_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb810) -#define MIPI_HS_TX_TIMEOUT(tc) _TRANSCODER(tc, _MIPIA_HS_TX_TIMEOUT, \ - _MIPIB_HS_TX_TIMEOUT) +#define _MIPIC_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb810) +#define MIPI_HS_TX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_HS_TX_TIMEOUT, \ + _MIPIC_HS_TX_TIMEOUT) #define HIGH_SPEED_TX_TIMEOUT_COUNTER_MASK 0xffffff #define _MIPIA_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb014) -#define _MIPIB_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb814) -#define MIPI_LP_RX_TIMEOUT(tc) _TRANSCODER(tc, _MIPIA_LP_RX_TIMEOUT, \ - _MIPIB_LP_RX_TIMEOUT) +#define _MIPIC_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb814) +#define MIPI_LP_RX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_LP_RX_TIMEOUT, \ + _MIPIC_LP_RX_TIMEOUT) #define LOW_POWER_RX_TIMEOUT_COUNTER_MASK 0xffffff #define _MIPIA_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb018) -#define _MIPIB_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb818) -#define MIPI_TURN_AROUND_TIMEOUT(tc) _TRANSCODER(tc, \ - _MIPIA_TURN_AROUND_TIMEOUT, _MIPIB_TURN_AROUND_TIMEOUT) +#define _MIPIC_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb818) +#define MIPI_TURN_AROUND_TIMEOUT(port) _MIPI_PORT(port, \ + _MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT) #define TURN_AROUND_TIMEOUT_MASK 0x3f #define _MIPIA_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb01c) -#define _MIPIB_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb81c) -#define MIPI_DEVICE_RESET_TIMER(tc) _TRANSCODER(tc, \ - _MIPIA_DEVICE_RESET_TIMER, _MIPIB_DEVICE_RESET_TIMER) +#define _MIPIC_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb81c) +#define MIPI_DEVICE_RESET_TIMER(port) _MIPI_PORT(port, \ + _MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER) #define DEVICE_RESET_TIMER_MASK 0xffff #define _MIPIA_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb020) -#define _MIPIB_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb820) -#define MIPI_DPI_RESOLUTION(tc) _TRANSCODER(tc, _MIPIA_DPI_RESOLUTION, \ - _MIPIB_DPI_RESOLUTION) +#define _MIPIC_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb820) +#define MIPI_DPI_RESOLUTION(port) _MIPI_PORT(port, _MIPIA_DPI_RESOLUTION, \ + _MIPIC_DPI_RESOLUTION) #define VERTICAL_ADDRESS_SHIFT 16 #define VERTICAL_ADDRESS_MASK (0xffff << 16) #define HORIZONTAL_ADDRESS_SHIFT 0 #define HORIZONTAL_ADDRESS_MASK 0xffff #define _MIPIA_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb024) -#define _MIPIB_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb824) -#define MIPI_DBI_FIFO_THROTTLE(tc) _TRANSCODER(tc, \ - _MIPIA_DBI_FIFO_THROTTLE, _MIPIB_DBI_FIFO_THROTTLE) +#define _MIPIC_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb824) +#define MIPI_DBI_FIFO_THROTTLE(port) _MIPI_PORT(port, \ + _MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE) #define DBI_FIFO_EMPTY_HALF (0 << 0) #define DBI_FIFO_EMPTY_QUARTER (1 << 0) #define DBI_FIFO_EMPTY_7_LOCATIONS (2 << 0) /* regs below are bits 15:0 */ #define _MIPIA_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb028) -#define _MIPIB_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb828) -#define MIPI_HSYNC_PADDING_COUNT(tc) _TRANSCODER(tc, \ - _MIPIA_HSYNC_PADDING_COUNT, _MIPIB_HSYNC_PADDING_COUNT) +#define _MIPIC_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb828) +#define MIPI_HSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \ + _MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT) #define _MIPIA_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb02c) -#define _MIPIB_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb82c) -#define MIPI_HBP_COUNT(tc) _TRANSCODER(tc, _MIPIA_HBP_COUNT, \ - _MIPIB_HBP_COUNT) +#define _MIPIC_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb82c) +#define MIPI_HBP_COUNT(port) _MIPI_PORT(port, _MIPIA_HBP_COUNT, \ + _MIPIC_HBP_COUNT) #define _MIPIA_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb030) -#define _MIPIB_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb830) -#define MIPI_HFP_COUNT(tc) _TRANSCODER(tc, _MIPIA_HFP_COUNT, \ - _MIPIB_HFP_COUNT) +#define _MIPIC_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb830) +#define MIPI_HFP_COUNT(port) _MIPI_PORT(port, _MIPIA_HFP_COUNT, \ + _MIPIC_HFP_COUNT) #define _MIPIA_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb034) -#define _MIPIB_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb834) -#define MIPI_HACTIVE_AREA_COUNT(tc) _TRANSCODER(tc, \ - _MIPIA_HACTIVE_AREA_COUNT, _MIPIB_HACTIVE_AREA_COUNT) +#define _MIPIC_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb834) +#define MIPI_HACTIVE_AREA_COUNT(port) _MIPI_PORT(port, \ + _MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT) #define _MIPIA_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb038) -#define _MIPIB_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb838) -#define MIPI_VSYNC_PADDING_COUNT(tc) _TRANSCODER(tc, \ - _MIPIA_VSYNC_PADDING_COUNT, _MIPIB_VSYNC_PADDING_COUNT) +#define _MIPIC_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb838) +#define MIPI_VSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \ + _MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT) #define _MIPIA_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb03c) -#define _MIPIB_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb83c) -#define MIPI_VBP_COUNT(tc) _TRANSCODER(tc, _MIPIA_VBP_COUNT, \ - _MIPIB_VBP_COUNT) +#define _MIPIC_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb83c) +#define MIPI_VBP_COUNT(port) _MIPI_PORT(port, _MIPIA_VBP_COUNT, \ + _MIPIC_VBP_COUNT) #define _MIPIA_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb040) -#define _MIPIB_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb840) -#define MIPI_VFP_COUNT(tc) _TRANSCODER(tc, _MIPIA_VFP_COUNT, \ - _MIPIB_VFP_COUNT) +#define _MIPIC_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb840) +#define MIPI_VFP_COUNT(port) _MIPI_PORT(port, _MIPIA_VFP_COUNT, \ + _MIPIC_VFP_COUNT) #define _MIPIA_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb044) -#define _MIPIB_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb844) -#define MIPI_HIGH_LOW_SWITCH_COUNT(tc) _TRANSCODER(tc, \ - _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIB_HIGH_LOW_SWITCH_COUNT) +#define _MIPIC_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb844) +#define MIPI_HIGH_LOW_SWITCH_COUNT(port) _MIPI_PORT(port, \ + _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT) /* regs above are bits 15:0 */ #define _MIPIA_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb048) -#define _MIPIB_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb848) -#define MIPI_DPI_CONTROL(tc) _TRANSCODER(tc, _MIPIA_DPI_CONTROL, \ - _MIPIB_DPI_CONTROL) +#define _MIPIC_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb848) +#define MIPI_DPI_CONTROL(port) _MIPI_PORT(port, _MIPIA_DPI_CONTROL, \ + _MIPIC_DPI_CONTROL) #define DPI_LP_MODE (1 << 6) #define BACKLIGHT_OFF (1 << 5) #define BACKLIGHT_ON (1 << 4) @@ -6882,30 +6885,30 @@ enum punit_power_well { #define SHUTDOWN (1 << 0) #define _MIPIA_DPI_DATA (dev_priv->mipi_mmio_base + 0xb04c) -#define _MIPIB_DPI_DATA (dev_priv->mipi_mmio_base + 0xb84c) -#define MIPI_DPI_DATA(tc) _TRANSCODER(tc, _MIPIA_DPI_DATA, \ - _MIPIB_DPI_DATA) +#define _MIPIC_DPI_DATA (dev_priv->mipi_mmio_base + 0xb84c) +#define MIPI_DPI_DATA(port) _MIPI_PORT(port, _MIPIA_DPI_DATA, \ + _MIPIC_DPI_DATA) #define COMMAND_BYTE_SHIFT 0 #define COMMAND_BYTE_MASK (0x3f << 0) #define _MIPIA_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb050) -#define _MIPIB_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb850) -#define MIPI_INIT_COUNT(tc) _TRANSCODER(tc, _MIPIA_INIT_COUNT, \ - _MIPIB_INIT_COUNT) +#define _MIPIC_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb850) +#define MIPI_INIT_COUNT(port) _MIPI_PORT(port, _MIPIA_INIT_COUNT, \ + _MIPIC_INIT_COUNT) #define MASTER_INIT_TIMER_SHIFT 0 #define MASTER_INIT_TIMER_MASK (0xffff << 0) #define _MIPIA_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb054) -#define _MIPIB_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb854) -#define MIPI_MAX_RETURN_PKT_SIZE(tc) _TRANSCODER(tc, \ - _MIPIA_MAX_RETURN_PKT_SIZE, _MIPIB_MAX_RETURN_PKT_SIZE) +#define _MIPIC_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb854) +#define MIPI_MAX_RETURN_PKT_SIZE(port) _MIPI_PORT(port, \ + _MIPIA_MAX_RETURN_PKT_SIZE, _MIPIC_MAX_RETURN_PKT_SIZE) #define MAX_RETURN_PKT_SIZE_SHIFT 0 #define MAX_RETURN_PKT_SIZE_MASK (0x3ff << 0) #define _MIPIA_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb058) -#define _MIPIB_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb858) -#define MIPI_VIDEO_MODE_FORMAT(tc) _TRANSCODER(tc, \ - _MIPIA_VIDEO_MODE_FORMAT, _MIPIB_VIDEO_MODE_FORMAT) +#define _MIPIC_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb858) +#define MIPI_VIDEO_MODE_FORMAT(port) _MIPI_PORT(port, \ + _MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT) #define RANDOM_DPI_DISPLAY_RESOLUTION (1 << 4) #define DISABLE_VIDEO_BTA (1 << 3) #define IP_TG_CONFIG (1 << 2) @@ -6914,9 +6917,9 @@ enum punit_power_well { #define VIDEO_MODE_BURST (3 << 0) #define _MIPIA_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb05c) -#define _MIPIB_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb85c) -#define MIPI_EOT_DISABLE(tc) _TRANSCODER(tc, _MIPIA_EOT_DISABLE, \ - _MIPIB_EOT_DISABLE) +#define _MIPIC_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb85c) +#define MIPI_EOT_DISABLE(port) _MIPI_PORT(port, _MIPIA_EOT_DISABLE, \ + _MIPIC_EOT_DISABLE) #define LP_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 7) #define HS_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 6) #define LOW_CONTENTION_RECOVERY_DISABLE (1 << 5) @@ -6927,32 +6930,32 @@ enum punit_power_well { #define EOT_DISABLE (1 << 0) #define _MIPIA_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb060) -#define _MIPIB_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb860) -#define MIPI_LP_BYTECLK(tc) _TRANSCODER(tc, _MIPIA_LP_BYTECLK, \ - _MIPIB_LP_BYTECLK) +#define _MIPIC_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb860) +#define MIPI_LP_BYTECLK(port) _MIPI_PORT(port, _MIPIA_LP_BYTECLK, \ + _MIPIC_LP_BYTECLK) #define LP_BYTECLK_SHIFT 0 #define LP_BYTECLK_MASK (0xffff << 0) /* bits 31:0 */ #define _MIPIA_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb064) -#define _MIPIB_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb864) -#define MIPI_LP_GEN_DATA(tc) _TRANSCODER(tc, _MIPIA_LP_GEN_DATA, \ - _MIPIB_LP_GEN_DATA) +#define _MIPIC_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb864) +#define MIPI_LP_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_LP_GEN_DATA, \ + _MIPIC_LP_GEN_DATA) /* bits 31:0 */ #define _MIPIA_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb068) -#define _MIPIB_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb868) -#define MIPI_HS_GEN_DATA(tc) _TRANSCODER(tc, _MIPIA_HS_GEN_DATA, \ - _MIPIB_HS_GEN_DATA) +#define _MIPIC_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb868) +#define MIPI_HS_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_HS_GEN_DATA, \ + _MIPIC_HS_GEN_DATA) #define _MIPIA_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb06c) -#define _MIPIB_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb86c) -#define MIPI_LP_GEN_CTRL(tc) _TRANSCODER(tc, _MIPIA_LP_GEN_CTRL, \ - _MIPIB_LP_GEN_CTRL) +#define _MIPIC_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb86c) +#define MIPI_LP_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_LP_GEN_CTRL, \ + _MIPIC_LP_GEN_CTRL) #define _MIPIA_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb070) -#define _MIPIB_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb870) -#define MIPI_HS_GEN_CTRL(tc) _TRANSCODER(tc, _MIPIA_HS_GEN_CTRL, \ - _MIPIB_HS_GEN_CTRL) +#define _MIPIC_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb870) +#define MIPI_HS_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_HS_GEN_CTRL, \ + _MIPIC_HS_GEN_CTRL) #define LONG_PACKET_WORD_COUNT_SHIFT 8 #define LONG_PACKET_WORD_COUNT_MASK (0xffff << 8) #define SHORT_PACKET_PARAM_SHIFT 8 @@ -6964,9 +6967,9 @@ enum punit_power_well { /* data type values, see include/video/mipi_display.h */ #define _MIPIA_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb074) -#define _MIPIB_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb874) -#define MIPI_GEN_FIFO_STAT(tc) _TRANSCODER(tc, _MIPIA_GEN_FIFO_STAT, \ - _MIPIB_GEN_FIFO_STAT) +#define _MIPIC_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb874) +#define MIPI_GEN_FIFO_STAT(port) _MIPI_PORT(port, _MIPIA_GEN_FIFO_STAT, \ + _MIPIC_GEN_FIFO_STAT) #define DPI_FIFO_EMPTY (1 << 28) #define DBI_FIFO_EMPTY (1 << 27) #define LP_CTRL_FIFO_EMPTY (1 << 26) @@ -6983,17 +6986,17 @@ enum punit_power_well { #define HS_DATA_FIFO_FULL (1 << 0) #define _MIPIA_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb078) -#define _MIPIB_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb878) -#define MIPI_HS_LP_DBI_ENABLE(tc) _TRANSCODER(tc, \ - _MIPIA_HS_LS_DBI_ENABLE, _MIPIB_HS_LS_DBI_ENABLE) +#define _MIPIC_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb878) +#define MIPI_HS_LP_DBI_ENABLE(port) _MIPI_PORT(port, \ + _MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE) #define DBI_HS_LP_MODE_MASK (1 << 0) #define DBI_LP_MODE (1 << 0) #define DBI_HS_MODE (0 << 0) #define _MIPIA_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb080) -#define _MIPIB_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb880) -#define MIPI_DPHY_PARAM(tc) _TRANSCODER(tc, _MIPIA_DPHY_PARAM, \ - _MIPIB_DPHY_PARAM) +#define _MIPIC_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb880) +#define MIPI_DPHY_PARAM(port) _MIPI_PORT(port, _MIPIA_DPHY_PARAM, \ + _MIPIC_DPHY_PARAM) #define EXIT_ZERO_COUNT_SHIFT 24 #define EXIT_ZERO_COUNT_MASK (0x3f << 24) #define TRAIL_COUNT_SHIFT 16 @@ -7005,36 +7008,36 @@ enum punit_power_well { /* bits 31:0 */ #define _MIPIA_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb084) -#define _MIPIB_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb884) -#define MIPI_DBI_BW_CTRL(tc) _TRANSCODER(tc, _MIPIA_DBI_BW_CTRL, \ - _MIPIB_DBI_BW_CTRL) +#define _MIPIC_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb884) +#define MIPI_DBI_BW_CTRL(port) _MIPI_PORT(port, _MIPIA_DBI_BW_CTRL, \ + _MIPIC_DBI_BW_CTRL) #define _MIPIA_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \ + 0xb088) -#define _MIPIB_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \ +#define _MIPIC_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \ + 0xb888) -#define MIPI_CLK_LANE_SWITCH_TIME_CNT(tc) _TRANSCODER(tc, \ - _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIB_CLK_LANE_SWITCH_TIME_CNT) +#define MIPI_CLK_LANE_SWITCH_TIME_CNT(port) _MIPI_PORT(port, \ + _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT) #define LP_HS_SSW_CNT_SHIFT 16 #define LP_HS_SSW_CNT_MASK (0xffff << 16) #define HS_LP_PWR_SW_CNT_SHIFT 0 #define HS_LP_PWR_SW_CNT_MASK (0xffff << 0) #define _MIPIA_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb08c) -#define _MIPIB_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb88c) -#define MIPI_STOP_STATE_STALL(tc) _TRANSCODER(tc, \ - _MIPIA_STOP_STATE_STALL, _MIPIB_STOP_STATE_STALL) +#define _MIPIC_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb88c) +#define MIPI_STOP_STATE_STALL(port) _MIPI_PORT(port, \ + _MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL) #define STOP_STATE_STALL_COUNTER_SHIFT 0 #define STOP_STATE_STALL_COUNTER_MASK (0xff << 0) #define _MIPIA_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb090) -#define _MIPIB_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb890) -#define MIPI_INTR_STAT_REG_1(tc) _TRANSCODER(tc, \ - _MIPIA_INTR_STAT_REG_1, _MIPIB_INTR_STAT_REG_1) +#define _MIPIC_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb890) +#define MIPI_INTR_STAT_REG_1(port) _MIPI_PORT(port, \ + _MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1) #define _MIPIA_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb094) -#define _MIPIB_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb894) -#define MIPI_INTR_EN_REG_1(tc) _TRANSCODER(tc, _MIPIA_INTR_EN_REG_1, \ - _MIPIB_INTR_EN_REG_1) +#define _MIPIC_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb894) +#define MIPI_INTR_EN_REG_1(port) _MIPI_PORT(port, _MIPIA_INTR_EN_REG_1, \ + _MIPIC_INTR_EN_REG_1) #define RX_CONTENTION_DETECTED (1 << 0) /* XXX: only pipe A ?!? */ @@ -7053,9 +7056,9 @@ enum punit_power_well { /* MIPI adapter registers */ #define _MIPIA_CTRL (dev_priv->mipi_mmio_base + 0xb104) -#define _MIPIB_CTRL (dev_priv->mipi_mmio_base + 0xb904) -#define MIPI_CTRL(tc) _TRANSCODER(tc, _MIPIA_CTRL, \ - _MIPIB_CTRL) +#define _MIPIC_CTRL (dev_priv->mipi_mmio_base + 0xb904) +#define MIPI_CTRL(port) _MIPI_PORT(port, _MIPIA_CTRL, \ + _MIPIC_CTRL) #define ESCAPE_CLOCK_DIVIDER_SHIFT 5 /* A only */ #define ESCAPE_CLOCK_DIVIDER_MASK (3 << 5) #define ESCAPE_CLOCK_DIVIDER_1 (0 << 5) @@ -7068,24 +7071,24 @@ enum punit_power_well { #define RGB_FLIP_TO_BGR (1 << 2) #define _MIPIA_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb108) -#define _MIPIB_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb908) -#define MIPI_DATA_ADDRESS(tc) _TRANSCODER(tc, _MIPIA_DATA_ADDRESS, \ - _MIPIB_DATA_ADDRESS) +#define _MIPIC_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb908) +#define MIPI_DATA_ADDRESS(port) _MIPI_PORT(port, _MIPIA_DATA_ADDRESS, \ + _MIPIC_DATA_ADDRESS) #define DATA_MEM_ADDRESS_SHIFT 5 #define DATA_MEM_ADDRESS_MASK (0x7ffffff << 5) #define DATA_VALID (1 << 0) #define _MIPIA_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb10c) -#define _MIPIB_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb90c) -#define MIPI_DATA_LENGTH(tc) _TRANSCODER(tc, _MIPIA_DATA_LENGTH, \ - _MIPIB_DATA_LENGTH) +#define _MIPIC_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb90c) +#define MIPI_DATA_LENGTH(port) _MIPI_PORT(port, _MIPIA_DATA_LENGTH, \ + _MIPIC_DATA_LENGTH) #define DATA_LENGTH_SHIFT 0 #define DATA_LENGTH_MASK (0xfffff << 0) #define _MIPIA_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb110) -#define _MIPIB_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb910) -#define MIPI_COMMAND_ADDRESS(tc) _TRANSCODER(tc, \ - _MIPIA_COMMAND_ADDRESS, _MIPIB_COMMAND_ADDRESS) +#define _MIPIC_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb910) +#define MIPI_COMMAND_ADDRESS(port) _MIPI_PORT(port, \ + _MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS) #define COMMAND_MEM_ADDRESS_SHIFT 5 #define COMMAND_MEM_ADDRESS_MASK (0x7ffffff << 5) #define AUTO_PWG_ENABLE (1 << 2) @@ -7093,22 +7096,22 @@ enum punit_power_well { #define COMMAND_VALID (1 << 0) #define _MIPIA_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb114) -#define _MIPIB_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb914) -#define MIPI_COMMAND_LENGTH(tc) _TRANSCODER(tc, _MIPIA_COMMAND_LENGTH, \ - _MIPIB_COMMAND_LENGTH) +#define _MIPIC_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb914) +#define MIPI_COMMAND_LENGTH(port) _MIPI_PORT(port, _MIPIA_COMMAND_LENGTH, \ + _MIPIC_COMMAND_LENGTH) #define COMMAND_LENGTH_SHIFT(n) (8 * (n)) /* n: 0...3 */ #define COMMAND_LENGTH_MASK(n) (0xff << (8 * (n))) #define _MIPIA_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb118) -#define _MIPIB_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb918) -#define MIPI_READ_DATA_RETURN(tc, n) \ - (_TRANSCODER(tc, _MIPIA_READ_DATA_RETURN0, _MIPIB_READ_DATA_RETURN0) \ +#define _MIPIC_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb918) +#define MIPI_READ_DATA_RETURN(port, n) \ + (_MIPI_PORT(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) \ + 4 * (n)) /* n: 0...7 */ #define _MIPIA_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb138) -#define _MIPIB_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb938) -#define MIPI_READ_DATA_VALID(tc) _TRANSCODER(tc, \ - _MIPIA_READ_DATA_VALID, _MIPIB_READ_DATA_VALID) +#define _MIPIC_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb938) +#define MIPI_READ_DATA_VALID(port) _MIPI_PORT(port, \ + _MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID) #define READ_DATA_VALID(n) (1 << (n)) /* For UMS only (deprecated): */ diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 0b18407..35842a6 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -106,7 +106,7 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 val; DRM_DEBUG_KMS("\n"); @@ -120,17 +120,17 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder) /* bandgap reset is needed after everytime we do power gate */ band_gap_reset(dev_priv); - I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER); + I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_ENTER); usleep_range(2500, 3000); - val = I915_READ(MIPI_PORT_CTRL(pipe)); - I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD); + val = I915_READ(MIPI_PORT_CTRL(port)); + I915_WRITE(MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD); usleep_range(1000, 1500); - I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_EXIT); + I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT); usleep_range(2500, 3000); - I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY); + I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY); usleep_range(2500, 3000); } @@ -140,13 +140,13 @@ static void intel_dsi_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); - int pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 temp; DRM_DEBUG_KMS("\n"); if (is_cmd_mode(intel_dsi)) - I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); + I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4); else { msleep(20); /* XXX */ dpi_send_cmd(intel_dsi, TURN_ON, DPI_LP_MODE_EN); @@ -158,10 +158,10 @@ static void intel_dsi_enable(struct intel_encoder *encoder) wait_for_dsi_fifo_empty(intel_dsi); /* assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK; + temp = I915_READ(MIPI_PORT_CTRL(port)) & ~LANE_CONFIGURATION_MASK; temp = temp | intel_dsi->port_bits; - I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE); - POSTING_READ(MIPI_PORT_CTRL(pipe)); + I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE); + POSTING_READ(MIPI_PORT_CTRL(port)); } } @@ -237,7 +237,7 @@ static void intel_dsi_disable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); - int pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 temp; DRM_DEBUG_KMS("\n"); @@ -246,29 +246,29 @@ static void intel_dsi_disable(struct intel_encoder *encoder) wait_for_dsi_fifo_empty(intel_dsi); /* de-assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(pipe)); - I915_WRITE(MIPI_PORT_CTRL(pipe), temp & ~DPI_ENABLE); - POSTING_READ(MIPI_PORT_CTRL(pipe)); + temp = I915_READ(MIPI_PORT_CTRL(port)); + I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE); + POSTING_READ(MIPI_PORT_CTRL(port)); msleep(2); } /* Panel commands can be sent when clock is in LP11 */ - I915_WRITE(MIPI_DEVICE_READY(pipe), 0x0); + I915_WRITE(MIPI_DEVICE_READY(port), 0x0); - temp = I915_READ(MIPI_CTRL(pipe)); + temp = I915_READ(MIPI_CTRL(port)); temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; - I915_WRITE(MIPI_CTRL(pipe), temp | + I915_WRITE(MIPI_CTRL(port), temp | intel_dsi->escape_clk_div << ESCAPE_CLOCK_DIVIDER_SHIFT); - I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP); + I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); - temp = I915_READ(MIPI_DSI_FUNC_PRG(pipe)); + temp = I915_READ(MIPI_DSI_FUNC_PRG(port)); temp &= ~VID_MODE_FORMAT_MASK; - I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), temp); + I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp); - I915_WRITE(MIPI_DEVICE_READY(pipe), 0x1); + I915_WRITE(MIPI_DEVICE_READY(port), 0x1); /* if disable packets are sent before sending shutdown packet then in * some next enable sequence send turn on packet error is observed */ @@ -282,29 +282,29 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 val; DRM_DEBUG_KMS("\n"); - I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_ENTER); + I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | ULPS_STATE_ENTER); usleep_range(2000, 2500); - I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_EXIT); + I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | ULPS_STATE_EXIT); usleep_range(2000, 2500); - I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_ENTER); + I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | ULPS_STATE_ENTER); usleep_range(2000, 2500); - if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT) + if (wait_for(((I915_READ(MIPI_PORT_CTRL(port)) & AFE_LATCHOUT) == 0x00000), 30)) DRM_ERROR("DSI LP not going Low\n"); - val = I915_READ(MIPI_PORT_CTRL(pipe)); - I915_WRITE(MIPI_PORT_CTRL(pipe), val & ~LP_OUTPUT_HOLD); + val = I915_READ(MIPI_PORT_CTRL(port)); + I915_WRITE(MIPI_PORT_CTRL(port), val & ~LP_OUTPUT_HOLD); usleep_range(1000, 1500); - I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00); + I915_WRITE(MIPI_DEVICE_READY(port), 0x00); usleep_range(2000, 2500); vlv_disable_dsi_pll(encoder); @@ -338,8 +338,8 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; enum intel_display_power_domain power_domain; - u32 port, func; - enum pipe p; + u32 port_ctl, func; + enum port port; DRM_DEBUG_KMS("\n"); @@ -348,13 +348,13 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, return false; /* XXX: this only works for one DSI output */ - for (p = PIPE_A; p <= PIPE_B; p++) { - port = I915_READ(MIPI_PORT_CTRL(p)); - func = I915_READ(MIPI_DSI_FUNC_PRG(p)); + for_each_dsi_port(port, (1 << PORT_A) | (1 << PORT_C)) { + port_ctl = I915_READ(MIPI_PORT_CTRL(port)); + func = I915_READ(MIPI_DSI_FUNC_PRG(port)); - if ((port & DPI_ENABLE) || (func & CMD_MODE_DATA_WIDTH_MASK)) { - if (I915_READ(MIPI_DEVICE_READY(p)) & DEVICE_READY) { - *pipe = p; + if ((port_ctl & DPI_ENABLE) || (func & CMD_MODE_DATA_WIDTH_MASK)) { + if (I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY) { + *pipe = port == PORT_A ? PIPE_A : PIPE_C; return true; } } @@ -437,7 +437,7 @@ static void set_dsi_timings(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); - int pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); unsigned int bpp = intel_crtc->config.pipe_bpp; unsigned int lane_count = intel_dsi->lane_count; @@ -460,18 +460,18 @@ static void set_dsi_timings(struct drm_encoder *encoder, intel_dsi->burst_mode_ratio); hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio); - I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive); - I915_WRITE(MIPI_HFP_COUNT(pipe), hfp); + I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive); + I915_WRITE(MIPI_HFP_COUNT(port), hfp); /* meaningful for video mode non-burst sync pulse mode only, can be zero * for non-burst sync events and burst modes */ - I915_WRITE(MIPI_HSYNC_PADDING_COUNT(pipe), hsync); - I915_WRITE(MIPI_HBP_COUNT(pipe), hbp); + I915_WRITE(MIPI_HSYNC_PADDING_COUNT(port), hsync); + I915_WRITE(MIPI_HBP_COUNT(port), hbp); /* vertical values are in terms of lines */ - I915_WRITE(MIPI_VFP_COUNT(pipe), vfp); - I915_WRITE(MIPI_VSYNC_PADDING_COUNT(pipe), vsync); - I915_WRITE(MIPI_VBP_COUNT(pipe), vbp); + I915_WRITE(MIPI_VFP_COUNT(port), vfp); + I915_WRITE(MIPI_VSYNC_PADDING_COUNT(port), vsync); + I915_WRITE(MIPI_VBP_COUNT(port), vbp); } static void intel_dsi_prepare(struct intel_encoder *intel_encoder) @@ -483,30 +483,30 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); struct drm_display_mode *adjusted_mode = &intel_crtc->config.adjusted_mode; - int pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); unsigned int bpp = intel_crtc->config.pipe_bpp; u32 val, tmp; - DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); + DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe)); /* escape clock divider, 20MHz, shared for A and C. device ready must be * off when doing this! txclkesc? */ - tmp = I915_READ(MIPI_CTRL(0)); + tmp = I915_READ(MIPI_CTRL(PORT_A)); tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK; - I915_WRITE(MIPI_CTRL(0), tmp | ESCAPE_CLOCK_DIVIDER_1); + I915_WRITE(MIPI_CTRL(PORT_A), tmp | ESCAPE_CLOCK_DIVIDER_1); /* read request priority is per pipe */ - tmp = I915_READ(MIPI_CTRL(pipe)); + tmp = I915_READ(MIPI_CTRL(port)); tmp &= ~READ_REQUEST_PRIORITY_MASK; - I915_WRITE(MIPI_CTRL(pipe), tmp | READ_REQUEST_PRIORITY_HIGH); + I915_WRITE(MIPI_CTRL(port), tmp | READ_REQUEST_PRIORITY_HIGH); /* XXX: why here, why like this? handling in irq handler?! */ - I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff); - I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff); + I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff); + I915_WRITE(MIPI_INTR_EN(port), 0xffffffff); - I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg); + I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg); - I915_WRITE(MIPI_DPI_RESOLUTION(pipe), + I915_WRITE(MIPI_DPI_RESOLUTION(port), adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | adjusted_mode->hdisplay << HORIZONTAL_ADDRESS_SHIFT); @@ -522,7 +522,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) /* XXX: cross-check bpp vs. pixel format? */ val |= intel_dsi->pixel_format; } - I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), val); + I915_WRITE(MIPI_DSI_FUNC_PRG(port), val); /* timeouts for recovery. one frame IIUC. if counter expires, EOT and * stop state. */ @@ -543,25 +543,25 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) if (is_vid_mode(intel_dsi) && intel_dsi->video_mode_format == VIDEO_MODE_BURST) { - I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe), + I915_WRITE(MIPI_HS_TX_TIMEOUT(port), txbyteclkhs(adjusted_mode->htotal, bpp, intel_dsi->lane_count, intel_dsi->burst_mode_ratio) + 1); } else { - I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe), + I915_WRITE(MIPI_HS_TX_TIMEOUT(port), txbyteclkhs(adjusted_mode->vtotal * adjusted_mode->htotal, bpp, intel_dsi->lane_count, intel_dsi->burst_mode_ratio) + 1); } - I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout); - I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val); - I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), intel_dsi->rst_timer_val); + I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout); + I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port), intel_dsi->turn_arnd_val); + I915_WRITE(MIPI_DEVICE_RESET_TIMER(port), intel_dsi->rst_timer_val); /* dphy stuff */ /* in terms of low power clock */ - I915_WRITE(MIPI_INIT_COUNT(pipe), txclkesc(intel_dsi->escape_clk_div, 100)); + I915_WRITE(MIPI_INIT_COUNT(port), txclkesc(intel_dsi->escape_clk_div, 100)); val = 0; if (intel_dsi->eotp_pkt == 0) @@ -571,17 +571,17 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) val |= CLOCKSTOP; /* recovery disables */ - I915_WRITE(MIPI_EOT_DISABLE(pipe), val); + I915_WRITE(MIPI_EOT_DISABLE(port), val); /* in terms of low power clock */ - I915_WRITE(MIPI_INIT_COUNT(pipe), intel_dsi->init_count); + I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count); /* in terms of txbyteclkhs. actual high to low switch + * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK. * * XXX: write MIPI_STOP_STATE_STALL? */ - I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), + I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(port), intel_dsi->hs_to_lp_count); /* XXX: low power clock equivalence in terms of byte clock. the number @@ -589,16 +589,16 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) * and txclkesc. txclkesc time / txbyteclk time * (105 + * MIPI_STOP_STATE_STALL) / 105.??? */ - I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk); + I915_WRITE(MIPI_LP_BYTECLK(port), intel_dsi->lp_byte_clk); /* the bw essential for transmitting 16 long packets containing 252 * bytes meant for dcs write memory command is programmed in this * register in terms of byte clocks. based on dsi transfer rate and the * number of lanes configured the time taken to transmit 16 long packets * in a dsi stream varies. */ - I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer); + I915_WRITE(MIPI_DBI_BW_CTRL(port), intel_dsi->bw_timer); - I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe), + I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(port), intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT | intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT); @@ -606,7 +606,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) /* Some panels might have resolution which is not a multiple of * 64 like 1366 x 768. Enable RANDOM resolution support for such * panels by default */ - I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe), + I915_WRITE(MIPI_VIDEO_MODE_FORMAT(port), intel_dsi->video_frmt_cfg_bits | intel_dsi->video_mode_format | IP_TG_CONFIG | @@ -748,6 +748,12 @@ void intel_dsi_init(struct drm_device *dev) intel_connector->get_hw_state = intel_connector_get_hw_state; intel_connector->unregister = intel_connector_unregister; + /* Pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI port C */ + if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) + intel_encoder->crtc_mask = (1 << PIPE_A); + else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIC) + intel_encoder->crtc_mask = (1 << PIPE_B); + for (i = 0; i < ARRAY_SIZE(intel_dsi_devices); i++) { dsi = &intel_dsi_devices[i]; intel_dsi->dev = *dsi; @@ -762,8 +768,6 @@ void intel_dsi_init(struct drm_device *dev) } intel_encoder->type = INTEL_OUTPUT_DSI; - intel_encoder->crtc_mask = (1 << 0); /* XXX */ - intel_encoder->cloneable = 0; drm_connector_init(dev, connector, &intel_dsi_connector_funcs, DRM_MODE_CONNECTOR_DSI); diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 657eb5c..97a6f62 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -127,6 +127,22 @@ struct intel_dsi { u16 panel_pwr_cycle_delay; }; +/* XXX: Transitional before dual port configuration */ +static inline enum port intel_dsi_pipe_to_port(enum pipe pipe) +{ + if (pipe == PIPE_A) + return PORT_A; + else if (pipe == PIPE_B) + return PORT_C; + + WARN(1, "DSI on pipe %c, assuming port C\n", pipe_name(pipe)); + return PORT_C; +} + +#define for_each_dsi_port(__port, __ports_mask) \ + for ((__port) = PORT_A; (__port) < I915_MAX_PORTS; (__port)++) \ + if ((__ports_mask) & (1 << (__port))) + static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) { return container_of(encoder, struct intel_dsi, base.base); diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.c b/drivers/gpu/drm/i915/intel_dsi_cmd.c index f4767fd..004fa91 100644 --- a/drivers/gpu/drm/i915/intel_dsi_cmd.c +++ b/drivers/gpu/drm/i915/intel_dsi_cmd.c @@ -54,15 +54,15 @@ static void print_stat(struct intel_dsi *intel_dsi) struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum pipe pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 val; - val = I915_READ(MIPI_INTR_STAT(pipe)); + val = I915_READ(MIPI_INTR_STAT(port)); #define STAT_BIT(val, bit) (val) & (bit) ? " " #bit : "" - DRM_DEBUG_KMS("MIPI_INTR_STAT(%d) = %08x" + DRM_DEBUG_KMS("MIPI_INTR_STAT(%c) = %08x" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" - "\n", pipe, val, + "\n", port_name(port), val, STAT_BIT(val, TEARING_EFFECT), STAT_BIT(val, SPL_PKT_SENT_INTERRUPT), STAT_BIT(val, GEN_READ_DATA_AVAIL), @@ -110,16 +110,16 @@ void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable) struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum pipe pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 temp; u32 mask = DBI_FIFO_EMPTY; - if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 50)) + if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == mask, 50)) DRM_ERROR("Timeout waiting for DBI FIFO empty\n"); - temp = I915_READ(MIPI_HS_LP_DBI_ENABLE(pipe)); + temp = I915_READ(MIPI_HS_LP_DBI_ENABLE(port)); temp &= DBI_HS_LP_MODE_MASK; - I915_WRITE(MIPI_HS_LP_DBI_ENABLE(pipe), enable ? DBI_HS_MODE : DBI_LP_MODE); + I915_WRITE(MIPI_HS_LP_DBI_ENABLE(port), enable ? DBI_HS_MODE : DBI_LP_MODE); intel_dsi->hs = enable; } @@ -131,7 +131,7 @@ static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum pipe pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 ctrl_reg; u32 ctrl; u32 mask; @@ -140,14 +140,14 @@ static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel, channel, data_type, data); if (intel_dsi->hs) { - ctrl_reg = MIPI_HS_GEN_CTRL(pipe); + ctrl_reg = MIPI_HS_GEN_CTRL(port); mask = HS_CTRL_FIFO_FULL; } else { - ctrl_reg = MIPI_LP_GEN_CTRL(pipe); + ctrl_reg = MIPI_LP_GEN_CTRL(port); mask = LP_CTRL_FIFO_FULL; } - if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == 0, 50)) { + if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == 0, 50)) { DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n"); print_stat(intel_dsi); } @@ -173,7 +173,7 @@ static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum pipe pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 data_reg; int i, j, n; u32 mask; @@ -182,14 +182,14 @@ static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel, channel, data_type, len); if (intel_dsi->hs) { - data_reg = MIPI_HS_GEN_DATA(pipe); + data_reg = MIPI_HS_GEN_DATA(port); mask = HS_DATA_FIFO_FULL; } else { - data_reg = MIPI_LP_GEN_DATA(pipe); + data_reg = MIPI_LP_GEN_DATA(port); mask = LP_DATA_FIFO_FULL; } - if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == 0, 50)) + if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == 0, 50)) DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n"); for (i = 0; i < len; i += n) { @@ -292,14 +292,14 @@ static int dsi_read_data_return(struct intel_dsi *intel_dsi, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum pipe pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); int i, len = 0; u32 data_reg, val; if (intel_dsi->hs) { - data_reg = MIPI_HS_GEN_DATA(pipe); + data_reg = MIPI_HS_GEN_DATA(port); } else { - data_reg = MIPI_LP_GEN_DATA(pipe); + data_reg = MIPI_LP_GEN_DATA(port); } while (len < buflen) { @@ -318,7 +318,7 @@ int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum pipe pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 mask; int ret; @@ -327,14 +327,14 @@ int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, * longer than MIPI_MAX_RETURN_PKT_SIZE */ - I915_WRITE(MIPI_INTR_STAT(pipe), GEN_READ_DATA_AVAIL); + I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL); ret = dsi_vc_dcs_send_read_request(intel_dsi, channel, dcs_cmd); if (ret) return ret; mask = GEN_READ_DATA_AVAIL; - if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 50)) + if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 50)) DRM_ERROR("Timeout waiting for read data.\n"); ret = dsi_read_data_return(intel_dsi, buf, buflen); @@ -354,7 +354,7 @@ int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum pipe pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 mask; int ret; @@ -363,7 +363,7 @@ int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, * longer than MIPI_MAX_RETURN_PKT_SIZE */ - I915_WRITE(MIPI_INTR_STAT(pipe), GEN_READ_DATA_AVAIL); + I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL); ret = dsi_vc_generic_send_read_request(intel_dsi, channel, reqdata, reqlen); @@ -371,7 +371,7 @@ int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, return ret; mask = GEN_READ_DATA_AVAIL; - if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 50)) + if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 50)) DRM_ERROR("Timeout waiting for read data.\n"); ret = dsi_read_data_return(intel_dsi, buf, buflen); @@ -395,7 +395,7 @@ int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs) struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum pipe pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 mask; /* XXX: pipe, hs */ @@ -405,16 +405,16 @@ int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs) cmd |= DPI_LP_MODE; /* clear bit */ - I915_WRITE(MIPI_INTR_STAT(pipe), SPL_PKT_SENT_INTERRUPT); + I915_WRITE(MIPI_INTR_STAT(port), SPL_PKT_SENT_INTERRUPT); /* XXX: old code skips write if control unchanged */ - if (cmd == I915_READ(MIPI_DPI_CONTROL(pipe))) + if (cmd == I915_READ(MIPI_DPI_CONTROL(port))) DRM_ERROR("Same special packet %02x twice in a row.\n", cmd); - I915_WRITE(MIPI_DPI_CONTROL(pipe), cmd); + I915_WRITE(MIPI_DPI_CONTROL(port), cmd); mask = SPL_PKT_SENT_INTERRUPT; - if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 100)) + if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 100)) DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd); return 0; @@ -426,12 +426,12 @@ void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi) struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum pipe pipe = intel_crtc->pipe; + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 mask; mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY | LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY; - if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 100)) + if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == mask, 100)) DRM_ERROR("DPI FIFOs are not empty\n"); } -- cgit v0.10.2 From 17af40a835f1805e8d0523dddf1fbabe06abf230 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 14 Nov 2014 16:54:22 +0200 Subject: drm/i915/dsi: add ports to intel_dsi to describe the ports being driven Later on this can include multiple ports (e.g. (1 << PORT_A) | (1 << PORT_C)) to describe dual link DSI. Signed-off-by: Jani Nikula Reviewed-by: Gaurav K Singh Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 35842a6..259cb4a 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -749,10 +749,13 @@ void intel_dsi_init(struct drm_device *dev) intel_connector->unregister = intel_connector_unregister; /* Pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI port C */ - if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) + if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) { intel_encoder->crtc_mask = (1 << PIPE_A); - else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIC) + intel_dsi->ports = (1 << PORT_A); + } else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIC) { intel_encoder->crtc_mask = (1 << PIPE_B); + intel_dsi->ports = (1 << PORT_C); + } for (i = 0; i < ARRAY_SIZE(intel_dsi_devices); i++) { dsi = &intel_dsi_devices[i]; diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 97a6f62..7f5d028 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -78,6 +78,9 @@ struct intel_dsi { struct intel_connector *attached_connector; + /* bit mask of ports being driven */ + u16 ports; + /* if true, use HS mode, otherwise LP */ bool hs; -- cgit v0.10.2 From 4f54741e07f9c4791f06a3d151b56ece08b27c20 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 27 Nov 2014 11:22:48 +0000 Subject: drm/i915: Make ring freespace calculation more robust The used space in a ring is given by the cyclic distance from the consumer (HEAD) to the producer (TAIL), i.e. ((tail-head) MOD size); conversely, the available space in a ring is the cyclic distance from the producer to the consumer, MINUS the amount reserved for a "gap" that is supposed to guarantee that the producer never catches up with or overruns the consumer. Note that some GEN h/w requires that TAIL never approach to within one cacheline of HEAD, so the gap is usually set to twice the cacheline size to ensure this. While the existing code gives the correct answer for correct inputs, if the producer HAS overrun into the reserved space, the result can be a value larger than the maximum valid value (size-reserved). We can improve this by reorganising the calculation, so that in the event of overrun the result will be negative rather than over-large. This means that the commonly-used test (available >= required) will then reject further writes into the ring after an overrun, giving some chance that we can recover from or at least diagnose the original problem; whereas allowing more writes would likely both confuse the h/w and destroy the evidence of what went wrong. Signed-off-by: Dave Gordon Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 788e1b6..2ac382a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -52,10 +52,10 @@ intel_ring_initialized(struct intel_engine_cs *ring) int __intel_ring_space(int head, int tail, int size) { - int space = head - (tail + I915_RING_FREE_SPACE); - if (space < 0) + int space = head - tail; + if (space <= 0) space += size; - return space; + return space - I915_RING_FREE_SPACE; } int intel_ring_space(struct intel_ringbuffer *ringbuf) -- cgit v0.10.2 From ebd0fd4bef6384dd422d6480b0d5b10b7bfe829a Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 27 Nov 2014 11:22:49 +0000 Subject: drm/i915: Consolidate ring freespace calculations There are numerous places in the code where the driver's idea of how much space is left in a ring is updated using the driver's latest notions of the positions of 'head' and 'tail' for the ring. Among them are some that update one or both of these values before (re)doing the calculation. In particular, there are four different places in the code where 'last_retired_head' is copied to 'head' and then set to -1; and two of these do not have a guard to check that it has actually been updated since last time it was consumed, leaving the possibility that the dummy -1 can be transferred from 'last_retired_head' to 'head', causing the space calculation to produce 'impossible' results (previously seen on Android/VLV). This code therefore consolidates all the calculation and updating of these values, such that there is only one place where the ring space is updated, and it ALWAYS uses (and consumes) 'last_retired_head' if (and ONLY if) it has been updated since the last call. Signed-off-by: Dave Gordon Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index b13221b..828cba4 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -925,14 +925,8 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, struct drm_i915_gem_request *request; int ret; - if (ringbuf->last_retired_head != -1) { - ringbuf->head = ringbuf->last_retired_head; - ringbuf->last_retired_head = -1; - - ringbuf->space = intel_ring_space(ringbuf); - if (ringbuf->space >= bytes) - return 0; - } + if (intel_ring_space(ringbuf) >= bytes) + return 0; list_for_each_entry(request, &ring->request_list, list) { /* @@ -959,11 +953,8 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, return ret; i915_gem_retire_requests_ring(ring); - ringbuf->head = ringbuf->last_retired_head; - ringbuf->last_retired_head = -1; - ringbuf->space = intel_ring_space(ringbuf); - return 0; + return intel_ring_space(ringbuf) >= bytes ? 0 : -ENOSPC; } static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, @@ -989,12 +980,10 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, * case by choosing an insanely large timeout. */ end = jiffies + 60 * HZ; + ret = 0; do { - ringbuf->space = intel_ring_space(ringbuf); - if (ringbuf->space >= bytes) { - ret = 0; + if (intel_ring_space(ringbuf) >= bytes) break; - } msleep(1); @@ -1035,7 +1024,7 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf) iowrite32(MI_NOOP, virt++); ringbuf->tail = 0; - ringbuf->space = intel_ring_space(ringbuf); + intel_ring_update_space(ringbuf); return 0; } @@ -1885,8 +1874,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, ringbuf->effective_size = ringbuf->size; ringbuf->head = 0; ringbuf->tail = 0; - ringbuf->space = ringbuf->size; ringbuf->last_retired_head = -1; + intel_ring_update_space(ringbuf); if (ringbuf->obj == NULL) { ret = intel_alloc_ringbuffer_obj(dev, ringbuf); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2ac382a..e0b76ff 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -58,10 +58,21 @@ int __intel_ring_space(int head, int tail, int size) return space - I915_RING_FREE_SPACE; } +void intel_ring_update_space(struct intel_ringbuffer *ringbuf) +{ + if (ringbuf->last_retired_head != -1) { + ringbuf->head = ringbuf->last_retired_head; + ringbuf->last_retired_head = -1; + } + + ringbuf->space = __intel_ring_space(ringbuf->head & HEAD_ADDR, + ringbuf->tail, ringbuf->size); +} + int intel_ring_space(struct intel_ringbuffer *ringbuf) { - return __intel_ring_space(ringbuf->head & HEAD_ADDR, - ringbuf->tail, ringbuf->size); + intel_ring_update_space(ringbuf); + return ringbuf->space; } bool intel_ring_stopped(struct intel_engine_cs *ring) @@ -589,10 +600,10 @@ static int init_ring_common(struct intel_engine_cs *ring) goto out; } + ringbuf->last_retired_head = -1; ringbuf->head = I915_READ_HEAD(ring); ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR; - ringbuf->space = intel_ring_space(ringbuf); - ringbuf->last_retired_head = -1; + intel_ring_update_space(ringbuf); memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); @@ -1901,14 +1912,8 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n) struct drm_i915_gem_request *request; int ret; - if (ringbuf->last_retired_head != -1) { - ringbuf->head = ringbuf->last_retired_head; - ringbuf->last_retired_head = -1; - - ringbuf->space = intel_ring_space(ringbuf); - if (ringbuf->space >= n) - return 0; - } + if (intel_ring_space(ringbuf) >= n) + return 0; list_for_each_entry(request, &ring->request_list, list) { if (__intel_ring_space(request->tail, ringbuf->tail, @@ -1925,10 +1930,7 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n) return ret; i915_gem_retire_requests_ring(ring); - ringbuf->head = ringbuf->last_retired_head; - ringbuf->last_retired_head = -1; - ringbuf->space = intel_ring_space(ringbuf); return 0; } @@ -1954,14 +1956,14 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n) * case by choosing an insanely large timeout. */ end = jiffies + 60 * HZ; + ret = 0; trace_i915_ring_wait_begin(ring); do { + if (intel_ring_space(ringbuf) >= n) + break; ringbuf->head = I915_READ_HEAD(ring); - ringbuf->space = intel_ring_space(ringbuf); - if (ringbuf->space >= n) { - ret = 0; + if (intel_ring_space(ringbuf) >= n) break; - } msleep(1); @@ -2002,7 +2004,7 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) iowrite32(MI_NOOP, virt++); ringbuf->tail = 0; - ringbuf->space = intel_ring_space(ringbuf); + intel_ring_update_space(ringbuf); return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 39e303d..17e9011 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -407,6 +407,7 @@ static inline void intel_ring_advance(struct intel_engine_cs *ring) ringbuf->tail &= ringbuf->size - 1; } int __intel_ring_space(int head, int tail, int size); +void intel_ring_update_space(struct intel_ringbuffer *ringbuf); int intel_ring_space(struct intel_ringbuffer *ringbuf); bool intel_ring_stopped(struct intel_engine_cs *ring); void __intel_ring_advance(struct intel_engine_cs *ring); -- cgit v0.10.2 From ecfe00d802d47af797f09cf8c88ad5ee7aa8d11b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 20 Nov 2014 00:33:04 +0100 Subject: drm/i915: s/init()/init_hw()/ in intel_engine_cs This is (mostly, some exceptions that need fixing) the hw setup function which starts the ring. And not the function which allocates all the resources. Make this clear by giving it a better name. Signed-off-by: Daniel Vetter Reviewed-by: Dave Gordon Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 828cba4..5e9bb53 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1391,8 +1391,8 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin if (ret) return ret; - if (ring->init) { - ret = ring->init(ring); + if (ring->init_hw) { + ret = ring->init_hw(ring); if (ret) return ret; } @@ -1417,7 +1417,7 @@ static int logical_render_ring_init(struct drm_device *dev) if (HAS_L3_DPF(dev)) ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; - ring->init = gen8_init_render_ring; + ring->init_hw = gen8_init_render_ring; ring->init_context = intel_logical_ring_workarounds_emit; ring->cleanup = intel_fini_pipe_control; ring->get_seqno = gen8_get_seqno; @@ -1444,7 +1444,7 @@ static int logical_bsd_ring_init(struct drm_device *dev) ring->irq_keep_mask = GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; - ring->init = gen8_init_common_ring; + ring->init_hw = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; @@ -1469,7 +1469,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev) ring->irq_keep_mask = GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT; - ring->init = gen8_init_common_ring; + ring->init_hw = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; @@ -1494,7 +1494,7 @@ static int logical_blt_ring_init(struct drm_device *dev) ring->irq_keep_mask = GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT; - ring->init = gen8_init_common_ring; + ring->init_hw = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; @@ -1519,7 +1519,7 @@ static int logical_vebox_ring_init(struct drm_device *dev) ring->irq_keep_mask = GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT; - ring->init = gen8_init_common_ring; + ring->init_hw = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e0b76ff..2a87b22 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1865,7 +1865,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, if (ret) goto error; - ret = ring->init(ring); + ret = ring->init_hw(ring); if (ret) goto error; @@ -2437,7 +2437,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->dispatch_execbuffer = i830_dispatch_execbuffer; else ring->dispatch_execbuffer = i915_dispatch_execbuffer; - ring->init = init_render_ring; + ring->init_hw = init_render_ring; ring->cleanup = render_ring_cleanup; /* Workaround batchbuffer to combat CS tlb bug. */ @@ -2530,7 +2530,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) } ring->dispatch_execbuffer = i965_dispatch_execbuffer; } - ring->init = init_ring_common; + ring->init_hw = init_ring_common; return intel_init_ring_buffer(dev, ring); } @@ -2569,7 +2569,7 @@ int intel_init_bsd2_ring_buffer(struct drm_device *dev) ring->semaphore.signal = gen8_xcs_signal; GEN8_RING_SEMAPHORE_INIT; } - ring->init = init_ring_common; + ring->init_hw = init_ring_common; return intel_init_ring_buffer(dev, ring); } @@ -2626,7 +2626,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC; } } - ring->init = init_ring_common; + ring->init_hw = init_ring_common; return intel_init_ring_buffer(dev, ring); } @@ -2677,7 +2677,7 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev) ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC; } } - ring->init = init_ring_common; + ring->init_hw = init_ring_common; return intel_init_ring_buffer(dev, ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 17e9011..6dbb6f4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -146,7 +146,7 @@ struct intel_engine_cs { bool __must_check (*irq_get)(struct intel_engine_cs *ring); void (*irq_put)(struct intel_engine_cs *ring); - int (*init)(struct intel_engine_cs *ring); + int (*init_hw)(struct intel_engine_cs *ring); int (*init_context)(struct intel_engine_cs *ring, struct intel_context *ctx); -- cgit v0.10.2 From 99be1dfe06e56b6e32f522979e9cf354dad5dc2e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 20 Nov 2014 00:33:06 +0100 Subject: drm/i915: Move intel_init_pipe_control out of engine->init_hw With this all the ->init_hw hooks really only set up hw state needed to start the ring, all the software state setup and memory/buffer allocations happen beforehand. v2: We need to call intel_init_pipe_control after the ring init since otherwise engine->dev is NULL and it falls over. Currently that's now after the hw ring is enabled but a) we'll be fine as long as no one submits a batch b) this will change soon. Signed-off-by: Daniel Vetter Reviewed-by: Dave Gordon Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 5e9bb53..542382f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1161,10 +1161,6 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring) */ I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); - ret = intel_init_pipe_control(ring); - if (ret) - return ret; - I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); return init_workarounds_ring(ring); @@ -1406,6 +1402,7 @@ static int logical_render_ring_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring = &dev_priv->ring[RCS]; + int ret; ring->name = "render ring"; ring->id = RCS; @@ -1428,7 +1425,12 @@ static int logical_render_ring_init(struct drm_device *dev) ring->irq_put = gen8_logical_ring_put_irq; ring->emit_bb_start = gen8_emit_bb_start; - return logical_ring_init(dev, ring); + ring->dev = dev; + ret = logical_ring_init(dev, ring); + if (ret) + return ret; + + return intel_init_pipe_control(ring); } static int logical_bsd_ring_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2a87b22..f0ffcf7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -865,12 +865,6 @@ static int init_render_ring(struct intel_engine_cs *ring) _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) | _MASKED_BIT_ENABLE(GFX_REPLAY_MODE)); - if (INTEL_INFO(dev)->gen >= 5) { - ret = intel_init_pipe_control(ring); - if (ret) - return ret; - } - if (IS_GEN6(dev)) { /* From the Sandybridge PRM, volume 1 part 3, page 24: * "If this bit is set, STCunit will have LRA as replacement @@ -2459,7 +2453,17 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj); } - return intel_init_ring_buffer(dev, ring); + ret = intel_init_ring_buffer(dev, ring); + if (ret) + return ret; + + if (INTEL_INFO(dev)->gen >= 5) { + ret = intel_init_pipe_control(ring); + if (ret) + return ret; + } + + return 0; } int intel_init_bsd_ring_buffer(struct drm_device *dev) -- cgit v0.10.2 From 35a57ffbb10840af219eeaf64718434242bb7c76 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 20 Nov 2014 00:33:07 +0100 Subject: drm/i915: Only init engines once We can do this. And now there's finally the clean split between software setup and hardware setup I kinda wanted since multi-ring support was merged aeons ago. It only took almost 5 years. Signed-off-by: Daniel Vetter Reviewed-by: Dave Gordon Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0751ec9..7a83a9f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4769,6 +4769,7 @@ int i915_gem_init_hw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *ring; int ret, i; if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) @@ -4795,9 +4796,11 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_init_swizzling(dev); - ret = dev_priv->gt.init_rings(dev); - if (ret) - return ret; + for_each_ring(ring, dev_priv, i) { + ret = ring->init_hw(ring); + if (ret) + return ret; + } for (i = 0; i < NUM_L3_SLICES(dev); i++) i915_gem_l3_remap(&dev_priv->ring[RCS], i); @@ -4870,6 +4873,10 @@ int i915_gem_init(struct drm_device *dev) return ret; } + ret = dev_priv->gt.init_rings(dev); + if (ret) + return ret; + ret = i915_gem_init_hw(dev); if (ret == -EIO) { /* Allow ring initialisation to fail by marking the GPU as diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 542382f..4ffb08c 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1387,12 +1387,6 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin if (ret) return ret; - if (ring->init_hw) { - ret = ring->init_hw(ring); - if (ret) - return ret; - } - ret = intel_lr_context_deferred_create(ring->default_context, ring); return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f0ffcf7..590b7c3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1859,10 +1859,6 @@ static int intel_init_ring_buffer(struct drm_device *dev, if (ret) goto error; - ret = ring->init_hw(ring); - if (ret) - goto error; - return 0; error: -- cgit v0.10.2 From 36d0a82ef4dbe8a586b1ca538cbd37c889829340 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Thu, 27 Nov 2014 15:32:34 +0200 Subject: drm/i915: Remove unnecessary goto in intel_primary_plane_disable() The same logic can be implemented without it, and it even saves a line of code. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 376ec89..3a088c0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11850,13 +11850,11 @@ intel_primary_plane_disable(struct drm_plane *plane) * In either case, we need to unpin the FB and let the fb pointer get * updated, but otherwise we don't need to touch the hardware. */ - if (!intel_crtc->primary_enabled) - goto disable_unpin; - - intel_crtc_wait_for_pending_flips(plane->crtc); - intel_disable_primary_hw_plane(plane, plane->crtc); + if (intel_crtc->primary_enabled) { + intel_crtc_wait_for_pending_flips(plane->crtc); + intel_disable_primary_hw_plane(plane, plane->crtc); + } -disable_unpin: mutex_lock(&dev->struct_mutex); i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe)); -- cgit v0.10.2 From bfc882b4e30fbc169ecfe3508378623743806f56 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 20 Nov 2014 00:33:08 +0100 Subject: drm/i915: Flatten engine init control flow Now that sanity prevails and we have the clean split between software init and starting the engines we can drop all the "have we allocate this struct already?" nonsense. Execlist code could benefit quite a bit more still, but that's for another patch. Reviewed-by: Dave Gordon Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 22c992a..6e9eac4 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -716,13 +716,13 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring) BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count)); BUG_ON(!validate_regs_sorted(ring)); - if (hash_empty(ring->cmd_hash)) { - ret = init_hash_table(ring, cmd_tables, cmd_table_count); - if (ret) { - DRM_ERROR("CMD: cmd_parser_init failed!\n"); - fini_hash_table(ring); - return ret; - } + WARN_ON(!hash_empty(ring->cmd_hash)); + + ret = init_hash_table(ring, cmd_tables, cmd_table_count); + if (ret) { + DRM_ERROR("CMD: cmd_parser_init failed!\n"); + fini_hash_table(ring); + return ret; } ring->needs_cmd_parser = true; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 4ffb08c..d6f8253 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1833,8 +1833,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, int ret; WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL); - if (ctx->engine[ring->id].state) - return 0; + WARN_ON(ctx->engine[ring->id].state); context_size = round_up(get_lr_context_size(ring), 4096); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 590b7c3..79b4ca5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -635,8 +635,7 @@ intel_init_pipe_control(struct intel_engine_cs *ring) { int ret; - if (ring->scratch.obj) - return 0; + WARN_ON(ring->scratch.obj); ring->scratch.obj = i915_gem_alloc_object(ring->dev, 4096); if (ring->scratch.obj == NULL) { @@ -1799,15 +1798,15 @@ int intel_alloc_ringbuffer_obj(struct drm_device *dev, static int intel_init_ring_buffer(struct drm_device *dev, struct intel_engine_cs *ring) { - struct intel_ringbuffer *ringbuf = ring->buffer; + struct intel_ringbuffer *ringbuf; int ret; - if (ringbuf == NULL) { - ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL); - if (!ringbuf) - return -ENOMEM; - ring->buffer = ringbuf; - } + WARN_ON(ring->buffer); + + ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL); + if (!ringbuf) + return -ENOMEM; + ring->buffer = ringbuf; ring->dev = dev; INIT_LIST_HEAD(&ring->active_list); @@ -1830,21 +1829,21 @@ static int intel_init_ring_buffer(struct drm_device *dev, goto error; } - if (ringbuf->obj == NULL) { - ret = intel_alloc_ringbuffer_obj(dev, ringbuf); - if (ret) { - DRM_ERROR("Failed to allocate ringbuffer %s: %d\n", - ring->name, ret); - goto error; - } + WARN_ON(ringbuf->obj); - ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf); - if (ret) { - DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n", - ring->name, ret); - intel_destroy_ringbuffer_obj(ringbuf); - goto error; - } + ret = intel_alloc_ringbuffer_obj(dev, ringbuf); + if (ret) { + DRM_ERROR("Failed to allocate ringbuffer %s: %d\n", + ring->name, ret); + goto error; + } + + ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf); + if (ret) { + DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n", + ring->name, ret); + intel_destroy_ringbuffer_obj(ringbuf); + goto error; } /* Workaround an erratum on the i830 which causes a hang if -- cgit v0.10.2 From d972d6ee55102f1acb48c55537fb5989136358b7 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 1 Dec 2014 18:01:05 +0200 Subject: drm/i915: Convert pxvid to extvid lookup table to a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion table can be replaced with simple enough function. text data bss dec hex filename 839688 10987 24 850699 cfb0b drivers/gpu/drm/i915/i915.ko 839224 10987 24 850235 cf93b drivers/gpu/drm/i915/i915.ko Result is 494 saved bytes (.05525%). v2: - no run on sentences from subject (Chris, Jani) - be verbose about the savings (Chris, Daniel) Reviewed-by: Ville Syrjälä (v1) Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9af0af4..78911e2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5681,146 +5681,27 @@ unsigned long i915_mch_val(struct drm_i915_private *dev_priv) return ((m * x) / 127) - b; } -static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) +static int _pxvid_to_vd(u8 pxvid) +{ + if (pxvid == 0) + return 0; + + if (pxvid >= 8 && pxvid < 31) + pxvid = 31; + + return (pxvid + 2) * 125; +} + +static u32 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) { struct drm_device *dev = dev_priv->dev; - static const struct v_table { - u16 vd; /* in .1 mil */ - u16 vm; /* in .1 mil */ - } v_table[] = { - { 0, 0, }, - { 375, 0, }, - { 500, 0, }, - { 625, 0, }, - { 750, 0, }, - { 875, 0, }, - { 1000, 0, }, - { 1125, 0, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4125, 3000, }, - { 4250, 3125, }, - { 4375, 3250, }, - { 4500, 3375, }, - { 4625, 3500, }, - { 4750, 3625, }, - { 4875, 3750, }, - { 5000, 3875, }, - { 5125, 4000, }, - { 5250, 4125, }, - { 5375, 4250, }, - { 5500, 4375, }, - { 5625, 4500, }, - { 5750, 4625, }, - { 5875, 4750, }, - { 6000, 4875, }, - { 6125, 5000, }, - { 6250, 5125, }, - { 6375, 5250, }, - { 6500, 5375, }, - { 6625, 5500, }, - { 6750, 5625, }, - { 6875, 5750, }, - { 7000, 5875, }, - { 7125, 6000, }, - { 7250, 6125, }, - { 7375, 6250, }, - { 7500, 6375, }, - { 7625, 6500, }, - { 7750, 6625, }, - { 7875, 6750, }, - { 8000, 6875, }, - { 8125, 7000, }, - { 8250, 7125, }, - { 8375, 7250, }, - { 8500, 7375, }, - { 8625, 7500, }, - { 8750, 7625, }, - { 8875, 7750, }, - { 9000, 7875, }, - { 9125, 8000, }, - { 9250, 8125, }, - { 9375, 8250, }, - { 9500, 8375, }, - { 9625, 8500, }, - { 9750, 8625, }, - { 9875, 8750, }, - { 10000, 8875, }, - { 10125, 9000, }, - { 10250, 9125, }, - { 10375, 9250, }, - { 10500, 9375, }, - { 10625, 9500, }, - { 10750, 9625, }, - { 10875, 9750, }, - { 11000, 9875, }, - { 11125, 10000, }, - { 11250, 10125, }, - { 11375, 10250, }, - { 11500, 10375, }, - { 11625, 10500, }, - { 11750, 10625, }, - { 11875, 10750, }, - { 12000, 10875, }, - { 12125, 11000, }, - { 12250, 11125, }, - { 12375, 11250, }, - { 12500, 11375, }, - { 12625, 11500, }, - { 12750, 11625, }, - { 12875, 11750, }, - { 13000, 11875, }, - { 13125, 12000, }, - { 13250, 12125, }, - { 13375, 12250, }, - { 13500, 12375, }, - { 13625, 12500, }, - { 13750, 12625, }, - { 13875, 12750, }, - { 14000, 12875, }, - { 14125, 13000, }, - { 14250, 13125, }, - { 14375, 13250, }, - { 14500, 13375, }, - { 14625, 13500, }, - { 14750, 13625, }, - { 14875, 13750, }, - { 15000, 13875, }, - { 15125, 14000, }, - { 15250, 14125, }, - { 15375, 14250, }, - { 15500, 14375, }, - { 15625, 14500, }, - { 15750, 14625, }, - { 15875, 14750, }, - { 16000, 14875, }, - { 16125, 15000, }, - }; + const int vd = _pxvid_to_vd(pxvid); + const int vm = vd - 1125; + if (INTEL_INFO(dev)->is_mobile) - return v_table[pxvid].vm; - else - return v_table[pxvid].vd; + return vm > 0 ? vm : 0; + + return vd; } static void __i915_update_gfx_val(struct drm_i915_private *dev_priv) -- cgit v0.10.2 From e7778be1eab918274f79603d7c17b3ec8be77386 Mon Sep 17 00:00:00 2001 From: Thomas Daniel Date: Tue, 2 Dec 2014 12:50:48 +0000 Subject: drm/i915: Fix startup failure in LRC mode after recent init changes A previous commit introduced engine init changes: commit 372ee59699d9 ("drm/i915: Only init engines once") This broke execlists as intel_lr_context_render_state_init was trying to emit commands to the RCS for the default context before the ring->init_hw was called. Made a new gen8_init_rcs_context function and assign in to render ring init_context. Moved call to intel_logical_ring_workarounds_emit into gen8_init_rcs_context to maintain previous functionality. Moved call to render_state_init from lr_context_deferred_create into gen8_init_rcs_context, and modified deferred_create to call ring->init_context for non-default contexts. Modified i915_gem_context_enable to call ring->init_context for the default context. So init_context will now always be called when the hw is ready - in i915_gem_context_enable for the default context and in lr_context_deferred_create for other contexts. Signed-off-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 3c3a9ff..5cd2b97 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -408,14 +408,25 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv) BUG_ON(!dev_priv->ring[RCS].default_context); - if (i915.enable_execlists) - return 0; + if (i915.enable_execlists) { + for_each_ring(ring, dev_priv, i) { + if (ring->init_context) { + ret = ring->init_context(ring, + ring->default_context); + if (ret) { + DRM_ERROR("ring init context: %d\n", + ret); + return ret; + } + } + } - for_each_ring(ring, dev_priv, i) { - ret = i915_switch_context(ring, ring->default_context); - if (ret) - return ret; - } + } else + for_each_ring(ring, dev_priv, i) { + ret = i915_switch_context(ring, ring->default_context); + if (ret) + return ret; + } return 0; } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d6f8253..52e9952 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1336,6 +1336,18 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf) return 0; } +static int gen8_init_rcs_context(struct intel_engine_cs *ring, + struct intel_context *ctx) +{ + int ret; + + ret = intel_logical_ring_workarounds_emit(ring, ctx); + if (ret) + return ret; + + return intel_lr_context_render_state_init(ring, ctx); +} + /** * intel_logical_ring_cleanup() - deallocate the Engine Command Streamer * @@ -1409,7 +1421,7 @@ static int logical_render_ring_init(struct drm_device *dev) ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; ring->init_hw = gen8_init_render_ring; - ring->init_context = intel_logical_ring_workarounds_emit; + ring->init_context = gen8_init_rcs_context; ring->cleanup = intel_fini_pipe_control; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; @@ -1904,21 +1916,17 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, if (ctx == ring->default_context) lrc_setup_hardware_status_page(ring, ctx_obj); - - if (ring->id == RCS && !ctx->rcs_initialized) { + else if (ring->id == RCS && !ctx->rcs_initialized) { if (ring->init_context) { ret = ring->init_context(ring, ctx); - if (ret) + if (ret) { DRM_ERROR("ring init context: %d\n", ret); + ctx->engine[ring->id].ringbuf = NULL; + ctx->engine[ring->id].state = NULL; + goto error; + } } - ret = intel_lr_context_render_state_init(ring, ctx); - if (ret) { - DRM_ERROR("Init render state failed: %d\n", ret); - ctx->engine[ring->id].ringbuf = NULL; - ctx->engine[ring->id].state = NULL; - goto error; - } ctx->rcs_initialized = true; } -- cgit v0.10.2 From d5abdfda91228349e7410e7a98f67fe044bfea7c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 20 Nov 2014 09:45:19 +0100 Subject: drm/i915: Move init_unused_rings to gem_init_hw We need to do that every time we resume the rings, not just at load. I've overlooked this in my untangling of the ring init code. Signed-off-by: Daniel Vetter Reviewed-by: Dave Gordon Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7a83a9f..9d362d3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4709,14 +4709,6 @@ int i915_gem_init_rings(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; - /* - * At least 830 can leave some of the unused rings - * "active" (ie. head != tail) after resume which - * will prevent c3 entry. Makes sure all unused rings - * are totally idle. - */ - init_unused_rings(dev); - ret = intel_init_render_ring_buffer(dev); if (ret) return ret; @@ -4796,6 +4788,14 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_init_swizzling(dev); + /* + * At least 830 can leave some of the unused rings + * "active" (ie. head != tail) after resume which + * will prevent c3 entry. Makes sure all unused rings + * are totally idle. + */ + init_unused_rings(dev); + for_each_ring(ring, dev_priv, i) { ret = ring->init_hw(ring); if (ret) -- cgit v0.10.2 From 6c930688cb04e81ca71092baf585f7ea1c670368 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Wed, 26 Nov 2014 13:37:26 +0000 Subject: drm/i915/skl: Update the DDI translation values for DP/eDP 1.3 Hardware team updated the recommended translation values for DP/eDP 1.3. This should help with some stability and HBR2 issues. Signed-off-by: Damien Lespiau Reviewed-by: Satheeshakrishna M Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e6b45cd..4e2e860 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -128,15 +128,15 @@ static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { }; static const struct ddi_buf_trans skl_ddi_translations_dp[] = { - { 0x00000018, 0x000000a0 }, - { 0x00004014, 0x00000098 }, + { 0x00000018, 0x000000a2 }, + { 0x00004014, 0x0000009B }, { 0x00006012, 0x00000088 }, - { 0x00008010, 0x00000080 }, - { 0x00000018, 0x00000098 }, + { 0x00008010, 0x00000087 }, + { 0x00000018, 0x0000009B }, { 0x00004014, 0x00000088 }, - { 0x00006012, 0x00000080 }, + { 0x00006012, 0x00000087 }, { 0x00000018, 0x00000088 }, - { 0x00004014, 0x00000080 }, + { 0x00004014, 0x00000087 }, }; static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { -- cgit v0.10.2 From f763566992bb004a27d620c9ad90ec9a4dff34c3 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 3 Dec 2014 14:59:24 +0000 Subject: drm/i915: Stop putting GGTT VMA at the head of the list Multiple GGTT VMAs per object will be introduced in the near future which will make it impossible to guarantee normal GGTT view is at the head of the list. Purpose of this patch is to break this assumption straight away so any potential hidden assumptions in the code base can be bisected to this simple patch. For: VIZ-4544 Signed-off-by: Tvrtko Ursulin Suggested-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9d362d3..c1c1141 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5303,11 +5303,13 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr) struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj) { + struct i915_address_space *ggtt = i915_obj_to_ggtt(obj); struct i915_vma *vma; - vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link); - if (vma->vm != i915_obj_to_ggtt(obj)) - return NULL; + list_for_each_entry(vma, &obj->vma_list, vma_link) { + if (vma->vm == ggtt) + return vma; + } - return vma; + return NULL; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 171f6ea..ac03a38 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2202,13 +2202,9 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, BUG(); } - /* Keep GGTT vmas first to make debug easier */ - if (i915_is_ggtt(vm)) - list_add(&vma->vma_link, &obj->vma_list); - else { - list_add_tail(&vma->vma_link, &obj->vma_list); + list_add_tail(&vma->vma_link, &obj->vma_list); + if (!i915_is_ggtt(vm)) i915_ppgtt_get(i915_vm_to_ppgtt(vm)); - } return vma; } -- cgit v0.10.2 From 2fcffe195ed3329082ce22f2118543871bfbbcf0 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Wed, 3 Dec 2014 17:33:24 +0000 Subject: drm/i915: Don't display nonsensical values in i915_ddb_info on gen < 9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When playing around with debugfs and a HSW machine I noticed that we were displaying some garbled value in i915_ddb_info. This debugfs file is only meaningful for gen9+, so don't display anything on earlier platforms. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6c16939..d0e445e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2743,6 +2743,9 @@ static int i915_ddb_info(struct seq_file *m, void *unused) enum pipe pipe; int plane; + if (INTEL_INFO(dev)->gen < 9) + return 0; + drm_modeset_lock_all(dev); ddb = &dev_priv->wm.skl_hw.ddb; -- cgit v0.10.2 From 5505a244901f28e21d7267246511a1ca2ce79bcc Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Thu, 4 Dec 2014 10:58:47 +0530 Subject: drm/i915: New functions added for enabling & disabling MIPI Port Ctrl reg This patch is in preparation for the DSI dual link port enable and disable related changes. Signed-off-by: Gaurav K Singh Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 259cb4a..693736b 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -102,6 +102,36 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, return true; } +static void intel_dsi_port_enable(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + u32 temp; + + /* assert ip_tg_enable signal */ + temp = I915_READ(MIPI_PORT_CTRL(port)) & ~LANE_CONFIGURATION_MASK; + temp = temp | intel_dsi->port_bits; + I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE); + POSTING_READ(MIPI_PORT_CTRL(port)); +} + +static void intel_dsi_port_disable(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + u32 temp; + + /* de-assert ip_tg_enable signal */ + temp = I915_READ(MIPI_PORT_CTRL(port)); + I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE); + POSTING_READ(MIPI_PORT_CTRL(port)); +} + static void intel_dsi_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; @@ -141,7 +171,6 @@ static void intel_dsi_enable(struct intel_encoder *encoder) struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); - u32 temp; DRM_DEBUG_KMS("\n"); @@ -157,11 +186,7 @@ static void intel_dsi_enable(struct intel_encoder *encoder) wait_for_dsi_fifo_empty(intel_dsi); - /* assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(port)) & ~LANE_CONFIGURATION_MASK; - temp = temp | intel_dsi->port_bits; - I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE); - POSTING_READ(MIPI_PORT_CTRL(port)); + intel_dsi_port_enable(encoder); } } @@ -245,11 +270,7 @@ static void intel_dsi_disable(struct intel_encoder *encoder) if (is_vid_mode(intel_dsi)) { wait_for_dsi_fifo_empty(intel_dsi); - /* de-assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(port)); - I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE); - POSTING_READ(MIPI_PORT_CTRL(port)); - + intel_dsi_port_disable(encoder); msleep(2); } -- cgit v0.10.2 From 8f4d2683b02ad8059bf1861acef64c022b9d5ce6 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Thu, 4 Dec 2014 10:58:48 +0530 Subject: drm/i915: Added port as parameter to the functions which does read/write of DSI Controller This patch is in preparation of DSI dual link panels. For dual link panels, few packets needs to be sent to Port A or Port C or both. Based on the portno from MIPI Sequence Block#53, these sequences needs to be sent accordingly. v2: Addressed review comments by Jani - port variables named properly Signed-off-by: Gaurav K Singh Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.c b/drivers/gpu/drm/i915/intel_dsi_cmd.c index 004fa91..8e30684 100644 --- a/drivers/gpu/drm/i915/intel_dsi_cmd.c +++ b/drivers/gpu/drm/i915/intel_dsi_cmd.c @@ -48,13 +48,11 @@ * For memory writes, these should probably be used for performance. */ -static void print_stat(struct intel_dsi *intel_dsi) +static void print_stat(struct intel_dsi *intel_dsi, enum port port) { struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 val; val = I915_READ(MIPI_INTR_STAT(port)); @@ -104,13 +102,12 @@ enum dsi_type { }; /* enable or disable command mode hs transmissions */ -void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable) +void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable, + enum port port) { struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 temp; u32 mask = DBI_FIFO_EMPTY; @@ -125,13 +122,11 @@ void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable) } static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel, - u8 data_type, u16 data) + u8 data_type, u16 data, enum port port) { struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 ctrl_reg; u32 ctrl; u32 mask; @@ -149,7 +144,7 @@ static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel, if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == 0, 50)) { DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n"); - print_stat(intel_dsi); + print_stat(intel_dsi, port); } /* @@ -167,13 +162,11 @@ static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel, } static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel, - u8 data_type, const u8 *data, int len) + u8 data_type, const u8 *data, int len, enum port port) { struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 data_reg; int i, j, n; u32 mask; @@ -204,12 +197,12 @@ static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel, * dwords, then wait for not set, then continue. */ } - return dsi_vc_send_short(intel_dsi, channel, data_type, len); + return dsi_vc_send_short(intel_dsi, channel, data_type, len, port); } static int dsi_vc_write_common(struct intel_dsi *intel_dsi, int channel, const u8 *data, int len, - enum dsi_type type) + enum dsi_type type, enum port port) { int ret; @@ -217,50 +210,54 @@ static int dsi_vc_write_common(struct intel_dsi *intel_dsi, BUG_ON(type == DSI_GENERIC); ret = dsi_vc_send_short(intel_dsi, channel, MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, - 0); + 0, port); } else if (len == 1) { ret = dsi_vc_send_short(intel_dsi, channel, type == DSI_GENERIC ? MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM : - MIPI_DSI_DCS_SHORT_WRITE, data[0]); + MIPI_DSI_DCS_SHORT_WRITE, data[0], + port); } else if (len == 2) { ret = dsi_vc_send_short(intel_dsi, channel, type == DSI_GENERIC ? MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM : MIPI_DSI_DCS_SHORT_WRITE_PARAM, - (data[1] << 8) | data[0]); + (data[1] << 8) | data[0], port); } else { ret = dsi_vc_send_long(intel_dsi, channel, - type == DSI_GENERIC ? - MIPI_DSI_GENERIC_LONG_WRITE : - MIPI_DSI_DCS_LONG_WRITE, data, len); + type == DSI_GENERIC ? + MIPI_DSI_GENERIC_LONG_WRITE : + MIPI_DSI_DCS_LONG_WRITE, data, len, + port); } return ret; } int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel, - const u8 *data, int len) + const u8 *data, int len, enum port port) { - return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_DCS); + return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_DCS, + port); } int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel, - const u8 *data, int len) + const u8 *data, int len, enum port port) { - return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_GENERIC); + return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_GENERIC, + port); } static int dsi_vc_dcs_send_read_request(struct intel_dsi *intel_dsi, - int channel, u8 dcs_cmd) + int channel, u8 dcs_cmd, enum port port) { return dsi_vc_send_short(intel_dsi, channel, MIPI_DSI_DCS_READ, - dcs_cmd); + dcs_cmd, port); } static int dsi_vc_generic_send_read_request(struct intel_dsi *intel_dsi, int channel, u8 *reqdata, - int reqlen) + int reqlen, enum port port) { u16 data; u8 data_type; @@ -282,17 +279,15 @@ static int dsi_vc_generic_send_read_request(struct intel_dsi *intel_dsi, BUG(); } - return dsi_vc_send_short(intel_dsi, channel, data_type, data); + return dsi_vc_send_short(intel_dsi, channel, data_type, data, port); } static int dsi_read_data_return(struct intel_dsi *intel_dsi, - u8 *buf, int buflen) + u8 *buf, int buflen, enum port port) { struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); int i, len = 0; u32 data_reg, val; @@ -312,13 +307,11 @@ static int dsi_read_data_return(struct intel_dsi *intel_dsi, } int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, - u8 *buf, int buflen) + u8 *buf, int buflen, enum port port) { struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 mask; int ret; @@ -329,7 +322,7 @@ int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL); - ret = dsi_vc_dcs_send_read_request(intel_dsi, channel, dcs_cmd); + ret = dsi_vc_dcs_send_read_request(intel_dsi, channel, dcs_cmd, port); if (ret) return ret; @@ -337,7 +330,7 @@ int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 50)) DRM_ERROR("Timeout waiting for read data.\n"); - ret = dsi_read_data_return(intel_dsi, buf, buflen); + ret = dsi_read_data_return(intel_dsi, buf, buflen, port); if (ret < 0) return ret; @@ -348,13 +341,11 @@ int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, } int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, - u8 *reqdata, int reqlen, u8 *buf, int buflen) + u8 *reqdata, int reqlen, u8 *buf, int buflen, enum port port) { struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); u32 mask; int ret; @@ -366,7 +357,7 @@ int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL); ret = dsi_vc_generic_send_read_request(intel_dsi, channel, reqdata, - reqlen); + reqlen, port); if (ret) return ret; @@ -374,7 +365,7 @@ int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 50)) DRM_ERROR("Timeout waiting for read data.\n"); - ret = dsi_read_data_return(intel_dsi, buf, buflen); + ret = dsi_read_data_return(intel_dsi, buf, buflen, port); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.h b/drivers/gpu/drm/i915/intel_dsi_cmd.h index 46aa1ac..326a5ac 100644 --- a/drivers/gpu/drm/i915/intel_dsi_cmd.h +++ b/drivers/gpu/drm/i915/intel_dsi_cmd.h @@ -36,77 +36,81 @@ #define DPI_LP_MODE_EN false #define DPI_HS_MODE_EN true -void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable); +void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable, + enum port port); int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel, - const u8 *data, int len); + const u8 *data, int len, enum port port); int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel, - const u8 *data, int len); + const u8 *data, int len, enum port port); int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, - u8 *buf, int buflen); + u8 *buf, int buflen, enum port port); int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, - u8 *reqdata, int reqlen, u8 *buf, int buflen); + u8 *reqdata, int reqlen, u8 *buf, int buflen, enum port port); int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs); void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi); /* XXX: questionable write helpers */ static inline int dsi_vc_dcs_write_0(struct intel_dsi *intel_dsi, - int channel, u8 dcs_cmd) + int channel, u8 dcs_cmd, enum port port) { - return dsi_vc_dcs_write(intel_dsi, channel, &dcs_cmd, 1); + return dsi_vc_dcs_write(intel_dsi, channel, &dcs_cmd, 1, port); } static inline int dsi_vc_dcs_write_1(struct intel_dsi *intel_dsi, - int channel, u8 dcs_cmd, u8 param) + int channel, u8 dcs_cmd, u8 param, enum port port) { u8 buf[2] = { dcs_cmd, param }; - return dsi_vc_dcs_write(intel_dsi, channel, buf, 2); + return dsi_vc_dcs_write(intel_dsi, channel, buf, 2, port); } static inline int dsi_vc_generic_write_0(struct intel_dsi *intel_dsi, - int channel) + int channel, enum port port) { - return dsi_vc_generic_write(intel_dsi, channel, NULL, 0); + return dsi_vc_generic_write(intel_dsi, channel, NULL, 0, port); } static inline int dsi_vc_generic_write_1(struct intel_dsi *intel_dsi, - int channel, u8 param) + int channel, u8 param, enum port port) { - return dsi_vc_generic_write(intel_dsi, channel, ¶m, 1); + return dsi_vc_generic_write(intel_dsi, channel, ¶m, 1, port); } static inline int dsi_vc_generic_write_2(struct intel_dsi *intel_dsi, - int channel, u8 param1, u8 param2) + int channel, u8 param1, u8 param2, enum port port) { u8 buf[2] = { param1, param2 }; - return dsi_vc_generic_write(intel_dsi, channel, buf, 2); + return dsi_vc_generic_write(intel_dsi, channel, buf, 2, port); } /* XXX: questionable read helpers */ static inline int dsi_vc_generic_read_0(struct intel_dsi *intel_dsi, - int channel, u8 *buf, int buflen) + int channel, u8 *buf, int buflen, enum port port) { - return dsi_vc_generic_read(intel_dsi, channel, NULL, 0, buf, buflen); + return dsi_vc_generic_read(intel_dsi, channel, NULL, 0, buf, buflen, + port); } static inline int dsi_vc_generic_read_1(struct intel_dsi *intel_dsi, int channel, u8 param, u8 *buf, - int buflen) + int buflen, enum port port) { - return dsi_vc_generic_read(intel_dsi, channel, ¶m, 1, buf, buflen); + return dsi_vc_generic_read(intel_dsi, channel, ¶m, 1, buf, buflen, + port); } static inline int dsi_vc_generic_read_2(struct intel_dsi *intel_dsi, int channel, u8 param1, u8 param2, - u8 *buf, int buflen) + u8 *buf, int buflen, enum port port) { u8 req[2] = { param1, param2 }; - return dsi_vc_generic_read(intel_dsi, channel, req, 2, buf, buflen); + return dsi_vc_generic_read(intel_dsi, channel, req, 2, buf, buflen, + port); } diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index f6bdd44..7766c42 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -94,16 +94,23 @@ static struct gpio_table gtable[] = { { GPIO_NC_11_PCONF0, GPIO_NC_11_PAD, 0} }; +static inline enum port intel_dsi_seq_port_to_port(u8 port) +{ + return port ? PORT_C : PORT_A; +} + static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data) { - u8 type, byte, mode, vc, port; + u8 type, byte, mode, vc, seq_port; u16 len; + enum port port; byte = *data++; mode = (byte >> MIPI_TRANSFER_MODE_SHIFT) & 0x1; vc = (byte >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 0x3; - port = (byte >> MIPI_PORT_SHIFT) & 0x3; + seq_port = (byte >> MIPI_PORT_SHIFT) & 0x3; + port = intel_dsi_seq_port_to_port(seq_port); /* LP or HS mode */ intel_dsi->hs = mode; @@ -115,13 +122,13 @@ static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data) switch (type) { case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: - dsi_vc_generic_write_0(intel_dsi, vc); + dsi_vc_generic_write_0(intel_dsi, vc, port); break; case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: - dsi_vc_generic_write_1(intel_dsi, vc, *data); + dsi_vc_generic_write_1(intel_dsi, vc, *data, port); break; case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: - dsi_vc_generic_write_2(intel_dsi, vc, *data, *(data + 1)); + dsi_vc_generic_write_2(intel_dsi, vc, *data, *(data + 1), port); break; case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: @@ -129,19 +136,19 @@ static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data) DRM_DEBUG_DRIVER("Generic Read not yet implemented or used\n"); break; case MIPI_DSI_GENERIC_LONG_WRITE: - dsi_vc_generic_write(intel_dsi, vc, data, len); + dsi_vc_generic_write(intel_dsi, vc, data, len, port); break; case MIPI_DSI_DCS_SHORT_WRITE: - dsi_vc_dcs_write_0(intel_dsi, vc, *data); + dsi_vc_dcs_write_0(intel_dsi, vc, *data, port); break; case MIPI_DSI_DCS_SHORT_WRITE_PARAM: - dsi_vc_dcs_write_1(intel_dsi, vc, *data, *(data + 1)); + dsi_vc_dcs_write_1(intel_dsi, vc, *data, *(data + 1), port); break; case MIPI_DSI_DCS_READ: DRM_DEBUG_DRIVER("DCS Read not yet implemented or used\n"); break; case MIPI_DSI_DCS_LONG_WRITE: - dsi_vc_dcs_write(intel_dsi, vc, data, len); + dsi_vc_dcs_write(intel_dsi, vc, data, len, port); break; } -- cgit v0.10.2 From 7bcc3777b12a05687e5080e4de3c108f35d6aec8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 5 Dec 2014 14:17:42 +0200 Subject: drm/i915: release struct_mutex on the i915_gem_init_hw fail path Release struct_mutex if init_rings() fails. This is a regression introduced in commit 35a57ffbb10840af219eeaf64718434242bb7c76 Author: Daniel Vetter Date: Thu Nov 20 00:33:07 2014 +0100 drm/i915: Only init engines once Reported-by: Wei Yongjun Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c1c1141..e3ce4be 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4860,22 +4860,18 @@ int i915_gem_init(struct drm_device *dev) } ret = i915_gem_init_userptr(dev); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return ret; - } + if (ret) + goto out_unlock; i915_gem_init_global_gtt(dev); ret = i915_gem_context_init(dev); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return ret; - } + if (ret) + goto out_unlock; ret = dev_priv->gt.init_rings(dev); if (ret) - return ret; + goto out_unlock; ret = i915_gem_init_hw(dev); if (ret == -EIO) { @@ -4887,6 +4883,8 @@ int i915_gem_init(struct drm_device *dev) atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter); ret = 0; } + +out_unlock: mutex_unlock(&dev->struct_mutex); return ret; -- cgit v0.10.2 From 8edfbb8bfc7ef291b12f683f40de8cf274ae8ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 14 Nov 2014 18:16:56 +0200 Subject: drm/i915: s/MI_STORE_DWORD_IMM_GEN8/MI_STORE_DWORD_IMM_GEN4/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MI_STORE_DWORD_IMM length has been the same ever since gen4. Rename the define to avoid potential confusion if someone tries to use this on pre-gen8. Also correct the comment on MI_MEM_VIRTUAL bit. It's present on 945,g33 and 965 only. Cc: Oscar Mateo Signed-off-by: Ville Syrjälä [danvet: Add USE_GGTT define for g4x+ too.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index dc03fac..82da232 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -293,8 +293,9 @@ #define MI_SEMAPHORE_POLL (1<<15) #define MI_SEMAPHORE_SAD_GTE_SDD (1<<12) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) -#define MI_STORE_DWORD_IMM_GEN8 MI_INSTR(0x20, 2) -#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ +#define MI_STORE_DWORD_IMM_GEN4 MI_INSTR(0x20, 2) +#define MI_MEM_VIRTUAL (1 << 22) /* 945,g33,965 */ +#define MI_USE_GGTT (1 << 22) /* g4x+ */ #define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) #define MI_STORE_DWORD_INDEX_SHIFT 2 /* Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM: diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 52e9952..7986eb3 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1319,7 +1319,7 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf) if (ret) return ret; - cmd = MI_STORE_DWORD_IMM_GEN8; + cmd = MI_STORE_DWORD_IMM_GEN4; cmd |= MI_GLOBAL_GTT; intel_logical_ring_emit(ringbuf, cmd); -- cgit v0.10.2 From 369602d370fac9d3bda125c8cc36c8f779910bf1 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Fri, 5 Dec 2014 14:09:28 +0530 Subject: drm/i915: Add support for port enable/disable for dual link configuration For Dual Link MIPI Panels, both Port A and Port C should be enabled during the MIPI encoder enabling sequence. Similarly, during the disabling sequence, both ports needs to be disabled. v2: Used for_each_dsi_port macro instead of for loop v3: Used intel_dsi->ports instead of dual_link var for dual link configuration check v4: Masking of the required MIPI port bits before writing proper values Signed-off-by: Gaurav K Singh Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 82da232..b4a11ab 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6665,6 +6665,7 @@ enum punit_power_well { #define DPI_ENABLE (1 << 31) /* A + C */ #define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27 #define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27) +#define DUAL_LINK_MODE_SHIFT 26 #define DUAL_LINK_MODE_MASK (1 << 26) #define DUAL_LINK_MODE_FRONT_BACK (0 << 26) #define DUAL_LINK_MODE_PIXEL_ALTERNATIVE (1 << 26) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 693736b..fd4d397 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -108,28 +108,41 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + enum port port; u32 temp; - /* assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(port)) & ~LANE_CONFIGURATION_MASK; - temp = temp | intel_dsi->port_bits; - I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE); - POSTING_READ(MIPI_PORT_CTRL(port)); + for_each_dsi_port(port, intel_dsi->ports) { + temp = I915_READ(MIPI_PORT_CTRL(port)); + temp &= ~LANE_CONFIGURATION_MASK; + temp &= ~DUAL_LINK_MODE_MASK; + + if (intel_dsi->ports == ((1 << PORT_A) | (1 << PORT_C))) { + temp |= (intel_dsi->dual_link - 1) + << DUAL_LINK_MODE_SHIFT; + temp |= intel_crtc->pipe ? + LANE_CONFIGURATION_DUAL_LINK_B : + LANE_CONFIGURATION_DUAL_LINK_A; + } + /* assert ip_tg_enable signal */ + I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE); + POSTING_READ(MIPI_PORT_CTRL(port)); + } } static void intel_dsi_port_disable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; u32 temp; - /* de-assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(port)); - I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE); - POSTING_READ(MIPI_PORT_CTRL(port)); + for_each_dsi_port(port, intel_dsi->ports) { + /* de-assert ip_tg_enable signal */ + temp = I915_READ(MIPI_PORT_CTRL(port)); + I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE); + POSTING_READ(MIPI_PORT_CTRL(port)); + } } static void intel_dsi_device_ready(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 7f5d028..f2cc2fc 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -104,6 +104,7 @@ struct intel_dsi { u8 clock_stop; u8 escape_clk_div; + u8 dual_link; u32 port_bits; u32 bw_timer; u32 dphy_reg; diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index 7766c42..f60146f 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -287,6 +287,10 @@ static bool generic_init(struct intel_dsi_device *dsi) intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0; intel_dsi->lane_count = mipi_config->lane_cnt + 1; intel_dsi->pixel_format = mipi_config->videomode_color_format << 7; + intel_dsi->dual_link = mipi_config->dual_link; + + if (intel_dsi->dual_link) + intel_dsi->ports = ((1 << PORT_A) | (1 << PORT_C)); if (intel_dsi->pixel_format == VID_MODE_FORMAT_RGB666) bits_per_pixel = 18; -- cgit v0.10.2 From a9da9bce88ee842c7904b5670c035ca759e77238 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Fri, 5 Dec 2014 14:13:41 +0530 Subject: drm/i915: Pixel Clock changes for DSI dual link For dual link MIPI Panels, each port needs half of pixel clock. Pixel overlap can be enabled if needed by panel, then in that case, pixel clock will be increased for extra pixels. v2 : Address review comments by Jani - Removed the bit mask used for ->dual_link - Used DSI instead of MIPI for #define variables v3: Added the VLV_DISPLAY_BASE to VLV_CHICKEN_3 register Signed-off-by: Gaurav K Singh Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b4a11ab..869e5ae 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6030,6 +6030,10 @@ enum punit_power_well { #define GEN8_PMINTR_REDIRECT_TO_NON_DISP (1<<31) #define VLV_PWRDWNUPCTL 0xA294 +#define VLV_CHICKEN_3 (VLV_DISPLAY_BASE + 0x7040C) +#define PIXEL_OVERLAP_CNT_MASK (3 << 30) +#define PIXEL_OVERLAP_CNT_SHIFT 30 + #define GEN6_PMISR 0x44020 #define GEN6_PMIMR 0x44024 /* rps_lock */ #define GEN6_PMIIR 0x44028 diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index de01167..a6a8710 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -818,7 +818,8 @@ struct mipi_config { #define DUAL_LINK_PIXEL_ALT 2 u16 dual_link:2; u16 lane_cnt:2; - u16 rsvd3:12; + u16 pixel_overlap:3; + u16 rsvd3:9; u16 rsvd4; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index fd4d397..a1b93c5 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -111,6 +111,14 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder) enum port port; u32 temp; + if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) { + temp = I915_READ(VLV_CHICKEN_3); + temp &= ~PIXEL_OVERLAP_CNT_MASK | + intel_dsi->pixel_overlap << + PIXEL_OVERLAP_CNT_SHIFT; + I915_WRITE(VLV_CHICKEN_3, temp); + } + for_each_dsi_port(port, intel_dsi->ports) { temp = I915_READ(MIPI_PORT_CTRL(port)); temp &= ~LANE_CONFIGURATION_MASK; diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index f2cc2fc..8fe2064 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -28,6 +28,11 @@ #include #include "intel_drv.h" +/* Dual Link support */ +#define DSI_DUAL_LINK_NONE 0 +#define DSI_DUAL_LINK_FRONT_BACK 1 +#define DSI_DUAL_LINK_PIXEL_ALT 2 + struct intel_dsi_device { unsigned int panel_id; const char *name; @@ -105,6 +110,7 @@ struct intel_dsi { u8 escape_clk_div; u8 dual_link; + u8 pixel_overlap; u32 port_bits; u32 bw_timer; u32 dphy_reg; diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index f60146f..f8c2269 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -288,6 +288,7 @@ static bool generic_init(struct intel_dsi_device *dsi) intel_dsi->lane_count = mipi_config->lane_cnt + 1; intel_dsi->pixel_format = mipi_config->videomode_color_format << 7; intel_dsi->dual_link = mipi_config->dual_link; + intel_dsi->pixel_overlap = mipi_config->pixel_overlap; if (intel_dsi->dual_link) intel_dsi->ports = ((1 << PORT_A) | (1 << PORT_C)); @@ -310,6 +311,20 @@ static bool generic_init(struct intel_dsi_device *dsi) pclk = mode->clock; + /* In dual link mode each port needs half of pixel clock */ + if (intel_dsi->dual_link) { + pclk = pclk / 2; + + /* we can enable pixel_overlap if needed by panel. In this + * case we need to increase the pixelclock for extra pixels + */ + if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) { + pclk += DIV_ROUND_UP(mode->vtotal * + intel_dsi->pixel_overlap * + 60, 1000); + } + } + /* Burst Mode Ratio * Target ddr frequency from VBT / non burst ddr freq * multiply by 100 to preserve remainder @@ -504,6 +519,12 @@ static bool generic_init(struct intel_dsi_device *dsi) DRM_DEBUG_KMS("Clockstop %s\n", intel_dsi->clock_stop ? "disabled" : "enabled"); DRM_DEBUG_KMS("Mode %s\n", intel_dsi->operation_mode ? "command" : "video"); + if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) + DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_FRONT_BACK\n"); + else if (intel_dsi->dual_link == DSI_DUAL_LINK_PIXEL_ALT) + DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_PIXEL_ALT\n"); + else + DRM_DEBUG_KMS("Dual link: NONE\n"); DRM_DEBUG_KMS("Pixel Format %d\n", intel_dsi->pixel_format); DRM_DEBUG_KMS("TLPX %d\n", intel_dsi->escape_clk_div); DRM_DEBUG_KMS("LP RX Timeout 0x%x\n", intel_dsi->lp_rx_timeout); -- cgit v0.10.2 From 4510cd779e5897eeb8691aecbd639bb62ec27d55 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Thu, 4 Dec 2014 10:58:51 +0530 Subject: drm/i915: Dual link needs Shutdown and Turn on packet for both ports For dual link MIPI panels, SHUTDOWN packet needs to send to both Ports A & C during MIPI encoder disabling sequence. Similarly, TURN ON packet to be sent to both Ports during MIPI encoder enabling sequence. v2: Address review comments by Jani - Used a for loop instead of do-while loop. v3: Used for_each_dsi_port macro instead of for loop Signed-off-by: Gaurav K Singh Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.c b/drivers/gpu/drm/i915/intel_dsi_cmd.c index 8e30684..562811c 100644 --- a/drivers/gpu/drm/i915/intel_dsi_cmd.c +++ b/drivers/gpu/drm/i915/intel_dsi_cmd.c @@ -385,8 +385,7 @@ int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs) struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + enum port port; u32 mask; /* XXX: pipe, hs */ @@ -395,18 +394,23 @@ int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs) else cmd |= DPI_LP_MODE; - /* clear bit */ - I915_WRITE(MIPI_INTR_STAT(port), SPL_PKT_SENT_INTERRUPT); + for_each_dsi_port(port, intel_dsi->ports) { + /* clear bit */ + I915_WRITE(MIPI_INTR_STAT(port), SPL_PKT_SENT_INTERRUPT); - /* XXX: old code skips write if control unchanged */ - if (cmd == I915_READ(MIPI_DPI_CONTROL(port))) - DRM_ERROR("Same special packet %02x twice in a row.\n", cmd); + /* XXX: old code skips write if control unchanged */ + if (cmd == I915_READ(MIPI_DPI_CONTROL(port))) + DRM_ERROR("Same special packet %02x twice in a row.\n", + cmd); - I915_WRITE(MIPI_DPI_CONTROL(port), cmd); + I915_WRITE(MIPI_DPI_CONTROL(port), cmd); - mask = SPL_PKT_SENT_INTERRUPT; - if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 100)) - DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd); + mask = SPL_PKT_SENT_INTERRUPT; + if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, + 100)) + DRM_ERROR("Video mode command 0x%08x send failed.\n", + cmd); + } return 0; } -- cgit v0.10.2 From 58cf8887c94d8dfe42206af7de57163ce0f46cf2 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Thu, 4 Dec 2014 10:58:52 +0530 Subject: drm/i915: Enable DSI PLL for both DSI0 and DSI1 in case of dual link For Dual link MIPI Panels, dsipll clock for both DSI0 and DSI1 needs to be enabled. v2: Address review comments by Jani - Added wait time for PLL to be locked. v3: separate patch created for cck read for checking PLL to be locked Signed-off-by: Gaurav K Singh Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index fa7a6ca..636d72f 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -243,6 +243,9 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder) dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL; + if (intel_dsi->dual_link) + dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL; + DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n", dsi_mnp.dsi_pll_div, dsi_mnp.dsi_pll_ctrl); -- cgit v0.10.2 From 3770f0eec40cb9f1fb7af6453f7bcb420a8a86bc Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Fri, 5 Dec 2014 14:16:58 +0530 Subject: drm/i915: cck reg used for checking DSI Pll locked Instead of pipe configuration reg, cck reg to be used for checking whether DSI Pll is getting locked or not. v2: dpio_lock unlocked now in case DSI PLL lock fails Signed-off-by: Gaurav K Singh Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 636d72f..8957f10 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -272,12 +272,14 @@ void vlv_enable_dsi_pll(struct intel_encoder *encoder) tmp |= DSI_PLL_VCO_EN; vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp); - mutex_unlock(&dev_priv->dpio_lock); + if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) & + DSI_PLL_LOCK, 20)) { - if (wait_for(I915_READ(PIPECONF(PIPE_A)) & PIPECONF_DSI_PLL_LOCKED, 20)) { + mutex_unlock(&dev_priv->dpio_lock); DRM_ERROR("DSI PLL lock failed\n"); return; } + mutex_unlock(&dev_priv->dpio_lock); DRM_DEBUG_KMS("DSI PLL locked\n"); } -- cgit v0.10.2 From aa102d286a022fb0f42238c62c2b05cdac12109d Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Thu, 4 Dec 2014 10:58:54 +0530 Subject: drm/i915: MIPI Timings related changes for dual link hactive, hfp, hbp, hsync needs to be halved for dual link MIPI Panels. Accordingly timing related mmio regs needs to be programmed for both MIPI Ports. v2: Address review comments by Jani - Used a for loop instead of do-while loop v3: Used for_each_dsi_port macro instead of for loop Signed-off-by: Gaurav K Singh Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index a1b93c5..585538b 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -479,7 +479,7 @@ static void set_dsi_timings(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + enum port port; unsigned int bpp = intel_crtc->config.pipe_bpp; unsigned int lane_count = intel_dsi->lane_count; @@ -490,6 +490,15 @@ static void set_dsi_timings(struct drm_encoder *encoder, hsync = mode->hsync_end - mode->hsync_start; hbp = mode->htotal - mode->hsync_end; + if (intel_dsi->dual_link) { + hactive /= 2; + if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) + hactive += intel_dsi->pixel_overlap; + hfp /= 2; + hsync /= 2; + hbp /= 2; + } + vfp = mode->vsync_start - mode->vdisplay; vsync = mode->vsync_end - mode->vsync_start; vbp = mode->vtotal - mode->vsync_end; @@ -502,18 +511,20 @@ static void set_dsi_timings(struct drm_encoder *encoder, intel_dsi->burst_mode_ratio); hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio); - I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive); - I915_WRITE(MIPI_HFP_COUNT(port), hfp); - - /* meaningful for video mode non-burst sync pulse mode only, can be zero - * for non-burst sync events and burst modes */ - I915_WRITE(MIPI_HSYNC_PADDING_COUNT(port), hsync); - I915_WRITE(MIPI_HBP_COUNT(port), hbp); - - /* vertical values are in terms of lines */ - I915_WRITE(MIPI_VFP_COUNT(port), vfp); - I915_WRITE(MIPI_VSYNC_PADDING_COUNT(port), vsync); - I915_WRITE(MIPI_VBP_COUNT(port), vbp); + for_each_dsi_port(port, intel_dsi->ports) { + I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive); + I915_WRITE(MIPI_HFP_COUNT(port), hfp); + + /* meaningful for video mode non-burst sync pulse mode only, + * can be zero for non-burst sync events and burst modes */ + I915_WRITE(MIPI_HSYNC_PADDING_COUNT(port), hsync); + I915_WRITE(MIPI_HBP_COUNT(port), hbp); + + /* vertical values are in terms of lines */ + I915_WRITE(MIPI_VFP_COUNT(port), vfp); + I915_WRITE(MIPI_VSYNC_PADDING_COUNT(port), vsync); + I915_WRITE(MIPI_VBP_COUNT(port), vbp); + } } static void intel_dsi_prepare(struct intel_encoder *intel_encoder) -- cgit v0.10.2 From 384f02a2c4551fc785477d1808a59d717fd70420 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Fri, 5 Dec 2014 14:22:44 +0530 Subject: drm/i915: Update the DSI disable path to support dual link panel disabling We need to program both port registers during dual link disable path. v2: Address review comments by Jani - Used a for loop instead of do-while loop. v3: Used for_each_dsi_port macro instead of for loop v4: Added comments for the usage of AFE latchout bit Signed-off-by: Gaurav K Singh Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 585538b..8054928 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -281,9 +281,8 @@ static void intel_dsi_disable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + enum port port; u32 temp; DRM_DEBUG_KMS("\n"); @@ -295,23 +294,24 @@ static void intel_dsi_disable(struct intel_encoder *encoder) msleep(2); } - /* Panel commands can be sent when clock is in LP11 */ - I915_WRITE(MIPI_DEVICE_READY(port), 0x0); - - temp = I915_READ(MIPI_CTRL(port)); - temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; - I915_WRITE(MIPI_CTRL(port), temp | - intel_dsi->escape_clk_div << - ESCAPE_CLOCK_DIVIDER_SHIFT); + for_each_dsi_port(port, intel_dsi->ports) { + /* Panel commands can be sent when clock is in LP11 */ + I915_WRITE(MIPI_DEVICE_READY(port), 0x0); - I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); + temp = I915_READ(MIPI_CTRL(port)); + temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; + I915_WRITE(MIPI_CTRL(port), temp | + intel_dsi->escape_clk_div << + ESCAPE_CLOCK_DIVIDER_SHIFT); - temp = I915_READ(MIPI_DSI_FUNC_PRG(port)); - temp &= ~VID_MODE_FORMAT_MASK; - I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp); + I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); - I915_WRITE(MIPI_DEVICE_READY(port), 0x1); + temp = I915_READ(MIPI_DSI_FUNC_PRG(port)); + temp &= ~VID_MODE_FORMAT_MASK; + I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp); + I915_WRITE(MIPI_DEVICE_READY(port), 0x1); + } /* if disable packets are sent before sending shutdown packet then in * some next enable sequence send turn on packet error is observed */ if (intel_dsi->dev.dev_ops->disable) @@ -323,31 +323,42 @@ static void intel_dsi_disable(struct intel_encoder *encoder) static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; u32 val; DRM_DEBUG_KMS("\n"); + for_each_dsi_port(port, intel_dsi->ports) { - I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | ULPS_STATE_ENTER); - usleep_range(2000, 2500); - - I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | ULPS_STATE_EXIT); - usleep_range(2000, 2500); - - I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | ULPS_STATE_ENTER); - usleep_range(2000, 2500); - - if (wait_for(((I915_READ(MIPI_PORT_CTRL(port)) & AFE_LATCHOUT) - == 0x00000), 30)) - DRM_ERROR("DSI LP not going Low\n"); - - val = I915_READ(MIPI_PORT_CTRL(port)); - I915_WRITE(MIPI_PORT_CTRL(port), val & ~LP_OUTPUT_HOLD); - usleep_range(1000, 1500); - - I915_WRITE(MIPI_DEVICE_READY(port), 0x00); - usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | + ULPS_STATE_ENTER); + usleep_range(2000, 2500); + + I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | + ULPS_STATE_EXIT); + usleep_range(2000, 2500); + + I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | + ULPS_STATE_ENTER); + usleep_range(2000, 2500); + + /* Wait till Clock lanes are in LP-00 state for MIPI Port A + * only. MIPI Port C has no similar bit for checking + */ + if (wait_for(((I915_READ(MIPI_PORT_CTRL(PORT_A)) & AFE_LATCHOUT) + == 0x00000), 30)) + DRM_ERROR("DSI LP not going Low\n"); + + val = I915_READ(MIPI_PORT_CTRL(port)); + /* Disable MIPI PHY transparent latch + * Common bit for both MIPI Port A & MIPI Port C + */ + I915_WRITE(MIPI_PORT_CTRL(PORT_A), val & ~LP_OUTPUT_HOLD); + usleep_range(1000, 1500); + + I915_WRITE(MIPI_DEVICE_READY(port), 0x00); + usleep_range(2000, 2500); + } vlv_disable_dsi_pll(encoder); } -- cgit v0.10.2 From 24ee0e64909bf7f1953d87d3e1e29d93eafcad73 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Fri, 5 Dec 2014 14:24:21 +0530 Subject: drm/i915: Update the DSI enable path to support dual We need to program both port registers during dual link enable path. v2: Address review comments by Jani - Used a for loop instead of do-while loop. v3: Used for_each_dsi_port macro instead of for loop v4: Renamed mode_hactive variable to mode_hdisplay Signed-off-by: Gaurav K Singh Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 8054928..8f8b952 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -156,8 +156,8 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder) static void intel_dsi_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; u32 val; DRM_DEBUG_KMS("\n"); @@ -171,18 +171,21 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder) /* bandgap reset is needed after everytime we do power gate */ band_gap_reset(dev_priv); - I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_ENTER); - usleep_range(2500, 3000); + for_each_dsi_port(port, intel_dsi->ports) { - val = I915_READ(MIPI_PORT_CTRL(port)); - I915_WRITE(MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD); - usleep_range(1000, 1500); + I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_ENTER); + usleep_range(2500, 3000); - I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT); - usleep_range(2500, 3000); + val = I915_READ(MIPI_PORT_CTRL(port)); + I915_WRITE(MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD); + usleep_range(1000, 1500); - I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY); - usleep_range(2500, 3000); + I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT); + usleep_range(2500, 3000); + + I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY); + usleep_range(2500, 3000); + } } static void intel_dsi_enable(struct intel_encoder *encoder) @@ -547,32 +550,43 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); struct drm_display_mode *adjusted_mode = &intel_crtc->config.adjusted_mode; - enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe); + enum port port; unsigned int bpp = intel_crtc->config.pipe_bpp; u32 val, tmp; + u16 mode_hdisplay; DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe)); - /* escape clock divider, 20MHz, shared for A and C. device ready must be - * off when doing this! txclkesc? */ - tmp = I915_READ(MIPI_CTRL(PORT_A)); - tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK; - I915_WRITE(MIPI_CTRL(PORT_A), tmp | ESCAPE_CLOCK_DIVIDER_1); - - /* read request priority is per pipe */ - tmp = I915_READ(MIPI_CTRL(port)); - tmp &= ~READ_REQUEST_PRIORITY_MASK; - I915_WRITE(MIPI_CTRL(port), tmp | READ_REQUEST_PRIORITY_HIGH); + mode_hdisplay = adjusted_mode->hdisplay; - /* XXX: why here, why like this? handling in irq handler?! */ - I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff); - I915_WRITE(MIPI_INTR_EN(port), 0xffffffff); - - I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg); + if (intel_dsi->dual_link) { + mode_hdisplay /= 2; + if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) + mode_hdisplay += intel_dsi->pixel_overlap; + } - I915_WRITE(MIPI_DPI_RESOLUTION(port), - adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | - adjusted_mode->hdisplay << HORIZONTAL_ADDRESS_SHIFT); + for_each_dsi_port(port, intel_dsi->ports) { + /* escape clock divider, 20MHz, shared for A and C. + * device ready must be off when doing this! txclkesc? */ + tmp = I915_READ(MIPI_CTRL(PORT_A)); + tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK; + I915_WRITE(MIPI_CTRL(PORT_A), tmp | ESCAPE_CLOCK_DIVIDER_1); + + /* read request priority is per pipe */ + tmp = I915_READ(MIPI_CTRL(port)); + tmp &= ~READ_REQUEST_PRIORITY_MASK; + I915_WRITE(MIPI_CTRL(port), tmp | READ_REQUEST_PRIORITY_HIGH); + + /* XXX: why here, why like this? handling in irq handler?! */ + I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff); + I915_WRITE(MIPI_INTR_EN(port), 0xffffffff); + + I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg); + + I915_WRITE(MIPI_DPI_RESOLUTION(port), + adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | + mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT); + } set_dsi_timings(encoder, adjusted_mode); @@ -586,95 +600,102 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) /* XXX: cross-check bpp vs. pixel format? */ val |= intel_dsi->pixel_format; } - I915_WRITE(MIPI_DSI_FUNC_PRG(port), val); - /* timeouts for recovery. one frame IIUC. if counter expires, EOT and - * stop state. */ - - /* - * In burst mode, value greater than one DPI line Time in byte clock - * (txbyteclkhs) To timeout this timer 1+ of the above said value is - * recommended. - * - * In non-burst mode, Value greater than one DPI frame time in byte - * clock(txbyteclkhs) To timeout this timer 1+ of the above said value - * is recommended. - * - * In DBI only mode, value greater than one DBI frame time in byte - * clock(txbyteclkhs) To timeout this timer 1+ of the above said value - * is recommended. - */ - - if (is_vid_mode(intel_dsi) && - intel_dsi->video_mode_format == VIDEO_MODE_BURST) { - I915_WRITE(MIPI_HS_TX_TIMEOUT(port), - txbyteclkhs(adjusted_mode->htotal, bpp, - intel_dsi->lane_count, - intel_dsi->burst_mode_ratio) + 1); - } else { - I915_WRITE(MIPI_HS_TX_TIMEOUT(port), - txbyteclkhs(adjusted_mode->vtotal * - adjusted_mode->htotal, - bpp, intel_dsi->lane_count, - intel_dsi->burst_mode_ratio) + 1); - } - I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout); - I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port), intel_dsi->turn_arnd_val); - I915_WRITE(MIPI_DEVICE_RESET_TIMER(port), intel_dsi->rst_timer_val); + tmp = 0; + if (intel_dsi->eotp_pkt == 0) + tmp |= EOT_DISABLE; + if (intel_dsi->clock_stop) + tmp |= CLOCKSTOP; - /* dphy stuff */ + for_each_dsi_port(port, intel_dsi->ports) { + I915_WRITE(MIPI_DSI_FUNC_PRG(port), val); + + /* timeouts for recovery. one frame IIUC. if counter expires, + * EOT and stop state. */ + + /* + * In burst mode, value greater than one DPI line Time in byte + * clock (txbyteclkhs) To timeout this timer 1+ of the above + * said value is recommended. + * + * In non-burst mode, Value greater than one DPI frame time in + * byte clock(txbyteclkhs) To timeout this timer 1+ of the above + * said value is recommended. + * + * In DBI only mode, value greater than one DBI frame time in + * byte clock(txbyteclkhs) To timeout this timer 1+ of the above + * said value is recommended. + */ - /* in terms of low power clock */ - I915_WRITE(MIPI_INIT_COUNT(port), txclkesc(intel_dsi->escape_clk_div, 100)); + if (is_vid_mode(intel_dsi) && + intel_dsi->video_mode_format == VIDEO_MODE_BURST) { + I915_WRITE(MIPI_HS_TX_TIMEOUT(port), + txbyteclkhs(adjusted_mode->htotal, bpp, + intel_dsi->lane_count, + intel_dsi->burst_mode_ratio) + 1); + } else { + I915_WRITE(MIPI_HS_TX_TIMEOUT(port), + txbyteclkhs(adjusted_mode->vtotal * + adjusted_mode->htotal, + bpp, intel_dsi->lane_count, + intel_dsi->burst_mode_ratio) + 1); + } + I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout); + I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port), + intel_dsi->turn_arnd_val); + I915_WRITE(MIPI_DEVICE_RESET_TIMER(port), + intel_dsi->rst_timer_val); - val = 0; - if (intel_dsi->eotp_pkt == 0) - val |= EOT_DISABLE; + /* dphy stuff */ - if (intel_dsi->clock_stop) - val |= CLOCKSTOP; + /* in terms of low power clock */ + I915_WRITE(MIPI_INIT_COUNT(port), + txclkesc(intel_dsi->escape_clk_div, 100)); - /* recovery disables */ - I915_WRITE(MIPI_EOT_DISABLE(port), val); - /* in terms of low power clock */ - I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count); + /* recovery disables */ + I915_WRITE(MIPI_EOT_DISABLE(port), val); - /* in terms of txbyteclkhs. actual high to low switch + - * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK. - * - * XXX: write MIPI_STOP_STATE_STALL? - */ - I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(port), - intel_dsi->hs_to_lp_count); + /* in terms of low power clock */ + I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count); - /* XXX: low power clock equivalence in terms of byte clock. the number - * of byte clocks occupied in one low power clock. based on txbyteclkhs - * and txclkesc. txclkesc time / txbyteclk time * (105 + - * MIPI_STOP_STATE_STALL) / 105.??? - */ - I915_WRITE(MIPI_LP_BYTECLK(port), intel_dsi->lp_byte_clk); - - /* the bw essential for transmitting 16 long packets containing 252 - * bytes meant for dcs write memory command is programmed in this - * register in terms of byte clocks. based on dsi transfer rate and the - * number of lanes configured the time taken to transmit 16 long packets - * in a dsi stream varies. */ - I915_WRITE(MIPI_DBI_BW_CTRL(port), intel_dsi->bw_timer); - - I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(port), - intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT | - intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT); - - if (is_vid_mode(intel_dsi)) - /* Some panels might have resolution which is not a multiple of - * 64 like 1366 x 768. Enable RANDOM resolution support for such - * panels by default */ - I915_WRITE(MIPI_VIDEO_MODE_FORMAT(port), - intel_dsi->video_frmt_cfg_bits | - intel_dsi->video_mode_format | - IP_TG_CONFIG | - RANDOM_DPI_DISPLAY_RESOLUTION); + /* in terms of txbyteclkhs. actual high to low switch + + * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK. + * + * XXX: write MIPI_STOP_STATE_STALL? + */ + I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(port), + intel_dsi->hs_to_lp_count); + + /* XXX: low power clock equivalence in terms of byte clock. + * the number of byte clocks occupied in one low power clock. + * based on txbyteclkhs and txclkesc. + * txclkesc time / txbyteclk time * (105 + MIPI_STOP_STATE_STALL + * ) / 105.??? + */ + I915_WRITE(MIPI_LP_BYTECLK(port), intel_dsi->lp_byte_clk); + + /* the bw essential for transmitting 16 long packets containing + * 252 bytes meant for dcs write memory command is programmed in + * this register in terms of byte clocks. based on dsi transfer + * rate and the number of lanes configured the time taken to + * transmit 16 long packets in a dsi stream varies. */ + I915_WRITE(MIPI_DBI_BW_CTRL(port), intel_dsi->bw_timer); + + I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(port), + intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT | + intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT); + + if (is_vid_mode(intel_dsi)) + /* Some panels might have resolution which is not a + * multiple of 64 like 1366 x 768. Enable RANDOM + * resolution support for such panels by default */ + I915_WRITE(MIPI_VIDEO_MODE_FORMAT(port), + intel_dsi->video_frmt_cfg_bits | + intel_dsi->video_mode_format | + IP_TG_CONFIG | + RANDOM_DPI_DISPLAY_RESOLUTION); + } } static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) -- cgit v0.10.2 From f3f32360b6d9e22ece894a4d49abdd2d9a82fe81 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Thu, 4 Dec 2014 15:07:52 +0000 Subject: drm/i915/bdw: Add WaHdcDisableFetchWhenMasked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have it for chv, but was missing for bdw. Signed-off-by: Michel Thierry Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 79b4ca5..f521015 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -766,9 +766,11 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) * workaround for for a possible hang in the unlikely event a TLB * invalidation occurs during a PSD flush. */ + /* WaHdcDisableFetchWhenMasked:bdw */ /* WaDisableFenceDestinationToSLM:bdw (GT3 pre-production) */ WA_SET_BIT_MASKED(HDC_CHICKEN0, HDC_FORCE_NON_COHERENT | + HDC_DONOT_FETCH_MEM_WHEN_MASKED | (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0)); /* Wa4x4STCOptimizationDisable:bdw */ -- cgit v0.10.2 From 93dc1b6529eb8acd98243caaf399daf3c2c665bd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Dec 2014 15:59:16 +0100 Subject: drm/i915: Update DRIVER_DATE to 20141205 Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 049482f..502a01b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -55,7 +55,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20141121" +#define DRIVER_DATE "20141205" #undef WARN_ON #define WARN_ON(x) WARN(x, "WARN_ON(" #x ")") -- cgit v0.10.2 From ecb7e16bf187bc369cf6a5cd108582c01329980d Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Dec 2014 15:40:09 -0800 Subject: drm: add helper to get crtc timings (v5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to get hdisplay and vdisplay in a few places so create a helper to make our job easier. Note that drm_crtc_check_viewport() and intel_modeset_pipe_config() were previously making adjustments for doublescan modes and vscan > 1 modes, which was incorrect. Using our new helper fixes this mistake. v2 (by Matt): Use new stereo doubling function (suggested by Ville) v3 (by Matt): - Add missing kerneldoc (Daniel) - Use drm_mode_copy() (Jani) v4 (by Matt): - Drop stereo doubling function again; add 'stereo only' flag to drm_mode_set_crtcinfo() instead (Ville) v5 (by Matt): - Note behavioral change in drm_crtc_check_viewport() and intel_modeset_pipe_config(). (Ander) - Describe new adjustment flags in drm_mode_set_crtcinfo()'s kerneldoc. (Ander) Cc: dri-devel@lists.freedesktop.org Suggested-by: Ville Syrjälä Signed-off-by: Gustavo Padovan Signed-off-by: Matt Roper Acked-by: Dave Airlie Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index de79283..2985e3f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2550,6 +2550,27 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) EXPORT_SYMBOL(drm_mode_set_config_internal); /** + * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode + * @mode: mode to query + * @hdisplay: hdisplay value to fill in + * @vdisplay: vdisplay value to fill in + * + * The vdisplay value will be doubled if the specified mode is a stereo mode of + * the appropriate layout. + */ +void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, + int *hdisplay, int *vdisplay) +{ + struct drm_display_mode adjusted; + + drm_mode_copy(&adjusted, mode); + drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); + *hdisplay = adjusted.crtc_hdisplay; + *vdisplay = adjusted.crtc_vdisplay; +} +EXPORT_SYMBOL(drm_crtc_get_hv_timing); + +/** * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the * CRTC viewport * @crtc: CRTC that framebuffer will be displayed on @@ -2566,16 +2587,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, { int hdisplay, vdisplay; - hdisplay = mode->hdisplay; - vdisplay = mode->vdisplay; - - if (drm_mode_is_stereo(mode)) { - struct drm_display_mode adjusted = *mode; - - drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE); - hdisplay = adjusted.crtc_hdisplay; - vdisplay = adjusted.crtc_vdisplay; - } + drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); if (crtc->invert_dimensions) swap(hdisplay, vdisplay); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 6d8b941..7689c14 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -739,6 +739,8 @@ EXPORT_SYMBOL(drm_mode_vrefresh); * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for * buffers containing two eyes (only adjust the timings when needed, eg. for * "frame packing" or "side by side full"). + * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not* + * be performed for doublescan and vscan > 1 modes respectively. */ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) { @@ -765,18 +767,22 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) } } - if (p->flags & DRM_MODE_FLAG_DBLSCAN) { - p->crtc_vdisplay *= 2; - p->crtc_vsync_start *= 2; - p->crtc_vsync_end *= 2; - p->crtc_vtotal *= 2; + if (!(adjust_flags & CRTC_NO_DBLSCAN)) { + if (p->flags & DRM_MODE_FLAG_DBLSCAN) { + p->crtc_vdisplay *= 2; + p->crtc_vsync_start *= 2; + p->crtc_vsync_end *= 2; + p->crtc_vtotal *= 2; + } } - if (p->vscan > 1) { - p->crtc_vdisplay *= p->vscan; - p->crtc_vsync_start *= p->vscan; - p->crtc_vsync_end *= p->vscan; - p->crtc_vtotal *= p->vscan; + if (!(adjust_flags & CRTC_NO_VSCAN)) { + if (p->vscan > 1) { + p->crtc_vdisplay *= p->vscan; + p->crtc_vsync_start *= p->vscan; + p->crtc_vsync_end *= p->vscan; + p->crtc_vtotal *= p->vscan; + } } if (adjust_flags & CRTC_STEREO_DOUBLE) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3a088c0..9eee2c9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10322,9 +10322,9 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, * computation to clearly distinguish it from the adjusted mode, which * can be changed by the connectors in the below retry loop. */ - drm_mode_set_crtcinfo(&pipe_config->requested_mode, CRTC_STEREO_DOUBLE); - pipe_config->pipe_src_w = pipe_config->requested_mode.crtc_hdisplay; - pipe_config->pipe_src_h = pipe_config->requested_mode.crtc_vdisplay; + drm_crtc_get_hv_timing(&pipe_config->requested_mode, + &pipe_config->pipe_src_w, + &pipe_config->pipe_src_h); encoder_retry: /* Ensure the port clock defaults are reset when retrying. */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index dd2c16e..969da0f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1161,6 +1161,8 @@ extern int drm_plane_init(struct drm_device *dev, extern void drm_plane_cleanup(struct drm_plane *plane); extern unsigned int drm_plane_index(struct drm_plane *plane); extern void drm_plane_force_disable(struct drm_plane *plane); +extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, + int *hdisplay, int *vdisplay); extern int drm_crtc_check_viewport(const struct drm_crtc *crtc, int x, int y, const struct drm_display_mode *mode, diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 91d0582..8f17811 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -90,6 +90,9 @@ enum drm_mode_status { #define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ #define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ +#define CRTC_NO_DBLSCAN (1 << 2) /* don't adjust doublescan */ +#define CRTC_NO_VSCAN (1 << 3) /* don't adjust doublescan */ +#define CRTC_STEREO_DOUBLE_ONLY (CRTC_NO_DBLSCAN | CRTC_NO_VSCAN) #define DRM_MODE_FLAG_3D_MAX DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF -- cgit v0.10.2 From a912f12fe8f2c386007d9f0776fd12dcba5c96cf Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Dec 2014 15:40:10 -0800 Subject: drm/i915: remove intel_crtc_cursor_set_obj() (v5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge it into the plane update_plane() callback and make other users use the update_plane() functions instead. The fb != crtc->cursor->fb was already inside intel_crtc_cursor_set_obj() so we fold intel_crtc_cursor_set_obj() inside intel_commit_cursor_plane() and merge both paths into one. v5 (by Matt): - Rebase onto latest di-nightly codebase - Drop extra unreference call when we fail to pin (Ville) Reviewed-by(v4): Ville Syrjälä Signed-off-by: Gustavo Padovan Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9eee2c9..3342eb7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8417,109 +8417,6 @@ static bool cursor_size_ok(struct drm_device *dev, return true; } -static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc, - struct drm_i915_gem_object *obj, - uint32_t width, uint32_t height) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - unsigned old_width; - uint32_t addr; - int ret; - - /* if we want to turn off the cursor ignore width and height */ - if (!obj) { - DRM_DEBUG_KMS("cursor off\n"); - addr = 0; - mutex_lock(&dev->struct_mutex); - goto finish; - } - - /* we only need to pin inside GTT if cursor is non-phy */ - mutex_lock(&dev->struct_mutex); - if (!INTEL_INFO(dev)->cursor_needs_physical) { - unsigned alignment; - - /* - * Global gtt pte registers are special registers which actually - * forward writes to a chunk of system memory. Which means that - * there is no risk that the register values disappear as soon - * as we call intel_runtime_pm_put(), so it is correct to wrap - * only the pin/unpin/fence and not more. - */ - intel_runtime_pm_get(dev_priv); - - /* Note that the w/a also requires 2 PTE of padding following - * the bo. We currently fill all unused PTE with the shadow - * page and so we should always have valid PTE following the - * cursor preventing the VT-d warning. - */ - alignment = 0; - if (need_vtd_wa(dev)) - alignment = 64*1024; - - ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL); - if (ret) { - DRM_DEBUG_KMS("failed to move cursor bo into the GTT\n"); - intel_runtime_pm_put(dev_priv); - goto fail_locked; - } - - ret = i915_gem_object_put_fence(obj); - if (ret) { - DRM_DEBUG_KMS("failed to release fence for cursor"); - intel_runtime_pm_put(dev_priv); - goto fail_unpin; - } - - addr = i915_gem_obj_ggtt_offset(obj); - - intel_runtime_pm_put(dev_priv); - } else { - int align = IS_I830(dev) ? 16 * 1024 : 256; - ret = i915_gem_object_attach_phys(obj, align); - if (ret) { - DRM_DEBUG_KMS("failed to attach phys object\n"); - goto fail_locked; - } - addr = obj->phys_handle->busaddr; - } - - finish: - if (intel_crtc->cursor_bo) { - if (!INTEL_INFO(dev)->cursor_needs_physical) - i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo); - } - - i915_gem_track_fb(intel_crtc->cursor_bo, obj, - INTEL_FRONTBUFFER_CURSOR(pipe)); - mutex_unlock(&dev->struct_mutex); - - old_width = intel_crtc->cursor_width; - - intel_crtc->cursor_addr = addr; - intel_crtc->cursor_bo = obj; - intel_crtc->cursor_width = width; - intel_crtc->cursor_height = height; - - if (intel_crtc->active) { - if (old_width != width) - intel_update_watermarks(crtc); - intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL); - - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe)); - } - - return 0; -fail_unpin: - i915_gem_object_unpin_from_display_plane(obj); -fail_locked: - mutex_unlock(&dev->struct_mutex); - return ret; -} - static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, uint32_t start, uint32_t size) { @@ -12129,7 +12026,8 @@ intel_cursor_plane_disable(struct drm_plane *plane) BUG_ON(!plane->crtc); - return intel_crtc_cursor_set_obj(plane->crtc, NULL, 0, 0); + return plane->funcs->update_plane(plane, plane->crtc, NULL, + 0, 0, 0, 0, 0, 0, 0, 0); } static int @@ -12193,12 +12091,15 @@ intel_commit_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_crtc *crtc = state->crtc; - struct drm_framebuffer *fb = state->fb; + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - int crtc_w, crtc_h; + struct drm_i915_gem_object *obj = intel_fb_obj(state->fb); + enum pipe pipe = intel_crtc->pipe; + unsigned old_width; + uint32_t addr; + int ret; crtc->cursor_x = state->orig_dst.x1; crtc->cursor_y = state->orig_dst.y1; @@ -12213,18 +12114,100 @@ intel_commit_cursor_plane(struct drm_plane *plane, intel_plane->src_h = drm_rect_height(&state->orig_src); intel_plane->obj = obj; - if (fb != crtc->cursor->fb) { - crtc_w = drm_rect_width(&state->orig_dst); - crtc_h = drm_rect_height(&state->orig_dst); - return intel_crtc_cursor_set_obj(crtc, obj, crtc_w, crtc_h); + if (intel_crtc->cursor_bo == obj) + goto update; + + /* if we want to turn off the cursor ignore width and height */ + if (!obj) { + DRM_DEBUG_KMS("cursor off\n"); + addr = 0; + mutex_lock(&dev->struct_mutex); + goto finish; + } + + /* we only need to pin inside GTT if cursor is non-phy */ + mutex_lock(&dev->struct_mutex); + if (!INTEL_INFO(dev)->cursor_needs_physical) { + unsigned alignment; + + /* + * Global gtt pte registers are special registers which actually + * forward writes to a chunk of system memory. Which means that + * there is no risk that the register values disappear as soon + * as we call intel_runtime_pm_put(), so it is correct to wrap + * only the pin/unpin/fence and not more. + */ + intel_runtime_pm_get(dev_priv); + + /* Note that the w/a also requires 2 PTE of padding following + * the bo. We currently fill all unused PTE with the shadow + * page and so we should always have valid PTE following the + * cursor preventing the VT-d warning. + */ + alignment = 0; + if (need_vtd_wa(dev)) + alignment = 64*1024; + + ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL); + if (ret) { + DRM_DEBUG_KMS("failed to move cursor bo into the GTT\n"); + intel_runtime_pm_put(dev_priv); + goto fail_locked; + } + + ret = i915_gem_object_put_fence(obj); + if (ret) { + DRM_DEBUG_KMS("failed to release fence for cursor"); + intel_runtime_pm_put(dev_priv); + goto fail_unpin; + } + + addr = i915_gem_obj_ggtt_offset(obj); + + intel_runtime_pm_put(dev_priv); + } else { - intel_crtc_update_cursor(crtc, state->visible); + int align = IS_I830(dev) ? 16 * 1024 : 256; + ret = i915_gem_object_attach_phys(obj, align); + if (ret) { + DRM_DEBUG_KMS("failed to attach phys object\n"); + goto fail_locked; + } + addr = obj->phys_handle->busaddr; + } - intel_frontbuffer_flip(crtc->dev, - INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe)); +finish: + if (intel_crtc->cursor_bo) { + if (!INTEL_INFO(dev)->cursor_needs_physical) + i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo); + } - return 0; + i915_gem_track_fb(intel_crtc->cursor_bo, obj, + INTEL_FRONTBUFFER_CURSOR(pipe)); + mutex_unlock(&dev->struct_mutex); + + intel_crtc->cursor_addr = addr; + intel_crtc->cursor_bo = obj; +update: + old_width = intel_crtc->cursor_width; + + intel_crtc->cursor_width = drm_rect_width(&state->orig_dst); + intel_crtc->cursor_height = drm_rect_height(&state->orig_dst); + + if (intel_crtc->active) { + if (old_width != intel_crtc->cursor_width) + intel_update_watermarks(crtc); + intel_crtc_update_cursor(crtc, state->visible); + + intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe)); } + + return 0; +fail_unpin: + i915_gem_object_unpin_from_display_plane(obj); +fail_locked: + mutex_unlock(&dev->struct_mutex); + return ret; } static int -- cgit v0.10.2 From 455a68086d1dfb801ad7c867d5ca0ed0e0f758b0 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Dec 2014 15:40:11 -0800 Subject: drm/i915: remove intel_pipe_set_base() (v4) After some refactor intel_primary_plane_setplane() does the same as intel_pipe_set_base() so we can get rid of it and replace the calls with intel_primary_plane_setplane(). v2: take Ville's comments: - get the right arguments for update_plane() - use drm_crtc_get_hv_timing() v3 (by Matt): - Rebase to latest di-nightly codebase - Use primary->funcs->update_plane() in __intel_set_mode() - Use primary->funcs->disable_plane() in intel_crtc_disable() v4 (by Matt): - Drop redundant calls to intel_crtc_wait_for_pending_flips() before calling update_plane() (Ville) Signed-off-by: Gustavo Padovan Signed-off-by: Matt Roper Acked-and-mourned-by: Jesse Barnes Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3342eb7..76896e8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2954,71 +2954,6 @@ static void intel_update_pipe_size(struct intel_crtc *crtc) crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay; } -static int -intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *fb) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - struct drm_framebuffer *old_fb = crtc->primary->fb; - struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb); - int ret; - - if (intel_crtc_has_pending_flip(crtc)) { - DRM_ERROR("pipe is still busy with an old pageflip\n"); - return -EBUSY; - } - - /* no fb bound */ - if (!fb) { - DRM_ERROR("No FB bound\n"); - return 0; - } - - if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) { - DRM_ERROR("no plane for crtc: plane %c, num_pipes %d\n", - plane_name(intel_crtc->plane), - INTEL_INFO(dev)->num_pipes); - return -EINVAL; - } - - mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL); - if (ret == 0) - i915_gem_track_fb(old_obj, intel_fb_obj(fb), - INTEL_FRONTBUFFER_PRIMARY(pipe)); - mutex_unlock(&dev->struct_mutex); - if (ret != 0) { - DRM_ERROR("pin & fence failed\n"); - return ret; - } - - dev_priv->display.update_primary_plane(crtc, fb, x, y); - - if (intel_crtc->active) - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); - - crtc->primary->fb = fb; - crtc->x = x; - crtc->y = y; - - if (old_fb) { - if (intel_crtc->active && old_fb != fb) - intel_wait_for_vblank(dev, intel_crtc->pipe); - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(old_obj); - mutex_unlock(&dev->struct_mutex); - } - - mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); - mutex_unlock(&dev->struct_mutex); - - return 0; -} - static void intel_fdi_normal_train(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -5312,8 +5247,6 @@ static void intel_crtc_disable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_connector *connector; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *old_obj = intel_fb_obj(crtc->primary->fb); - enum pipe pipe = to_intel_crtc(crtc)->pipe; /* crtc should still be enabled when we disable it. */ WARN_ON(!crtc->enabled); @@ -5321,14 +5254,7 @@ static void intel_crtc_disable(struct drm_crtc *crtc) dev_priv->display.crtc_disable(crtc); dev_priv->display.off(crtc); - if (crtc->primary->fb) { - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(old_obj); - i915_gem_track_fb(old_obj, NULL, - INTEL_FRONTBUFFER_PRIMARY(pipe)); - mutex_unlock(&dev->struct_mutex); - crtc->primary->fb = NULL; - } + crtc->primary->funcs->disable_plane(crtc->primary); /* Update computed state. */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -9691,6 +9617,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *old_fb = crtc->primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_plane *primary = crtc->primary; + struct intel_plane *intel_plane = to_intel_plane(primary); enum pipe pipe = intel_crtc->pipe; struct intel_unpin_work *work; struct intel_engine_cs *ring; @@ -9849,8 +9777,15 @@ free_work: if (ret == -EIO) { out_hang: - intel_crtc_wait_for_pending_flips(crtc); - ret = intel_pipe_set_base(crtc, crtc->x, crtc->y, fb); + ret = primary->funcs->update_plane(primary, crtc, fb, + intel_plane->crtc_x, + intel_plane->crtc_y, + intel_plane->crtc_h, + intel_plane->crtc_w, + intel_plane->src_x, + intel_plane->src_y, + intel_plane->src_h, + intel_plane->src_w); if (ret == 0 && event) { spin_lock_irq(&dev->event_lock); drm_send_vblank_event(dev, pipe, event); @@ -11079,26 +11014,15 @@ static int __intel_set_mode(struct drm_crtc *crtc, * on the DPLL. */ for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { - struct drm_framebuffer *old_fb = crtc->primary->fb; - struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb); - struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct drm_plane *primary = intel_crtc->base.primary; + int vdisplay, hdisplay; - mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL); - if (ret != 0) { - DRM_ERROR("pin & fence failed\n"); - mutex_unlock(&dev->struct_mutex); - goto done; - } - if (old_fb) - intel_unpin_fb_obj(old_obj); - i915_gem_track_fb(old_obj, obj, - INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe)); - mutex_unlock(&dev->struct_mutex); - - crtc->primary->fb = fb; - crtc->x = x; - crtc->y = y; + drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); + ret = primary->funcs->update_plane(primary, &intel_crtc->base, + fb, 0, 0, + hdisplay, vdisplay, + x << 16, y << 16, + hdisplay << 16, vdisplay << 16); } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ @@ -11564,11 +11488,14 @@ static int intel_crtc_set_config(struct drm_mode_set *set) disable_pipes); } else if (config->fb_changed) { struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); - - intel_crtc_wait_for_pending_flips(set->crtc); - - ret = intel_pipe_set_base(set->crtc, - set->x, set->y, set->fb); + struct drm_plane *primary = set->crtc->primary; + int vdisplay, hdisplay; + + drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay); + ret = primary->funcs->update_plane(primary, set->crtc, set->fb, + 0, 0, hdisplay, vdisplay, + set->x << 16, set->y << 16, + hdisplay << 16, vdisplay << 16); /* * We need to make sure the primary plane is re-enabled if it -- cgit v0.10.2 From f4a2cf295d07b1fba9fc3599c1579681132b658a Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 1 Dec 2014 15:40:12 -0800 Subject: drm/i915: Introduce intel_prepare_cursor_plane() (v2) Primary and sprite planes have already been refactored to include a 'prepare' step which handles all the commit-time operations that could fail (i.e., pinning buffers and such). Refactor the cursor commit in a similar manner. For simplicity and consistency with other plane types, we also switch to using intel_pin_and_fence_fb_obj() to perform our pinning for non-physical cursors. This will allow us to more easily migrate the code into the atomic 'begin' handler in a plane-agnostic manner in a future patchset. v2: - Update GEM fb tracking for physical cursors too. (Ander) - Use intel_unpin_fb_obj() rather than i915_gem_object_unpin_from_display_plane() and do so while holding struct_mutex. (Ander) - Update plane->fb in commit_cursor_plane. This isn't really necessary since the DRM core does this for us in __setplane_internal(), but doing it in our driver once we know we're going to succeed helps avoid confusion. (Ander) Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 76896e8..78c0e1c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12014,20 +12014,55 @@ intel_check_cursor_plane(struct drm_plane *plane, } static int +intel_prepare_cursor_plane(struct drm_plane *plane, + struct intel_plane_state *state) +{ + struct drm_device *dev = plane->dev; + struct drm_framebuffer *fb = state->fb; + struct intel_crtc *intel_crtc = to_intel_crtc(state->crtc); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); + enum pipe pipe = intel_crtc->pipe; + int ret = 0; + + if (old_obj != obj) { + /* we only need to pin inside GTT if cursor is non-phy */ + mutex_lock(&dev->struct_mutex); + if (!INTEL_INFO(dev)->cursor_needs_physical) { + if (obj) + ret = intel_pin_and_fence_fb_obj(plane, fb, NULL); + } else { + int align = IS_I830(dev) ? 16 * 1024 : 256; + if (obj) + ret = i915_gem_object_attach_phys(obj, align); + if (ret) + DRM_DEBUG_KMS("failed to attach phys object\n"); + } + + if (ret == 0) + i915_gem_track_fb(intel_crtc->cursor_bo, obj, + INTEL_FRONTBUFFER_CURSOR(pipe)); + + mutex_unlock(&dev->struct_mutex); + } + + return ret; +} + +static void intel_commit_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_crtc *crtc = state->crtc; struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_i915_gem_object *obj = intel_fb_obj(state->fb); enum pipe pipe = intel_crtc->pipe; unsigned old_width; uint32_t addr; - int ret; + plane->fb = state->fb; crtc->cursor_x = state->orig_dst.x1; crtc->cursor_y = state->orig_dst.y1; @@ -12044,75 +12079,21 @@ intel_commit_cursor_plane(struct drm_plane *plane, if (intel_crtc->cursor_bo == obj) goto update; - /* if we want to turn off the cursor ignore width and height */ - if (!obj) { - DRM_DEBUG_KMS("cursor off\n"); + if (!obj) addr = 0; - mutex_lock(&dev->struct_mutex); - goto finish; - } - - /* we only need to pin inside GTT if cursor is non-phy */ - mutex_lock(&dev->struct_mutex); - if (!INTEL_INFO(dev)->cursor_needs_physical) { - unsigned alignment; - - /* - * Global gtt pte registers are special registers which actually - * forward writes to a chunk of system memory. Which means that - * there is no risk that the register values disappear as soon - * as we call intel_runtime_pm_put(), so it is correct to wrap - * only the pin/unpin/fence and not more. - */ - intel_runtime_pm_get(dev_priv); - - /* Note that the w/a also requires 2 PTE of padding following - * the bo. We currently fill all unused PTE with the shadow - * page and so we should always have valid PTE following the - * cursor preventing the VT-d warning. - */ - alignment = 0; - if (need_vtd_wa(dev)) - alignment = 64*1024; - - ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL); - if (ret) { - DRM_DEBUG_KMS("failed to move cursor bo into the GTT\n"); - intel_runtime_pm_put(dev_priv); - goto fail_locked; - } - - ret = i915_gem_object_put_fence(obj); - if (ret) { - DRM_DEBUG_KMS("failed to release fence for cursor"); - intel_runtime_pm_put(dev_priv); - goto fail_unpin; - } - + else if (!INTEL_INFO(dev)->cursor_needs_physical) addr = i915_gem_obj_ggtt_offset(obj); - - intel_runtime_pm_put(dev_priv); - - } else { - int align = IS_I830(dev) ? 16 * 1024 : 256; - ret = i915_gem_object_attach_phys(obj, align); - if (ret) { - DRM_DEBUG_KMS("failed to attach phys object\n"); - goto fail_locked; - } + else addr = obj->phys_handle->busaddr; - } -finish: if (intel_crtc->cursor_bo) { - if (!INTEL_INFO(dev)->cursor_needs_physical) - i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo); + if (!INTEL_INFO(dev)->cursor_needs_physical) { + mutex_lock(&dev->struct_mutex); + intel_unpin_fb_obj(intel_crtc->cursor_bo); + mutex_unlock(&dev->struct_mutex); + } } - i915_gem_track_fb(intel_crtc->cursor_bo, obj, - INTEL_FRONTBUFFER_CURSOR(pipe)); - mutex_unlock(&dev->struct_mutex); - intel_crtc->cursor_addr = addr; intel_crtc->cursor_bo = obj; update: @@ -12128,13 +12109,6 @@ update: intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe)); } - - return 0; -fail_unpin: - i915_gem_object_unpin_from_display_plane(obj); -fail_locked: - mutex_unlock(&dev->struct_mutex); - return ret; } static int @@ -12175,7 +12149,13 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, if (ret) return ret; - return intel_commit_cursor_plane(plane, &state); + ret = intel_prepare_cursor_plane(plane, &state); + if (ret) + return ret; + + intel_commit_cursor_plane(plane, &state); + + return 0; } static const struct drm_plane_funcs intel_cursor_plane_funcs = { -- cgit v0.10.2 From 2b875c22fa77dfc895d3cf8287a553813d3e64c8 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 1 Dec 2014 15:40:13 -0800 Subject: drm/i915: Make intel_plane_state subclass drm_plane_state Reviewed-by: Bob Paauwe Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 78c0e1c..de6768f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11693,8 +11693,8 @@ static int intel_check_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) { - struct drm_crtc *crtc = state->crtc; - struct drm_framebuffer *fb = state->fb; + struct drm_crtc *crtc = state->base.crtc; + struct drm_framebuffer *fb = state->base.fb; struct drm_rect *dest = &state->dst; struct drm_rect *src = &state->src; const struct drm_rect *clip = &state->clip; @@ -11710,8 +11710,8 @@ static int intel_prepare_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) { - struct drm_crtc *crtc = state->crtc; - struct drm_framebuffer *fb = state->fb; + struct drm_crtc *crtc = state->base.crtc; + struct drm_framebuffer *fb = state->base.fb; struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; @@ -11746,9 +11746,9 @@ static void intel_commit_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) { - struct drm_crtc *crtc = state->crtc; - struct drm_framebuffer *fb = state->fb; - struct drm_device *dev = crtc->dev; + struct drm_crtc *crtc = state->base.crtc; + struct drm_framebuffer *fb = state->base.fb; + struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; @@ -11847,8 +11847,8 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; - state.crtc = crtc; - state.fb = fb; + state.base.crtc = crtc; + state.base.fb = fb; /* sample coordinates in 16.16 fixed point */ state.src.x1 = src_x; @@ -11961,9 +11961,9 @@ static int intel_check_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) { - struct drm_crtc *crtc = state->crtc; + struct drm_crtc *crtc = state->base.crtc; struct drm_device *dev = crtc->dev; - struct drm_framebuffer *fb = state->fb; + struct drm_framebuffer *fb = state->base.fb; struct drm_rect *dest = &state->dst; struct drm_rect *src = &state->src; const struct drm_rect *clip = &state->clip; @@ -12018,8 +12018,8 @@ intel_prepare_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_device *dev = plane->dev; - struct drm_framebuffer *fb = state->fb; - struct intel_crtc *intel_crtc = to_intel_crtc(state->crtc); + struct drm_framebuffer *fb = state->base.fb; + struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); enum pipe pipe = intel_crtc->pipe; @@ -12053,16 +12053,16 @@ static void intel_commit_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) { - struct drm_crtc *crtc = state->crtc; + struct drm_crtc *crtc = state->base.crtc; struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); - struct drm_i915_gem_object *obj = intel_fb_obj(state->fb); + struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb); enum pipe pipe = intel_crtc->pipe; unsigned old_width; uint32_t addr; - plane->fb = state->fb; + plane->fb = state->base.fb; crtc->cursor_x = state->orig_dst.x1; crtc->cursor_y = state->orig_dst.y1; @@ -12122,8 +12122,8 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct intel_plane_state state; int ret; - state.crtc = crtc; - state.fb = fb; + state.base.crtc = crtc; + state.base.fb = fb; /* sample coordinates in 16.16 fixed point */ state.src.x1 = src_x; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index abb2cf4..b4d181f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -244,8 +244,7 @@ typedef struct dpll { } intel_clock_t; struct intel_plane_state { - struct drm_crtc *crtc; - struct drm_framebuffer *fb; + struct drm_plane_state base; struct drm_rect src; struct drm_rect dst; struct drm_rect clip; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 7d9c340..fc96d13 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1096,9 +1096,9 @@ static int intel_check_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) { - struct intel_crtc *intel_crtc = to_intel_crtc(state->crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); struct intel_plane *intel_plane = to_intel_plane(plane); - struct drm_framebuffer *fb = state->fb; + struct drm_framebuffer *fb = state->base.fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); int crtc_x, crtc_y; unsigned int crtc_w, crtc_h; @@ -1262,11 +1262,11 @@ intel_prepare_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_device *dev = plane->dev; - struct drm_crtc *crtc = state->crtc; + struct drm_crtc *crtc = state->base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); enum pipe pipe = intel_crtc->pipe; - struct drm_framebuffer *fb = state->fb; + struct drm_framebuffer *fb = state->base.fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *old_obj = intel_plane->obj; int ret; @@ -1297,11 +1297,11 @@ intel_commit_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_device *dev = plane->dev; - struct drm_crtc *crtc = state->crtc; + struct drm_crtc *crtc = state->base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); enum pipe pipe = intel_crtc->pipe; - struct drm_framebuffer *fb = state->fb; + struct drm_framebuffer *fb = state->base.fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *old_obj = intel_plane->obj; int crtc_x, crtc_y; @@ -1391,8 +1391,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; - state.crtc = crtc; - state.fb = fb; + state.base.crtc = crtc; + state.base.fb = fb; /* sample coordinates in 16.16 fixed point */ state.src.x1 = src_x; -- cgit v0.10.2 From 6beb8c23ebcc3d3287d8a247d11b73d7d0eaa475 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 1 Dec 2014 15:40:14 -0800 Subject: drm/i915: Consolidate plane 'prepare' functions (v2) The 'prepare' step for all types of planes are pretty similar; consolidate the three 'prepare' functions into a single function. This paves the way for future integration with the atomic plane handlers. Note that we pull the 'wait for pending flips' functionality out of the primary plane's prepare step and place it directly in the 'setplane' code. When we move to the atomic plane handlers, this code will be in the 'atomic begin' step. v2: Update GEM fb tracking for physical cursors also (Ander) Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index de6768f..262e890 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11689,6 +11689,65 @@ intel_primary_plane_disable(struct drm_plane *plane) return 0; } +/** + * intel_prepare_plane_fb - Prepare fb for usage on plane + * @plane: drm plane to prepare for + * @fb: framebuffer to prepare for presentation + * + * Prepares a framebuffer for usage on a display plane. Generally this + * involves pinning the underlying object and updating the frontbuffer tracking + * bits. Some older platforms need special physical address handling for + * cursor planes. + * + * Returns 0 on success, negative error code on failure. + */ +int +intel_prepare_plane_fb(struct drm_plane *plane, + struct drm_framebuffer *fb) +{ + struct drm_device *dev = plane->dev; + struct intel_plane *intel_plane = to_intel_plane(plane); + enum pipe pipe = intel_plane->pipe; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); + unsigned frontbuffer_bits = 0; + int ret = 0; + + if (WARN_ON(fb == plane->fb || !obj)) + return 0; + + switch (plane->type) { + case DRM_PLANE_TYPE_PRIMARY: + frontbuffer_bits = INTEL_FRONTBUFFER_PRIMARY(pipe); + break; + case DRM_PLANE_TYPE_CURSOR: + frontbuffer_bits = INTEL_FRONTBUFFER_CURSOR(pipe); + break; + case DRM_PLANE_TYPE_OVERLAY: + frontbuffer_bits = INTEL_FRONTBUFFER_SPRITE(pipe); + break; + } + + mutex_lock(&dev->struct_mutex); + + if (plane->type == DRM_PLANE_TYPE_CURSOR && + INTEL_INFO(dev)->cursor_needs_physical) { + int align = IS_I830(dev) ? 16 * 1024 : 256; + ret = i915_gem_object_attach_phys(obj, align); + if (ret) + DRM_DEBUG_KMS("failed to attach phys object\n"); + } else { + ret = intel_pin_and_fence_fb_obj(plane, fb, NULL); + } + + if (ret == 0) + i915_gem_track_fb(old_obj, obj, frontbuffer_bits); + + mutex_unlock(&dev->struct_mutex); + + return ret; +} + static int intel_check_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) @@ -11706,42 +11765,6 @@ intel_check_primary_plane(struct drm_plane *plane, false, true, &state->visible); } -static int -intel_prepare_primary_plane(struct drm_plane *plane, - struct intel_plane_state *state) -{ - struct drm_crtc *crtc = state->base.crtc; - struct drm_framebuffer *fb = state->base.fb; - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); - int ret; - - intel_crtc_wait_for_pending_flips(crtc); - - if (intel_crtc_has_pending_flip(crtc)) { - DRM_ERROR("pipe is still busy with an old pageflip\n"); - return -EBUSY; - } - - if (old_obj != obj) { - mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(plane, fb, NULL); - if (ret == 0) - i915_gem_track_fb(old_obj, obj, - INTEL_FRONTBUFFER_PRIMARY(pipe)); - mutex_unlock(&dev->struct_mutex); - if (ret != 0) { - DRM_DEBUG_KMS("pin & fence failed\n"); - return ret; - } - } - - return 0; -} - static void intel_commit_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) @@ -11843,6 +11866,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_framebuffer *old_fb = plane->fb; struct intel_plane_state state; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; @@ -11874,9 +11898,18 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, if (ret) return ret; - ret = intel_prepare_primary_plane(plane, &state); - if (ret) - return ret; + intel_crtc_wait_for_pending_flips(crtc); + + if (intel_crtc_has_pending_flip(crtc)) { + DRM_ERROR("pipe is still busy with an old pageflip\n"); + return -EBUSY; + } + + if (fb != old_fb && fb) { + ret = intel_prepare_plane_fb(plane, fb); + if (ret) + return ret; + } intel_commit_primary_plane(plane, &state); @@ -12013,42 +12046,6 @@ intel_check_cursor_plane(struct drm_plane *plane, return ret; } -static int -intel_prepare_cursor_plane(struct drm_plane *plane, - struct intel_plane_state *state) -{ - struct drm_device *dev = plane->dev; - struct drm_framebuffer *fb = state->base.fb; - struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); - enum pipe pipe = intel_crtc->pipe; - int ret = 0; - - if (old_obj != obj) { - /* we only need to pin inside GTT if cursor is non-phy */ - mutex_lock(&dev->struct_mutex); - if (!INTEL_INFO(dev)->cursor_needs_physical) { - if (obj) - ret = intel_pin_and_fence_fb_obj(plane, fb, NULL); - } else { - int align = IS_I830(dev) ? 16 * 1024 : 256; - if (obj) - ret = i915_gem_object_attach_phys(obj, align); - if (ret) - DRM_DEBUG_KMS("failed to attach phys object\n"); - } - - if (ret == 0) - i915_gem_track_fb(intel_crtc->cursor_bo, obj, - INTEL_FRONTBUFFER_CURSOR(pipe)); - - mutex_unlock(&dev->struct_mutex); - } - - return ret; -} - static void intel_commit_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) @@ -12058,6 +12055,7 @@ intel_commit_cursor_plane(struct drm_plane *plane, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb); + struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); enum pipe pipe = intel_crtc->pipe; unsigned old_width; uint32_t addr; @@ -12079,6 +12077,17 @@ intel_commit_cursor_plane(struct drm_plane *plane, if (intel_crtc->cursor_bo == obj) goto update; + /* + * 'prepare' is only called when fb != NULL; we still need to update + * frontbuffer tracking for the 'disable' case here. + */ + if (!obj) { + mutex_lock(&dev->struct_mutex); + i915_gem_track_fb(old_obj, NULL, + INTEL_FRONTBUFFER_CURSOR(pipe)); + mutex_unlock(&dev->struct_mutex); + } + if (!obj) addr = 0; else if (!INTEL_INFO(dev)->cursor_needs_physical) @@ -12118,6 +12127,7 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_framebuffer *old_fb = plane->fb; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane_state state; int ret; @@ -12149,9 +12159,11 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, if (ret) return ret; - ret = intel_prepare_cursor_plane(plane, &state); - if (ret) - return ret; + if (fb != old_fb && fb) { + ret = intel_prepare_plane_fb(plane, fb); + if (ret) + return ret; + } intel_commit_cursor_plane(plane, &state); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b4d181f..a36f696 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -922,6 +922,8 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane); void intel_finish_page_flip(struct drm_device *dev, int pipe); void intel_finish_page_flip_plane(struct drm_device *dev, int plane); void intel_check_page_flip(struct drm_device *dev, int pipe); +int intel_prepare_plane_fb(struct drm_plane *plane, + struct drm_framebuffer *fb); /* shared dpll functions */ struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index fc96d13..5d8c2e0 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1257,41 +1257,6 @@ intel_check_sprite_plane(struct drm_plane *plane, return 0; } -static int -intel_prepare_sprite_plane(struct drm_plane *plane, - struct intel_plane_state *state) -{ - struct drm_device *dev = plane->dev; - struct drm_crtc *crtc = state->base.crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_plane *intel_plane = to_intel_plane(plane); - enum pipe pipe = intel_crtc->pipe; - struct drm_framebuffer *fb = state->base.fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct drm_i915_gem_object *old_obj = intel_plane->obj; - int ret; - - if (old_obj != obj) { - mutex_lock(&dev->struct_mutex); - - /* Note that this will apply the VT-d workaround for scanouts, - * which is more restrictive than required for sprites. (The - * primary plane requires 256KiB alignment with 64 PTE padding, - * the sprite planes only require 128KiB alignment and 32 PTE - * padding. - */ - ret = intel_pin_and_fence_fb_obj(plane, fb, NULL); - if (ret == 0) - i915_gem_track_fb(old_obj, obj, - INTEL_FRONTBUFFER_SPRITE(pipe)); - mutex_unlock(&dev->struct_mutex); - if (ret) - return ret; - } - - return 0; -} - static void intel_commit_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) @@ -1387,6 +1352,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_framebuffer *old_fb = plane->fb; struct intel_plane_state state; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; @@ -1417,9 +1383,11 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (ret) return ret; - ret = intel_prepare_sprite_plane(plane, &state); - if (ret) - return ret; + if (fb != old_fb && fb) { + ret = intel_prepare_plane_fb(plane, fb); + if (ret) + return ret; + } intel_commit_sprite_plane(plane, &state); return 0; -- cgit v0.10.2 From 38f3ce3af5742eb5a3e9b01997f5ab85109c5762 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Tue, 2 Dec 2014 07:45:25 -0800 Subject: drm/i915: Consolidate plane 'cleanup' operations (v3) All plane update functions need to unpin the old framebuffer when flipping to a new one. Pull this logic into a separate function to ease the integration with atomic plane helpers. v2: Don't wait for vblank if we don't have an old fb to cleanup (Ander) v3: Really don't wait for vblank if we don't have an old fb to cleanup. Previous version only handled this for primary planes; we need the same change on cursors/sprites too! (Ander) Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 262e890..0488700 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11748,6 +11748,31 @@ intel_prepare_plane_fb(struct drm_plane *plane, return ret; } +/** + * intel_cleanup_plane_fb - Cleans up an fb after plane use + * @plane: drm plane to clean up for + * @fb: old framebuffer that was on plane + * + * Cleans up a framebuffer that has just been removed from a plane. + */ +void +intel_cleanup_plane_fb(struct drm_plane *plane, + struct drm_framebuffer *fb) +{ + struct drm_device *dev = plane->dev; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + + if (WARN_ON(!obj)) + return; + + if (plane->type != DRM_PLANE_TYPE_CURSOR || + !INTEL_INFO(dev)->cursor_needs_physical) { + mutex_lock(&dev->struct_mutex); + intel_unpin_fb_obj(obj); + mutex_unlock(&dev->struct_mutex); + } +} + static int intel_check_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) @@ -11775,9 +11800,7 @@ intel_commit_primary_plane(struct drm_plane *plane, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; - struct drm_framebuffer *old_fb = plane->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_rect *src = &state->src; @@ -11848,15 +11871,6 @@ intel_commit_primary_plane(struct drm_plane *plane, intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); } - - if (old_fb && old_fb != fb) { - if (intel_crtc->active) - intel_wait_for_vblank(dev, intel_crtc->pipe); - - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(old_obj); - mutex_unlock(&dev->struct_mutex); - } } static int @@ -11866,6 +11880,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_device *dev = plane->dev; struct drm_framebuffer *old_fb = plane->fb; struct intel_plane_state state; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -11913,6 +11928,12 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, intel_commit_primary_plane(plane, &state); + if (fb != old_fb && old_fb) { + if (intel_crtc->active) + intel_wait_for_vblank(dev, intel_crtc->pipe); + intel_cleanup_plane_fb(plane, old_fb); + } + return 0; } @@ -12095,14 +12116,6 @@ intel_commit_cursor_plane(struct drm_plane *plane, else addr = obj->phys_handle->busaddr; - if (intel_crtc->cursor_bo) { - if (!INTEL_INFO(dev)->cursor_needs_physical) { - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(intel_crtc->cursor_bo); - mutex_unlock(&dev->struct_mutex); - } - } - intel_crtc->cursor_addr = addr; intel_crtc->cursor_bo = obj; update: @@ -12127,6 +12140,7 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_device *dev = plane->dev; struct drm_framebuffer *old_fb = plane->fb; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane_state state; @@ -12167,6 +12181,12 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, intel_commit_cursor_plane(plane, &state); + if (fb != old_fb && old_fb) { + if (intel_crtc->active) + intel_wait_for_vblank(dev, intel_crtc->pipe); + intel_cleanup_plane_fb(plane, old_fb); + } + return 0; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a36f696..38cb553 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -924,6 +924,8 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane); void intel_check_page_flip(struct drm_device *dev, int pipe); int intel_prepare_plane_fb(struct drm_plane *plane, struct drm_framebuffer *fb); +void intel_cleanup_plane_fb(struct drm_plane *plane, + struct drm_framebuffer *fb); /* shared dpll functions */ struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 5d8c2e0..031f95e 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1268,7 +1268,6 @@ intel_commit_sprite_plane(struct drm_plane *plane, enum pipe pipe = intel_crtc->pipe; struct drm_framebuffer *fb = state->base.fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct drm_i915_gem_object *old_obj = intel_plane->obj; int crtc_x, crtc_y; unsigned int crtc_w, crtc_h; uint32_t src_x, src_y, src_w, src_h; @@ -1326,23 +1325,6 @@ intel_commit_sprite_plane(struct drm_plane *plane, if (!primary_was_enabled && primary_enabled) intel_post_enable_primary(crtc); } - - /* Unpin old obj after new one is active to avoid ugliness */ - if (old_obj && old_obj != obj) { - - /* - * It's fairly common to simply update the position of - * an existing object. In that case, we don't need to - * wait for vblank to avoid ugliness, we only need to - * do the pin & ref bookkeeping. - */ - if (intel_crtc->active) - intel_wait_for_vblank(dev, intel_crtc->pipe); - - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(old_obj); - mutex_unlock(&dev->struct_mutex); - } } static int @@ -1352,6 +1334,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_device *dev = plane->dev; struct drm_framebuffer *old_fb = plane->fb; struct intel_plane_state state; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -1390,6 +1373,13 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } intel_commit_sprite_plane(plane, &state); + + if (fb != old_fb && old_fb) { + if (intel_crtc->active) + intel_wait_for_vblank(dev, intel_crtc->pipe); + intel_cleanup_plane_fb(plane, old_fb); + } + return 0; } -- cgit v0.10.2 From c59cb179aaf444931cf9c547a514e383da3d2526 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 1 Dec 2014 15:40:16 -0800 Subject: drm/i915: Consolidate top-level .update_plane() handlers Our .update_plane() handlers do the same check/prepare/commit/cleanup steps regardless of plane type. Consolidate them all into a single function that calls check/commit through a vtable. Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0488700..f6334e6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11782,12 +11782,23 @@ intel_check_primary_plane(struct drm_plane *plane, struct drm_rect *dest = &state->dst; struct drm_rect *src = &state->src; const struct drm_rect *clip = &state->clip; + int ret; + + ret = drm_plane_helper_check_update(plane, crtc, fb, + src, dest, clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true, &state->visible); + if (ret) + return ret; - return drm_plane_helper_check_update(plane, crtc, fb, - src, dest, clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - false, true, &state->visible); + intel_crtc_wait_for_pending_flips(crtc); + if (intel_crtc_has_pending_flip(crtc)) { + DRM_ERROR("pipe is still busy with an old pageflip\n"); + return -EBUSY; + } + + return 0; } static void @@ -11873,16 +11884,17 @@ intel_commit_primary_plane(struct drm_plane *plane, } } -static int -intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) +int +intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) { struct drm_device *dev = plane->dev; struct drm_framebuffer *old_fb = plane->fb; struct intel_plane_state state; + struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; @@ -11909,24 +11921,17 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, state.orig_src = state.src; state.orig_dst = state.dst; - ret = intel_check_primary_plane(plane, &state); + ret = intel_plane->check_plane(plane, &state); if (ret) return ret; - intel_crtc_wait_for_pending_flips(crtc); - - if (intel_crtc_has_pending_flip(crtc)) { - DRM_ERROR("pipe is still busy with an old pageflip\n"); - return -EBUSY; - } - if (fb != old_fb && fb) { ret = intel_prepare_plane_fb(plane, fb); if (ret) return ret; } - intel_commit_primary_plane(plane, &state); + intel_plane->commit_plane(plane, &state); if (fb != old_fb && old_fb) { if (intel_crtc->active) @@ -11934,6 +11939,8 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, intel_cleanup_plane_fb(plane, old_fb); } + plane->fb = fb; + return 0; } @@ -11946,7 +11953,7 @@ static void intel_plane_destroy(struct drm_plane *plane) } static const struct drm_plane_funcs intel_primary_plane_funcs = { - .update_plane = intel_primary_plane_setplane, + .update_plane = intel_update_plane, .disable_plane = intel_primary_plane_disable, .destroy = intel_plane_destroy, .set_property = intel_plane_set_property @@ -11968,6 +11975,8 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, primary->pipe = pipe; primary->plane = pipe; primary->rotation = BIT(DRM_ROTATE_0); + primary->check_plane = intel_check_primary_plane; + primary->commit_plane = intel_commit_primary_plane; if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4) primary->plane = !pipe; @@ -12133,65 +12142,8 @@ update: } } -static int -intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) -{ - struct drm_device *dev = plane->dev; - struct drm_framebuffer *old_fb = plane->fb; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_plane_state state; - int ret; - - state.base.crtc = crtc; - state.base.fb = fb; - - /* sample coordinates in 16.16 fixed point */ - state.src.x1 = src_x; - state.src.x2 = src_x + src_w; - state.src.y1 = src_y; - state.src.y2 = src_y + src_h; - - /* integer pixels */ - state.dst.x1 = crtc_x; - state.dst.x2 = crtc_x + crtc_w; - state.dst.y1 = crtc_y; - state.dst.y2 = crtc_y + crtc_h; - - state.clip.x1 = 0; - state.clip.y1 = 0; - state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0; - state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0; - - state.orig_src = state.src; - state.orig_dst = state.dst; - - ret = intel_check_cursor_plane(plane, &state); - if (ret) - return ret; - - if (fb != old_fb && fb) { - ret = intel_prepare_plane_fb(plane, fb); - if (ret) - return ret; - } - - intel_commit_cursor_plane(plane, &state); - - if (fb != old_fb && old_fb) { - if (intel_crtc->active) - intel_wait_for_vblank(dev, intel_crtc->pipe); - intel_cleanup_plane_fb(plane, old_fb); - } - - return 0; -} - static const struct drm_plane_funcs intel_cursor_plane_funcs = { - .update_plane = intel_cursor_plane_update, + .update_plane = intel_update_plane, .disable_plane = intel_cursor_plane_disable, .destroy = intel_plane_destroy, .set_property = intel_plane_set_property, @@ -12211,6 +12163,8 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, cursor->pipe = pipe; cursor->plane = pipe; cursor->rotation = BIT(DRM_ROTATE_0); + cursor->check_plane = intel_check_cursor_plane; + cursor->commit_plane = intel_commit_cursor_plane; drm_universal_plane_init(dev, &cursor->base, 0, &intel_cursor_plane_funcs, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 38cb553..f7b6619 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -508,6 +508,10 @@ struct intel_plane { uint32_t src_w, uint32_t src_h); void (*disable_plane)(struct drm_plane *plane, struct drm_crtc *crtc); + int (*check_plane)(struct drm_plane *plane, + struct intel_plane_state *state); + void (*commit_plane)(struct drm_plane *plane, + struct intel_plane_state *state); int (*update_colorkey)(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key); void (*get_colorkey)(struct drm_plane *plane, @@ -1011,6 +1015,11 @@ void intel_dp_hot_plug(struct intel_encoder *intel_encoder); void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv); uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes); void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes); +int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h); /* intel_dp_mst.c */ int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 031f95e..bfd5270 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1328,62 +1328,6 @@ intel_commit_sprite_plane(struct drm_plane *plane, } static int -intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) -{ - struct drm_device *dev = plane->dev; - struct drm_framebuffer *old_fb = plane->fb; - struct intel_plane_state state; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int ret; - - state.base.crtc = crtc; - state.base.fb = fb; - - /* sample coordinates in 16.16 fixed point */ - state.src.x1 = src_x; - state.src.x2 = src_x + src_w; - state.src.y1 = src_y; - state.src.y2 = src_y + src_h; - - /* integer pixels */ - state.dst.x1 = crtc_x; - state.dst.x2 = crtc_x + crtc_w; - state.dst.y1 = crtc_y; - state.dst.y2 = crtc_y + crtc_h; - - state.clip.x1 = 0; - state.clip.y1 = 0; - state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0; - state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0; - state.orig_src = state.src; - state.orig_dst = state.dst; - - ret = intel_check_sprite_plane(plane, &state); - if (ret) - return ret; - - if (fb != old_fb && fb) { - ret = intel_prepare_plane_fb(plane, fb); - if (ret) - return ret; - } - - intel_commit_sprite_plane(plane, &state); - - if (fb != old_fb && old_fb) { - if (intel_crtc->active) - intel_wait_for_vblank(dev, intel_crtc->pipe); - intel_cleanup_plane_fb(plane, old_fb); - } - - return 0; -} - -static int intel_disable_plane(struct drm_plane *plane) { struct drm_device *dev = plane->dev; @@ -1678,6 +1622,8 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) intel_plane->pipe = pipe; intel_plane->plane = plane; intel_plane->rotation = BIT(DRM_ROTATE_0); + intel_plane->check_plane = intel_check_sprite_plane; + intel_plane->commit_plane = intel_commit_sprite_plane; possible_crtcs = (1 << pipe); ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, &intel_plane_funcs, -- cgit v0.10.2 From e614c3c946ae5b50a679d65d2c981615d8ceccab Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 1 Dec 2014 15:40:17 -0800 Subject: drm/i915: Ensure state->crtc is non-NULL for plane updates When disabling a plane, it is legal to pass crtc = NULL. Since planes on Intel hardware are tied to a fixed CRTC, go ahead and set state->crtc to the appropriate crtc in cases where it is passed to us as NULL. In a future patch, we will start using the update handler for plane disables, so this will help ensure we always have a non-NULL crtc pointer to work with. Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f6334e6..4f24cce 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11898,7 +11898,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; - state.base.crtc = crtc; + state.base.crtc = crtc ? crtc : plane->crtc; state.base.fb = fb; /* sample coordinates in 16.16 fixed point */ -- cgit v0.10.2 From cf4c7c12258ed9367f4fc45238f5f50d2db892c1 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 4 Dec 2014 10:27:42 -0800 Subject: drm/i915: Make all plane disables use 'update_plane' (v5) If we extend the commit_plane handlers for each plane type to be able to handle fb=0, then we can easily implement plane disable via the update_plane handler. The cursor plane already works this way, and this is the direction we need to go to integrate with the atomic plane handler. We can now kill off the type-specific disable functions, as well as the redundant intel_plane_disable() (not to be confused with intel_disable_plane()). Note that prepare_plane_fb() only gets called as part of update_plane when fb!=NULL (by design, to match the semantics of the atomic plane helpers); this means that our commit_plane handlers need to handle the frontbuffer tracking for the disable case, even though they don't handle it for normal updates. v2: - Change BUG_ON to WARN_ON (Ander/Daniel) v3: - Drop unnecessary plane->crtc check since a previous patch to plane update ensures that plane->crtc will always be non-NULL, even for disable calls that might pass NULL from userspace. (Ander) - Drop a s/crtc/plane->crtc/ hunk that was unnecessary. (Ander) v4: - Fix missing whitespace (Ander) v5: - Use state's crtc rather than plane's crtc in intel_check_primary_plane(). plane->crtc could be NULL, but we've already fixed up state->crtc to ensure it's non-NULL (even if userspace passed it as NULL during a disable call). (Ander) Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4f24cce..c17419b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4060,7 +4060,7 @@ static void intel_disable_planes(struct drm_crtc *crtc) drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { intel_plane = to_intel_plane(plane); if (intel_plane->pipe == pipe) - intel_plane_disable(&intel_plane->base); + plane->funcs->disable_plane(plane); } } @@ -11652,43 +11652,6 @@ static void intel_shared_dpll_init(struct drm_device *dev) BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); } -static int -intel_primary_plane_disable(struct drm_plane *plane) -{ - struct drm_device *dev = plane->dev; - struct intel_crtc *intel_crtc; - - if (!plane->fb) - return 0; - - BUG_ON(!plane->crtc); - - intel_crtc = to_intel_crtc(plane->crtc); - - /* - * Even though we checked plane->fb above, it's still possible that - * the primary plane has been implicitly disabled because the crtc - * coordinates given weren't visible, or because we detected - * that it was 100% covered by a sprite plane. Or, the CRTC may be - * off and we've set a fb, but haven't actually turned on the CRTC yet. - * In either case, we need to unpin the FB and let the fb pointer get - * updated, but otherwise we don't need to touch the hardware. - */ - if (intel_crtc->primary_enabled) { - intel_crtc_wait_for_pending_flips(plane->crtc); - intel_disable_primary_hw_plane(plane, plane->crtc); - } - - mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, - INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe)); - intel_unpin_fb_obj(intel_fb_obj(plane->fb)); - mutex_unlock(&dev->struct_mutex); - plane->fb = NULL; - - return 0; -} - /** * intel_prepare_plane_fb - Prepare fb for usage on plane * @plane: drm plane to prepare for @@ -11810,12 +11773,23 @@ intel_commit_primary_plane(struct drm_plane *plane, struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_rect *src = &state->src; + enum pipe pipe = intel_plane->pipe; - crtc->primary->fb = fb; + if (!fb) { + /* + * 'prepare' is never called when plane is being disabled, so + * we need to handle frontbuffer tracking here + */ + mutex_lock(&dev->struct_mutex); + i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, + INTEL_FRONTBUFFER_PRIMARY(pipe)); + mutex_unlock(&dev->struct_mutex); + } + + plane->fb = fb; crtc->x = src->x1 >> 16; crtc->y = src->y1 >> 16; @@ -11944,6 +11918,25 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, return 0; } +/** + * intel_disable_plane - disable a plane + * @plane: plane to disable + * + * General disable handler for all plane types. + */ +int +intel_disable_plane(struct drm_plane *plane) +{ + if (!plane->fb) + return 0; + + if (WARN_ON(!plane->crtc)) + return -EINVAL; + + return plane->funcs->update_plane(plane, plane->crtc, NULL, + 0, 0, 0, 0, 0, 0, 0, 0); +} + /* Common destruction function for both primary and cursor planes */ static void intel_plane_destroy(struct drm_plane *plane) { @@ -11954,7 +11947,7 @@ static void intel_plane_destroy(struct drm_plane *plane) static const struct drm_plane_funcs intel_primary_plane_funcs = { .update_plane = intel_update_plane, - .disable_plane = intel_primary_plane_disable, + .disable_plane = intel_disable_plane, .destroy = intel_plane_destroy, .set_property = intel_plane_set_property }; @@ -12009,18 +12002,6 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, } static int -intel_cursor_plane_disable(struct drm_plane *plane) -{ - if (!plane->fb) - return 0; - - BUG_ON(!plane->crtc); - - return plane->funcs->update_plane(plane, plane->crtc, NULL, - 0, 0, 0, 0, 0, 0, 0, 0); -} - -static int intel_check_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) { @@ -12144,7 +12125,7 @@ update: static const struct drm_plane_funcs intel_cursor_plane_funcs = { .update_plane = intel_update_plane, - .disable_plane = intel_cursor_plane_disable, + .disable_plane = intel_disable_plane, .destroy = intel_plane_destroy, .set_property = intel_plane_set_property, }; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f7b6619..53b696e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1020,6 +1020,7 @@ int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h); +int intel_disable_plane(struct drm_plane *plane); /* intel_dp_mst.c */ int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); @@ -1201,7 +1202,6 @@ int intel_plane_set_property(struct drm_plane *plane, struct drm_property *prop, uint64_t val); int intel_plane_restore(struct drm_plane *plane); -void intel_plane_disable(struct drm_plane *plane); int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); int intel_sprite_get_colorkey(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index bfd5270..bc5834b 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1109,7 +1109,12 @@ intel_check_sprite_plane(struct drm_plane *plane, const struct drm_rect *clip = &state->clip; int hscale, vscale; int max_scale, min_scale; - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + int pixel_size; + + if (!fb) { + state->visible = false; + return 0; + } /* Don't modify another pipe's plane */ if (intel_plane->pipe != intel_crtc->pipe) { @@ -1232,6 +1237,7 @@ intel_check_sprite_plane(struct drm_plane *plane, if (src_w < 3 || src_h < 3) state->visible = false; + pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); width_bytes = ((src_x * pixel_size) & 63) + src_w * pixel_size; @@ -1276,6 +1282,17 @@ intel_commit_sprite_plane(struct drm_plane *plane, bool primary_enabled; /* + * 'prepare' is never called when plane is being disabled, so we need + * to handle frontbuffer tracking here + */ + if (!fb) { + mutex_lock(&dev->struct_mutex); + i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, + INTEL_FRONTBUFFER_SPRITE(pipe)); + mutex_unlock(&dev->struct_mutex); + } + + /* * If the sprite is completely covering the primary plane, * we can disable the primary and save power. */ @@ -1327,50 +1344,6 @@ intel_commit_sprite_plane(struct drm_plane *plane, } } -static int -intel_disable_plane(struct drm_plane *plane) -{ - struct drm_device *dev = plane->dev; - struct intel_plane *intel_plane = to_intel_plane(plane); - struct intel_crtc *intel_crtc; - enum pipe pipe; - - if (!plane->fb) - return 0; - - if (WARN_ON(!plane->crtc)) - return -EINVAL; - - intel_crtc = to_intel_crtc(plane->crtc); - pipe = intel_crtc->pipe; - - if (intel_crtc->active) { - bool primary_was_enabled = intel_crtc->primary_enabled; - - intel_crtc->primary_enabled = true; - - intel_plane->disable_plane(plane, plane->crtc); - - if (!primary_was_enabled && intel_crtc->primary_enabled) - intel_post_enable_primary(plane->crtc); - } - - if (intel_plane->obj) { - if (intel_crtc->active) - intel_wait_for_vblank(dev, intel_plane->pipe); - - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(intel_plane->obj); - i915_gem_track_fb(intel_plane->obj, NULL, - INTEL_FRONTBUFFER_SPRITE(pipe)); - mutex_unlock(&dev->struct_mutex); - - intel_plane->obj = NULL; - } - - return 0; -} - static void intel_destroy_plane(struct drm_plane *plane) { struct intel_plane *intel_plane = to_intel_plane(plane); @@ -1478,14 +1451,6 @@ int intel_plane_restore(struct drm_plane *plane) intel_plane->src_w, intel_plane->src_h); } -void intel_plane_disable(struct drm_plane *plane) -{ - if (!plane->crtc || !plane->fb) - return; - - intel_disable_plane(plane); -} - static const struct drm_plane_funcs intel_plane_funcs = { .update_plane = intel_update_plane, .disable_plane = intel_disable_plane, -- cgit v0.10.2 From 146d84f0f2707bfe2c67114eeefac30da8584b3b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 5 Dec 2014 13:49:33 +0000 Subject: drm/i915: Fix up seqno -> request merge issues The display related patches earlier in this series were edited during merge to improve the request unreferencing. Specifically, the need for de-referencing at interrupt time was removed. However, the resulting code did a 'deref(req) ; req = NULL' sequence rather than using the 'req_assign(req, NULL)' wrapper. The two are functionally equivalent, but using the wrapper is more consistent with all the other places where requests are assigned. Note that the whole point of the wrapper is that using it everywhere that request pointers are assigned means that the reference counting is done automatically and can't be accidentally forgotten about. Plus it allows simpler future maintainance if the reference counting mechanisms ever need to change. For: VIZ-4377 Signed-off-by: John Harrison Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c17419b..42e661e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8953,8 +8953,7 @@ static void intel_unpin_work_fn(struct work_struct *__work) intel_update_fbc(dev); if (work->flip_queued_req) - i915_gem_request_unreference(work->flip_queued_req); - work->flip_queued_req = NULL; + i915_gem_request_assign(&work->flip_queued_req, NULL); mutex_unlock(&dev->struct_mutex); intel_frontbuffer_flip_complete(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); @@ -9452,10 +9451,9 @@ static void intel_mmio_flip_work_func(struct work_struct *work) intel_do_mmio_flip(crtc); if (mmio_flip->req) { mutex_lock(&crtc->base.dev->struct_mutex); - i915_gem_request_unreference(mmio_flip->req); + i915_gem_request_assign(&mmio_flip->req, NULL); mutex_unlock(&crtc->base.dev->struct_mutex); } - mmio_flip->req = NULL; } static int intel_queue_mmio_flip(struct drm_device *dev, -- cgit v0.10.2 From aaeb1ba041aedf2b58cd1303fd5fa9cf9173fa9b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 5 Dec 2014 13:49:34 +0000 Subject: drm/i915: Zero fill the request structure There is a general theory that kzmalloc is better/safer than kmalloc, especially for interesting data structures. This change updates the request structure allocation to be zero filled. This also fixes crashes in the reset code. Quoting Mika's patch: "Clean the request structure on alloc. Otherwise we might end up referencing uninitialized fields. This is apparent when we try to cleanup the preallocated request on ring reset, before any request has been submitted to the ring. The request->ctx is foobar and we end up freeing the foobarness." Note that this fixes a regression introduced in commit 9eba5d4a1d79d5094321469479b4dbe418f60110 Author: John Harrison Date: Mon Nov 24 18:49:23 2014 +0000 drm/i915: Ensure OLS & PLR are always in sync References: https://bugs.freedesktop.org/show_bug.cgi?id=86959 References: https://bugs.freedesktop.org/show_bug.cgi?id=86962 References: https://bugs.freedesktop.org/show_bug.cgi?id=86992 Change-Id: I68715ef758025fab8db763941ef63bf60d7031e2 For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Cc: Mika Kuoppala Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7986eb3..782e976 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -885,7 +885,7 @@ static int logical_ring_alloc_request(struct intel_engine_cs *ring, if (ring->outstanding_lazy_request) return 0; - request = kmalloc(sizeof(*request), GFP_KERNEL); + request = kzalloc(sizeof(*request), GFP_KERNEL); if (request == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f521015..8828219 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2032,7 +2032,7 @@ intel_ring_alloc_request(struct intel_engine_cs *ring) if (ring->outstanding_lazy_request) return 0; - request = kmalloc(sizeof(*request), GFP_KERNEL); + request = kzalloc(sizeof(*request), GFP_KERNEL); if (request == NULL) return -ENOMEM; -- cgit v0.10.2 From 67e2937bf470718b3a7812de80c8a3dc2c2136f9 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 5 Dec 2014 13:49:35 +0000 Subject: drm/i915: Add unique id to the request structure for debugging For debugging purposes, it is useful to be able to uniquely identify a given request structure as it works its way through the system. This becomes especially tricky once the seqno value is lazily allocated as then the request has nothing but its pointer to identify it for much of its life. Change-Id: Ie76b2268b940467f4cdf5a4ba6f5a54cbb96445d For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 502a01b..95dfa2d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1787,6 +1787,8 @@ struct drm_i915_private { void (*stop_ring)(struct intel_engine_cs *ring); } gt; + uint32_t request_uniq; + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. @@ -2019,6 +2021,8 @@ struct drm_i915_gem_request { struct drm_i915_file_private *file_priv; /** file_priv list entry for this request */ struct list_head client_list; + + uint32_t uniq; }; void i915_gem_request_free(struct kref *req_ref); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 782e976..a82020e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -880,6 +880,7 @@ static int logical_ring_alloc_request(struct intel_engine_cs *ring, struct intel_context *ctx) { struct drm_i915_gem_request *request; + struct drm_i915_private *dev_private = ring->dev->dev_private; int ret; if (ring->outstanding_lazy_request) @@ -899,6 +900,7 @@ static int logical_ring_alloc_request(struct intel_engine_cs *ring, kref_init(&request->ref); request->ring = ring; + request->uniq = dev_private->request_uniq++; ret = i915_gem_get_seqno(ring->dev, &request->seqno); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8828219..3887f1a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2028,6 +2028,7 @@ intel_ring_alloc_request(struct intel_engine_cs *ring) { int ret; struct drm_i915_gem_request *request; + struct drm_i915_private *dev_private = ring->dev->dev_private; if (ring->outstanding_lazy_request) return 0; @@ -2038,6 +2039,7 @@ intel_ring_alloc_request(struct intel_engine_cs *ring) kref_init(&request->ref); request->ring = ring; + request->uniq = dev_private->request_uniq++; ret = i915_gem_get_seqno(ring->dev, &request->seqno); if (ret) { -- cgit v0.10.2 From bcfcc8ba29c933ee98c7f498ee7ccfa17be400dd Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 5 Dec 2014 13:49:36 +0000 Subject: drm/i915: Additional request structure tracing Added the request structure's 'uniq' identifier to the trace information. Also renamed the '_complete' trace event to '_notify' as it actually happens in the IRQ 'notify_ring()' function. The intention is to add a new '_complete' trace event which occurs when a request structure is actually marked as complete. However, at the moment the completion status is re-tested every time the query is made so there isn't a completion event as such. v2: New patch added to series. v3: Rebased to remove completion caching as that is apparently contentious. Change-Id: Ic9bcde67d175c6c03b96217cdcb6e4cc4aa45d67 For: VIZ-4377 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7913a72..08a5a4b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1013,7 +1013,7 @@ static void notify_ring(struct drm_device *dev, if (!intel_ring_initialized(ring)) return; - trace_i915_gem_request_complete(ring); + trace_i915_gem_request_notify(ring); wake_up_all(&ring->irq_queue); } diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 2ade958..6058a01 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -406,6 +406,7 @@ DECLARE_EVENT_CLASS(i915_gem_request, TP_STRUCT__entry( __field(u32, dev) __field(u32, ring) + __field(u32, uniq) __field(u32, seqno) ), @@ -414,11 +415,13 @@ DECLARE_EVENT_CLASS(i915_gem_request, i915_gem_request_get_ring(req); __entry->dev = ring->dev->primary->index; __entry->ring = ring->id; + __entry->uniq = req ? req->uniq : 0; __entry->seqno = i915_gem_request_get_seqno(req); ), - TP_printk("dev=%u, ring=%u, seqno=%u", - __entry->dev, __entry->ring, __entry->seqno) + TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u", + __entry->dev, __entry->ring, __entry->uniq, + __entry->seqno) ); DEFINE_EVENT(i915_gem_request, i915_gem_request_add, @@ -426,7 +429,7 @@ DEFINE_EVENT(i915_gem_request, i915_gem_request_add, TP_ARGS(req) ); -TRACE_EVENT(i915_gem_request_complete, +TRACE_EVENT(i915_gem_request_notify, TP_PROTO(struct intel_engine_cs *ring), TP_ARGS(ring), @@ -451,6 +454,11 @@ DEFINE_EVENT(i915_gem_request, i915_gem_request_retire, TP_ARGS(req) ); +DEFINE_EVENT(i915_gem_request, i915_gem_request_complete, + TP_PROTO(struct drm_i915_gem_request *req), + TP_ARGS(req) +); + TRACE_EVENT(i915_gem_request_wait_begin, TP_PROTO(struct drm_i915_gem_request *req), TP_ARGS(req), @@ -458,6 +466,7 @@ TRACE_EVENT(i915_gem_request_wait_begin, TP_STRUCT__entry( __field(u32, dev) __field(u32, ring) + __field(u32, uniq) __field(u32, seqno) __field(bool, blocking) ), @@ -473,14 +482,15 @@ TRACE_EVENT(i915_gem_request_wait_begin, i915_gem_request_get_ring(req); __entry->dev = ring->dev->primary->index; __entry->ring = ring->id; + __entry->uniq = req ? req->uniq : 0; __entry->seqno = i915_gem_request_get_seqno(req); __entry->blocking = mutex_is_locked(&ring->dev->struct_mutex); ), - TP_printk("dev=%u, ring=%u, seqno=%u, blocking=%s", - __entry->dev, __entry->ring, __entry->seqno, - __entry->blocking ? "yes (NB)" : "no") + TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u, blocking=%s", + __entry->dev, __entry->ring, __entry->uniq, + __entry->seqno, __entry->blocking ? "yes (NB)" : "no") ); DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end, -- cgit v0.10.2 From b05ddd4dfb6303ee9dde359ec913aa7a918fd813 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 7 Dec 2014 19:29:17 +0100 Subject: gpu: drm: i915: intel_display.c: Remove unused function Remove the function intel_output_name() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 42e661e..d5153a4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12302,28 +12302,6 @@ static bool has_edp_a(struct drm_device *dev) return true; } -const char *intel_output_name(int output) -{ - static const char *names[] = { - [INTEL_OUTPUT_UNUSED] = "Unused", - [INTEL_OUTPUT_ANALOG] = "Analog", - [INTEL_OUTPUT_DVO] = "DVO", - [INTEL_OUTPUT_SDVO] = "SDVO", - [INTEL_OUTPUT_LVDS] = "LVDS", - [INTEL_OUTPUT_TVOUT] = "TV", - [INTEL_OUTPUT_HDMI] = "HDMI", - [INTEL_OUTPUT_DISPLAYPORT] = "DisplayPort", - [INTEL_OUTPUT_EDP] = "eDP", - [INTEL_OUTPUT_DSI] = "DSI", - [INTEL_OUTPUT_UNKNOWN] = "Unknown", - }; - - if (output < 0 || output >= ARRAY_SIZE(names) || !names[output]) - return "Invalid"; - - return names[output]; -} - static bool intel_crt_present(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 53b696e..61a88fa 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -875,7 +875,6 @@ void intel_audio_codec_enable(struct intel_encoder *encoder); void intel_audio_codec_disable(struct intel_encoder *encoder); /* intel_display.c */ -const char *intel_output_name(int output); bool intel_has_pending_fb_unpin(struct drm_device *dev); int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); -- cgit v0.10.2 From 8f0e2b9d95a88ca5d8349deef2375644faf184ae Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 2 Dec 2014 16:19:07 +0100 Subject: drm/i915: Move golden context init into ->init_context Similar to a patch from Thomas Daniel for lrc contexts. This keeps both sides somewhat in sync and should make Dave Gordon happy. Note that both the wa and the golden context init code suffer a bit from an inssuficient split into driver load and hw init code. Which means we have a bunch of tests all over the place to check whether the one-time initialization has been done already or not. All that one-tim code should be moved into the one-time ring setup code, but that's work for later. Cc: Dave Gordon Cc: Thomas Daniel Signed-off-by: Daniel Vetter Reviewed-by: Dave Gordon Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 5cd2b97..2acf580 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -651,10 +651,6 @@ done: if (ret) DRM_ERROR("ring init context: %d\n", ret); } - - ret = i915_gem_render_state_init(ring); - if (ret) - DRM_ERROR("init render state: %d\n", ret); } return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 3887f1a..a8dc158 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -710,6 +710,22 @@ static int intel_ring_workarounds_emit(struct intel_engine_cs *ring, return 0; } +static int intel_rcs_ctx_init(struct intel_engine_cs *ring, + struct intel_context *ctx) +{ + int ret; + + ret = intel_ring_workarounds_emit(ring, ctx); + if (ret != 0) + return ret; + + ret = i915_gem_render_state_init(ring); + if (ret) + DRM_ERROR("init render state: %d\n", ret); + + return ret; +} + static int wa_add(struct drm_i915_private *dev_priv, const u32 addr, const u32 val, const u32 mask) { @@ -2345,7 +2361,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) } } - ring->init_context = intel_ring_workarounds_emit; + ring->init_context = intel_rcs_ctx_init; ring->add_request = gen6_add_request; ring->flush = gen8_render_ring_flush; ring->irq_get = gen8_ring_get_irq; -- cgit v0.10.2 From 15a17aae5f803551981a7acc6a4058b247a7452c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 8 Dec 2014 16:30:00 +0100 Subject: drm/i915: Check mask/bit helper functions After a bit of irc discussion we've concluded that it would be prudent to check that callers use the mask/enable paramters correctly. So add a WARN_ON. Spurred by Damien's bugfix which added _MASKED_FIELD. v2: We use WARN_ON(1) a lot to catch default cases in switch blocks which should always be extended. So this doesn't work really. Dunno why gcc only started complaining when I've moved the WARN out of the static inline helper to address a feedback from Jani. Cc: Damien Lespiau Cc: Chris Wilson Cc: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 08a5a4b..e6a1db3 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -183,6 +183,8 @@ static void ilk_update_gt_irq(struct drm_i915_private *dev_priv, { assert_spin_locked(&dev_priv->irq_lock); + WARN_ON(enabled_irq_mask & ~interrupt_mask); + if (WARN_ON(!intel_irqs_enabled(dev_priv))) return; @@ -229,6 +231,8 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv, { uint32_t new_val; + WARN_ON(enabled_irq_mask & ~interrupt_mask); + assert_spin_locked(&dev_priv->irq_lock); new_val = dev_priv->pm_irq_mask; @@ -328,6 +332,8 @@ void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, sdeimr &= ~interrupt_mask; sdeimr |= (~enabled_irq_mask & interrupt_mask); + WARN_ON(enabled_irq_mask & ~interrupt_mask); + assert_spin_locked(&dev_priv->irq_lock); if (WARN_ON(!intel_irqs_enabled(dev_priv))) -- cgit v0.10.2 From e1f69e615f18b2cd31b04a4773a5438f6c4a797b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 12:29:58 +0100 Subject: drm/armada: Remove dummy ->load_lut() implementation The ->load_lut() callback is optional, therefore a dummy implementation is not needed. Cc: Russell King Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index e3a7a50..42d2ffa 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -653,10 +653,6 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -static void armada_drm_crtc_load_lut(struct drm_crtc *crtc) -{ -} - /* The mode_config.mutex will be held for this call */ static void armada_drm_crtc_disable(struct drm_crtc *crtc) { @@ -678,7 +674,6 @@ static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { .mode_fixup = armada_drm_crtc_mode_fixup, .mode_set = armada_drm_crtc_mode_set, .mode_set_base = armada_drm_crtc_mode_set_base, - .load_lut = armada_drm_crtc_load_lut, .disable = armada_drm_crtc_disable, }; -- cgit v0.10.2 From d2e2b26bb5606763593b341476a9f5baf95ccad6 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 12:29:59 +0100 Subject: drm/bochs: Remove dummy ->load_lut() implementation The ->load_lut() callback is optional, therefore a dummy implementation is not needed. Cc: Gerd Hoffmann Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index 85f0f8cf..26bcd03 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -18,10 +18,6 @@ MODULE_PARM_DESC(defy, "default y resolution"); /* ---------------------------------------------------------------------- */ -static void bochs_crtc_load_lut(struct drm_crtc *crtc) -{ -} - static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode) { switch (mode) { @@ -144,7 +140,6 @@ static const struct drm_crtc_helper_funcs bochs_helper_funcs = { .mode_set_base = bochs_crtc_mode_set_base, .prepare = bochs_crtc_prepare, .commit = bochs_crtc_commit, - .load_lut = bochs_crtc_load_lut, }; static void bochs_crtc_init(struct drm_device *dev) -- cgit v0.10.2 From 6f6f0929e2d86779c6fe796495d4f73b026128f8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 12:30:00 +0100 Subject: drm/msm: Remove dummy ->load_lut() implementation The ->load_lut() callback is optional, therefore a dummy implementation is not needed. Cc: Rob Clark Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index a7672e1..ac2a6eb 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -323,10 +323,6 @@ static void mdp4_crtc_commit(struct drm_crtc *crtc) drm_crtc_vblank_put(crtc); } -static void mdp4_crtc_load_lut(struct drm_crtc *crtc) -{ -} - static int mdp4_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -524,7 +520,6 @@ static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = { .mode_set_base = drm_helper_crtc_mode_set_base, .prepare = mdp4_crtc_prepare, .commit = mdp4_crtc_commit, - .load_lut = mdp4_crtc_load_lut, .atomic_check = mdp4_crtc_atomic_check, .atomic_begin = mdp4_crtc_atomic_begin, .atomic_flush = mdp4_crtc_atomic_flush, diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 0e9a2e3..92d52a5 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -275,10 +275,6 @@ static void mdp5_crtc_commit(struct drm_crtc *crtc) mdp5_disable(get_kms(crtc)); } -static void mdp5_crtc_load_lut(struct drm_crtc *crtc) -{ -} - struct plane_state { struct drm_plane *plane; struct mdp5_plane_state *state; @@ -407,7 +403,6 @@ static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = { .mode_set_base = drm_helper_crtc_mode_set_base, .prepare = mdp5_crtc_prepare, .commit = mdp5_crtc_commit, - .load_lut = mdp5_crtc_load_lut, .atomic_check = mdp5_crtc_atomic_check, .atomic_begin = mdp5_crtc_atomic_begin, .atomic_flush = mdp5_crtc_atomic_flush, -- cgit v0.10.2 From e6966da2ac1d4b7e52772378f0292255ea92617c Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 12:30:01 +0100 Subject: drm/sti: Remove dummy ->load_lut() implementation The ->load_lut() callback is optional, therefore a dummy implementation is not needed. Cc: Benjamin Gaignard Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c index 36a1ad3..70e6e97 100644 --- a/drivers/gpu/drm/sti/sti_drm_crtc.c +++ b/drivers/gpu/drm/sti/sti_drm_crtc.c @@ -184,11 +184,6 @@ out: return ret; } -static void sti_drm_crtc_load_lut(struct drm_crtc *crtc) -{ - /* do nothing */ -} - static void sti_drm_crtc_disable(struct drm_crtc *crtc) { struct sti_mixer *mixer = to_sti_mixer(crtc); @@ -243,7 +238,6 @@ static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { .mode_fixup = sti_drm_crtc_mode_fixup, .mode_set = sti_drm_crtc_mode_set, .mode_set_base = sti_drm_crtc_mode_set_base, - .load_lut = sti_drm_crtc_load_lut, .disable = sti_drm_crtc_disable, }; -- cgit v0.10.2 From c422f31d5654a4787a226bb684bd601d4db9558d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 12:30:02 +0100 Subject: drm/tegra: Remove dummy ->load_lut() implementation The ->load_lut() callback is optional, therefore a dummy implementation is not needed. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index b957908..d9076a10cb 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1095,10 +1095,6 @@ static void tegra_crtc_commit(struct drm_crtc *crtc) tegra_dc_commit(dc); } -static void tegra_crtc_load_lut(struct drm_crtc *crtc) -{ -} - static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { .disable = tegra_crtc_disable, .mode_fixup = tegra_crtc_mode_fixup, @@ -1106,7 +1102,6 @@ static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { .mode_set_base = tegra_crtc_mode_set_base, .prepare = tegra_crtc_prepare, .commit = tegra_crtc_commit, - .load_lut = tegra_crtc_load_lut, }; static irqreturn_t tegra_dc_irq(int irq, void *data) -- cgit v0.10.2 From 4dfd909f92d623d79a23985526314bb31bdd110a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:34 +0100 Subject: drm: Miscellaneous checkpatch whitespace cleanups A couple of whitespace changes required to silent various errors and warnings flagged by checkpatch. checkpatch requires that the opening brace be on the same line as a variable declaration. Furthermore an empty line is required after a block of variable declarations. Trailing whitespace as well as using spaces before tabs is considered an error or warning, respectively. Finally, the closing parenthesis of an if condition and the opening brace of the conditional block should be separated by a space. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 632e6ea..76aa8fb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -61,8 +61,8 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, /* * Global properties */ -static const struct drm_prop_enum_list drm_dpms_enum_list[] = -{ { DRM_MODE_DPMS_ON, "On" }, +static const struct drm_prop_enum_list drm_dpms_enum_list[] = { + { DRM_MODE_DPMS_ON, "On" }, { DRM_MODE_DPMS_STANDBY, "Standby" }, { DRM_MODE_DPMS_SUSPEND, "Suspend" }, { DRM_MODE_DPMS_OFF, "Off" } @@ -70,8 +70,7 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] = DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) -static const struct drm_prop_enum_list drm_plane_type_enum_list[] = -{ +static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, { DRM_PLANE_TYPE_PRIMARY, "Primary" }, { DRM_PLANE_TYPE_CURSOR, "Cursor" }, @@ -80,8 +79,7 @@ static const struct drm_prop_enum_list drm_plane_type_enum_list[] = /* * Optional properties */ -static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = -{ +static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { { DRM_MODE_SCALE_NONE, "None" }, { DRM_MODE_SCALE_FULLSCREEN, "Full" }, { DRM_MODE_SCALE_CENTER, "Center" }, @@ -97,8 +95,7 @@ static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { /* * Non-global properties, but "required" for certain connectors. */ -static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = -{ +static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ @@ -106,8 +103,7 @@ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) -static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = -{ +static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ @@ -116,8 +112,7 @@ static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, drm_dvi_i_subconnector_enum_list) -static const struct drm_prop_enum_list drm_tv_select_enum_list[] = -{ +static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ @@ -127,8 +122,7 @@ static const struct drm_prop_enum_list drm_tv_select_enum_list[] = DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) -static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = -{ +static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ @@ -154,8 +148,8 @@ struct drm_conn_prop_enum_list { /* * Connector and encoder types. */ -static struct drm_conn_prop_enum_list drm_connector_enum_list[] = -{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, +static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { + { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, { DRM_MODE_CONNECTOR_VGA, "VGA" }, { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, @@ -174,8 +168,8 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { DRM_MODE_CONNECTOR_DSI, "DSI" }, }; -static const struct drm_prop_enum_list drm_encoder_enum_list[] = -{ { DRM_MODE_ENCODER_NONE, "None" }, +static const struct drm_prop_enum_list drm_encoder_enum_list[] = { + { DRM_MODE_ENCODER_NONE, "None" }, { DRM_MODE_ENCODER_DAC, "DAC" }, { DRM_MODE_ENCODER_TMDS, "TMDS" }, { DRM_MODE_ENCODER_LVDS, "LVDS" }, @@ -185,8 +179,7 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] = { DRM_MODE_ENCODER_DPMST, "DP MST" }, }; -static const struct drm_prop_enum_list drm_subpixel_enum_list[] = -{ +static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { { SubPixelUnknown, "Unknown" }, { SubPixelHorizontalRGB, "Horizontal RGB" }, { SubPixelHorizontalBGR, "Horizontal BGR" }, @@ -1137,6 +1130,7 @@ EXPORT_SYMBOL(drm_encoder_init); void drm_encoder_cleanup(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; + drm_modeset_lock_all(dev); drm_mode_object_put(dev, &encoder->base); kfree(encoder->name); @@ -2519,7 +2513,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, * * This is a little helper to wrap internal calls to the ->set_config driver * interface. The only thing it adds is correct refcounting dance. - * + * * Returns: * Zero on success, negative errno on failure. */ @@ -2958,6 +2952,7 @@ int drm_mode_cursor2_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_cursor2 *req = data; + return drm_mode_cursor_common(dev, req, file_priv); } @@ -4047,7 +4042,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, if (out_resp->length == blob->length) { blob_ptr = (void __user *)(unsigned long)out_resp->data; - if (copy_to_user(blob_ptr, blob->data, blob->length)){ + if (copy_to_user(blob_ptr, blob->data, blob->length)) { ret = -EFAULT; goto done; } @@ -4149,6 +4144,7 @@ static bool drm_property_change_is_valid(struct drm_property *property, return true; } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { int64_t svalue = U642I64(value); + if (svalue < U642I64(property->values[0]) || svalue > U642I64(property->values[1])) return false; @@ -4156,6 +4152,7 @@ static bool drm_property_change_is_valid(struct drm_property *property, } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { int i; uint64_t valid_mask = 0; + for (i = 0; i < property->num_values; i++) valid_mask |= (1ULL << property->values[i]); return !(value & ~valid_mask); @@ -4164,6 +4161,7 @@ static bool drm_property_change_is_valid(struct drm_property *property, return true; } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { struct drm_mode_object *obj; + /* a zero value for an object property translates to null: */ if (value == 0) return true; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f5a5f18..fadcd16 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -778,7 +778,7 @@ static struct timeval get_drm_timestamp(void) /** * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent - * vblank interval + * vblank interval * @dev: DRM device * @crtc: which CRTC's vblank timestamp to retrieve * @tvblank: Pointer to target struct timeval which should receive the timestamp @@ -910,6 +910,7 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc, { struct timeval now; unsigned int seq; + if (crtc >= 0) { seq = drm_vblank_count_and_time(dev, crtc, &now); } else { -- cgit v0.10.2 From bd3f0ff98a849e04dc2c0236f32cc75b8c8630db Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:35 +0100 Subject: drm: Prefer kcalloc() over kzalloc() with multiply Fixes a couple of checkpatch warnings regarding the use of kzalloc() with a multiplication. kcalloc() is the preferred API. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 76aa8fb..45e17df 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1583,7 +1583,7 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr total_objects += dev->mode_config.num_encoder; total_objects += dev->mode_config.num_bridge; - group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL); + group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); if (!group->id_list) return -ENOMEM; @@ -3400,7 +3400,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, ret = -EINVAL; goto out_err1; } - clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); + clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); if (!clips) { ret = -ENOMEM; goto out_err1; @@ -3501,7 +3501,8 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, property->dev = dev; if (num_values) { - property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL); + property->values = kcalloc(num_values, sizeof(uint64_t), + GFP_KERNEL); if (!property->values) goto fail; } @@ -4468,7 +4469,8 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, { crtc->gamma_size = gamma_size; - crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL); + crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, + GFP_KERNEL); if (!crtc->gamma_store) { crtc->gamma_size = 0; return -ENOMEM; -- cgit v0.10.2 From 2f6c538924108fbffb72a0696f28537b364080fa Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:36 +0100 Subject: drm: Prefer kmalloc_array() over kmalloc() with multiply Fixes a couple of checkpatch warnings regarding the use of kmalloc() with a multiplication. kmalloc_array() is the preferred API. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 45e17df..0d3a410 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1174,8 +1174,8 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, plane->base.properties = &plane->properties; plane->dev = dev; plane->funcs = funcs; - plane->format_types = kmalloc(sizeof(uint32_t) * format_count, - GFP_KERNEL); + plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), + GFP_KERNEL); if (!plane->format_types) { DRM_DEBUG_KMS("out of memory when allocating plane\n"); drm_mode_object_put(dev, &plane->base); @@ -2705,9 +2705,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } - connector_set = kmalloc(crtc_req->count_connectors * - sizeof(struct drm_connector *), - GFP_KERNEL); + connector_set = kmalloc_array(crtc_req->count_connectors, + sizeof(struct drm_connector *), + GFP_KERNEL); if (!connector_set) { ret = -ENOMEM; goto out; -- cgit v0.10.2 From 0cc0b223e7c9b4642c86d46f20d3d4a4a89bede3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:37 +0100 Subject: drm: Do not assign in if condition checkpatch requires the assignment and the check to be separate statements. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0d3a410..e8036fd 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1613,7 +1613,8 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_bridge *bridge; int ret; - if ((ret = drm_mode_group_init(dev, group))) + ret = drm_mode_group_init(dev, group); + if (ret) return ret; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) -- cgit v0.10.2 From 01073b0846c7c13438ef9b4d62e0747aed2db15d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:38 +0100 Subject: drm: Remove unneeded braces for single statement blocks Single statement blocks don't need to be enclosed in a pair of braces. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e8036fd..fa1b1a5 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2030,11 +2030,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, props_count = connector->properties.count; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] != 0) { + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) + if (connector->encoder_ids[i] != 0) encoders_count++; - } - } if (out_resp->count_modes == 0) { connector->funcs->fill_modes(connector, -- cgit v0.10.2 From 2ca651d15aff0f613d11913e8a10e3b86b3dc44a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:39 +0100 Subject: drm: Remove useless else block All prior conditional blocks return from the function, so the else block can be at the top level of the function. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index fa1b1a5..4f4fcd3 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4135,6 +4135,8 @@ EXPORT_SYMBOL(drm_mode_connector_update_edid_property); static bool drm_property_change_is_valid(struct drm_property *property, uint64_t value) { + int i; + if (property->flags & DRM_MODE_PROP_IMMUTABLE) return false; @@ -4150,7 +4152,6 @@ static bool drm_property_change_is_valid(struct drm_property *property, return false; return true; } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { - int i; uint64_t valid_mask = 0; for (i = 0; i < property->num_values; i++) @@ -4174,13 +4175,12 @@ static bool drm_property_change_is_valid(struct drm_property *property, */ obj = _object_find(property->dev, value, property->values[0]); return obj != NULL; - } else { - int i; - for (i = 0; i < property->num_values; i++) - if (property->values[i] == value) - return true; - return false; } + + for (i = 0; i < property->num_values; i++) + if (property->values[i] == value) + return true; + return false; } /** -- cgit v0.10.2 From f76511b97237f159b6b9a951a4f7fdd773d9698d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:40 +0100 Subject: drm: Prefer sizeof(type) over sizeof type sizeof(type) is the variant used most commonly and required by checkpatch. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 4f4fcd3..6700eba 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4684,23 +4684,23 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { ret = -ENOMEM; spin_lock_irqsave(&dev->event_lock, flags); - if (file_priv->event_space < sizeof e->event) { + if (file_priv->event_space < sizeof(e->event)) { spin_unlock_irqrestore(&dev->event_lock, flags); goto out; } - file_priv->event_space -= sizeof e->event; + file_priv->event_space -= sizeof(e->event); spin_unlock_irqrestore(&dev->event_lock, flags); - e = kzalloc(sizeof *e, GFP_KERNEL); + e = kzalloc(sizeof(*e), GFP_KERNEL); if (e == NULL) { spin_lock_irqsave(&dev->event_lock, flags); - file_priv->event_space += sizeof e->event; + file_priv->event_space += sizeof(e->event); spin_unlock_irqrestore(&dev->event_lock, flags); goto out; } e->event.base.type = DRM_EVENT_FLIP_COMPLETE; - e->event.base.length = sizeof e->event; + e->event.base.length = sizeof(e->event); e->event.user_data = page_flip->user_data; e->base.event = &e->event.base; e->base.file_priv = file_priv; @@ -4713,7 +4713,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, if (ret) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { spin_lock_irqsave(&dev->event_lock, flags); - file_priv->event_space += sizeof e->event; + file_priv->event_space += sizeof(e->event); spin_unlock_irqrestore(&dev->event_lock, flags); kfree(e); } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index fadcd16..920cdb9 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1383,7 +1383,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, unsigned int seq; int ret; - e = kzalloc(sizeof *e, GFP_KERNEL); + e = kzalloc(sizeof(*e), GFP_KERNEL); if (e == NULL) { ret = -ENOMEM; goto err_put; @@ -1392,7 +1392,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, e->pipe = pipe; e->base.pid = current->pid; e->event.base.type = DRM_EVENT_VBLANK; - e->event.base.length = sizeof e->event; + e->event.base.length = sizeof(e->event); e->event.user_data = vblwait->request.signal; e->base.event = &e->event.base; e->base.file_priv = file_priv; @@ -1412,12 +1412,12 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, goto err_unlock; } - if (file_priv->event_space < sizeof e->event) { + if (file_priv->event_space < sizeof(e->event)) { ret = -EBUSY; goto err_unlock; } - file_priv->event_space -= sizeof e->event; + file_priv->event_space -= sizeof(e->event); seq = drm_vblank_count_and_time(dev, pipe, &now); if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && -- cgit v0.10.2 From 7ff0ebcc1e30e3216c8c62ee71f59ac830b10364 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 8 Dec 2014 14:09:10 -0200 Subject: drm/i915: Move FBC stuff to intel_fbc.c No functional changes. This is just the begin of a FBC rework. v2 (Paulo): - Revert intel_fbc_init() changed parameter. - Revert set_no_fbc_reason() rename. - Rebase. Cc: Paulo Zanoni Signed-off-by: Rodrigo Vivi Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e4083e4..3cf70a6 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -47,6 +47,7 @@ i915-y += intel_renderstate_gen6.o \ i915-y += intel_audio.o \ intel_bios.o \ intel_display.o \ + intel_fbc.o \ intel_fifo_underrun.o \ intel_frontbuffer.o \ intel_modes.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 95dfa2d..c74dc94 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2963,9 +2963,6 @@ extern void intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore); extern void i915_redisable_vga(struct drm_device *dev); extern void i915_redisable_vga_power_on(struct drm_device *dev); -extern bool intel_fbc_enabled(struct drm_device *dev); -extern void bdw_fbc_sw_flush(struct drm_device *dev, u32 value); -extern void intel_disable_fbc(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern void intel_init_pch_refclk(struct drm_device *dev); extern void gen6_set_rps(struct drm_device *dev, u8 val); diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index dfe6617..1e4999d 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -264,7 +264,7 @@ static void i915_restore_display(struct drm_device *dev) } /* only restore FBC info on the platform that supports FBC*/ - intel_disable_fbc(dev); + intel_fbc_disable(dev); /* restore FBC interval */ if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev)) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d5153a4..841af6c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4201,7 +4201,7 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) hsw_enable_ips(intel_crtc); mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); + intel_fbc_update(dev); mutex_unlock(&dev->struct_mutex); /* @@ -4223,7 +4223,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) intel_crtc_wait_for_pending_flips(crtc); if (dev_priv->fbc.plane == plane) - intel_disable_fbc(dev); + intel_fbc_disable(dev); hsw_disable_ips(intel_crtc); @@ -4527,7 +4527,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_update_watermarks(crtc); mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); + intel_fbc_update(dev); mutex_unlock(&dev->struct_mutex); } @@ -4584,7 +4584,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_update_watermarks(crtc); mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); + intel_fbc_update(dev); mutex_unlock(&dev->struct_mutex); if (intel_crtc_to_shared_dpll(intel_crtc)) @@ -5189,7 +5189,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_update_watermarks(crtc); mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); + intel_fbc_update(dev); mutex_unlock(&dev->struct_mutex); } @@ -8950,7 +8950,7 @@ static void intel_unpin_work_fn(struct work_struct *__work) drm_gem_object_unreference(&work->pending_flip_obj->base); drm_gem_object_unreference(&work->old_fb_obj->base); - intel_update_fbc(dev); + intel_fbc_update(dev); if (work->flip_queued_req) i915_gem_request_assign(&work->flip_queued_req, NULL); @@ -9747,7 +9747,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, i915_gem_track_fb(work->old_fb_obj, obj, INTEL_FRONTBUFFER_PRIMARY(pipe)); - intel_disable_fbc(dev); + intel_fbc_disable(dev); intel_frontbuffer_flip_prepare(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); mutex_unlock(&dev->struct_mutex); @@ -11816,7 +11816,7 @@ intel_commit_primary_plane(struct drm_plane *plane, INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && dev_priv->fbc.plane == intel_crtc->plane && intel_plane->rotation != BIT(DRM_ROTATE_0)) { - intel_disable_fbc(dev); + intel_fbc_disable(dev); } if (state->visible) { @@ -11851,7 +11851,7 @@ intel_commit_primary_plane(struct drm_plane *plane, intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); + intel_fbc_update(dev); mutex_unlock(&dev->struct_mutex); } } @@ -13050,7 +13050,7 @@ void intel_modeset_init(struct drm_device *dev) intel_setup_outputs(dev); /* Just in case the BIOS is doing something questionable. */ - intel_disable_fbc(dev); + intel_fbc_disable(dev); drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, false); @@ -13567,7 +13567,7 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_unregister_dsm_handler(); - intel_disable_fbc(dev); + intel_fbc_disable(dev); ironlake_teardown_rc6(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 61a88fa..588b618 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1063,6 +1063,13 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev) } #endif +/* intel_fbc.c */ +bool intel_fbc_enabled(struct drm_device *dev); +void intel_fbc_update(struct drm_device *dev); +void intel_fbc_init(struct drm_i915_private *dev_priv); +void intel_fbc_disable(struct drm_device *dev); +void bdw_fbc_sw_flush(struct drm_device *dev, u32 value); + /* intel_hdmi.c */ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, @@ -1169,8 +1176,6 @@ void intel_update_sprite_watermarks(struct drm_plane *plane, bool enabled, bool scaled); void intel_init_pm(struct drm_device *dev); void intel_pm_setup(struct drm_device *dev); -bool intel_fbc_enabled(struct drm_device *dev); -void intel_update_fbc(struct drm_device *dev); void intel_gpu_ips_init(struct drm_i915_private *dev_priv); void intel_gpu_ips_teardown(void); void intel_init_gt_powersave(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c new file mode 100644 index 0000000..f1eeb86 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -0,0 +1,675 @@ +/* + * Copyright © 2014 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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 "intel_drv.h" +#include "i915_drv.h" + +/* FBC, or Frame Buffer Compression, is a technique employed to compress the + * framebuffer contents in-memory, aiming at reducing the required bandwidth + * during in-memory transfers and, therefore, reduce the power packet. + * + * The benefits of FBC are mostly visible with solid backgrounds and + * variation-less patterns. + * + * FBC-related functionality can be enabled by the means of the + * i915.i915_fbc_enable parameter + */ + +static void i8xx_fbc_disable(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 fbc_ctl; + + dev_priv->fbc.enabled = false; + + /* Disable compression */ + fbc_ctl = I915_READ(FBC_CONTROL); + if ((fbc_ctl & FBC_CTL_EN) == 0) + return; + + fbc_ctl &= ~FBC_CTL_EN; + I915_WRITE(FBC_CONTROL, fbc_ctl); + + /* Wait for compressing bit to clear */ + if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) { + DRM_DEBUG_KMS("FBC idle timed out\n"); + return; + } + + DRM_DEBUG_KMS("disabled FBC\n"); +} + +static void i8xx_fbc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int cfb_pitch; + int i; + u32 fbc_ctl; + + dev_priv->fbc.enabled = true; + + cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE; + if (fb->pitches[0] < cfb_pitch) + cfb_pitch = fb->pitches[0]; + + /* FBC_CTL wants 32B or 64B units */ + if (IS_GEN2(dev)) + cfb_pitch = (cfb_pitch / 32) - 1; + else + cfb_pitch = (cfb_pitch / 64) - 1; + + /* Clear old tags */ + for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) + I915_WRITE(FBC_TAG + (i * 4), 0); + + if (IS_GEN4(dev)) { + u32 fbc_ctl2; + + /* Set it up... */ + fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; + fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane); + I915_WRITE(FBC_CONTROL2, fbc_ctl2); + I915_WRITE(FBC_FENCE_OFF, crtc->y); + } + + /* enable it... */ + fbc_ctl = I915_READ(FBC_CONTROL); + fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT; + fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC; + if (IS_I945GM(dev)) + fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ + fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; + fbc_ctl |= obj->fence_reg; + I915_WRITE(FBC_CONTROL, fbc_ctl); + + DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n", + cfb_pitch, crtc->y, plane_name(intel_crtc->plane)); +} + +static bool i8xx_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(FBC_CONTROL) & FBC_CTL_EN; +} + +static void g4x_fbc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + u32 dpfc_ctl; + + dev_priv->fbc.enabled = true; + + dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN; + if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) + dpfc_ctl |= DPFC_CTL_LIMIT_2X; + else + dpfc_ctl |= DPFC_CTL_LIMIT_1X; + dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; + + I915_WRITE(DPFC_FENCE_YOFF, crtc->y); + + /* enable it... */ + I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); + + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); +} + +static void g4x_fbc_disable(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpfc_ctl; + + dev_priv->fbc.enabled = false; + + /* Disable compression */ + dpfc_ctl = I915_READ(DPFC_CONTROL); + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(DPFC_CONTROL, dpfc_ctl); + + DRM_DEBUG_KMS("disabled FBC\n"); + } +} + +static bool g4x_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; +} + +static void snb_fbc_blit_update(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 blt_ecoskpd; + + /* Make sure blitter notifies FBC of writes */ + + /* Blitter is part of Media powerwell on VLV. No impact of + * his param in other platforms for now */ + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA); + + blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); + blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << + GEN6_BLITTER_LOCK_SHIFT; + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY; + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY << + GEN6_BLITTER_LOCK_SHIFT); + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + POSTING_READ(GEN6_BLITTER_ECOSKPD); + + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA); +} + +static void ilk_fbc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + u32 dpfc_ctl; + + dev_priv->fbc.enabled = true; + + dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane); + if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) + dev_priv->fbc.threshold++; + + switch (dev_priv->fbc.threshold) { + case 4: + case 3: + dpfc_ctl |= DPFC_CTL_LIMIT_4X; + break; + case 2: + dpfc_ctl |= DPFC_CTL_LIMIT_2X; + break; + case 1: + dpfc_ctl |= DPFC_CTL_LIMIT_1X; + break; + } + dpfc_ctl |= DPFC_CTL_FENCE_EN; + if (IS_GEN5(dev)) + dpfc_ctl |= obj->fence_reg; + + I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); + I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); + /* enable it... */ + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); + + if (IS_GEN6(dev)) { + I915_WRITE(SNB_DPFC_CTL_SA, + SNB_CPU_FENCE_ENABLE | obj->fence_reg); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + snb_fbc_blit_update(dev); + } + + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); +} + +static void ilk_fbc_disable(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpfc_ctl; + + dev_priv->fbc.enabled = false; + + /* Disable compression */ + dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); + + DRM_DEBUG_KMS("disabled FBC\n"); + } +} + +static bool ilk_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; +} + +static void gen7_fbc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + u32 dpfc_ctl; + + dev_priv->fbc.enabled = true; + + dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane); + if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) + dev_priv->fbc.threshold++; + + switch (dev_priv->fbc.threshold) { + case 4: + case 3: + dpfc_ctl |= DPFC_CTL_LIMIT_4X; + break; + case 2: + dpfc_ctl |= DPFC_CTL_LIMIT_2X; + break; + case 1: + dpfc_ctl |= DPFC_CTL_LIMIT_1X; + break; + } + + dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN; + + if (dev_priv->fbc.false_color) + dpfc_ctl |= FBC_CTL_FALSE_COLOR; + + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); + + if (IS_IVYBRIDGE(dev)) { + /* WaFbcAsynchFlipDisableFbcQueue:ivb */ + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS); + } else { + /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ + I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe), + I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) | + HSW_FBCQ_DIS); + } + + I915_WRITE(SNB_DPFC_CTL_SA, + SNB_CPU_FENCE_ENABLE | obj->fence_reg); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + + snb_fbc_blit_update(dev); + + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); +} + +bool intel_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return dev_priv->fbc.enabled; +} + +void bdw_fbc_sw_flush(struct drm_device *dev, u32 value) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_GEN8(dev)) + return; + + if (!intel_fbc_enabled(dev)) + return; + + I915_WRITE(MSG_FBC_REND_STATE, value); +} + +static void intel_fbc_work_fn(struct work_struct *__work) +{ + struct intel_fbc_work *work = + container_of(to_delayed_work(__work), + struct intel_fbc_work, work); + struct drm_device *dev = work->crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev->struct_mutex); + if (work == dev_priv->fbc.fbc_work) { + /* Double check that we haven't switched fb without cancelling + * the prior work. + */ + if (work->crtc->primary->fb == work->fb) { + dev_priv->display.enable_fbc(work->crtc); + + dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane; + dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id; + dev_priv->fbc.y = work->crtc->y; + } + + dev_priv->fbc.fbc_work = NULL; + } + mutex_unlock(&dev->struct_mutex); + + kfree(work); +} + +static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) +{ + if (dev_priv->fbc.fbc_work == NULL) + return; + + DRM_DEBUG_KMS("cancelling pending FBC enable\n"); + + /* Synchronisation is provided by struct_mutex and checking of + * dev_priv->fbc.fbc_work, so we can perform the cancellation + * entirely asynchronously. + */ + if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work)) + /* tasklet was killed before being run, clean up */ + kfree(dev_priv->fbc.fbc_work); + + /* Mark the work as no longer wanted so that if it does + * wake-up (because the work was already running and waiting + * for our mutex), it will discover that is no longer + * necessary to run. + */ + dev_priv->fbc.fbc_work = NULL; +} + +static void intel_fbc_enable(struct drm_crtc *crtc) +{ + struct intel_fbc_work *work; + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!dev_priv->display.enable_fbc) + return; + + intel_fbc_cancel_work(dev_priv); + + work = kzalloc(sizeof(*work), GFP_KERNEL); + if (work == NULL) { + DRM_ERROR("Failed to allocate FBC work structure\n"); + dev_priv->display.enable_fbc(crtc); + return; + } + + work->crtc = crtc; + work->fb = crtc->primary->fb; + INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); + + dev_priv->fbc.fbc_work = work; + + /* Delay the actual enabling to let pageflipping cease and the + * display to settle before starting the compression. Note that + * this delay also serves a second purpose: it allows for a + * vblank to pass after disabling the FBC before we attempt + * to modify the control registers. + * + * A more complicated solution would involve tracking vblanks + * following the termination of the page-flipping sequence + * and indeed performing the enable as a co-routine and not + * waiting synchronously upon the vblank. + * + * WaFbcWaitForVBlankBeforeEnable:ilk,snb + */ + schedule_delayed_work(&work->work, msecs_to_jiffies(50)); +} + +void intel_fbc_disable(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + intel_fbc_cancel_work(dev_priv); + + if (!dev_priv->display.disable_fbc) + return; + + dev_priv->display.disable_fbc(dev); + dev_priv->fbc.plane = -1; +} + +static bool set_no_fbc_reason(struct drm_i915_private *dev_priv, + enum no_fbc_reason reason) +{ + if (dev_priv->fbc.no_fbc_reason == reason) + return false; + + dev_priv->fbc.no_fbc_reason = reason; + return true; +} + +/** + * intel_fbc_update - enable/disable FBC as needed + * @dev: the drm_device + * + * Set up the framebuffer compression hardware at mode set time. We + * enable it if possible: + * - plane A only (on pre-965) + * - no pixel mulitply/line duplication + * - no alpha buffer discard + * - no dual wide + * - framebuffer <= max_hdisplay in width, max_vdisplay in height + * + * We can't assume that any compression will take place (worst case), + * so the compressed buffer has to be the same size as the uncompressed + * one. It also must reside (along with the line length buffer) in + * stolen memory. + * + * We need to enable/disable FBC on a global basis. + */ +void intel_fbc_update(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = NULL, *tmp_crtc; + struct intel_crtc *intel_crtc; + struct drm_framebuffer *fb; + struct drm_i915_gem_object *obj; + const struct drm_display_mode *adjusted_mode; + unsigned int max_width, max_height; + + if (!HAS_FBC(dev)) { + set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED); + return; + } + + if (!i915.powersave) { + if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM)) + DRM_DEBUG_KMS("fbc disabled per module param\n"); + return; + } + + /* + * If FBC is already on, we just have to verify that we can + * keep it that way... + * Need to disable if: + * - more than one pipe is active + * - changing FBC params (stride, fence, mode) + * - new fb is too large to fit in compressed buffer + * - going to an unsupported config (interlace, pixel multiply, etc.) + */ + for_each_crtc(dev, tmp_crtc) { + if (intel_crtc_active(tmp_crtc) && + to_intel_crtc(tmp_crtc)->primary_enabled) { + if (crtc) { + if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES)) + DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); + goto out_disable; + } + crtc = tmp_crtc; + } + } + + if (!crtc || crtc->primary->fb == NULL) { + if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT)) + DRM_DEBUG_KMS("no output, disabling\n"); + goto out_disable; + } + + intel_crtc = to_intel_crtc(crtc); + fb = crtc->primary->fb; + obj = intel_fb_obj(fb); + adjusted_mode = &intel_crtc->config.adjusted_mode; + + if (i915.enable_fbc < 0) { + if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT)) + DRM_DEBUG_KMS("disabled per chip default\n"); + goto out_disable; + } + if (!i915.enable_fbc) { + if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM)) + DRM_DEBUG_KMS("fbc disabled per module param\n"); + goto out_disable; + } + if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) || + (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) { + if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE)) + DRM_DEBUG_KMS("mode incompatible with compression, " + "disabling\n"); + goto out_disable; + } + + if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) { + max_width = 4096; + max_height = 4096; + } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + max_width = 4096; + max_height = 2048; + } else { + max_width = 2048; + max_height = 1536; + } + if (intel_crtc->config.pipe_src_w > max_width || + intel_crtc->config.pipe_src_h > max_height) { + if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE)) + DRM_DEBUG_KMS("mode too large for compression, disabling\n"); + goto out_disable; + } + if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) && + intel_crtc->plane != PLANE_A) { + if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE)) + DRM_DEBUG_KMS("plane not A, disabling compression\n"); + goto out_disable; + } + + /* The use of a CPU fence is mandatory in order to detect writes + * by the CPU to the scanout and trigger updates to the FBC. + */ + if (obj->tiling_mode != I915_TILING_X || + obj->fence_reg == I915_FENCE_REG_NONE) { + if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED)) + DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n"); + goto out_disable; + } + if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && + to_intel_plane(crtc->primary)->rotation != BIT(DRM_ROTATE_0)) { + if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE)) + DRM_DEBUG_KMS("Rotation unsupported, disabling\n"); + goto out_disable; + } + + /* If the kernel debugger is active, always disable compression */ + if (in_dbg_master()) + goto out_disable; + + if (i915_gem_stolen_setup_compression(dev, obj->base.size, + drm_format_plane_cpp(fb->pixel_format, 0))) { + if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL)) + DRM_DEBUG_KMS("framebuffer too large, disabling compression\n"); + goto out_disable; + } + + /* If the scanout has not changed, don't modify the FBC settings. + * Note that we make the fundamental assumption that the fb->obj + * cannot be unpinned (and have its GTT offset and fence revoked) + * without first being decoupled from the scanout and FBC disabled. + */ + if (dev_priv->fbc.plane == intel_crtc->plane && + dev_priv->fbc.fb_id == fb->base.id && + dev_priv->fbc.y == crtc->y) + return; + + if (intel_fbc_enabled(dev)) { + /* We update FBC along two paths, after changing fb/crtc + * configuration (modeswitching) and after page-flipping + * finishes. For the latter, we know that not only did + * we disable the FBC at the start of the page-flip + * sequence, but also more than one vblank has passed. + * + * For the former case of modeswitching, it is possible + * to switch between two FBC valid configurations + * instantaneously so we do need to disable the FBC + * before we can modify its control registers. We also + * have to wait for the next vblank for that to take + * effect. However, since we delay enabling FBC we can + * assume that a vblank has passed since disabling and + * that we can safely alter the registers in the deferred + * callback. + * + * In the scenario that we go from a valid to invalid + * and then back to valid FBC configuration we have + * no strict enforcement that a vblank occurred since + * disabling the FBC. However, along all current pipe + * disabling paths we do need to wait for a vblank at + * some point. And we wait before enabling FBC anyway. + */ + DRM_DEBUG_KMS("disabling active FBC for update\n"); + intel_fbc_disable(dev); + } + + intel_fbc_enable(crtc); + dev_priv->fbc.no_fbc_reason = FBC_OK; + return; + +out_disable: + /* Multiple disables should be harmless */ + if (intel_fbc_enabled(dev)) { + DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); + intel_fbc_disable(dev); + } + i915_gem_stolen_cleanup_compression(dev); +} + +void intel_fbc_init(struct drm_i915_private *dev_priv) +{ + if (!HAS_FBC(dev_priv)) { + dev_priv->fbc.enabled = false; + return; + } + + if (INTEL_INFO(dev_priv)->gen >= 7) { + dev_priv->display.fbc_enabled = ilk_fbc_enabled; + dev_priv->display.enable_fbc = gen7_fbc_enable; + dev_priv->display.disable_fbc = ilk_fbc_disable; + } else if (INTEL_INFO(dev_priv)->gen >= 5) { + dev_priv->display.fbc_enabled = ilk_fbc_enabled; + dev_priv->display.enable_fbc = ilk_fbc_enable; + dev_priv->display.disable_fbc = ilk_fbc_disable; + } else if (IS_GM45(dev_priv)) { + dev_priv->display.fbc_enabled = g4x_fbc_enabled; + dev_priv->display.enable_fbc = g4x_fbc_enable; + dev_priv->display.disable_fbc = g4x_fbc_disable; + } else { + dev_priv->display.fbc_enabled = i8xx_fbc_enabled; + dev_priv->display.enable_fbc = i8xx_fbc_enable; + dev_priv->display.disable_fbc = i8xx_fbc_disable; + + /* This value was pulled out of someone's hat */ + I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); + } + + dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev); +} diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 78911e2..99865c0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -52,17 +52,6 @@ #define INTEL_RC6p_ENABLE (1<<1) #define INTEL_RC6pp_ENABLE (1<<2) -/* FBC, or Frame Buffer Compression, is a technique employed to compress the - * framebuffer contents in-memory, aiming at reducing the required bandwidth - * during in-memory transfers and, therefore, reduce the power packet. - * - * The benefits of FBC are mostly visible with solid backgrounds and - * variation-less patterns. - * - * FBC-related functionality can be enabled by the means of the - * i915.i915_enable_fbc parameter - */ - static void gen9_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -87,613 +76,6 @@ static void gen9_init_clock_gating(struct drm_device *dev) _MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE)); } -static void i8xx_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 fbc_ctl; - - dev_priv->fbc.enabled = false; - - /* Disable compression */ - fbc_ctl = I915_READ(FBC_CONTROL); - if ((fbc_ctl & FBC_CTL_EN) == 0) - return; - - fbc_ctl &= ~FBC_CTL_EN; - I915_WRITE(FBC_CONTROL, fbc_ctl); - - /* Wait for compressing bit to clear */ - if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) { - DRM_DEBUG_KMS("FBC idle timed out\n"); - return; - } - - DRM_DEBUG_KMS("disabled FBC\n"); -} - -static void i8xx_enable_fbc(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int cfb_pitch; - int i; - u32 fbc_ctl; - - dev_priv->fbc.enabled = true; - - cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE; - if (fb->pitches[0] < cfb_pitch) - cfb_pitch = fb->pitches[0]; - - /* FBC_CTL wants 32B or 64B units */ - if (IS_GEN2(dev)) - cfb_pitch = (cfb_pitch / 32) - 1; - else - cfb_pitch = (cfb_pitch / 64) - 1; - - /* Clear old tags */ - for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) - I915_WRITE(FBC_TAG + (i * 4), 0); - - if (IS_GEN4(dev)) { - u32 fbc_ctl2; - - /* Set it up... */ - fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane); - I915_WRITE(FBC_CONTROL2, fbc_ctl2); - I915_WRITE(FBC_FENCE_OFF, crtc->y); - } - - /* enable it... */ - fbc_ctl = I915_READ(FBC_CONTROL); - fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT; - fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC; - if (IS_I945GM(dev)) - fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ - fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; - fbc_ctl |= obj->fence_reg; - I915_WRITE(FBC_CONTROL, fbc_ctl); - - DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n", - cfb_pitch, crtc->y, plane_name(intel_crtc->plane)); -} - -static bool i8xx_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return I915_READ(FBC_CONTROL) & FBC_CTL_EN; -} - -static void g4x_enable_fbc(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - u32 dpfc_ctl; - - dev_priv->fbc.enabled = true; - - dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN; - if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) - dpfc_ctl |= DPFC_CTL_LIMIT_2X; - else - dpfc_ctl |= DPFC_CTL_LIMIT_1X; - dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; - - I915_WRITE(DPFC_FENCE_YOFF, crtc->y); - - /* enable it... */ - I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - - DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); -} - -static void g4x_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpfc_ctl; - - dev_priv->fbc.enabled = false; - - /* Disable compression */ - dpfc_ctl = I915_READ(DPFC_CONTROL); - if (dpfc_ctl & DPFC_CTL_EN) { - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(DPFC_CONTROL, dpfc_ctl); - - DRM_DEBUG_KMS("disabled FBC\n"); - } -} - -static bool g4x_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; -} - -static void sandybridge_blit_fbc_update(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 blt_ecoskpd; - - /* Make sure blitter notifies FBC of writes */ - - /* Blitter is part of Media powerwell on VLV. No impact of - * his param in other platforms for now */ - gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA); - - blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); - blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << - GEN6_BLITTER_LOCK_SHIFT; - I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); - blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY; - I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); - blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY << - GEN6_BLITTER_LOCK_SHIFT); - I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); - POSTING_READ(GEN6_BLITTER_ECOSKPD); - - gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA); -} - -static void ironlake_enable_fbc(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - u32 dpfc_ctl; - - dev_priv->fbc.enabled = true; - - dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane); - if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) - dev_priv->fbc.threshold++; - - switch (dev_priv->fbc.threshold) { - case 4: - case 3: - dpfc_ctl |= DPFC_CTL_LIMIT_4X; - break; - case 2: - dpfc_ctl |= DPFC_CTL_LIMIT_2X; - break; - case 1: - dpfc_ctl |= DPFC_CTL_LIMIT_1X; - break; - } - dpfc_ctl |= DPFC_CTL_FENCE_EN; - if (IS_GEN5(dev)) - dpfc_ctl |= obj->fence_reg; - - I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); - I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); - /* enable it... */ - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - - if (IS_GEN6(dev)) { - I915_WRITE(SNB_DPFC_CTL_SA, - SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); - sandybridge_blit_fbc_update(dev); - } - - DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); -} - -static void ironlake_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpfc_ctl; - - dev_priv->fbc.enabled = false; - - /* Disable compression */ - dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); - if (dpfc_ctl & DPFC_CTL_EN) { - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); - - DRM_DEBUG_KMS("disabled FBC\n"); - } -} - -static bool ironlake_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; -} - -static void gen7_enable_fbc(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - u32 dpfc_ctl; - - dev_priv->fbc.enabled = true; - - dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane); - if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) - dev_priv->fbc.threshold++; - - switch (dev_priv->fbc.threshold) { - case 4: - case 3: - dpfc_ctl |= DPFC_CTL_LIMIT_4X; - break; - case 2: - dpfc_ctl |= DPFC_CTL_LIMIT_2X; - break; - case 1: - dpfc_ctl |= DPFC_CTL_LIMIT_1X; - break; - } - - dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN; - - if (dev_priv->fbc.false_color) - dpfc_ctl |= FBC_CTL_FALSE_COLOR; - - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - - if (IS_IVYBRIDGE(dev)) { - /* WaFbcAsynchFlipDisableFbcQueue:ivb */ - I915_WRITE(ILK_DISPLAY_CHICKEN1, - I915_READ(ILK_DISPLAY_CHICKEN1) | - ILK_FBCQ_DIS); - } else { - /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ - I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe), - I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) | - HSW_FBCQ_DIS); - } - - I915_WRITE(SNB_DPFC_CTL_SA, - SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); - - sandybridge_blit_fbc_update(dev); - - DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); -} - -bool intel_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return dev_priv->fbc.enabled; -} - -void bdw_fbc_sw_flush(struct drm_device *dev, u32 value) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!IS_GEN8(dev)) - return; - - if (!intel_fbc_enabled(dev)) - return; - - I915_WRITE(MSG_FBC_REND_STATE, value); -} - -static void intel_fbc_work_fn(struct work_struct *__work) -{ - struct intel_fbc_work *work = - container_of(to_delayed_work(__work), - struct intel_fbc_work, work); - struct drm_device *dev = work->crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - mutex_lock(&dev->struct_mutex); - if (work == dev_priv->fbc.fbc_work) { - /* Double check that we haven't switched fb without cancelling - * the prior work. - */ - if (work->crtc->primary->fb == work->fb) { - dev_priv->display.enable_fbc(work->crtc); - - dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane; - dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id; - dev_priv->fbc.y = work->crtc->y; - } - - dev_priv->fbc.fbc_work = NULL; - } - mutex_unlock(&dev->struct_mutex); - - kfree(work); -} - -static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) -{ - if (dev_priv->fbc.fbc_work == NULL) - return; - - DRM_DEBUG_KMS("cancelling pending FBC enable\n"); - - /* Synchronisation is provided by struct_mutex and checking of - * dev_priv->fbc.fbc_work, so we can perform the cancellation - * entirely asynchronously. - */ - if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work)) - /* tasklet was killed before being run, clean up */ - kfree(dev_priv->fbc.fbc_work); - - /* Mark the work as no longer wanted so that if it does - * wake-up (because the work was already running and waiting - * for our mutex), it will discover that is no longer - * necessary to run. - */ - dev_priv->fbc.fbc_work = NULL; -} - -static void intel_enable_fbc(struct drm_crtc *crtc) -{ - struct intel_fbc_work *work; - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!dev_priv->display.enable_fbc) - return; - - intel_cancel_fbc_work(dev_priv); - - work = kzalloc(sizeof(*work), GFP_KERNEL); - if (work == NULL) { - DRM_ERROR("Failed to allocate FBC work structure\n"); - dev_priv->display.enable_fbc(crtc); - return; - } - - work->crtc = crtc; - work->fb = crtc->primary->fb; - INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); - - dev_priv->fbc.fbc_work = work; - - /* Delay the actual enabling to let pageflipping cease and the - * display to settle before starting the compression. Note that - * this delay also serves a second purpose: it allows for a - * vblank to pass after disabling the FBC before we attempt - * to modify the control registers. - * - * A more complicated solution would involve tracking vblanks - * following the termination of the page-flipping sequence - * and indeed performing the enable as a co-routine and not - * waiting synchronously upon the vblank. - * - * WaFbcWaitForVBlankBeforeEnable:ilk,snb - */ - schedule_delayed_work(&work->work, msecs_to_jiffies(50)); -} - -void intel_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - intel_cancel_fbc_work(dev_priv); - - if (!dev_priv->display.disable_fbc) - return; - - dev_priv->display.disable_fbc(dev); - dev_priv->fbc.plane = -1; -} - -static bool set_no_fbc_reason(struct drm_i915_private *dev_priv, - enum no_fbc_reason reason) -{ - if (dev_priv->fbc.no_fbc_reason == reason) - return false; - - dev_priv->fbc.no_fbc_reason = reason; - return true; -} - -/** - * intel_update_fbc - enable/disable FBC as needed - * @dev: the drm_device - * - * Set up the framebuffer compression hardware at mode set time. We - * enable it if possible: - * - plane A only (on pre-965) - * - no pixel mulitply/line duplication - * - no alpha buffer discard - * - no dual wide - * - framebuffer <= max_hdisplay in width, max_vdisplay in height - * - * We can't assume that any compression will take place (worst case), - * so the compressed buffer has to be the same size as the uncompressed - * one. It also must reside (along with the line length buffer) in - * stolen memory. - * - * We need to enable/disable FBC on a global basis. - */ -void intel_update_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = NULL, *tmp_crtc; - struct intel_crtc *intel_crtc; - struct drm_framebuffer *fb; - struct drm_i915_gem_object *obj; - const struct drm_display_mode *adjusted_mode; - unsigned int max_width, max_height; - - if (!HAS_FBC(dev)) { - set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED); - return; - } - - if (!i915.powersave) { - if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM)) - DRM_DEBUG_KMS("fbc disabled per module param\n"); - return; - } - - /* - * If FBC is already on, we just have to verify that we can - * keep it that way... - * Need to disable if: - * - more than one pipe is active - * - changing FBC params (stride, fence, mode) - * - new fb is too large to fit in compressed buffer - * - going to an unsupported config (interlace, pixel multiply, etc.) - */ - for_each_crtc(dev, tmp_crtc) { - if (intel_crtc_active(tmp_crtc) && - to_intel_crtc(tmp_crtc)->primary_enabled) { - if (crtc) { - if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES)) - DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); - goto out_disable; - } - crtc = tmp_crtc; - } - } - - if (!crtc || crtc->primary->fb == NULL) { - if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT)) - DRM_DEBUG_KMS("no output, disabling\n"); - goto out_disable; - } - - intel_crtc = to_intel_crtc(crtc); - fb = crtc->primary->fb; - obj = intel_fb_obj(fb); - adjusted_mode = &intel_crtc->config.adjusted_mode; - - if (i915.enable_fbc < 0) { - if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT)) - DRM_DEBUG_KMS("disabled per chip default\n"); - goto out_disable; - } - if (!i915.enable_fbc) { - if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM)) - DRM_DEBUG_KMS("fbc disabled per module param\n"); - goto out_disable; - } - if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) || - (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) { - if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE)) - DRM_DEBUG_KMS("mode incompatible with compression, " - "disabling\n"); - goto out_disable; - } - - if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) { - max_width = 4096; - max_height = 4096; - } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { - max_width = 4096; - max_height = 2048; - } else { - max_width = 2048; - max_height = 1536; - } - if (intel_crtc->config.pipe_src_w > max_width || - intel_crtc->config.pipe_src_h > max_height) { - if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE)) - DRM_DEBUG_KMS("mode too large for compression, disabling\n"); - goto out_disable; - } - if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) && - intel_crtc->plane != PLANE_A) { - if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE)) - DRM_DEBUG_KMS("plane not A, disabling compression\n"); - goto out_disable; - } - - /* The use of a CPU fence is mandatory in order to detect writes - * by the CPU to the scanout and trigger updates to the FBC. - */ - if (obj->tiling_mode != I915_TILING_X || - obj->fence_reg == I915_FENCE_REG_NONE) { - if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED)) - DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n"); - goto out_disable; - } - if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && - to_intel_plane(crtc->primary)->rotation != BIT(DRM_ROTATE_0)) { - if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE)) - DRM_DEBUG_KMS("Rotation unsupported, disabling\n"); - goto out_disable; - } - - /* If the kernel debugger is active, always disable compression */ - if (in_dbg_master()) - goto out_disable; - - if (i915_gem_stolen_setup_compression(dev, obj->base.size, - drm_format_plane_cpp(fb->pixel_format, 0))) { - if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL)) - DRM_DEBUG_KMS("framebuffer too large, disabling compression\n"); - goto out_disable; - } - - /* If the scanout has not changed, don't modify the FBC settings. - * Note that we make the fundamental assumption that the fb->obj - * cannot be unpinned (and have its GTT offset and fence revoked) - * without first being decoupled from the scanout and FBC disabled. - */ - if (dev_priv->fbc.plane == intel_crtc->plane && - dev_priv->fbc.fb_id == fb->base.id && - dev_priv->fbc.y == crtc->y) - return; - - if (intel_fbc_enabled(dev)) { - /* We update FBC along two paths, after changing fb/crtc - * configuration (modeswitching) and after page-flipping - * finishes. For the latter, we know that not only did - * we disable the FBC at the start of the page-flip - * sequence, but also more than one vblank has passed. - * - * For the former case of modeswitching, it is possible - * to switch between two FBC valid configurations - * instantaneously so we do need to disable the FBC - * before we can modify its control registers. We also - * have to wait for the next vblank for that to take - * effect. However, since we delay enabling FBC we can - * assume that a vblank has passed since disabling and - * that we can safely alter the registers in the deferred - * callback. - * - * In the scenario that we go from a valid to invalid - * and then back to valid FBC configuration we have - * no strict enforcement that a vblank occurred since - * disabling the FBC. However, along all current pipe - * disabling paths we do need to wait for a vblank at - * some point. And we wait before enabling FBC anyway. - */ - DRM_DEBUG_KMS("disabling active FBC for update\n"); - intel_disable_fbc(dev); - } - - intel_enable_fbc(crtc); - dev_priv->fbc.no_fbc_reason = FBC_OK; - return; - -out_disable: - /* Multiple disables should be harmless */ - if (intel_fbc_enabled(dev)) { - DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); - intel_disable_fbc(dev); - } - i915_gem_stolen_cleanup_compression(dev); -} static void i915_pineview_get_mem_freq(struct drm_device *dev) { @@ -6922,43 +6304,12 @@ void intel_suspend_hw(struct drm_device *dev) lpt_suspend_hw(dev); } -static void intel_init_fbc(struct drm_i915_private *dev_priv) -{ - if (!HAS_FBC(dev_priv)) { - dev_priv->fbc.enabled = false; - return; - } - - if (INTEL_INFO(dev_priv)->gen >= 7) { - dev_priv->display.fbc_enabled = ironlake_fbc_enabled; - dev_priv->display.enable_fbc = gen7_enable_fbc; - dev_priv->display.disable_fbc = ironlake_disable_fbc; - } else if (INTEL_INFO(dev_priv)->gen >= 5) { - dev_priv->display.fbc_enabled = ironlake_fbc_enabled; - dev_priv->display.enable_fbc = ironlake_enable_fbc; - dev_priv->display.disable_fbc = ironlake_disable_fbc; - } else if (IS_GM45(dev_priv)) { - dev_priv->display.fbc_enabled = g4x_fbc_enabled; - dev_priv->display.enable_fbc = g4x_enable_fbc; - dev_priv->display.disable_fbc = g4x_disable_fbc; - } else { - dev_priv->display.fbc_enabled = i8xx_fbc_enabled; - dev_priv->display.enable_fbc = i8xx_enable_fbc; - dev_priv->display.disable_fbc = i8xx_disable_fbc; - - /* This value was pulled out of someone's hat */ - I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); - } - - dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev); -} - /* Set up chip specific power management-related functions */ void intel_init_pm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - intel_init_fbc(dev_priv); + intel_fbc_init(dev_priv); /* For cxsr */ if (IS_PINEVIEW(dev)) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index bc5834b..c18e57d 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1004,7 +1004,7 @@ intel_post_enable_primary(struct drm_crtc *crtc) hsw_enable_ips(intel_crtc); mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); + intel_fbc_update(dev); mutex_unlock(&dev->struct_mutex); } @@ -1017,7 +1017,7 @@ intel_pre_disable_primary(struct drm_crtc *crtc) mutex_lock(&dev->struct_mutex); if (dev_priv->fbc.plane == intel_crtc->plane) - intel_disable_fbc(dev); + intel_fbc_disable(dev); mutex_unlock(&dev->struct_mutex); /* -- cgit v0.10.2 From 86ef630d53d6ae93f4a83fc3bfebaa111f8f83ce Mon Sep 17 00:00:00 2001 From: "Michael H. Nguyen" Date: Fri, 21 Nov 2014 09:35:36 -0800 Subject: drm/i915: Add MI_SET_APPID cmd to cmd parser tables Was missing. Issue: VIZ-4701 Signed-off-by: Michael H. Nguyen Reviewed-by: Jon Bloomfield Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 6e9eac4..b882bf2 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -152,6 +152,7 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = { CMD( MI_PREDICATE, SMI, F, 1, S ), CMD( MI_TOPOLOGY_FILTER, SMI, F, 1, S ), CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), + CMD( MI_SET_APPID, SMI, F, 1, S ), CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, R ), CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3F, B, @@ -210,6 +211,7 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { CMD( MI_SET_PREDICATE, SMI, F, 1, S ), CMD( MI_RS_CONTROL, SMI, F, 1, S ), CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ), + CMD( MI_SET_APPID, SMI, F, 1, S ), CMD( MI_RS_CONTEXT, SMI, F, 1, S ), CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), @@ -229,6 +231,7 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { static const struct drm_i915_cmd_descriptor video_cmds[] = { CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), + CMD( MI_SET_APPID, SMI, F, 1, S ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, .bits = {{ .offset = 0, @@ -272,6 +275,7 @@ static const struct drm_i915_cmd_descriptor video_cmds[] = { static const struct drm_i915_cmd_descriptor vecs_cmds[] = { CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), + CMD( MI_SET_APPID, SMI, F, 1, S ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, .bits = {{ .offset = 0, @@ -481,13 +485,17 @@ static u32 gen7_bsd_get_cmd_length_mask(u32 cmd_header) u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; u32 subclient = (cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT; + u32 op = (cmd_header & INSTR_26_TO_24_MASK) >> INSTR_26_TO_24_SHIFT; if (client == INSTR_MI_CLIENT) return 0x3F; else if (client == INSTR_RC_CLIENT) { - if (subclient == INSTR_MEDIA_SUBCLIENT) - return 0xFFF; - else + if (subclient == INSTR_MEDIA_SUBCLIENT) { + if (op == 6) + return 0xFFFF; + else + return 0xFFF; + } else return 0xFF; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 869e5ae..aa62899 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -207,6 +207,8 @@ #define INSTR_SUBCLIENT_SHIFT 27 #define INSTR_SUBCLIENT_MASK 0x18000000 #define INSTR_MEDIA_SUBCLIENT 0x2 +#define INSTR_26_TO_24_MASK 0x7000000 +#define INSTR_26_TO_24_SHIFT 24 /* * Memory interface instructions used by the kernel @@ -236,6 +238,7 @@ #define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) #define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0) #define MI_SUSPEND_FLUSH_EN (1<<0) +#define MI_SET_APPID MI_INSTR(0x0e, 0) #define MI_OVERLAY_FLIP MI_INSTR(0x11, 0) #define MI_OVERLAY_CONTINUE (0x0<<21) #define MI_OVERLAY_ON (0x1<<21) -- cgit v0.10.2 From 3c860ab40cf1719977b78ef58942b9be46013319 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Tue, 9 Dec 2014 10:57:00 +0530 Subject: drm/i915: Use DSI Pll1 for enabling MIPI DSI on Port C DSI Pll1 is used for enabling DSI on Port C. v2: Addressed review comments of Jani - Used & operator instead of == for intel_dsi->ports Signed-off-by: Gaurav K Singh Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 8957f10..3622d0b 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -241,9 +241,10 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder) return; } - dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL; + if (intel_dsi->ports & (1 << PORT_A)) + dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL; - if (intel_dsi->dual_link) + if (intel_dsi->ports & (1 << PORT_C)) dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL; DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n", -- cgit v0.10.2 From bf344e8090110a70bd630563e1324b103bdfecb2 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Sun, 7 Dec 2014 16:13:54 +0530 Subject: drm/i915: Enable MIPI PHY transparent latch for DSI Port C Common bit to be used for both DSI Port A & DSI Port C. Signed-off-by: Gaurav K Singh Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 8f8b952..215d004 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -177,7 +177,12 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder) usleep_range(2500, 3000); val = I915_READ(MIPI_PORT_CTRL(port)); - I915_WRITE(MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD); + + /* Enable MIPI PHY transparent latch + * Common bit for both MIPI Port A & MIPI Port C + * No similar bit in MIPI Port C reg + */ + I915_WRITE(MIPI_PORT_CTRL(PORT_A), val | LP_OUTPUT_HOLD); usleep_range(1000, 1500); I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT); -- cgit v0.10.2 From c0beefd29fcb1ca998f0f9ba41be8539f8eeba9b Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Tue, 9 Dec 2014 10:59:20 +0530 Subject: drm/i915: Software workaround for getting the HW status of DSI Port C on BYT Due to hardware limitations on BYT, MIPI Port C DPI Enable bit does not get set. To check whether DSI Port C was enabled in BIOS, check the Pipe B enable bit for DSI Port C. In hardware, DSI Port C is linked with Pipe B. v2: Addressed review comments of Jani, Nikula - Used platform checks for this software workaround for BYT Signed-off-by: Gaurav K Singh Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 215d004..42b6d6f 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -398,8 +398,10 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + struct drm_device *dev = encoder->base.dev; enum intel_display_power_domain power_domain; - u32 port_ctl, func; + u32 dpi_enabled, func; enum port port; DRM_DEBUG_KMS("\n"); @@ -409,13 +411,23 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, return false; /* XXX: this only works for one DSI output */ - for_each_dsi_port(port, (1 << PORT_A) | (1 << PORT_C)) { - port_ctl = I915_READ(MIPI_PORT_CTRL(port)); + for_each_dsi_port(port, intel_dsi->ports) { func = I915_READ(MIPI_DSI_FUNC_PRG(port)); + dpi_enabled = I915_READ(MIPI_PORT_CTRL(port)) & + DPI_ENABLE; + + /* Due to some hardware limitations on BYT, MIPI Port C DPI + * Enable bit does not get set. To check whether DSI Port C + * was enabled in BIOS, check the Pipe B enable bit + */ + if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) && + (port == PORT_C)) + dpi_enabled = I915_READ(PIPECONF(PIPE_B)) & + PIPECONF_ENABLE; - if ((port_ctl & DPI_ENABLE) || (func & CMD_MODE_DATA_WIDTH_MASK)) { + if (dpi_enabled || (func & CMD_MODE_DATA_WIDTH_MASK)) { if (I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY) { - *pipe = port == PORT_A ? PIPE_A : PIPE_C; + *pipe = port == PORT_A ? PIPE_A : PIPE_B; return true; } } -- cgit v0.10.2 From 94b8395755cca629d9f8fc66912cd56e13f35bf6 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 8 Dec 2014 06:46:31 -0800 Subject: drm/i915: Introduce FBC DocBook. No functional changes. v2 (Paulo): Rebase. v3: Accept Daniel's suggestions: * remove unclear and duplicated explanation. * remove marketing like doc and replace by a simple one. * remove bdw_fbc_sw_flush documentation. Signed-off-by: Rodrigo Vivi Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 56e2a9b..4fc5d73 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -3926,6 +3926,11 @@ int num_ioctls; !Idrivers/gpu/drm/i915/intel_psr.c + Frame Buffer Compression (FBC) +!Pdrivers/gpu/drm/i915/intel_fbc.c Frame Buffer Compression (FBC) +!Idrivers/gpu/drm/i915/intel_fbc.c + + DPIO !Pdrivers/gpu/drm/i915/i915_reg.h DPIO diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index f1eeb86..4daceae 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -21,20 +21,26 @@ * DEALINGS IN THE SOFTWARE. */ -#include "intel_drv.h" -#include "i915_drv.h" - -/* FBC, or Frame Buffer Compression, is a technique employed to compress the - * framebuffer contents in-memory, aiming at reducing the required bandwidth - * during in-memory transfers and, therefore, reduce the power packet. +/** + * DOC: Frame Buffer Compression (FBC) + * + * FBC tries to save memory bandwidth (and so power consumption) by + * compressing the amount of memory used by the display. It is total + * transparent to user space and completely handled in the kernel. * * The benefits of FBC are mostly visible with solid backgrounds and - * variation-less patterns. + * variation-less patterns. It comes from keeping the memory footprint small + * and having fewer memory pages opened and accessed for refreshing the display. * - * FBC-related functionality can be enabled by the means of the - * i915.i915_fbc_enable parameter + * i915 is responsible to reserve stolen memory for FBC and configure its + * offset on proper registers. The hardware takes care of all + * compress/decompress. However there are many known cases where we have to + * forcibly disable it to allow proper screen updates. */ +#include "intel_drv.h" +#include "i915_drv.h" + static void i8xx_fbc_disable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -318,6 +324,14 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } +/** + * intel_fbc_enabled - Is FBC enabled? + * @dev: the drm_device + * + * This function is used to verify the current state of FBC. + * FIXME: This should be tracked in the plane config eventually + * instead of queried at runtime for most callers. + */ bool intel_fbc_enabled(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -429,6 +443,12 @@ static void intel_fbc_enable(struct drm_crtc *crtc) schedule_delayed_work(&work->work, msecs_to_jiffies(50)); } +/** + * intel_fbc_disable - disable FBC + * @dev: the drm_device + * + * This function disables FBC. + */ void intel_fbc_disable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -643,6 +663,12 @@ out_disable: i915_gem_stolen_cleanup_compression(dev); } +/** + * intel_fbc_init - Initialize FBC + * @dev_priv: the i915 device + * + * This function might be called during PM init process. + */ void intel_fbc_init(struct drm_i915_private *dev_priv) { if (!HAS_FBC(dev_priv)) { -- cgit v0.10.2 From 16e5ab14d7828c461c346e78f9ba1e9bdd0257aa Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 9 Dec 2014 17:23:22 +0000 Subject: drm/i915: Add headers to the various render state intel-gpu-tools now generates the render state with license headers and the version of i-g-t that generated the files. A similar patch was previously sent but wasn't actually generated with the make target so was lacking the i-g-t revision. So here another version before we totally forget about this. Cc: Armin Reese Cc: Mika Kuoppala Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen6.c b/drivers/gpu/drm/i915/intel_renderstate_gen6.c index 56c1429..11c8e7b 100644 --- a/drivers/gpu/drm/i915/intel_renderstate_gen6.c +++ b/drivers/gpu/drm/i915/intel_renderstate_gen6.c @@ -1,3 +1,28 @@ +/* + * Copyright © 2014 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Generated by: intel-gpu-tools-1.8-220-g01153e7 + */ + #include "intel_renderstate.h" static const u32 gen6_null_state_relocs[] = { diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen7.c b/drivers/gpu/drm/i915/intel_renderstate_gen7.c index 419e35a..6551806 100644 --- a/drivers/gpu/drm/i915/intel_renderstate_gen7.c +++ b/drivers/gpu/drm/i915/intel_renderstate_gen7.c @@ -1,3 +1,28 @@ +/* + * Copyright © 2014 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Generated by: intel-gpu-tools-1.8-220-g01153e7 + */ + #include "intel_renderstate.h" static const u32 gen7_null_state_relocs[] = { diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen8.c b/drivers/gpu/drm/i915/intel_renderstate_gen8.c index 78011d7..95288a3 100644 --- a/drivers/gpu/drm/i915/intel_renderstate_gen8.c +++ b/drivers/gpu/drm/i915/intel_renderstate_gen8.c @@ -1,3 +1,28 @@ +/* + * Copyright © 2014 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Generated by: intel-gpu-tools-1.8-220-g01153e7 + */ + #include "intel_renderstate.h" static const u32 gen8_null_state_relocs[] = { diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen9.c b/drivers/gpu/drm/i915/intel_renderstate_gen9.c index 8750753..16a7ec2 100644 --- a/drivers/gpu/drm/i915/intel_renderstate_gen9.c +++ b/drivers/gpu/drm/i915/intel_renderstate_gen9.c @@ -1,3 +1,28 @@ +/* + * Copyright © 2014 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Generated by: intel-gpu-tools-1.8-220-g01153e7 + */ + #include "intel_renderstate.h" static const u32 gen9_null_state_relocs[] = { -- cgit v0.10.2 From eb736679aa7e6d6de647909fdf13075605927b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Dec 2014 21:28:28 +0200 Subject: drm/i915: Engage the DP scramble reset for pipe C on CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To get stable CRCs from the DP CRC source we need to reset the scrambler for each frame. Enable the reset feature when grabbing CRCs for pipe C on CHV. Pipes A and B were already covered due sharing the code with VLV. We can safely extend PIPE_SCRAMBLE_RESET_MASK to deal with CHV since the extra bit was MBZ on the older platforms. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d0e445e..d74b62d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3120,11 +3120,19 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev, uint32_t tmp = I915_READ(PORT_DFT2_G4X); tmp |= DC_BALANCE_RESET_VLV; - if (pipe == PIPE_A) + switch (pipe) { + case PIPE_A: tmp |= PIPE_A_SCRAMBLE_RESET; - else + break; + case PIPE_B: tmp |= PIPE_B_SCRAMBLE_RESET; - + break; + case PIPE_C: + tmp |= PIPE_C_SCRAMBLE_RESET; + break; + default: + return -EINVAL; + } I915_WRITE(PORT_DFT2_G4X, tmp); } @@ -3213,10 +3221,19 @@ static void vlv_undo_pipe_scramble_reset(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp = I915_READ(PORT_DFT2_G4X); - if (pipe == PIPE_A) + switch (pipe) { + case PIPE_A: tmp &= ~PIPE_A_SCRAMBLE_RESET; - else + break; + case PIPE_B: tmp &= ~PIPE_B_SCRAMBLE_RESET; + break; + case PIPE_C: + tmp &= ~PIPE_C_SCRAMBLE_RESET; + break; + default: + return; + } if (!(tmp & PIPE_SCRAMBLE_RESET_MASK)) tmp &= ~DC_BALANCE_RESET_VLV; I915_WRITE(PORT_DFT2_G4X, tmp); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index aa62899..451d526 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2789,7 +2789,8 @@ enum punit_power_well { #define DC_BALANCE_RESET (1 << 25) #define PORT_DFT2_G4X (dev_priv->info.display_mmio_offset + 0x61154) #define DC_BALANCE_RESET_VLV (1 << 31) -#define PIPE_SCRAMBLE_RESET_MASK (0x3 << 0) +#define PIPE_SCRAMBLE_RESET_MASK ((1 << 14) | (0x3 << 0)) +#define PIPE_C_SCRAMBLE_RESET (1 << 14) /* chv */ #define PIPE_B_SCRAMBLE_RESET (1 << 1) #define PIPE_A_SCRAMBLE_RESET (1 << 0) -- cgit v0.10.2 From 2be57922d46fdec4360ced2eb108832c5a90bc0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Dec 2014 21:28:29 +0200 Subject: drm/i915: Fix CRC support for DP port D on CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the missing CRC control register value for DP port D on CHV. Untested as I don't have a CHV machine with DP on port D. Signed-off-by: Ville Syrjälä [danvet: Add a check to only allow DP D on chv, not vlv.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d74b62d..0779e7f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3100,6 +3100,12 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev, *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_C_VLV; need_stable_symbols = true; break; + case INTEL_PIPE_CRC_SOURCE_DP_D: + if (!IS_CHERRYVIEW(dev)) + return -EINVAL; + *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_D_VLV; + need_stable_symbols = true; + break; case INTEL_PIPE_CRC_SOURCE_NONE: *val = 0; break; -- cgit v0.10.2 From 4252fbc3d4d3abd09ccc7598342cc930d09aac27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Dec 2014 21:28:30 +0200 Subject: drm/i915: Protect pipe_crc->entries update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the pipe_crc->entries pointer while holding the relevant spinlock. Doesn't matter too much since a spurious pipe crc interrupt would then just update one entry but later that entry would get cleared when head and tail are both set to 0. But being a bit more paranoid doesn't hurt. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 0779e7f..218e27c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3410,13 +3410,15 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, /* none -> real source transition */ if (source) { + struct intel_pipe_crc_entry *entries; + DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n", pipe_name(pipe), pipe_crc_source_name(source)); - pipe_crc->entries = kzalloc(sizeof(*pipe_crc->entries) * - INTEL_PIPE_CRC_ENTRIES_NR, - GFP_KERNEL); - if (!pipe_crc->entries) + entries = kzalloc(sizeof(*pipe_crc->entries) * + INTEL_PIPE_CRC_ENTRIES_NR, + GFP_KERNEL); + if (!entries) return -ENOMEM; /* @@ -3428,6 +3430,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, hsw_disable_ips(crtc); spin_lock_irq(&pipe_crc->lock); + pipe_crc->entries = entries; pipe_crc->head = 0; pipe_crc->tail = 0; spin_unlock_irq(&pipe_crc->lock); -- cgit v0.10.2 From 3cf54b34dafe800d9522b93249b6f4c1bfb50de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Dec 2014 21:28:31 +0200 Subject: drm/i915: Allocate the pipe_crc->entires with kcalloc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pipe_crc->entries[] is an array so allocate with kcalloc() instead of kzalloc(). Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 218e27c..95829eb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3415,8 +3415,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n", pipe_name(pipe), pipe_crc_source_name(source)); - entries = kzalloc(sizeof(*pipe_crc->entries) * - INTEL_PIPE_CRC_ENTRIES_NR, + entries = kcalloc(INTEL_PIPE_CRC_ENTRIES_NR, + sizeof(pipe_crc->entries[0]), GFP_KERNEL); if (!entries) return -ENOMEM; -- cgit v0.10.2 From 9ad6d99f189c274b42bedd6efc2b31a17ce733a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Dec 2014 21:28:32 +0200 Subject: drm/i915: Make i915_pipe_crc_read() oops proof MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently i915_pipe_crc_read() will drop pipe_crc->lock for the entire duration of the copy_to_user() loop, which means it'll access pipe_crc->entries without any protection. If another thread sneaks in and frees pipe_crc->entries the code will oops. Reorganize the code to hold the lock around everything except copy_to_user(). After the copy the lock is reacquired and the the number of available entries is rechecked. Since this is a debug feature simplify the error handling a bit by consuming the crc entry even if copy_to_user() would fail. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 95829eb..252b0b2 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2858,7 +2858,7 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; char buf[PIPE_CRC_BUFFER_LEN]; - int head, tail, n_entries, n; + int n_entries; ssize_t bytes_read; /* @@ -2890,36 +2890,39 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count, } /* We now have one or more entries to read */ - head = pipe_crc->head; - tail = pipe_crc->tail; - n_entries = min((size_t)CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR), - count / PIPE_CRC_LINE_LEN); - spin_unlock_irq(&pipe_crc->lock); + n_entries = count / PIPE_CRC_LINE_LEN; bytes_read = 0; - n = 0; - do { - struct intel_pipe_crc_entry *entry = &pipe_crc->entries[tail]; + while (n_entries > 0) { + struct intel_pipe_crc_entry *entry = + &pipe_crc->entries[pipe_crc->tail]; int ret; + if (CIRC_CNT(pipe_crc->head, pipe_crc->tail, + INTEL_PIPE_CRC_ENTRIES_NR) < 1) + break; + + BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR); + pipe_crc->tail = (pipe_crc->tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); + bytes_read += snprintf(buf, PIPE_CRC_BUFFER_LEN, "%8u %8x %8x %8x %8x %8x\n", entry->frame, entry->crc[0], entry->crc[1], entry->crc[2], entry->crc[3], entry->crc[4]); - ret = copy_to_user(user_buf + n * PIPE_CRC_LINE_LEN, - buf, PIPE_CRC_LINE_LEN); + spin_unlock_irq(&pipe_crc->lock); + + ret = copy_to_user(user_buf, buf, PIPE_CRC_LINE_LEN); if (ret == PIPE_CRC_LINE_LEN) return -EFAULT; - BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR); - tail = (tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); - n++; - } while (--n_entries); + user_buf += PIPE_CRC_LINE_LEN; + n_entries--; + + spin_lock_irq(&pipe_crc->lock); + } - spin_lock_irq(&pipe_crc->lock); - pipe_crc->tail = tail; spin_unlock_irq(&pipe_crc->lock); return bytes_read; @@ -3458,6 +3461,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, spin_lock_irq(&pipe_crc->lock); entries = pipe_crc->entries; pipe_crc->entries = NULL; + pipe_crc->head = 0; + pipe_crc->tail = 0; spin_unlock_irq(&pipe_crc->lock); kfree(entries); -- cgit v0.10.2 From 64387b613a43713d0e03d9d43bfbb1727e8475e1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 10 Dec 2014 11:00:29 +0100 Subject: drm/i915: Protect against leaks in pipe_crc_set_source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stupid userspace (there is no evil userspace in debugfs by assumption) might provoke a leak since we allocate the new array without holding any locks. Drop in an unconditional kfree to deal with this - kfree can handle NULL. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 252b0b2..165a38f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3433,6 +3433,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, hsw_disable_ips(crtc); spin_lock_irq(&pipe_crc->lock); + kfree(pipe_crc->entries); pipe_crc->entries = entries; pipe_crc->head = 0; pipe_crc->tail = 0; -- cgit v0.10.2 From 1a2520582ec7e7f802a4a22b6ff6db8e49cf6929 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Wed, 10 Dec 2014 09:43:37 +0000 Subject: drm/i915/bdw: Add WaForceEnableNonCoherent label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already implement this workaround, but it was missing its name. Reviewed-by: Ville Syrjälä Signed-off-by: Michel Thierry Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a8dc158..f1ce169 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -782,6 +782,7 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) * workaround for for a possible hang in the unlikely event a TLB * invalidation occurs during a PSD flush. */ + /* WaForceEnableNonCoherent:bdw */ /* WaHdcDisableFetchWhenMasked:bdw */ /* WaDisableFenceDestinationToSLM:bdw (GT3 pre-production) */ WA_SET_BIT_MASKED(HDC_CHICKEN0, -- cgit v0.10.2 From ae28290be3871969fc3f64b480d42575a16ae990 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 10 Dec 2014 12:17:41 -0500 Subject: drm: bit of spell-check / editorializing. Signed-off-by: Rob Clark Signed-off-by: Daniel Vetter diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 86574b0..aae71cb 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -338,7 +338,7 @@ struct drm_mode_fb_cmd2 { /* * In case of planar formats, this ioctl allows up to 4 - * buffer objects with offets and pitches per plane. + * buffer objects with offsets and pitches per plane. * The pitch and offset order is dictated by the fourcc, * e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as: * @@ -346,9 +346,9 @@ struct drm_mode_fb_cmd2 { * followed by an interleaved U/V plane containing * 8 bit 2x2 subsampled colour difference samples. * - * So it would consist of Y as offset[0] and UV as - * offeset[1]. Note that offset[0] will generally - * be 0. + * So it would consist of Y as offsets[0] and UV as + * offsets[1]. Note that offsets[0] will generally + * be 0 (but this is not required). */ __u32 handles[4]; __u32 pitches[4]; /* pitch for each plane */ -- cgit v0.10.2 From c631c7156fc6dc50758ad99b5600c1eebd88c6a6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 10 Dec 2014 21:11:31 +0200 Subject: drm/doc: Document drm_add_modes_noedid() usage And fix a spelling mistake. Signed-off-by: Laurent Pinchart Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index b344bc3..3e212b9 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1947,10 +1947,16 @@ void intel_crt_init(struct drm_device *dev) and then retrieves a list of modes by calling the connector get_modes helper operation. + + If the helper operation returns no mode, and if the connector status + is connector_status_connected, standard VESA DMT modes up to + 1024x768 are automatically added to the modes list by a call to + drm_add_modes_noedid. + - The function filters out modes larger than + The function then filters out modes larger than max_width and max_height - if specified. It then calls the optional connector + if specified. It finally calls the optional connector mode_valid helper operation for each mode in the probed list to check whether the mode is valid for the connector. @@ -2090,12 +2096,20 @@ void intel_crt_init(struct drm_device *dev) int (*get_modes)(struct drm_connector *connector); Fill the connector's probed_modes list - by parsing EDID data with drm_add_edid_modes or - calling drm_mode_probed_add directly for every + by parsing EDID data with drm_add_edid_modes, + adding standard VESA DMT modes with drm_add_modes_noedid, + or calling drm_mode_probed_add directly for every supported mode and return the number of modes it has detected. This operation is mandatory. + Note that the caller function will automatically add standard VESA + DMT modes up to 1024x768 if the get_modes + helper operation returns no mode and if the connector status is + connector_status_connected. There is no need to call + drm_add_edid_modes manually in that case. + + When adding modes manually the driver creates each mode with a call to drm_mode_create and must fill the following fields. @@ -2292,7 +2306,7 @@ void intel_crt_init(struct drm_device *dev) drm_helper_probe_single_connector_modes. - When parsing EDID data, drm_add_edid_modes fill the + When parsing EDID data, drm_add_edid_modes fills the connector display_info width_mm and height_mm fields. When creating modes -- cgit v0.10.2 From 7432ca5acec8a24a7e576c92d28449e2d790b734 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 11 Dec 2014 07:20:57 -0800 Subject: drm/plane-helper: Test for plane disable earlier drm_plane_helper_check_update() currently uses crtc before testing whether we're disabling the plane (fb == NULL). Move the fb test before the first crtc usage so that crtc == NULL doesn't have to be handled by the caller. Signed-off-by: Matt Roper Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 18a1ac6..391dfb7 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -142,6 +142,17 @@ int drm_plane_helper_check_update(struct drm_plane *plane, { int hscale, vscale; + if (!fb) { + *visible = false; + return 0; + } + + /* crtc should only be NULL when disabling (i.e., !fb) */ + if (WARN_ON(!crtc)) { + *visible = false; + return 0; + } + if (!crtc->enabled && !can_update_disabled) { DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n"); return -EINVAL; @@ -155,11 +166,6 @@ int drm_plane_helper_check_update(struct drm_plane *plane, return -ERANGE; } - if (!fb) { - *visible = false; - return 0; - } - *visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale); if (!*visible) /* -- cgit v0.10.2 From 3f7531c3b37d232122d5b7c8564d4ea800adaa88 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 10 Dec 2014 17:41:43 +0100 Subject: drm/i915: Name the lrc irq handler correctly We consistently use the _irq_handler postfix for functions called in hardirq context. Especially when it's a non-static function hardirq is a crazy enough calling context to warrant this level of ocd. So rename it. Cc: Thomas Daniel Reviewed-by: Thomas Daniel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e6a1db3..e3dd2d6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1385,14 +1385,14 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, if (rcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, ring); if (rcs & GT_CONTEXT_SWITCH_INTERRUPT) - intel_execlists_handle_ctx_events(ring); + intel_lrc_irq_handler(ring); bcs = tmp >> GEN8_BCS_IRQ_SHIFT; ring = &dev_priv->ring[BCS]; if (bcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, ring); if (bcs & GT_CONTEXT_SWITCH_INTERRUPT) - intel_execlists_handle_ctx_events(ring); + intel_lrc_irq_handler(ring); } else DRM_ERROR("The master control interrupt lied (GT0)!\n"); } @@ -1408,14 +1408,14 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, if (vcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, ring); if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) - intel_execlists_handle_ctx_events(ring); + intel_lrc_irq_handler(ring); vcs = tmp >> GEN8_VCS2_IRQ_SHIFT; ring = &dev_priv->ring[VCS2]; if (vcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, ring); if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) - intel_execlists_handle_ctx_events(ring); + intel_lrc_irq_handler(ring); } else DRM_ERROR("The master control interrupt lied (GT1)!\n"); } @@ -1442,7 +1442,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, if (vcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, ring); if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) - intel_execlists_handle_ctx_events(ring); + intel_lrc_irq_handler(ring); } else DRM_ERROR("The master control interrupt lied (GT3)!\n"); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a82020e..89b5577 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -474,13 +474,13 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring, } /** - * intel_execlists_handle_ctx_events() - handle Context Switch interrupts + * intel_lrc_irq_handler() - handle Context Switch interrupts * @ring: Engine Command Streamer to handle. * * Check the unread Context Status Buffers and manage the submission of new * contexts to the ELSP accordingly. */ -void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring) +void intel_lrc_irq_handler(struct intel_engine_cs *ring) { struct drm_i915_private *dev_priv = ring->dev->dev_private; u32 status_pointer; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 14b216b..960fcbd 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -112,7 +112,7 @@ struct intel_ctx_submit_request { int elsp_submitted; }; -void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring); +void intel_lrc_irq_handler(struct intel_engine_cs *ring); void intel_execlists_retire_requests(struct intel_engine_cs *ring); #endif /* _INTEL_LRC_H_ */ -- cgit v0.10.2 From 5f77eeb05c9ee1de03fbe695b41362aae401726a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 8 Dec 2014 16:40:10 +0100 Subject: drm/i915: Use BUILD_BUG if possible in the i915 WARN_ON Faster feedback to errors is always better. This is inspired by the addition to WARN_ONs to mask/enable helpers for registers to make sure callers have the arguments ordered correctly: Pretty much always the arguments are static. We use WARN_ON(1) a lot in default switch statements though where we should always handle all cases. So add a new macro specifically for that. The idea to use __builtin_constant_p is from Chris Wilson. v2: Use the ({}) gcc-ism to avoid the static inline, suggested by Dave. My first attempt used __cond as the temp var, which is the same used by BUILD_BUG_ON, but with inverted sense. Hilarity ensued, so sprinkle i915 into the name. Also use a temporary variable to only evaluate the condition once, suggested by Damien. v3: It's crazy but apparently 32bit gcc can't compile out the BUILD_BUG_ON in a lot of cases and just falls over. I have no idea why, but until clue grows just disable this nifty idea on 32bit builds. Reported by 0-day builder. v4: Got it all wrong, apparently its the gcc version. We need 4.9+. Now reported by Imre. v5: Chris suggested to add the case to MISSING_CASE for speedier debug. v6: Even some gcc 4.9 versions don't see through the maze, so give up for now. Keep the skeleton and MISSING_CASE stuff though. Cc: Imre Deak Cc: Damien Lespiau Cc: Chris Wilson Cc: Jani Nikula Cc: Dave Gordon Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 165a38f..479e0c1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2347,7 +2347,7 @@ static const char *power_domain_str(enum intel_display_power_domain domain) case POWER_DOMAIN_INIT: return "INIT"; default: - WARN_ON(1); + MISSING_CASE(domain); return "?"; } } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c74dc94..5f4cca3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -58,7 +58,19 @@ #define DRIVER_DATE "20141205" #undef WARN_ON -#define WARN_ON(x) WARN(x, "WARN_ON(" #x ")") +/* Many gcc seem to no see through this and fall over :( */ +#if 0 +#define WARN_ON(x) ({ \ + bool __i915_warn_cond = (x); \ + if (__builtin_constant_p(__i915_warn_cond)) \ + BUILD_BUG_ON(__i915_warn_cond); \ + WARN(__i915_warn_cond, "WARN_ON(" #x ")"); }) +#else +#define WARN_ON(x) WARN((x), "WARN_ON(" #x ")") +#endif + +#define MISSING_CASE(x) WARN(1, "Missing switch case (%lu) in %s\n", \ + (long) (x), __func__); enum pipe { INVALID_PIPE = -1, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ac03a38..ce4e46c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -132,7 +132,7 @@ static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr, pte |= GEN6_PTE_UNCACHED; break; default: - WARN_ON(1); + MISSING_CASE(level); } return pte; @@ -156,7 +156,7 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr, pte |= GEN6_PTE_UNCACHED; break; default: - WARN_ON(1); + MISSING_CASE(level); } return pte; @@ -1146,7 +1146,7 @@ int i915_ppgtt_init_hw(struct drm_device *dev) else if (INTEL_INFO(dev)->gen >= 8) gen8_ppgtt_enable(dev); else - WARN_ON(1); + MISSING_CASE(INTEL_INFO(dev)->gen); if (ppgtt) { for_each_ring(ring, dev_priv, i) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 841af6c..878c485 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4847,7 +4847,7 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk) cmd = 0; break; default: - WARN_ON(1); + MISSING_CASE(cdclk); return; } @@ -8224,7 +8224,7 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) cntl |= CURSOR_MODE_256_ARGB_AX; break; default: - WARN_ON(1); + MISSING_CASE(intel_crtc->cursor_width); return; } cntl |= pipe << 28; /* Connect to correct pipe */ diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 46de8d7..883d2fe 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1202,7 +1202,7 @@ void intel_uncore_init(struct drm_device *dev) switch (INTEL_INFO(dev)->gen) { default: - WARN_ON(1); + MISSING_CASE(INTEL_INFO(dev)->gen); return; case 9: ASSIGN_WRITE_MMIO_VFUNCS(gen9); @@ -1300,7 +1300,7 @@ int i915_reg_read_ioctl(struct drm_device *dev, reg->val = I915_READ8(reg->offset); break; default: - WARN_ON(1); + MISSING_CASE(entry->size); ret = -EINVAL; goto out; } -- cgit v0.10.2 From f915084edc5aad351d6a4675b0bcdded9a00090d Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Wed, 10 Dec 2014 22:07:40 +0530 Subject: drm/i915: Changes related to the sequence port no for From now on for both DSI Ports A & C, the seq_port value has been set to 0. seq_port value is parsed from Sequence block#53 of VBT. So, for packets that needs to be read/write for DSI single link on Port A and Port C will now be based on the DVO port from VBT block 2, instead of seq_port. Signed-off-by: Gaurav K Singh Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index f8c2269..5493aef 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -110,7 +110,15 @@ static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data) vc = (byte >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 0x3; seq_port = (byte >> MIPI_PORT_SHIFT) & 0x3; - port = intel_dsi_seq_port_to_port(seq_port); + /* For DSI single link on Port A & C, the seq_port value which is + * parsed from Sequence Block#53 of VBT has been set to 0 + * Now, read/write of packets for the DSI single link on Port A and + * Port C will based on the DVO port from VBT block 2. + */ + if (intel_dsi->ports == (1 << PORT_C)) + port = PORT_C; + else + port = intel_dsi_seq_port_to_port(seq_port); /* LP or HS mode */ intel_dsi->hs = mode; -- cgit v0.10.2 From db5ff4ac97f6602360645414b698a05f91b40542 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Thu, 11 Dec 2014 21:42:49 +0530 Subject: drm/i915: Forcewake Register Range changes for CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to updated BSpec, Render/Common/media Wells register range changed. Updating the same to match the spec and avoid extra forcewake for none forcewake range. v2: Update media forcewake range (Ville) Signed-off-by: Deepak S Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 883d2fe..e9561de 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -647,9 +647,9 @@ void assert_force_wake_inactive(struct drm_i915_private *dev_priv) #define FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg) \ (REG_RANGE((reg), 0x2000, 0x4000) || \ - REG_RANGE((reg), 0x5000, 0x8000) || \ + REG_RANGE((reg), 0x5200, 0x8000) || \ REG_RANGE((reg), 0x8300, 0x8500) || \ - REG_RANGE((reg), 0xB000, 0xC000) || \ + REG_RANGE((reg), 0xB000, 0xB480) || \ REG_RANGE((reg), 0xE000, 0xE800)) #define FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg) \ @@ -658,17 +658,14 @@ void assert_force_wake_inactive(struct drm_i915_private *dev_priv) REG_RANGE((reg), 0x12000, 0x14000) || \ REG_RANGE((reg), 0x1A000, 0x1C000) || \ REG_RANGE((reg), 0x1E800, 0x1EA00) || \ - REG_RANGE((reg), 0x30000, 0x40000)) + REG_RANGE((reg), 0x30000, 0x38000)) #define FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg) \ (REG_RANGE((reg), 0x4000, 0x5000) || \ REG_RANGE((reg), 0x8000, 0x8300) || \ REG_RANGE((reg), 0x8500, 0x8600) || \ REG_RANGE((reg), 0x9000, 0xB000) || \ - REG_RANGE((reg), 0xC000, 0xC800) || \ - REG_RANGE((reg), 0xF000, 0x10000) || \ - REG_RANGE((reg), 0x14000, 0x14400) || \ - REG_RANGE((reg), 0x22000, 0x24000)) + REG_RANGE((reg), 0xF000, 0x10000)) #define FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg) \ REG_RANGE((reg), 0xB00, 0x2000) -- cgit v0.10.2 From fe14d5f4e5468c5b80a24f1a64abcbe116143670 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 10 Dec 2014 17:27:58 +0000 Subject: drm/i915: Infrastructure for supporting different GGTT views per object Things like reliable GGTT mappings and mirrored 2d-on-3d display will need to map objects into the same address space multiple times. Added a GGTT view concept and linked it with the VMA to distinguish between multiple instances per address space. New objects and GEM functions which do not take this new view as a parameter assume the default of zero (I915_GGTT_VIEW_NORMAL) which preserves the previous behaviour. This now means that objects can have multiple VMA entries so the code which assumed there will only be one also had to be modified. Alternative GGTT views are supposed to borrow DMA addresses from obj->pages which is DMA mapped on first VMA instantiation and unmapped on the last one going away. v2: * Removed per view special casing in i915_gem_ggtt_prepare / finish_object in favour of creating and destroying DMA mappings on first VMA instantiation and last VMA destruction. (Daniel Vetter) * Simplified i915_vma_unbind which does not need to count the GGTT views. (Daniel Vetter) * Also moved obj->map_and_fenceable reset under the same check. * Checkpatch cleanups. v3: * Only retire objects once the last VMA is unbound. v4: * Keep scatter-gather table for alternative views persistent for the lifetime of the VMA. * Propagate binding errors to callers and handle appropriately. v5: * Explicitly look for normal GGTT view in i915_gem_obj_bound to align usage in i915_gem_object_ggtt_unpin. (Michel Thierry) * Change to single if statement in i915_gem_obj_to_ggtt. (Michel Thierry) * Removed stray semi-colon in i915_gem_object_set_cache_level. For: VIZ-4544 Signed-off-by: Tvrtko Ursulin Cc: Daniel Vetter Reviewed-by: Michel Thierry [danvet: Drop hunk from i915_gem_shrink since it's just prettification but upsets a __must_check warning.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 479e0c1..8d2988a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -152,8 +152,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) seq_puts(m, " (pp"); else seq_puts(m, " (g"); - seq_printf(m, "gtt offset: %08lx, size: %08lx)", - vma->node.start, vma->node.size); + seq_printf(m, "gtt offset: %08lx, size: %08lx, type: %u)", + vma->node.start, vma->node.size, + vma->ggtt_view.type); } if (obj->stolen) seq_printf(m, " (stolen: %08lx)", obj->stolen->start); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5f4cca3..eb47990 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2530,10 +2530,23 @@ void i915_gem_vma_destroy(struct i915_vma *vma); #define PIN_GLOBAL 0x4 #define PIN_OFFSET_BIAS 0x8 #define PIN_OFFSET_MASK (~4095) +int __must_check i915_gem_object_pin_view(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + uint32_t alignment, + uint64_t flags, + const struct i915_ggtt_view *view); +static inline int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, struct i915_address_space *vm, uint32_t alignment, - uint64_t flags); + uint64_t flags) +{ + return i915_gem_object_pin_view(obj, vm, alignment, flags, + &i915_ggtt_view_normal); +} + +int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level, + u32 flags); int __must_check i915_vma_unbind(struct i915_vma *vma); int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv); @@ -2695,18 +2708,51 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev, void i915_gem_restore_fences(struct drm_device *dev); +unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o, + struct i915_address_space *vm, + enum i915_ggtt_view_type view); +static inline unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o, - struct i915_address_space *vm); + struct i915_address_space *vm) +{ + return i915_gem_obj_offset_view(o, vm, I915_GGTT_VIEW_NORMAL); +} bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o); +bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o, + struct i915_address_space *vm, + enum i915_ggtt_view_type view); +static inline bool i915_gem_obj_bound(struct drm_i915_gem_object *o, - struct i915_address_space *vm); + struct i915_address_space *vm) +{ + return i915_gem_obj_bound_view(o, vm, I915_GGTT_VIEW_NORMAL); +} + unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o, struct i915_address_space *vm); +struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + const struct i915_ggtt_view *view); +static inline struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, - struct i915_address_space *vm); + struct i915_address_space *vm) +{ + return i915_gem_obj_to_vma_view(obj, vm, &i915_ggtt_view_normal); +} + +struct i915_vma * +i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + const struct i915_ggtt_view *view); + +static inline struct i915_vma * i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, - struct i915_address_space *vm); + struct i915_address_space *vm) +{ + return i915_gem_obj_lookup_or_create_vma_view(obj, vm, + &i915_ggtt_view_normal); +} struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj); static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) { diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e3ce4be..c26d4cc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2297,17 +2297,14 @@ void i915_vma_move_to_active(struct i915_vma *vma, static void i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - struct i915_address_space *vm; struct i915_vma *vma; BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); BUG_ON(!obj->active); - list_for_each_entry(vm, &dev_priv->vm_list, global_link) { - vma = i915_gem_obj_to_vma(obj, vm); - if (vma && !list_empty(&vma->mm_list)) - list_move_tail(&vma->mm_list, &vm->inactive_list); + list_for_each_entry(vma, &obj->vma_list, vma_link) { + if (!list_empty(&vma->mm_list)) + list_move_tail(&vma->mm_list, &vma->vm->inactive_list); } intel_fb_obj_flush(obj, true); @@ -3062,10 +3059,8 @@ int i915_vma_unbind(struct i915_vma *vma) * cause memory corruption through use-after-free. */ - /* Throw away the active reference before moving to the unbound list */ - i915_gem_object_retire(obj); - - if (i915_is_ggtt(vma->vm)) { + if (i915_is_ggtt(vma->vm) && + vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) { i915_gem_object_finish_gtt(obj); /* release the fence reg _after_ flushing */ @@ -3079,8 +3074,15 @@ int i915_vma_unbind(struct i915_vma *vma) vma->unbind_vma(vma); list_del_init(&vma->mm_list); - if (i915_is_ggtt(vma->vm)) - obj->map_and_fenceable = false; + if (i915_is_ggtt(vma->vm)) { + if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) { + obj->map_and_fenceable = false; + } else if (vma->ggtt_view.pages) { + sg_free_table(vma->ggtt_view.pages); + kfree(vma->ggtt_view.pages); + vma->ggtt_view.pages = NULL; + } + } drm_mm_remove_node(&vma->node); i915_gem_vma_destroy(vma); @@ -3088,6 +3090,10 @@ int i915_vma_unbind(struct i915_vma *vma) /* Since the unbound list is global, only move to that list if * no more VMAs exist. */ if (list_empty(&obj->vma_list)) { + /* Throw away the active reference before + * moving to the unbound list. */ + i915_gem_object_retire(obj); + i915_gem_gtt_finish_object(obj); list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list); } @@ -3498,7 +3504,8 @@ static struct i915_vma * i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, struct i915_address_space *vm, unsigned alignment, - uint64_t flags) + uint64_t flags, + const struct i915_ggtt_view *view) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -3548,7 +3555,7 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, i915_gem_object_pin_pages(obj); - vma = i915_gem_obj_lookup_or_create_vma(obj, vm); + vma = i915_gem_obj_lookup_or_create_vma_view(obj, vm, view); if (IS_ERR(vma)) goto err_unpin; @@ -3578,15 +3585,19 @@ search_free: if (ret) goto err_remove_node; + trace_i915_vma_bind(vma, flags); + ret = i915_vma_bind(vma, obj->cache_level, + flags & PIN_GLOBAL ? GLOBAL_BIND : 0); + if (ret) + goto err_finish_gtt; + list_move_tail(&obj->global_list, &dev_priv->mm.bound_list); list_add_tail(&vma->mm_list, &vm->inactive_list); - trace_i915_vma_bind(vma, flags); - vma->bind_vma(vma, obj->cache_level, - flags & PIN_GLOBAL ? GLOBAL_BIND : 0); - return vma; +err_finish_gtt: + i915_gem_gtt_finish_object(obj); err_remove_node: drm_mm_remove_node(&vma->node); err_free_vma: @@ -3789,9 +3800,12 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, } list_for_each_entry(vma, &obj->vma_list, vma_link) - if (drm_mm_node_allocated(&vma->node)) - vma->bind_vma(vma, cache_level, - vma->bound & GLOBAL_BIND); + if (drm_mm_node_allocated(&vma->node)) { + ret = i915_vma_bind(vma, cache_level, + vma->bound & GLOBAL_BIND); + if (ret) + return ret; + } } list_for_each_entry(vma, &obj->vma_list, vma_link) @@ -4144,10 +4158,11 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags) } int -i915_gem_object_pin(struct drm_i915_gem_object *obj, - struct i915_address_space *vm, - uint32_t alignment, - uint64_t flags) +i915_gem_object_pin_view(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + uint32_t alignment, + uint64_t flags, + const struct i915_ggtt_view *view) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; struct i915_vma *vma; @@ -4163,7 +4178,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE)) return -EINVAL; - vma = i915_gem_obj_to_vma(obj, vm); + vma = i915_gem_obj_to_vma_view(obj, vm, view); if (vma) { if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) return -EBUSY; @@ -4173,7 +4188,8 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, "bo is already pinned with incorrect alignment:" " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d," " obj->map_and_fenceable=%d\n", - i915_gem_obj_offset(obj, vm), alignment, + i915_gem_obj_offset_view(obj, vm, view->type), + alignment, !!(flags & PIN_MAPPABLE), obj->map_and_fenceable); ret = i915_vma_unbind(vma); @@ -4186,13 +4202,17 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, bound = vma ? vma->bound : 0; if (vma == NULL || !drm_mm_node_allocated(&vma->node)) { - vma = i915_gem_object_bind_to_vm(obj, vm, alignment, flags); + vma = i915_gem_object_bind_to_vm(obj, vm, alignment, + flags, view); if (IS_ERR(vma)) return PTR_ERR(vma); } - if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) - vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND); + if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) { + ret = i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND); + if (ret) + return ret; + } if ((bound ^ vma->bound) & GLOBAL_BIND) { bool mappable, fenceable; @@ -4528,12 +4548,13 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) intel_runtime_pm_put(dev_priv); } -struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, - struct i915_address_space *vm) +struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + const struct i915_ggtt_view *view) { struct i915_vma *vma; list_for_each_entry(vma, &obj->vma_list, vma_link) - if (vma->vm == vm) + if (vma->vm == vm && vma->ggtt_view.type == view->type) return vma; return NULL; @@ -5145,8 +5166,9 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) } /* All the new VM stuff */ -unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o, - struct i915_address_space *vm) +unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o, + struct i915_address_space *vm, + enum i915_ggtt_view_type view) { struct drm_i915_private *dev_priv = o->base.dev->dev_private; struct i915_vma *vma; @@ -5154,7 +5176,7 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o, WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base); list_for_each_entry(vma, &o->vma_list, vma_link) { - if (vma->vm == vm) + if (vma->vm == vm && vma->ggtt_view.type == view) return vma->node.start; } @@ -5163,13 +5185,16 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o, return -1; } -bool i915_gem_obj_bound(struct drm_i915_gem_object *o, - struct i915_address_space *vm) +bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o, + struct i915_address_space *vm, + enum i915_ggtt_view_type view) { struct i915_vma *vma; list_for_each_entry(vma, &o->vma_list, vma_link) - if (vma->vm == vm && drm_mm_node_allocated(&vma->node)) + if (vma->vm == vm && + vma->ggtt_view.type == view && + drm_mm_node_allocated(&vma->node)) return true; return false; @@ -5304,10 +5329,10 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj) struct i915_address_space *ggtt = i915_obj_to_ggtt(obj); struct i915_vma *vma; - list_for_each_entry(vma, &obj->vma_list, vma_link) { - if (vma->vm == ggtt) + list_for_each_entry(vma, &obj->vma_list, vma_link) + if (vma->vm == ggtt && + vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) return vma; - } return NULL; } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 2acf580..b9deade 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -590,9 +590,14 @@ static int do_switch(struct intel_engine_cs *ring, goto unpin_out; vma = i915_gem_obj_to_ggtt(to->legacy_hw_ctx.rcs_state); - if (!(vma->bound & GLOBAL_BIND)) - vma->bind_vma(vma, to->legacy_hw_ctx.rcs_state->cache_level, - GLOBAL_BIND); + if (!(vma->bound & GLOBAL_BIND)) { + ret = i915_vma_bind(vma, + to->legacy_hw_ctx.rcs_state->cache_level, + GLOBAL_BIND); + /* This shouldn't ever fail. */ + if (WARN_ONCE(ret, "GGTT context bind failed!")) + goto unpin_out; + } if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to)) hw_flags |= MI_RESTORE_INHIBIT; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 0c25f62..3927d93 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -360,9 +360,12 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, * through the ppgtt for non_secure batchbuffers. */ if (unlikely(IS_GEN6(dev) && reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION && - !(target_vma->bound & GLOBAL_BIND))) - target_vma->bind_vma(target_vma, target_i915_obj->cache_level, - GLOBAL_BIND); + !(target_vma->bound & GLOBAL_BIND))) { + ret = i915_vma_bind(target_vma, target_i915_obj->cache_level, + GLOBAL_BIND); + if (WARN_ONCE(ret, "Unexpected failure to bind target VMA!")) + return ret; + } /* Validate that the target is in a valid r/w GPU domain */ if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ce4e46c..9821a60 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -30,6 +30,8 @@ #include "i915_trace.h" #include "intel_drv.h" +const struct i915_ggtt_view i915_ggtt_view_normal; + static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv); static void chv_setup_private_ppat(struct drm_i915_private *dev_priv); @@ -1341,9 +1343,12 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) /* The bind_vma code tries to be smart about tracking mappings. * Unfortunately above, we've just wiped out the mappings * without telling our object about it. So we need to fake it. + * + * Bind is not expected to fail since this is only called on + * resume and assumption is all requirements exist already. */ vma->bound &= ~GLOBAL_BIND; - vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND); + WARN_ON(i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND)); } @@ -1538,7 +1543,7 @@ static void i915_ggtt_bind_vma(struct i915_vma *vma, AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; BUG_ON(!i915_is_ggtt(vma->vm)); - intel_gtt_insert_sg_entries(vma->obj->pages, entry, flags); + intel_gtt_insert_sg_entries(vma->ggtt_view.pages, entry, flags); vma->bound = GLOBAL_BIND; } @@ -1588,7 +1593,7 @@ static void ggtt_bind_vma(struct i915_vma *vma, if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) { if (!(vma->bound & GLOBAL_BIND) || (cache_level != obj->cache_level)) { - vma->vm->insert_entries(vma->vm, obj->pages, + vma->vm->insert_entries(vma->vm, vma->ggtt_view.pages, vma->node.start, cache_level, flags); vma->bound |= GLOBAL_BIND; @@ -1600,7 +1605,7 @@ static void ggtt_bind_vma(struct i915_vma *vma, (cache_level != obj->cache_level))) { struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt; appgtt->base.insert_entries(&appgtt->base, - vma->obj->pages, + vma->ggtt_view.pages, vma->node.start, cache_level, flags); vma->bound |= LOCAL_BIND; @@ -2165,7 +2170,8 @@ int i915_gem_gtt_init(struct drm_device *dev) } static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, - struct i915_address_space *vm) + struct i915_address_space *vm, + const struct i915_ggtt_view *view) { struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL); if (vma == NULL) @@ -2176,6 +2182,7 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, INIT_LIST_HEAD(&vma->exec_list); vma->vm = vm; vma->obj = obj; + vma->ggtt_view = *view; switch (INTEL_INFO(vm->dev)->gen) { case 9: @@ -2210,14 +2217,59 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, } struct i915_vma * -i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, - struct i915_address_space *vm) +i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj, + struct i915_address_space *vm, + const struct i915_ggtt_view *view) { struct i915_vma *vma; - vma = i915_gem_obj_to_vma(obj, vm); + vma = i915_gem_obj_to_vma_view(obj, vm, view); if (!vma) - vma = __i915_gem_vma_create(obj, vm); + vma = __i915_gem_vma_create(obj, vm, view); return vma; } + +static inline +int i915_get_vma_pages(struct i915_vma *vma) +{ + if (vma->ggtt_view.pages) + return 0; + + if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) + vma->ggtt_view.pages = vma->obj->pages; + else + WARN_ONCE(1, "GGTT view %u not implemented!\n", + vma->ggtt_view.type); + + if (!vma->ggtt_view.pages) { + DRM_ERROR("Failed to get pages for VMA view type %u!\n", + vma->ggtt_view.type); + return -EINVAL; + } + + return 0; +} + +/** + * i915_vma_bind - Sets up PTEs for an VMA in it's corresponding address space. + * @vma: VMA to map + * @cache_level: mapping cache level + * @flags: flags like global or local mapping + * + * DMA addresses are taken from the scatter-gather table of this object (or of + * this VMA in case of non-default GGTT views) and PTE entries set up. + * Note that DMA addresses are also the only part of the SG table we care about. + */ +int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level, + u32 flags) +{ + int ret = i915_get_vma_pages(vma); + + if (ret) + return ret; + + vma->bind_vma(vma, cache_level, flags); + + return 0; +} diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index dd849df..e377c7d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -109,7 +109,20 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t; #define GEN8_PPAT_ELLC_OVERRIDE (0<<2) #define GEN8_PPAT(i, x) ((uint64_t) (x) << ((i) * 8)) +enum i915_ggtt_view_type { + I915_GGTT_VIEW_NORMAL = 0, +}; + +struct i915_ggtt_view { + enum i915_ggtt_view_type type; + + struct sg_table *pages; +}; + +extern const struct i915_ggtt_view i915_ggtt_view_normal; + enum i915_cache_level; + /** * A VMA represents a GEM BO that is bound into an address space. Therefore, a * VMA's presence cannot be guaranteed before binding, or after unbinding the @@ -129,6 +142,15 @@ struct i915_vma { #define PTE_READ_ONLY (1<<2) unsigned int bound : 4; + /** + * Support different GGTT views into the same object. + * This means there can be multiple VMA mappings per object and per VM. + * i915_ggtt_view_type is used to distinguish between those entries. + * The default one of zero (I915_GGTT_VIEW_NORMAL) is default and also + * assumed in GEM functions which take no ggtt view parameter. + */ + struct i915_ggtt_view ggtt_view; + /** This object's place on the active/inactive lists */ struct list_head mm_list; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index c4536e1..f97479a 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -718,10 +718,8 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, break; list_for_each_entry(vma, &obj->vma_list, vma_link) - if (vma->vm == vm && vma->pin_count > 0) { + if (vma->vm == vm && vma->pin_count > 0) capture_bo(err++, vma); - break; - } } return err - first; @@ -1096,10 +1094,8 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv, list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { list_for_each_entry(vma, &obj->vma_list, vma_link) - if (vma->vm == vm && vma->pin_count > 0) { + if (vma->vm == vm && vma->pin_count > 0) i++; - break; - } } error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx]; -- cgit v0.10.2 From 45f8f69abc789acea7f0b06e604644945794c709 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 10 Dec 2014 17:27:59 +0000 Subject: drm/i915: Documentation for multiple GGTT views A short section describing background, implementation and intended usage. v2: * Align section name between template and DOC comment. (Michel Thierry) For: VIZ-4544 Signed-off-by: Tvrtko Ursulin Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 4fc5d73..f931b3d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4038,6 +4038,11 @@ int num_ioctls; !Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists !Idrivers/gpu/drm/i915/intel_lrc.c + + Global GTT views +!Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views +!Idrivers/gpu/drm/i915/i915_gem_gtt.c + diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 9821a60..cc3056f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -30,6 +30,66 @@ #include "i915_trace.h" #include "intel_drv.h" +/** + * DOC: Global GTT views + * + * Background and previous state + * + * Historically objects could exists (be bound) in global GTT space only as + * singular instances with a view representing all of the object's backing pages + * in a linear fashion. This view will be called a normal view. + * + * To support multiple views of the same object, where the number of mapped + * pages is not equal to the backing store, or where the layout of the pages + * is not linear, concept of a GGTT view was added. + * + * One example of an alternative view is a stereo display driven by a single + * image. In this case we would have a framebuffer looking like this + * (2x2 pages): + * + * 12 + * 34 + * + * Above would represent a normal GGTT view as normally mapped for GPU or CPU + * rendering. In contrast, fed to the display engine would be an alternative + * view which could look something like this: + * + * 1212 + * 3434 + * + * In this example both the size and layout of pages in the alternative view is + * different from the normal view. + * + * Implementation and usage + * + * GGTT views are implemented using VMAs and are distinguished via enum + * i915_ggtt_view_type and struct i915_ggtt_view. + * + * A new flavour of core GEM functions which work with GGTT bound objects were + * added with the _view suffix. They take the struct i915_ggtt_view parameter + * encapsulating all metadata required to implement a view. + * + * As a helper for callers which are only interested in the normal view, + * globally const i915_ggtt_view_normal singleton instance exists. All old core + * GEM API functions, the ones not taking the view parameter, are operating on, + * or with the normal GGTT view. + * + * Code wanting to add or use a new GGTT view needs to: + * + * 1. Add a new enum with a suitable name. + * 2. Extend the metadata in the i915_ggtt_view structure if required. + * 3. Add support to i915_get_vma_pages(). + * + * New views are required to build a scatter-gather table from within the + * i915_get_vma_pages function. This table is stored in the vma.ggtt_view and + * exists for the lifetime of an VMA. + * + * Core API is designed to have copy semantics which means that passed in + * struct i915_ggtt_view does not need to be persistent (left around after + * calling the core API functions). + * + */ + const struct i915_ggtt_view i915_ggtt_view_normal; static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv); -- cgit v0.10.2 From a712f8ebf80319e29eac117dc614eabecdc31c71 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Tue, 9 Dec 2014 10:59:15 +0530 Subject: drm/i915/skl: Correctly updating sprite wm parameter The pipe wm parameters is not correctly updated with sprite parameters because it copies them for each plane from plane_list to the sprite offset in pipe wm parameters. Since plane_list also contains primary and cursor planes, we end up updating wrong params for sprites. Signed-off-by: Sonika Jindal Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 99865c0..0f7ceba 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2668,7 +2668,8 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc, list_for_each_entry(plane, &dev->mode_config.plane_list, head) { struct intel_plane *intel_plane = to_intel_plane(plane); - if (intel_plane->pipe == pipe) + if (intel_plane->pipe == pipe && + plane->type == DRM_PLANE_TYPE_OVERLAY) p->plane[i++] = intel_plane->wm; } } -- cgit v0.10.2 From 27401d126b5b1c8dd4df98bbb60b09ff2b3d5e60 Mon Sep 17 00:00:00 2001 From: Thomas Daniel Date: Thu, 11 Dec 2014 12:48:35 +0000 Subject: drm/i915/bdw: Enable execlists by default where supported Execlist support in the i915 driver is now considered good enough for the feature to be enabled by default on Gen8 and later and routinely tested. Adjusted i915 parameters structure initialization to reflect this and updated the comment in intel_sanitize_enable_execlists(). There's still work to do before we can let the wider massive onto it, but there's still time left before the 3.20 cutoff. v2: Update the MODULE_PARM_DESC too. Issue: VIZ-2020 Signed-off-by: Thomas Daniel [danvet: Add note that there's still some work left to do.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index c91cb20..f6af6d4 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -35,7 +35,7 @@ struct i915_params i915 __read_mostly = { .vbt_sdvo_panel_type = -1, .enable_rc6 = -1, .enable_fbc = -1, - .enable_execlists = 0, + .enable_execlists = -1, .enable_hangcheck = true, .enable_ppgtt = -1, .enable_psr = 0, @@ -122,7 +122,7 @@ MODULE_PARM_DESC(enable_ppgtt, module_param_named(enable_execlists, i915.enable_execlists, int, 0400); MODULE_PARM_DESC(enable_execlists, "Override execlists usage. " - "(-1=auto, 0=disabled [default], 1=enabled)"); + "(-1=auto [default], 0=disabled, 1=enabled)"); module_param_named(enable_psr, i915.enable_psr, int, 0600); MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)"); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 89b5577..4dc6d42 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -212,8 +212,7 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring, * @enable_execlists: value of i915.enable_execlists module parameter. * * Only certain platforms support Execlists (the prerequisites being - * support for Logical Ring Contexts and Aliasing PPGTT or better), - * and only when enabled via module parameter. + * support for Logical Ring Contexts and Aliasing PPGTT or better). * * Return: 1 if Execlists is supported and has to be enabled. */ -- cgit v0.10.2 From d9d8e6b3c01386e5b39b70dc07156ff0e407d984 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Thu, 11 Dec 2014 17:58:15 +0530 Subject: drm/i915/skl: Correcting the flushing of pipe We were incorreectly bypassing the flush everytime which led to fifo underrun when more than one plane is enabled. Signed-off-by: Sonika Jindal Reviewed-by: Tvrtko Ursulin Reviewed-by: Satheeshakrishna M Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0f7ceba..8a960d1 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3004,9 +3004,8 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv, skl_ddb_entry_size(&cur_ddb->pipe[pipe])) { skl_wm_flush_pipe(dev_priv, pipe, 2); intel_wait_for_vblank(dev, pipe); + reallocated[pipe] = true; } - - reallocated[pipe] = true; } /* -- cgit v0.10.2 From 371abae844ede392066bfc21202b2e40f4a654d1 Mon Sep 17 00:00:00 2001 From: Deepak M Date: Mon, 15 Dec 2014 15:58:21 +0530 Subject: drm/i915: Parsing LFP brightness control from VBT LFP brighness control from the VBT block 43 indicates which controller is used for brightness. LFP1 brightness control method: Bit 7-4 = This field controller number of the brightnes controller. 0 = Controller 0 1 = Controller 1 2 = Controller 2 3 = Controller 3 Others = Reserved Bits 3-0 = This field specifies the brightness control pin to be used on the platform. 0 = PMIC pin is used for brightness control 1 = LPSS PWM is used for brightness control 2 = Display DDI is used for brightness control 3 = CABC method to control brightness Others = Reserved Adding the above fields in dev_priv->vbt and corresponding changes in parse_backlight() v2: Jani's review comments addressed - Move PWM definitions to intel_bios.h - Moving vbt_version to intel_vbt_data - Rename brightness to bl_ctrl_data - Logging just control_pin instead of string - Avoid adding vbt_version in dev_priv - Since only DDI option is available as of now, let control pin DDI affect dev_priv->vbt.backlight.present v3: Jani's review comments addressed - Drop control_pin - Use bdb->version - set controller to 0 instead of using control pin define - check controller bounds - remove superfluous changes in intel_parse_bios Signed-off-by: Deepak M Signed-off-by: Vandana Kannan Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eb47990..104c288 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1367,6 +1367,7 @@ struct intel_vbt_data { bool present; bool active_low_pwm; u8 min_brightness; /* min_brightness/255 of max */ + u8 controller; /* brightness controller number */ } backlight; /* MIPI DSI */ diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 3f17825..65b1fbc 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -314,6 +314,7 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { const struct bdb_lfp_backlight_data *backlight_data; const struct bdb_lfp_backlight_data_entry *entry; + const struct bdb_lfp_backlight_control_data *bl_ctrl_data; backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); if (!backlight_data) @@ -326,6 +327,7 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) } entry = &backlight_data->data[panel_type]; + bl_ctrl_data = &backlight_data->blc_ctl[panel_type]; dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; if (!dev_priv->vbt.backlight.present) { @@ -337,12 +339,30 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; dev_priv->vbt.backlight.min_brightness = entry->min_brightness; + + dev_priv->vbt.backlight.controller = 0; + if (bdb->version >= 191) { + dev_priv->vbt.backlight.present = + bl_ctrl_data->pin == BLC_CONTROL_PIN_DDI; + if (!dev_priv->vbt.backlight.present) { + DRM_DEBUG_KMS("BL control pin is not DDI (pin %u)\n", + bl_ctrl_data->pin); + return; + } + if (bl_ctrl_data->controller == 1) + dev_priv->vbt.backlight.controller = + bl_ctrl_data->controller; + } + DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " "active %s, min brightness %u, level %u\n", dev_priv->vbt.backlight.pwm_freq_hz, dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", dev_priv->vbt.backlight.min_brightness, backlight_data->level[panel_type]); + + DRM_DEBUG_KMS("VBT BL controller %u\n", + dev_priv->vbt.backlight.controller); } /* Try to find sdvo panel data */ diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index a6a8710..9a7202e 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -402,10 +402,21 @@ struct bdb_lfp_backlight_data_entry { u8 obsolete3; } __packed; +#define BLC_CONTROL_PIN_PMIC 0 +#define BLC_CONTROL_PIN_LPSS_PWM 1 +#define BLC_CONTROL_PIN_DDI 2 +#define BLC_CONTROL_PIN_CABC 3 + +struct bdb_lfp_backlight_control_data { + u8 controller:4; + u8 pin:4; +} __packed; + struct bdb_lfp_backlight_data { u8 entry_size; struct bdb_lfp_backlight_data_entry data[16]; u8 level[16]; + struct bdb_lfp_backlight_control_data blc_ctl[16]; } __packed; struct aimdb_header { -- cgit v0.10.2 From 22606a18be1af3d703eab873cb2df83b799a683a Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 12 Dec 2014 14:26:57 +0000 Subject: drm/i915: Consolidate DDI clock reading out in a single function 2 pieces of code need to read out the DDI clock: the DDI encoder and the MST encoder .get_config() vfuncs. Until now the SKL read out code was only in the former, so let's move the pre and post SKL logic in intel_ddi_clock_get() and this this one everywhere. Signed-off-by: Damien Lespiau Reviewed-by: Dave Airlie Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 4e2e860..1c92ad4 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -834,7 +834,12 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder, void intel_ddi_clock_get(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) { - hsw_ddi_clock_get(encoder, pipe_config); + struct drm_device *dev = encoder->base.dev; + + if (INTEL_INFO(dev)->gen <= 8) + hsw_ddi_clock_get(encoder, pipe_config); + else + skl_ddi_clock_get(encoder, pipe_config); } static void @@ -2029,7 +2034,6 @@ void intel_ddi_get_config(struct intel_encoder *encoder, enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; struct intel_hdmi *intel_hdmi; u32 temp, flags = 0; - struct drm_device *dev = dev_priv->dev; temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); if (temp & TRANS_DDI_PHSYNC) @@ -2106,10 +2110,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder, dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp; } - if (INTEL_INFO(dev)->gen <= 8) - hsw_ddi_clock_get(encoder, pipe_config); - else - skl_ddi_clock_get(encoder, pipe_config); + intel_ddi_clock_get(encoder, pipe_config); } static void intel_ddi_destroy(struct drm_encoder *encoder) -- cgit v0.10.2 From c86ea3d0ad7e60fb92e3d4a0aa4906ec2868a7cd Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 12 Dec 2014 14:26:58 +0000 Subject: drm/i915/skl: Skylake also supports DP MST I've checked that TRANS_DDI_MODE, DP_TP_CTL MST bits are identical to HSW/BDW on SKL, as well as the long vs short HPD bits. So we have a good chance to be working as well as prevous platforms. Signed-off-by: Damien Lespiau Reviewed-by: Dave Airlie Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3fc3296..8e276c4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5085,7 +5085,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp_aux_init(intel_dp, intel_connector); /* init MST on ports that can support it */ - if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + if (IS_HASWELL(dev) || IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) { if (port == PORT_B || port == PORT_C || port == PORT_D) { intel_dp_mst_encoder_init(intel_dig_port, intel_connector->base.base.id); -- cgit v0.10.2 From b04d4a38c0691e4467fa2988b6fe481bf759daaf Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 15 Dec 2014 12:26:46 -0800 Subject: drm/cache: Use wbinvd helpers When the original drm code was written there were no centralized functions for doing a coordinated wbinvd across all CPUs. Now (since 2010) there are, so use them instead of rolling a new one. v2: On x86 UP systems the wbinvd_on_all_cpus() is defined as a static inline in smp.h. We must therefore include this file so we don't get compiler errors. This error was found by 0-DAY kernel test infrastructure. We only need this for x86. Cc: Intel GFX Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson (v1) Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index a6b6906..9a62d7a 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -32,6 +32,7 @@ #include #if defined(CONFIG_X86) +#include /* * clflushopt is an unordered instruction which needs fencing with mfence or @@ -64,12 +65,6 @@ static void drm_cache_flush_clflush(struct page *pages[], drm_clflush_page(*pages++); mb(); } - -static void -drm_clflush_ipi_handler(void *null) -{ - wbinvd(); -} #endif void @@ -82,7 +77,7 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages) return; } - if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0) + if (wbinvd_on_all_cpus()) printk(KERN_ERR "Timed out waiting for cache flush.\n"); #elif defined(__powerpc__) @@ -121,7 +116,7 @@ drm_clflush_sg(struct sg_table *st) return; } - if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0) + if (wbinvd_on_all_cpus()) printk(KERN_ERR "Timed out waiting for cache flush.\n"); #else printk(KERN_ERR "Architecture has no drm_cache.c support\n"); @@ -144,7 +139,7 @@ drm_clflush_virt_range(void *addr, unsigned long length) return; } - if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0) + if (wbinvd_on_all_cpus()) printk(KERN_ERR "Timed out waiting for cache flush.\n"); #else printk(KERN_ERR "Architecture has no drm_cache.c support\n"); -- cgit v0.10.2 From c8bd0e49519ce1d80196e54ba2e20c3a1b7c88c0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 12 Dec 2014 17:57:38 +0200 Subject: drm/i915: fix use after free during eDP encoder destroying MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit a18c0af171bfb875012da26f23df051004726973 uthor: Thierry Reding Date: Wed Dec 10 11:38:49 2014 +0100 drm: Zero out DRM object memory upon cleanup we will use the eDP encoder during destroying it. Fix this by calling drm_encoder_cleanup() at a point when the encoder is not used any more. This caused a NULL pointer dereference in pps_lock(), I can't see that it caused any other problem. All the other encoders seem to call drm_encoder_cleanup() at a safe place. Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8e276c4..8b31e01 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4310,7 +4310,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) drm_dp_aux_unregister(&intel_dp->aux); intel_dp_mst_encoder_cleanup(intel_dig_port); - drm_encoder_cleanup(encoder); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); /* @@ -4326,6 +4325,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) intel_dp->edp_notifier.notifier_call = NULL; } } + drm_encoder_cleanup(encoder); kfree(intel_dig_port); } -- cgit v0.10.2 From 493018dcb1c7a17f2a811db41522a3a5350304fe Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Thu, 11 Dec 2014 12:13:08 -0800 Subject: drm/i915: Implement a framework for batch buffer pools This adds a small module for managing a pool of batch buffers. The only current use case is for the command parser, as described in the kerneldoc in the patch. The code is simple, but separating it out makes it easier to change the underlying algorithms and to extend to future use cases should they arise. The interface is simple: init to create an empty pool, fini to clean it up, get to obtain a new buffer. Note that all buffers are expected to be inactive before cleaning up the pool. Locking is currently based on the caller holding the struct_mutex. We already do that in the places where we will use the batch pool for the command parser. v2: - s/BUG_ON/WARN_ON/ for locking assertions - Remove the cap on pool size - Switch from alloc/free to init/fini v3: - Idiomatic looping structure in _fini - Correct handling of purged objects - Don't return a buffer that's too much larger than needed v4: - Rebased to latest -nightly v5: - Remove _put() function and clean up comments to match v6: - Move purged check inside the loop (danvet, from v4 1/7 feedback) v7: - Use single list instead of two. (Chris W) - s/active_list/cache_list - Squashed in debug patches (Chris W) drm/i915: Add a batch pool debugfs file It provides some useful information about the buffers in the global command parser batch pool. v2: rebase on global pool instead of per-ring pools v3: rebase drm/i915: Add batch pool details to i915_gem_objects debugfs To better account for the potentially large memory consumption of the batch pool. v8: - Keep cache in LRU order (danvet, from v6 1/5 feedback) Issue: VIZ-4719 Signed-off-by: Brad Volkin Reviewed-By: Jon Bloomfield Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index f931b3d..bd1456a 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4034,6 +4034,11 @@ int num_ioctls; !Idrivers/gpu/drm/i915/i915_cmd_parser.c + Batchbuffer Pools +!Pdrivers/gpu/drm/i915/i915_gem_batch_pool.c batch pool +!Idrivers/gpu/drm/i915/i915_gem_batch_pool.c + + Logical Rings, Logical Ring Contexts and Execlists !Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists !Idrivers/gpu/drm/i915/intel_lrc.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 3cf70a6..1849ffa 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -19,6 +19,7 @@ i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o # GEM code i915-y += i915_cmd_parser.o \ + i915_gem_batch_pool.o \ i915_gem_context.o \ i915_gem_render_state.o \ i915_gem_debug.o \ diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 8d2988a..e515aad 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -360,6 +360,33 @@ static int per_file_stats(int id, void *ptr, void *data) return 0; } +#define print_file_stats(m, name, stats) \ + seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", \ + name, \ + stats.count, \ + stats.total, \ + stats.active, \ + stats.inactive, \ + stats.global, \ + stats.shared, \ + stats.unbound) + +static void print_batch_pool_stats(struct seq_file *m, + struct drm_i915_private *dev_priv) +{ + struct drm_i915_gem_object *obj; + struct file_stats stats; + + memset(&stats, 0, sizeof(stats)); + + list_for_each_entry(obj, + &dev_priv->mm.batch_pool.cache_list, + batch_pool_list) + per_file_stats(0, obj, &stats); + + print_file_stats(m, "batch pool", stats); +} + #define count_vmas(list, member) do { \ list_for_each_entry(vma, list, member) { \ size += i915_gem_obj_ggtt_size(vma->obj); \ @@ -442,6 +469,9 @@ static int i915_gem_object_info(struct seq_file *m, void* data) dev_priv->gtt.mappable_end - dev_priv->gtt.base.start); seq_putc(m, '\n'); + print_batch_pool_stats(m, dev_priv); + + seq_putc(m, '\n'); list_for_each_entry_reverse(file, &dev->filelist, lhead) { struct file_stats stats; struct task_struct *task; @@ -459,15 +489,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) */ rcu_read_lock(); task = pid_task(file->pid, PIDTYPE_PID); - seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", - task ? task->comm : "", - stats.count, - stats.total, - stats.active, - stats.inactive, - stats.global, - stats.shared, - stats.unbound); + print_file_stats(m, task ? task->comm : "", stats); rcu_read_unlock(); } @@ -584,6 +606,36 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) return 0; } +static int i915_gem_batch_pool_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + int count = 0; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_puts(m, "cache:\n"); + list_for_each_entry(obj, + &dev_priv->mm.batch_pool.cache_list, + batch_pool_list) { + seq_puts(m, " "); + describe_obj(m, obj); + seq_putc(m, '\n'); + count++; + } + + seq_printf(m, "total: %d\n", count); + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static int i915_gem_request_info(struct seq_file *m, void *data) { struct drm_info_node *node = m->private; @@ -4357,6 +4409,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS}, {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS}, {"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS}, + {"i915_gem_batch_pool", i915_gem_batch_pool_info, 0}, {"i915_frequency_info", i915_frequency_info, 0}, {"i915_drpc_info", i915_drpc_info, 0}, {"i915_emon_status", i915_emon_status, 0}, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 104c288..6490fef 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1141,6 +1141,11 @@ struct intel_l3_parity { int which_slice; }; +struct i915_gem_batch_pool { + struct drm_device *dev; + struct list_head cache_list; +}; + struct i915_gem_mm { /** Memory allocator for GTT stolen memory */ struct drm_mm stolen; @@ -1154,6 +1159,13 @@ struct i915_gem_mm { */ struct list_head unbound_list; + /* + * A pool of objects to use as shadow copies of client batch buffers + * when the command parser is enabled. Prevents the client from + * modifying the batch contents after software parsing. + */ + struct i915_gem_batch_pool batch_pool; + /** Usable portion of the GTT for GEM */ unsigned long stolen_base; /* limited to low memory (32-bit) */ @@ -1885,6 +1897,8 @@ struct drm_i915_gem_object { /** Used in execbuf to temporarily hold a ref */ struct list_head obj_exec_link; + struct list_head batch_pool_list; + /** * This is set if the object is on the active lists (has pending * rendering and so a non-zero seqno), and is not set if it i s on @@ -2935,6 +2949,13 @@ void i915_destroy_error_state(struct drm_device *dev); void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone); const char *i915_cache_level_str(struct drm_i915_private *i915, int type); +/* i915_gem_batch_pool.c */ +void i915_gem_batch_pool_init(struct drm_device *dev, + struct i915_gem_batch_pool *pool); +void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool); +struct drm_i915_gem_object* +i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, size_t size); + /* i915_cmd_parser.c */ int i915_cmd_parser_get_version(void); int i915_cmd_parser_init_ring(struct intel_engine_cs *ring); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c26d4cc..b100cec 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4393,6 +4393,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, INIT_LIST_HEAD(&obj->ring_list); INIT_LIST_HEAD(&obj->obj_exec_link); INIT_LIST_HEAD(&obj->vma_list); + INIT_LIST_HEAD(&obj->batch_pool_list); obj->ops = ops; diff --git a/drivers/gpu/drm/i915/i915_gem_batch_pool.c b/drivers/gpu/drm/i915/i915_gem_batch_pool.c new file mode 100644 index 0000000..6016125 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_batch_pool.c @@ -0,0 +1,135 @@ +/* + * Copyright © 2014 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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 "i915_drv.h" + +/** + * DOC: batch pool + * + * In order to submit batch buffers as 'secure', the software command parser + * must ensure that a batch buffer cannot be modified after parsing. It does + * this by copying the user provided batch buffer contents to a kernel owned + * buffer from which the hardware will actually execute, and by carefully + * managing the address space bindings for such buffers. + * + * The batch pool framework provides a mechanism for the driver to manage a + * set of scratch buffers to use for this purpose. The framework can be + * extended to support other uses cases should they arise. + */ + +/** + * i915_gem_batch_pool_init() - initialize a batch buffer pool + * @dev: the drm device + * @pool: the batch buffer pool + */ +void i915_gem_batch_pool_init(struct drm_device *dev, + struct i915_gem_batch_pool *pool) +{ + pool->dev = dev; + INIT_LIST_HEAD(&pool->cache_list); +} + +/** + * i915_gem_batch_pool_fini() - clean up a batch buffer pool + * @pool: the pool to clean up + * + * Note: Callers must hold the struct_mutex. + */ +void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool) +{ + WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex)); + + while (!list_empty(&pool->cache_list)) { + struct drm_i915_gem_object *obj = + list_first_entry(&pool->cache_list, + struct drm_i915_gem_object, + batch_pool_list); + + WARN_ON(obj->active); + + list_del_init(&obj->batch_pool_list); + drm_gem_object_unreference(&obj->base); + } +} + +/** + * i915_gem_batch_pool_get() - select a buffer from the pool + * @pool: the batch buffer pool + * @size: the minimum desired size of the returned buffer + * + * Finds or allocates a batch buffer in the pool with at least the requested + * size. The caller is responsible for any domain, active/inactive, or + * purgeability management for the returned buffer. + * + * Note: Callers must hold the struct_mutex + * + * Return: the selected batch buffer object + */ +struct drm_i915_gem_object * +i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, + size_t size) +{ + struct drm_i915_gem_object *obj = NULL; + struct drm_i915_gem_object *tmp, *next; + + WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex)); + + list_for_each_entry_safe(tmp, next, + &pool->cache_list, batch_pool_list) { + + if (tmp->active) + continue; + + /* While we're looping, do some clean up */ + if (tmp->madv == __I915_MADV_PURGED) { + list_del(&tmp->batch_pool_list); + drm_gem_object_unreference(&tmp->base); + continue; + } + + /* + * Select a buffer that is at least as big as needed + * but not 'too much' bigger. A better way to do this + * might be to bucket the pool objects based on size. + */ + if (tmp->base.size >= size && + tmp->base.size <= (2 * size)) { + obj = tmp; + break; + } + } + + if (!obj) { + obj = i915_gem_alloc_object(pool->dev, size); + if (!obj) + return ERR_PTR(-ENOMEM); + + list_add_tail(&obj->batch_pool_list, &pool->cache_list); + } + else + /* Keep list in LRU order */ + list_move_tail(&obj->batch_pool_list, &pool->cache_list); + + return obj; +} -- cgit v0.10.2 From 78a423772d08eb5a048765a883b5b5a308ea0d0f Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Thu, 11 Dec 2014 12:13:09 -0800 Subject: drm/i915: Use batch pools with the command parser This patch sets up all of the tracking and copying necessary to use batch pools with the command parser and dispatches the copied (shadow) batch to the hardware. After this patch, the parser is in 'enabling' mode. Note that performance takes a hit from the copy in some cases and will likely need some work. At a rough pass, the memcpy appears to be the bottleneck. Without having done a deeper analysis, two ideas that come to mind are: 1) Copy sections of the batch at a time, as they are reached by parsing. Might improve cache locality. 2) Copy only up to the userspace-supplied batch length and memset the rest of the buffer. Reduces the number of reads. v2: - Remove setting the capacity of the pool - One global pool instead of per-ring pools - Replace batch_obj with shadow_batch_obj and hook into eb->vmas - Memset any space in the shadow batch beyond what gets copied - Rebased on execlist prep refactoring v3: - Rebase on chained batch handling - Squash in setting the secure dispatch flag - Add a note about the interaction w/secure dispatch pinning - Check for request->batch_obj == NULL in i915_gem_free_request v4: - Fix read domains for shadow_batch_obj - Remove the set_to_gtt_domain call from i915_parse_cmds - ggtt_pin/unpin in the parser block to simplify error handling - Check USES_FULL_PPGTT before setting DISPATCH_SECURE flag - Remove i915_gem_batch_pool_put calls v5: - Move 'pending_read_domains |= I915_GEM_DOMAIN_COMMAND' after the parser (danvet, from v4 0/7 feedback) Issue: VIZ-4719 Signed-off-by: Brad Volkin Reviewed-By: Jon Bloomfield Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index b882bf2..2a4ccac 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -848,6 +848,56 @@ finish: return (u32*)addr; } +/* Returns a vmap'd pointer to dest_obj, which the caller must unmap */ +static u32 *copy_batch(struct drm_i915_gem_object *dest_obj, + struct drm_i915_gem_object *src_obj) +{ + int ret = 0; + int needs_clflush = 0; + u32 *src_addr, *dest_addr = NULL; + + ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush); + if (ret) { + DRM_DEBUG_DRIVER("CMD: failed to prep read\n"); + return ERR_PTR(ret); + } + + src_addr = vmap_batch(src_obj); + if (!src_addr) { + DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n"); + ret = -ENOMEM; + goto unpin_src; + } + + if (needs_clflush) + drm_clflush_virt_range((char *)src_addr, src_obj->base.size); + + ret = i915_gem_object_set_to_cpu_domain(dest_obj, true); + if (ret) { + DRM_DEBUG_DRIVER("CMD: Failed to set batch CPU domain\n"); + goto unmap_src; + } + + dest_addr = vmap_batch(dest_obj); + if (!dest_addr) { + DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n"); + ret = -ENOMEM; + goto unmap_src; + } + + memcpy(dest_addr, src_addr, src_obj->base.size); + if (dest_obj->base.size > src_obj->base.size) + memset((u8 *)dest_addr + src_obj->base.size, 0, + dest_obj->base.size - src_obj->base.size); + +unmap_src: + vunmap(src_addr); +unpin_src: + i915_gem_object_unpin_pages(src_obj); + + return ret ? ERR_PTR(ret) : dest_addr; +} + /** * i915_needs_cmd_parser() - should a given ring use software command parsing? * @ring: the ring in question @@ -964,6 +1014,7 @@ static bool check_cmd(const struct intel_engine_cs *ring, * i915_parse_cmds() - parse a submitted batch buffer for privilege violations * @ring: the ring on which the batch is to execute * @batch_obj: the batch buffer in question + * @shadow_batch_obj: copy of the batch buffer in question * @batch_start_offset: byte offset in the batch at which execution starts * @is_master: is the submitting process the drm master? * @@ -975,32 +1026,28 @@ static bool check_cmd(const struct intel_engine_cs *ring, */ int i915_parse_cmds(struct intel_engine_cs *ring, struct drm_i915_gem_object *batch_obj, + struct drm_i915_gem_object *shadow_batch_obj, u32 batch_start_offset, bool is_master) { int ret = 0; u32 *cmd, *batch_base, *batch_end; struct drm_i915_cmd_descriptor default_desc = { 0 }; - int needs_clflush = 0; bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */ - ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush); - if (ret) { - DRM_DEBUG_DRIVER("CMD: failed to prep read\n"); - return ret; + batch_base = copy_batch(shadow_batch_obj, batch_obj); + if (IS_ERR(batch_base)) { + DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n"); + return PTR_ERR(batch_base); } - batch_base = vmap_batch(batch_obj); - if (!batch_base) { - DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n"); - i915_gem_object_unpin_pages(batch_obj); - return -ENOMEM; - } - - if (needs_clflush) - drm_clflush_virt_range((char *)batch_base, batch_obj->base.size); - cmd = batch_base + (batch_start_offset / sizeof(*cmd)); + + /* + * We use the source object's size because the shadow object is as + * large or larger and copy_batch() will write MI_NOPs to the extra + * space. Parsing should be faster in some cases this way. + */ batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end)); while (cmd < batch_end) { @@ -1062,8 +1109,6 @@ int i915_parse_cmds(struct intel_engine_cs *ring, vunmap(batch_base); - i915_gem_object_unpin_pages(batch_obj); - return ret; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 887d88f..52730ed 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -928,6 +928,7 @@ int i915_driver_unload(struct drm_device *dev) mutex_lock(&dev->struct_mutex); i915_gem_cleanup_ringbuffer(dev); + i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool); i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); i915_gem_cleanup_stolen(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6490fef..25832e5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2963,6 +2963,7 @@ void i915_cmd_parser_fini_ring(struct intel_engine_cs *ring); bool i915_needs_cmd_parser(struct intel_engine_cs *ring); int i915_parse_cmds(struct intel_engine_cs *ring, struct drm_i915_gem_object *batch_obj, + struct drm_i915_gem_object *shadow_batch_obj, u32 batch_start_offset, bool is_master); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b100cec..a7bf31a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5007,6 +5007,8 @@ i915_gem_load(struct drm_device *dev) dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom; register_oom_notifier(&dev_priv->mm.oom_notifier); + i915_gem_batch_pool_init(dev, &dev_priv->mm.batch_pool); + mutex_init(&dev_priv->fb_tracking.lock); } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3927d93..cadb04d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1283,6 +1283,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_private *dev_priv = dev->dev_private; struct eb_vmas *eb; struct drm_i915_gem_object *batch_obj; + struct drm_i915_gem_object *shadow_batch_obj = NULL; + struct drm_i915_gem_exec_object2 shadow_exec_entry; struct intel_engine_cs *ring; struct intel_context *ctx; struct i915_address_space *vm; @@ -1399,28 +1401,66 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ret = -EINVAL; goto err; } - batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; if (i915_needs_cmd_parser(ring)) { + shadow_batch_obj = + i915_gem_batch_pool_get(&dev_priv->mm.batch_pool, + batch_obj->base.size); + if (IS_ERR(shadow_batch_obj)) { + ret = PTR_ERR(shadow_batch_obj); + /* Don't try to clean up the obj in the error path */ + shadow_batch_obj = NULL; + goto err; + } + + ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 4096, 0); + if (ret) + goto err; + ret = i915_parse_cmds(ring, batch_obj, + shadow_batch_obj, args->batch_start_offset, file->is_master); + i915_gem_object_ggtt_unpin(shadow_batch_obj); + if (ret) { if (ret != -EACCES) goto err; } else { + struct i915_vma *vma; + + memset(&shadow_exec_entry, 0, + sizeof(shadow_exec_entry)); + + vma = i915_gem_obj_to_ggtt(shadow_batch_obj); + vma->exec_entry = &shadow_exec_entry; + drm_gem_object_reference(&shadow_batch_obj->base); + list_add_tail(&vma->exec_list, &eb->vmas); + + shadow_batch_obj->base.pending_read_domains = + batch_obj->base.pending_read_domains; + + batch_obj = shadow_batch_obj; + /* - * XXX: Actually do this when enabling batch copy... + * Set the DISPATCH_SECURE bit to remove the NON_SECURE + * bit from MI_BATCH_BUFFER_START commands issued in the + * dispatch_execbuffer implementations. We specifically + * don't want that set when the command parser is + * enabled. * - * Set the DISPATCH_SECURE bit to remove the NON_SECURE bit - * from MI_BATCH_BUFFER_START commands issued in the - * dispatch_execbuffer implementations. We specifically don't - * want that set when the command parser is enabled. + * FIXME: with aliasing ppgtt, buffers that should only + * be in ggtt still end up in the aliasing ppgtt. remove + * this check when that is fixed. */ + if (USES_FULL_PPGTT(dev)) + flags |= I915_DISPATCH_SECURE; } } + batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; + /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure * batch" bit. Hence we need to pin secure batches into the global gtt. * hsw should have this fixed, but bdw mucks it up again. */ -- cgit v0.10.2 From b9ffd80ed659c559152c042e74741f4f60cac691 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Thu, 11 Dec 2014 12:13:10 -0800 Subject: drm/i915: Use batch length instead of object size in command parser Previously we couldn't trust the user-supplied batch length because it came directly from userspace (i.e. untrusted code). It would have affected what commands software parsed without regard to what hardware would actually execute, leaving a potential hole. With the parser now copying the user supplied batch buffer and writing MI_NOP commands to any space after the copied region, we can safely use the batch length input. This should be a performance win as the actual batch length is frequently much smaller than the allocated object size. v2: Fix handling of non-zero batch_start_offset Issue: VIZ-4719 Signed-off-by: Brad Volkin Reviewed-By: Jon Bloomfield Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 2a4ccac..a698b47 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -850,11 +850,19 @@ finish: /* Returns a vmap'd pointer to dest_obj, which the caller must unmap */ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj, - struct drm_i915_gem_object *src_obj) + struct drm_i915_gem_object *src_obj, + u32 batch_start_offset, + u32 batch_len) { int ret = 0; int needs_clflush = 0; - u32 *src_addr, *dest_addr = NULL; + u32 *src_base, *dest_base = NULL; + u32 *src_addr, *dest_addr; + u32 offset = batch_start_offset / sizeof(*dest_addr); + u32 end = batch_start_offset + batch_len; + + if (end > dest_obj->base.size || end > src_obj->base.size) + return ERR_PTR(-E2BIG); ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush); if (ret) { @@ -862,15 +870,17 @@ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj, return ERR_PTR(ret); } - src_addr = vmap_batch(src_obj); - if (!src_addr) { + src_base = vmap_batch(src_obj); + if (!src_base) { DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n"); ret = -ENOMEM; goto unpin_src; } + src_addr = src_base + offset; + if (needs_clflush) - drm_clflush_virt_range((char *)src_addr, src_obj->base.size); + drm_clflush_virt_range((char *)src_addr, batch_len); ret = i915_gem_object_set_to_cpu_domain(dest_obj, true); if (ret) { @@ -878,24 +888,27 @@ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj, goto unmap_src; } - dest_addr = vmap_batch(dest_obj); - if (!dest_addr) { + dest_base = vmap_batch(dest_obj); + if (!dest_base) { DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n"); ret = -ENOMEM; goto unmap_src; } - memcpy(dest_addr, src_addr, src_obj->base.size); - if (dest_obj->base.size > src_obj->base.size) - memset((u8 *)dest_addr + src_obj->base.size, 0, - dest_obj->base.size - src_obj->base.size); + dest_addr = dest_base + offset; + + if (batch_start_offset != 0) + memset((u8 *)dest_base, 0, batch_start_offset); + + memcpy(dest_addr, src_addr, batch_len); + memset((u8 *)dest_addr + batch_len, 0, dest_obj->base.size - end); unmap_src: - vunmap(src_addr); + vunmap(src_base); unpin_src: i915_gem_object_unpin_pages(src_obj); - return ret ? ERR_PTR(ret) : dest_addr; + return ret ? ERR_PTR(ret) : dest_base; } /** @@ -1016,6 +1029,7 @@ static bool check_cmd(const struct intel_engine_cs *ring, * @batch_obj: the batch buffer in question * @shadow_batch_obj: copy of the batch buffer in question * @batch_start_offset: byte offset in the batch at which execution starts + * @batch_len: length of the commands in batch_obj * @is_master: is the submitting process the drm master? * * Parses the specified batch buffer looking for privilege violations as @@ -1028,6 +1042,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring, struct drm_i915_gem_object *batch_obj, struct drm_i915_gem_object *shadow_batch_obj, u32 batch_start_offset, + u32 batch_len, bool is_master) { int ret = 0; @@ -1035,7 +1050,8 @@ int i915_parse_cmds(struct intel_engine_cs *ring, struct drm_i915_cmd_descriptor default_desc = { 0 }; bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */ - batch_base = copy_batch(shadow_batch_obj, batch_obj); + batch_base = copy_batch(shadow_batch_obj, batch_obj, + batch_start_offset, batch_len); if (IS_ERR(batch_base)) { DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n"); return PTR_ERR(batch_base); @@ -1044,11 +1060,11 @@ int i915_parse_cmds(struct intel_engine_cs *ring, cmd = batch_base + (batch_start_offset / sizeof(*cmd)); /* - * We use the source object's size because the shadow object is as + * We use the batch length as size because the shadow object is as * large or larger and copy_batch() will write MI_NOPs to the extra * space. Parsing should be faster in some cases this way. */ - batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end)); + batch_end = cmd + (batch_len / sizeof(*batch_end)); while (cmd < batch_end) { const struct drm_i915_cmd_descriptor *desc; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 25832e5..eb4d64f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2965,6 +2965,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring, struct drm_i915_gem_object *batch_obj, struct drm_i915_gem_object *shadow_batch_obj, u32 batch_start_offset, + u32 batch_len, bool is_master); /* i915_suspend.c */ diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index cadb04d..5973e20 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1421,6 +1421,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, batch_obj, shadow_batch_obj, args->batch_start_offset, + args->batch_len, file->is_master); i915_gem_object_ggtt_unpin(shadow_batch_obj); -- cgit v0.10.2 From 0079a7df3a47bfd0b64dc6e6ef47a651263760dc Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Thu, 11 Dec 2014 12:13:11 -0800 Subject: drm/i915: Mark shadow batch buffers as purgeable By adding a new exec_entry flag, we cleanly mark the shadow objects as purgeable after they are on the active list. v2: - Move 'shadow_batch_obj->madv = I915_MADV_WILLNEED' inside _get fnc (danvet, from v4 6/7 feedback) v3: - Remove duplicate 'madv = I915_MADV_WILLNEED' (danvet, from v6 4/5) Issue: VIZ-4719 Signed-off-by: Brad Volkin Reviewed-By: Jon Bloomfield Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_batch_pool.c b/drivers/gpu/drm/i915/i915_gem_batch_pool.c index 6016125..c690170 100644 --- a/drivers/gpu/drm/i915/i915_gem_batch_pool.c +++ b/drivers/gpu/drm/i915/i915_gem_batch_pool.c @@ -131,5 +131,7 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, /* Keep list in LRU order */ list_move_tail(&obj->batch_pool_list, &pool->cache_list); + obj->madv = I915_MADV_WILLNEED; + return obj; } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 5973e20..86de372 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -37,6 +37,7 @@ #define __EXEC_OBJECT_HAS_FENCE (1<<30) #define __EXEC_OBJECT_NEEDS_MAP (1<<29) #define __EXEC_OBJECT_NEEDS_BIAS (1<<28) +#define __EXEC_OBJECT_PURGEABLE (1<<27) #define BATCH_OFFSET_BIAS (256*1024) @@ -226,7 +227,12 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma) if (entry->flags & __EXEC_OBJECT_HAS_PIN) vma->pin_count--; - entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN); + if (entry->flags & __EXEC_OBJECT_PURGEABLE) + obj->madv = I915_MADV_DONTNEED; + + entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | + __EXEC_OBJECT_HAS_PIN | + __EXEC_OBJECT_PURGEABLE); } static void eb_destroy(struct eb_vmas *eb) @@ -1436,6 +1442,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, vma = i915_gem_obj_to_ggtt(shadow_batch_obj); vma->exec_entry = &shadow_exec_entry; + vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE; drm_gem_object_reference(&shadow_batch_obj->base); list_add_tail(&vma->exec_list, &eb->vmas); -- cgit v0.10.2 From 7174537627836119e8b960afcc7139a138e02802 Mon Sep 17 00:00:00 2001 From: Brad Volkin Date: Thu, 11 Dec 2014 12:13:12 -0800 Subject: drm/i915: Tidy up execbuffer command parsing code Move it to a separate function since the main do_execbuffer function already has so much going on. v2: - Move pin/unpin calls inside i915_parse_cmds() (Chris W, v4 7/7 feedback) Issue: VIZ-4719 Signed-off-by: Brad Volkin Reviewed-By: Jon Bloomfield Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index a698b47..0d757cd 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -1050,10 +1050,17 @@ int i915_parse_cmds(struct intel_engine_cs *ring, struct drm_i915_cmd_descriptor default_desc = { 0 }; bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */ + ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 4096, 0); + if (ret) { + DRM_DEBUG_DRIVER("CMD: Failed to pin shadow batch\n"); + return -1; + } + batch_base = copy_batch(shadow_batch_obj, batch_obj, batch_start_offset, batch_len); if (IS_ERR(batch_base)) { DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n"); + i915_gem_object_ggtt_unpin(shadow_batch_obj); return PTR_ERR(batch_base); } @@ -1124,6 +1131,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring, } vunmap(batch_base); + i915_gem_object_ggtt_unpin(shadow_batch_obj); return ret; } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 86de372..8330660 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1072,6 +1072,65 @@ i915_emit_box(struct intel_engine_cs *ring, return 0; } +static struct drm_i915_gem_object* +i915_gem_execbuffer_parse(struct intel_engine_cs *ring, + struct drm_i915_gem_exec_object2 *shadow_exec_entry, + struct eb_vmas *eb, + struct drm_i915_gem_object *batch_obj, + u32 batch_start_offset, + u32 batch_len, + bool is_master, + u32 *flags) +{ + struct drm_i915_private *dev_priv = to_i915(batch_obj->base.dev); + struct drm_i915_gem_object *shadow_batch_obj; + int ret; + + shadow_batch_obj = i915_gem_batch_pool_get(&dev_priv->mm.batch_pool, + batch_obj->base.size); + if (IS_ERR(shadow_batch_obj)) + return shadow_batch_obj; + + ret = i915_parse_cmds(ring, + batch_obj, + shadow_batch_obj, + batch_start_offset, + batch_len, + is_master); + if (ret) { + if (ret == -EACCES) + return batch_obj; + } else { + struct i915_vma *vma; + + memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry)); + + vma = i915_gem_obj_to_ggtt(shadow_batch_obj); + vma->exec_entry = shadow_exec_entry; + vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE; + drm_gem_object_reference(&shadow_batch_obj->base); + list_add_tail(&vma->exec_list, &eb->vmas); + + shadow_batch_obj->base.pending_read_domains = + batch_obj->base.pending_read_domains; + + /* + * Set the DISPATCH_SECURE bit to remove the NON_SECURE + * bit from MI_BATCH_BUFFER_START commands issued in the + * dispatch_execbuffer implementations. We specifically + * don't want that set when the command parser is + * enabled. + * + * FIXME: with aliasing ppgtt, buffers that should only + * be in ggtt still end up in the aliasing ppgtt. remove + * this check when that is fixed. + */ + if (USES_FULL_PPGTT(dev)) + *flags |= I915_DISPATCH_SECURE; + } + + return ret ? ERR_PTR(ret) : shadow_batch_obj; +} int i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, @@ -1289,7 +1348,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_private *dev_priv = dev->dev_private; struct eb_vmas *eb; struct drm_i915_gem_object *batch_obj; - struct drm_i915_gem_object *shadow_batch_obj = NULL; struct drm_i915_gem_exec_object2 shadow_exec_entry; struct intel_engine_cs *ring; struct intel_context *ctx; @@ -1409,62 +1467,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } if (i915_needs_cmd_parser(ring)) { - shadow_batch_obj = - i915_gem_batch_pool_get(&dev_priv->mm.batch_pool, - batch_obj->base.size); - if (IS_ERR(shadow_batch_obj)) { - ret = PTR_ERR(shadow_batch_obj); - /* Don't try to clean up the obj in the error path */ - shadow_batch_obj = NULL; + batch_obj = i915_gem_execbuffer_parse(ring, + &shadow_exec_entry, + eb, + batch_obj, + args->batch_start_offset, + args->batch_len, + file->is_master, + &flags); + if (IS_ERR(batch_obj)) { + ret = PTR_ERR(batch_obj); goto err; } - - ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 4096, 0); - if (ret) - goto err; - - ret = i915_parse_cmds(ring, - batch_obj, - shadow_batch_obj, - args->batch_start_offset, - args->batch_len, - file->is_master); - i915_gem_object_ggtt_unpin(shadow_batch_obj); - - if (ret) { - if (ret != -EACCES) - goto err; - } else { - struct i915_vma *vma; - - memset(&shadow_exec_entry, 0, - sizeof(shadow_exec_entry)); - - vma = i915_gem_obj_to_ggtt(shadow_batch_obj); - vma->exec_entry = &shadow_exec_entry; - vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE; - drm_gem_object_reference(&shadow_batch_obj->base); - list_add_tail(&vma->exec_list, &eb->vmas); - - shadow_batch_obj->base.pending_read_domains = - batch_obj->base.pending_read_domains; - - batch_obj = shadow_batch_obj; - - /* - * Set the DISPATCH_SECURE bit to remove the NON_SECURE - * bit from MI_BATCH_BUFFER_START commands issued in the - * dispatch_execbuffer implementations. We specifically - * don't want that set when the command parser is - * enabled. - * - * FIXME: with aliasing ppgtt, buffers that should only - * be in ggtt still end up in the aliasing ppgtt. remove - * this check when that is fixed. - */ - if (USES_FULL_PPGTT(dev)) - flags |= I915_DISPATCH_SECURE; - } } batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; -- cgit v0.10.2 From c61200c2c7e42fa6481638b7c8c3b5dc89c60eb9 Mon Sep 17 00:00:00 2001 From: Jordan Justen Date: Thu, 11 Dec 2014 13:28:09 -0800 Subject: drm/i915: Add GPGPU_THREADS_DISPATCHED to the register whitelist This will allow us to read the number of dispatched compute threads for GL_ARB_pipeline_statistics_query. Signed-off-by: Jordan Justen Cc: Ben Widawsky Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 0d757cd..806e812 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -405,6 +405,7 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { #define REG64(addr) (addr), (addr + sizeof(u32)) static const u32 gen7_render_regs[] = { + REG64(GPGPU_THREADS_DISPATCHED), REG64(HS_INVOCATION_COUNT), REG64(DS_INVOCATION_COUNT), REG64(IA_VERTICES_COUNT), @@ -1153,6 +1154,7 @@ int i915_cmd_parser_get_version(void) * hardware parsing enabled (so does not allow new use cases). * 2. Allow access to the MI_PREDICATE_SRC0 and * MI_PREDICATE_SRC1 registers. + * 3. Allow access to the GPGPU_THREADS_DISPATCHED register. */ - return 2; + return 3; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 451d526..1fdda42 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -463,17 +463,18 @@ */ #define BCS_SWCTRL 0x22200 -#define HS_INVOCATION_COUNT 0x2300 -#define DS_INVOCATION_COUNT 0x2308 -#define IA_VERTICES_COUNT 0x2310 -#define IA_PRIMITIVES_COUNT 0x2318 -#define VS_INVOCATION_COUNT 0x2320 -#define GS_INVOCATION_COUNT 0x2328 -#define GS_PRIMITIVES_COUNT 0x2330 -#define CL_INVOCATION_COUNT 0x2338 -#define CL_PRIMITIVES_COUNT 0x2340 -#define PS_INVOCATION_COUNT 0x2348 -#define PS_DEPTH_COUNT 0x2350 +#define GPGPU_THREADS_DISPATCHED 0x2290 +#define HS_INVOCATION_COUNT 0x2300 +#define DS_INVOCATION_COUNT 0x2308 +#define IA_VERTICES_COUNT 0x2310 +#define IA_PRIMITIVES_COUNT 0x2318 +#define VS_INVOCATION_COUNT 0x2320 +#define GS_INVOCATION_COUNT 0x2328 +#define GS_PRIMITIVES_COUNT 0x2330 +#define CL_INVOCATION_COUNT 0x2338 +#define CL_PRIMITIVES_COUNT 0x2340 +#define PS_INVOCATION_COUNT 0x2348 +#define PS_DEPTH_COUNT 0x2350 /* There are the 4 64-bit counter registers, one for each stream output */ #define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8) -- cgit v0.10.2 From 5a0afd4b78ec23f27f5d486ac3d102c2e8d66bd7 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Sat, 13 Dec 2014 11:43:27 +0530 Subject: drm/i915/chv: Use timeout mode for RC6 on chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Higher RC6 residency is observed using timeout mode instead of EI mode. It's Recommended to use TO Method for RC6. v2: Add comment about timeout threshold. (Tom) Signed-off-by: Deepak S Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8a960d1..4254e91 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4689,7 +4689,8 @@ static void cherryview_enable_rps(struct drm_device *dev) I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10); I915_WRITE(GEN6_RC_SLEEP, 0); - I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */ + /* TO threshold set to 1750 us ( 0x557 * 1.28 us) */ + I915_WRITE(GEN6_RC6_THRESHOLD, 0x557); /* allows RC6 residency counter to work */ I915_WRITE(VLV_COUNTER_CONTROL, @@ -4703,7 +4704,7 @@ static void cherryview_enable_rps(struct drm_device *dev) /* 3: Enable RC6 */ if ((intel_enable_rc6(dev) & INTEL_RC6_ENABLE) && (pcbr >> VLV_PCBR_ADDR_SHIFT)) - rc6_mode = GEN6_RC_CTL_EI_MODE(1); + rc6_mode = GEN7_RC_CTL_TO_MODE; I915_WRITE(GEN6_RC_CONTROL, rc6_mode); -- cgit v0.10.2 From 98711167ce9e734dc0e41e158debb7f4c1269917 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Fri, 12 Dec 2014 14:18:16 +0530 Subject: drm/i915: Skip gunit save/restore for cherryview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With cherryview onwards, Gunit hardware itself save and restore all the Gunit registers. Skipping the "vlv_save_gunit_s0ix_state" & "vlv_restore_gunit_s0ix_state" for cherryview in S3/S0ix sequence. Signed-off-by: Deepak S Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 71be3c9..95bc829 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1298,7 +1298,9 @@ static int vlv_suspend_complete(struct drm_i915_private *dev_priv) err = vlv_allow_gt_wake(dev_priv, false); if (err) goto err2; - vlv_save_gunit_s0ix_state(dev_priv); + + if (!IS_CHERRYVIEW(dev_priv->dev)) + vlv_save_gunit_s0ix_state(dev_priv); err = vlv_force_gfx_clock(dev_priv, false); if (err) @@ -1329,7 +1331,8 @@ static int vlv_resume_prepare(struct drm_i915_private *dev_priv, */ ret = vlv_force_gfx_clock(dev_priv, true); - vlv_restore_gunit_s0ix_state(dev_priv); + if (!IS_CHERRYVIEW(dev_priv->dev)) + vlv_restore_gunit_s0ix_state(dev_priv); err = vlv_allow_gt_wake(dev_priv, true); if (!ret) -- cgit v0.10.2 From 2f82bbdf3d4f1361c3d713c516d8aa390102374d Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Mon, 15 Dec 2014 14:58:00 +0000 Subject: drm/i915: Use true PPGTT in Gen8+ when execlists are enabled In Gen8+, full ppgtt needs execlist, otherwise the ctx switch can hang. Also remove the current restriction, a user should be able to explicitly set ppgtt=2. Note, this patch considers that execlist support has been enabled by default on Gen8. v2: Remove non-default restriction and clarify commit message (Daniel) Cc: Daniel Vetter Signed-off-by: Michel Thierry [danvet: s/comment/commit message/ in the commit message since that's what Michel meant as per our irc discussion.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index cc3056f..75a29a3 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -102,8 +102,6 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt) has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6; has_full_ppgtt = INTEL_INFO(dev)->gen >= 7; - if (IS_GEN8(dev)) - has_full_ppgtt = false; /* XXX why? */ /* * We don't allow disabling PPGTT for gen9+ as it's a requirement for @@ -134,7 +132,10 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt) return 0; } - return has_aliasing_ppgtt ? 1 : 0; + if (INTEL_INFO(dev)->gen >= 8 && i915.enable_execlists) + return 2; + else + return has_aliasing_ppgtt ? 1 : 0; } -- cgit v0.10.2 From e6c1abb7392f548f47b03dac6179916cd87f501e Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Wed, 26 Nov 2014 14:21:02 +0000 Subject: drm/i915: Warn about missing context state workarounds only once Otherwise, new platforms without workarounds will hit this warning for every new context created. Cc: Tvrtko Ursulin Signed-off-by: Michel Thierry Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 4dc6d42..7670a0f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1096,7 +1096,7 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring, struct drm_i915_private *dev_priv = dev->dev_private; struct i915_workarounds *w = &dev_priv->workarounds; - if (WARN_ON(w->count == 0)) + if (WARN_ON_ONCE(w->count == 0)) return 0; ring->gpu_caches_dirty = true; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f1ce169..3cad32a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -679,7 +679,7 @@ static int intel_ring_workarounds_emit(struct intel_engine_cs *ring, struct drm_i915_private *dev_priv = dev->dev_private; struct i915_workarounds *w = &dev_priv->workarounds; - if (WARN_ON(w->count == 0)) + if (WARN_ON_ONCE(w->count == 0)) return 0; ring->gpu_caches_dirty = true; -- cgit v0.10.2 From e2c719b75c8c186deb86570d8466df9e9eff919b Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 15 Dec 2014 13:56:32 -0500 Subject: drm/i915: tame the chattermouth (v2) Many distro's have mechanism in place to collect and automatically file bugs for failed WARN()s. And since i915 has a lot of hw state sanity checks which result in WARN(), it generates quite a lot of noise which is somewhat disconcerting to the end user. Separate out the internal hw-is-in-the-state-I-expected checks into I915_STATE_WARN()s and allow configuration via i915.verbose_checks module param about whether this will generate a full blown stacktrace or just DRM_ERROR(). The new moduleparam defaults to true, so by default there is no change in behavior. And even when disabled, you will still get an error message logged. v2: paint the macro names blue, clarify that the default behavior remains the same as before Signed-off-by: Rob Clark Acked-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eb4d64f..f318529 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -72,6 +72,35 @@ #define MISSING_CASE(x) WARN(1, "Missing switch case (%lu) in %s\n", \ (long) (x), __func__); +/* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and + * WARN_ON()) for hw state sanity checks to check for unexpected conditions + * which may not necessarily be a user visible problem. This will either + * WARN() or DRM_ERROR() depending on the verbose_checks moduleparam, to + * enable distros and users to tailor their preferred amount of i915 abrt + * spam. + */ +#define I915_STATE_WARN(condition, format...) ({ \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) { \ + if (i915.verbose_state_checks) \ + __WARN_printf(format); \ + else \ + DRM_ERROR(format); \ + } \ + unlikely(__ret_warn_on); \ +}) + +#define I915_STATE_WARN_ON(condition) ({ \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) { \ + if (i915.verbose_state_checks) \ + __WARN_printf("WARN_ON(" #condition ")\n"); \ + else \ + DRM_ERROR("WARN_ON(" #condition ")\n"); \ + } \ + unlikely(__ret_warn_on); \ +}) + enum pipe { INVALID_PIPE = -1, PIPE_A = 0, @@ -2401,6 +2430,7 @@ struct i915_params { bool disable_vtd_wa; int use_mmio_flip; bool mmio_debug; + bool verbose_state_checks; }; extern struct i915_params i915 __read_mostly; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index f6af6d4..07252d8 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -51,6 +51,7 @@ struct i915_params i915 __read_mostly = { .disable_vtd_wa = 0, .use_mmio_flip = 0, .mmio_debug = 0, + .verbose_state_checks = 1, }; module_param_named(modeset, i915.modeset, int, 0400); @@ -173,3 +174,7 @@ module_param_named(mmio_debug, i915.mmio_debug, bool, 0600); MODULE_PARM_DESC(mmio_debug, "Enable the MMIO debug code (default: false). This may negatively " "affect performance."); + +module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600); +MODULE_PARM_DESC(verbose_state_checks, + "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions."); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 878c485..0a09473 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1024,7 +1024,7 @@ void assert_pll(struct drm_i915_private *dev_priv, reg = DPLL(pipe); val = I915_READ(reg); cur_state = !!(val & DPLL_VCO_ENABLE); - WARN(cur_state != state, + I915_STATE_WARN(cur_state != state, "PLL state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); } @@ -1040,7 +1040,7 @@ static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state) mutex_unlock(&dev_priv->dpio_lock); cur_state = val & DSI_PLL_VCO_EN; - WARN(cur_state != state, + I915_STATE_WARN(cur_state != state, "DSI PLL state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); } @@ -1071,7 +1071,7 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv, return; cur_state = pll->get_hw_state(dev_priv, pll, &hw_state); - WARN(cur_state != state, + I915_STATE_WARN(cur_state != state, "%s assertion failure (expected %s, current %s)\n", pll->name, state_string(state), state_string(cur_state)); } @@ -1095,7 +1095,7 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv, val = I915_READ(reg); cur_state = !!(val & FDI_TX_ENABLE); } - WARN(cur_state != state, + I915_STATE_WARN(cur_state != state, "FDI TX state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); } @@ -1112,7 +1112,7 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv, reg = FDI_RX_CTL(pipe); val = I915_READ(reg); cur_state = !!(val & FDI_RX_ENABLE); - WARN(cur_state != state, + I915_STATE_WARN(cur_state != state, "FDI RX state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); } @@ -1135,7 +1135,7 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, reg = FDI_TX_CTL(pipe); val = I915_READ(reg); - WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n"); + I915_STATE_WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n"); } void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, @@ -1148,7 +1148,7 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, reg = FDI_RX_CTL(pipe); val = I915_READ(reg); cur_state = !!(val & FDI_RX_PLL_ENABLE); - WARN(cur_state != state, + I915_STATE_WARN(cur_state != state, "FDI RX PLL assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); } @@ -1190,7 +1190,7 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv, ((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS)) locked = false; - WARN(panel_pipe == pipe && locked, + I915_STATE_WARN(panel_pipe == pipe && locked, "panel assertion failure, pipe %c regs locked\n", pipe_name(pipe)); } @@ -1206,7 +1206,7 @@ static void assert_cursor(struct drm_i915_private *dev_priv, else cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE; - WARN(cur_state != state, + I915_STATE_WARN(cur_state != state, "cursor on pipe %c assertion failure (expected %s, current %s)\n", pipe_name(pipe), state_string(state), state_string(cur_state)); } @@ -1236,7 +1236,7 @@ void assert_pipe(struct drm_i915_private *dev_priv, cur_state = !!(val & PIPECONF_ENABLE); } - WARN(cur_state != state, + I915_STATE_WARN(cur_state != state, "pipe %c assertion failure (expected %s, current %s)\n", pipe_name(pipe), state_string(state), state_string(cur_state)); } @@ -1251,7 +1251,7 @@ static void assert_plane(struct drm_i915_private *dev_priv, reg = DSPCNTR(plane); val = I915_READ(reg); cur_state = !!(val & DISPLAY_PLANE_ENABLE); - WARN(cur_state != state, + I915_STATE_WARN(cur_state != state, "plane %c assertion failure (expected %s, current %s)\n", plane_name(plane), state_string(state), state_string(cur_state)); } @@ -1271,7 +1271,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv, if (INTEL_INFO(dev)->gen >= 4) { reg = DSPCNTR(pipe); val = I915_READ(reg); - WARN(val & DISPLAY_PLANE_ENABLE, + I915_STATE_WARN(val & DISPLAY_PLANE_ENABLE, "plane %c assertion failure, should be disabled but not\n", plane_name(pipe)); return; @@ -1283,7 +1283,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv, val = I915_READ(reg); cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >> DISPPLANE_SEL_PIPE_SHIFT; - WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe, + I915_STATE_WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe, "plane %c assertion failure, should be off on pipe %c but is still active\n", plane_name(i), pipe_name(pipe)); } @@ -1299,7 +1299,7 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, if (INTEL_INFO(dev)->gen >= 9) { for_each_sprite(pipe, sprite) { val = I915_READ(PLANE_CTL(pipe, sprite)); - WARN(val & PLANE_CTL_ENABLE, + I915_STATE_WARN(val & PLANE_CTL_ENABLE, "plane %d assertion failure, should be off on pipe %c but is still active\n", sprite, pipe_name(pipe)); } @@ -1307,20 +1307,20 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, for_each_sprite(pipe, sprite) { reg = SPCNTR(pipe, sprite); val = I915_READ(reg); - WARN(val & SP_ENABLE, + I915_STATE_WARN(val & SP_ENABLE, "sprite %c assertion failure, should be off on pipe %c but is still active\n", sprite_name(pipe, sprite), pipe_name(pipe)); } } else if (INTEL_INFO(dev)->gen >= 7) { reg = SPRCTL(pipe); val = I915_READ(reg); - WARN(val & SPRITE_ENABLE, + I915_STATE_WARN(val & SPRITE_ENABLE, "sprite %c assertion failure, should be off on pipe %c but is still active\n", plane_name(pipe), pipe_name(pipe)); } else if (INTEL_INFO(dev)->gen >= 5) { reg = DVSCNTR(pipe); val = I915_READ(reg); - WARN(val & DVS_ENABLE, + I915_STATE_WARN(val & DVS_ENABLE, "sprite %c assertion failure, should be off on pipe %c but is still active\n", plane_name(pipe), pipe_name(pipe)); } @@ -1328,7 +1328,7 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, static void assert_vblank_disabled(struct drm_crtc *crtc) { - if (WARN_ON(drm_crtc_vblank_get(crtc) == 0)) + if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0)) drm_crtc_vblank_put(crtc); } @@ -1337,12 +1337,12 @@ static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) u32 val; bool enabled; - WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev))); + I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev))); val = I915_READ(PCH_DREF_CONTROL); enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK | DREF_SUPERSPREAD_SOURCE_MASK)); - WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n"); + I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n"); } static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, @@ -1355,7 +1355,7 @@ static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, reg = PCH_TRANSCONF(pipe); val = I915_READ(reg); enabled = !!(val & TRANS_ENABLE); - WARN(enabled, + I915_STATE_WARN(enabled, "transcoder assertion failed, should be off on pipe %c but is still active\n", pipe_name(pipe)); } @@ -1435,11 +1435,11 @@ static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, enum pipe pipe, int reg, u32 port_sel) { u32 val = I915_READ(reg); - WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val), + I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val), "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); - WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0 + I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0 && (val & DP_PIPEB_SELECT), "IBX PCH dp port still using transcoder B\n"); } @@ -1448,11 +1448,11 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = I915_READ(reg); - WARN(hdmi_pipe_enabled(dev_priv, pipe, val), + I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val), "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); - WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0 + I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0 && (val & SDVO_PIPE_B_SELECT), "IBX PCH hdmi port still using transcoder B\n"); } @@ -1469,13 +1469,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, reg = PCH_ADPA; val = I915_READ(reg); - WARN(adpa_pipe_enabled(dev_priv, pipe, val), + I915_STATE_WARN(adpa_pipe_enabled(dev_priv, pipe, val), "PCH VGA enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); reg = PCH_LVDS; val = I915_READ(reg); - WARN(lvds_pipe_enabled(dev_priv, pipe, val), + I915_STATE_WARN(lvds_pipe_enabled(dev_priv, pipe, val), "PCH LVDS enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); @@ -5311,25 +5311,25 @@ static void intel_connector_check_state(struct intel_connector *connector) if (connector->mst_port) return; - WARN(connector->base.dpms == DRM_MODE_DPMS_OFF, + I915_STATE_WARN(connector->base.dpms == DRM_MODE_DPMS_OFF, "wrong connector dpms state\n"); - WARN(connector->base.encoder != &encoder->base, + I915_STATE_WARN(connector->base.encoder != &encoder->base, "active connector not linked to encoder\n"); if (encoder) { - WARN(!encoder->connectors_active, + I915_STATE_WARN(!encoder->connectors_active, "encoder->connectors_active not set\n"); encoder_enabled = encoder->get_hw_state(encoder, &pipe); - WARN(!encoder_enabled, "encoder not enabled\n"); - if (WARN_ON(!encoder->base.crtc)) + I915_STATE_WARN(!encoder_enabled, "encoder not enabled\n"); + if (I915_STATE_WARN_ON(!encoder->base.crtc)) return; crtc = encoder->base.crtc; - WARN(!crtc->enabled, "crtc not enabled\n"); - WARN(!to_intel_crtc(crtc)->active, "crtc not active\n"); - WARN(pipe != to_intel_crtc(crtc)->pipe, + I915_STATE_WARN(!crtc->enabled, "crtc not enabled\n"); + I915_STATE_WARN(!to_intel_crtc(crtc)->active, "crtc not active\n"); + I915_STATE_WARN(pipe != to_intel_crtc(crtc)->pipe, "encoder active on the wrong pipe\n"); } } @@ -7739,24 +7739,24 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) struct intel_crtc *crtc; for_each_intel_crtc(dev, crtc) - WARN(crtc->active, "CRTC for pipe %c enabled\n", + I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n", pipe_name(crtc->pipe)); - WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n"); - WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n"); - WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n"); - WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n"); - WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n"); - WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE, + I915_STATE_WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n"); + I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n"); + I915_STATE_WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n"); + I915_STATE_WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n"); + I915_STATE_WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n"); + I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE, "CPU PWM1 enabled\n"); if (IS_HASWELL(dev)) - WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE, + I915_STATE_WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE, "CPU PWM2 enabled\n"); - WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE, + I915_STATE_WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE, "PCH PWM1 enabled\n"); - WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE, + I915_STATE_WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE, "Utility pin enabled\n"); - WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n"); + I915_STATE_WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n"); /* * In theory we can still leave IRQs enabled, as long as only the HPD @@ -7764,7 +7764,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) * gen-specific and since we only disable LCPLL after we fully disable * the interrupts, the check below should be enough. */ - WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n"); + I915_STATE_WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n"); } static uint32_t hsw_read_dcomp(struct drm_i915_private *dev_priv) @@ -10640,7 +10640,7 @@ check_connector_state(struct drm_device *dev) * ->get_hw_state callbacks. */ intel_connector_check_state(connector); - WARN(&connector->new_encoder->base != connector->base.encoder, + I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder, "connector's staged encoder doesn't match current encoder\n"); } } @@ -10660,9 +10660,9 @@ check_encoder_state(struct drm_device *dev) encoder->base.base.id, encoder->base.name); - WARN(&encoder->new_crtc->base != encoder->base.crtc, + I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc, "encoder's stage crtc doesn't match current crtc\n"); - WARN(encoder->connectors_active && !encoder->base.crtc, + I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc, "encoder's active_connectors set, but no crtc\n"); list_for_each_entry(connector, &dev->mode_config.connector_list, @@ -10681,19 +10681,19 @@ check_encoder_state(struct drm_device *dev) if (!enabled && encoder->base.encoder_type == DRM_MODE_ENCODER_DPMST) continue; - WARN(!!encoder->base.crtc != enabled, + I915_STATE_WARN(!!encoder->base.crtc != enabled, "encoder's enabled state mismatch " "(expected %i, found %i)\n", !!encoder->base.crtc, enabled); - WARN(active && !encoder->base.crtc, + I915_STATE_WARN(active && !encoder->base.crtc, "active encoder with no crtc\n"); - WARN(encoder->connectors_active != active, + I915_STATE_WARN(encoder->connectors_active != active, "encoder's computed active state doesn't match tracked active state " "(expected %i, found %i)\n", active, encoder->connectors_active); active = encoder->get_hw_state(encoder, &pipe); - WARN(active != encoder->connectors_active, + I915_STATE_WARN(active != encoder->connectors_active, "encoder's hw state doesn't match sw tracking " "(expected %i, found %i)\n", encoder->connectors_active, active); @@ -10702,7 +10702,7 @@ check_encoder_state(struct drm_device *dev) continue; tracked_pipe = to_intel_crtc(encoder->base.crtc)->pipe; - WARN(active && pipe != tracked_pipe, + I915_STATE_WARN(active && pipe != tracked_pipe, "active encoder's pipe doesn't match" "(expected %i, found %i)\n", tracked_pipe, pipe); @@ -10727,7 +10727,7 @@ check_crtc_state(struct drm_device *dev) DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.base.id); - WARN(crtc->active && !crtc->base.enabled, + I915_STATE_WARN(crtc->active && !crtc->base.enabled, "active crtc, but not enabled in sw tracking\n"); for_each_intel_encoder(dev, encoder) { @@ -10738,10 +10738,10 @@ check_crtc_state(struct drm_device *dev) active = true; } - WARN(active != crtc->active, + I915_STATE_WARN(active != crtc->active, "crtc's computed active state doesn't match tracked active state " "(expected %i, found %i)\n", active, crtc->active); - WARN(enabled != crtc->base.enabled, + I915_STATE_WARN(enabled != crtc->base.enabled, "crtc's computed enabled state doesn't match tracked enabled state " "(expected %i, found %i)\n", enabled, crtc->base.enabled); @@ -10761,13 +10761,13 @@ check_crtc_state(struct drm_device *dev) encoder->get_config(encoder, &pipe_config); } - WARN(crtc->active != active, + I915_STATE_WARN(crtc->active != active, "crtc active state doesn't match with hw state " "(expected %i, found %i)\n", crtc->active, active); if (active && !intel_pipe_config_compare(dev, &crtc->config, &pipe_config)) { - WARN(1, "pipe state doesn't match!\n"); + I915_STATE_WARN(1, "pipe state doesn't match!\n"); intel_dump_pipe_config(crtc, &pipe_config, "[hw state]"); intel_dump_pipe_config(crtc, &crtc->config, @@ -10795,14 +10795,14 @@ check_shared_dpll_state(struct drm_device *dev) active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state); - WARN(pll->active > hweight32(pll->config.crtc_mask), + I915_STATE_WARN(pll->active > hweight32(pll->config.crtc_mask), "more active pll users than references: %i vs %i\n", pll->active, hweight32(pll->config.crtc_mask)); - WARN(pll->active && !pll->on, + I915_STATE_WARN(pll->active && !pll->on, "pll in active use but not on in sw tracking\n"); - WARN(pll->on && !pll->active, + I915_STATE_WARN(pll->on && !pll->active, "pll in on but not on in use in sw tracking\n"); - WARN(pll->on != active, + I915_STATE_WARN(pll->on != active, "pll on state mismatch (expected %i, found %i)\n", pll->on, active); @@ -10812,14 +10812,14 @@ check_shared_dpll_state(struct drm_device *dev) if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) active_crtcs++; } - WARN(pll->active != active_crtcs, + I915_STATE_WARN(pll->active != active_crtcs, "pll active crtcs mismatch (expected %i, found %i)\n", pll->active, active_crtcs); - WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs, + I915_STATE_WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs, "pll enabled crtcs mismatch (expected %i, found %i)\n", hweight32(pll->config.crtc_mask), enabled_crtcs); - WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state, + I915_STATE_WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state, sizeof(dpll_hw_state)), "pll hw state mismatch\n"); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8b31e01..88d81a8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1558,7 +1558,7 @@ void intel_edp_panel_vdd_on(struct intel_dp *intel_dp) vdd = edp_panel_vdd_on(intel_dp); pps_unlock(intel_dp); - WARN(!vdd, "eDP port %c VDD already requested on\n", + I915_STATE_WARN(!vdd, "eDP port %c VDD already requested on\n", port_name(dp_to_dig_port(intel_dp)->port)); } @@ -1642,7 +1642,7 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) if (!is_edp(intel_dp)) return; - WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on", + I915_STATE_WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on", port_name(dp_to_dig_port(intel_dp)->port)); intel_dp->want_panel_vdd = false; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 8a2bd18..6aa3a81 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -633,7 +633,7 @@ static void check_power_well_state(struct drm_i915_private *dev_priv, return; mismatch: - WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n", + I915_STATE_WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n", power_well->name, power_well->always_on, enabled, power_well->count, i915.disable_power_well); } -- cgit v0.10.2 From dafffda023b04f87e695dfcf5448e4da964d2e95 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 16 Dec 2014 12:02:13 +0100 Subject: drm/info: Remove unused code Commit 28a62277e06f ("drm: Convert proc files to seq_file and introduce debugfs") converted /proc files to debugfs and in the process dropped the entry for the vblank statistics. Since that file has been gone for almost five years, there is no use to keep the code that provides the file's content around. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 51efebd..f1b32f9 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -153,30 +153,6 @@ int drm_bufs_info(struct seq_file *m, void *data) } /** - * Called when "/proc/dri/.../vblank" is read. - */ -int drm_vblank_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; - int crtc; - - mutex_lock(&dev->struct_mutex); - for (crtc = 0; crtc < dev->num_crtcs; crtc++) { - seq_printf(m, "CRTC %d enable: %d\n", - crtc, atomic_read(&dev->vblank[crtc].refcount)); - seq_printf(m, "CRTC %d counter: %d\n", - crtc, drm_vblank_count(dev, crtc)); - seq_printf(m, "CRTC %d last wait: %d\n", - crtc, dev->vblank[crtc].last_wait); - seq_printf(m, "CRTC %d in modeset: %d\n", - crtc, dev->vblank[crtc].inmodeset); - } - mutex_unlock(&dev->struct_mutex); - return 0; -} - -/** * Called when "/proc/dri/.../clients" is read. * */ diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 7cc0a35..12a61d7 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -55,7 +55,6 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr int drm_name_info(struct seq_file *m, void *data); int drm_vm_info(struct seq_file *m, void *data); int drm_bufs_info(struct seq_file *m, void *data); -int drm_vblank_info(struct seq_file *m, void *data); int drm_clients_info(struct seq_file *m, void* data); int drm_gem_name_info(struct seq_file *m, void *data); -- cgit v0.10.2 From ef21bf73b9ae1e4b39ff984dc327f185d9c331b3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 17 Dec 2014 16:13:17 +0100 Subject: drm/doc: Remove duplicate "by" Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 3e212b9..d45b267 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1377,7 +1377,7 @@ int max_width, max_height; DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC. Primary - planes are the planes operated upon by by CRTC modesetting and flipping + planes are the planes operated upon by CRTC modesetting and flipping operations described in . -- cgit v0.10.2 From ce38ab05931484e72f776d04bb5d27c82744dd24 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 4 Dec 2014 06:48:10 -0800 Subject: drm/i915: Organize Fence registers for future enablement. Let's be optimistic that for future platforms this will remain the same and reorg a bit. This reorg in if blocks instead of switch make life easier for future platform support addition. v2: Jani pointed out I was missing reg_830 for some gen3 platforms. So let's make this platforms subcases of Gen checks. Cc: Jani Nikula Cc: Damien Lespiau Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a7bf31a..f678017 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3277,17 +3277,12 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg, "bogus fence setup with stride: 0x%x, tiling mode: %i\n", obj->stride, obj->tiling_mode); - switch (INTEL_INFO(dev)->gen) { - case 9: - case 8: - case 7: - case 6: - case 5: - case 4: i965_write_fence_reg(dev, reg, obj); break; - case 3: i915_write_fence_reg(dev, reg, obj); break; - case 2: i830_write_fence_reg(dev, reg, obj); break; - default: BUG(); - } + if (IS_GEN2(dev)) + i830_write_fence_reg(dev, reg, obj); + else if (IS_GEN3(dev)) + i915_write_fence_reg(dev, reg, obj); + else if (INTEL_INFO(dev)->gen >= 4) + i965_write_fence_reg(dev, reg, obj); /* And similarly be paranoid that no direct access to this region * is reordered to before the fence is installed. diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index f97479a..010f57f 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -764,32 +764,21 @@ static void i915_gem_record_fences(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; int i; - /* Fences */ - switch (INTEL_INFO(dev)->gen) { - case 9: - case 8: - case 7: - case 6: - for (i = 0; i < dev_priv->num_fence_regs; i++) - error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); - break; - case 5: - case 4: - for (i = 0; i < 16; i++) - error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); - break; - case 3: - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); - case 2: + if (IS_GEN3(dev) || IS_GEN2(dev)) { for (i = 0; i < 8; i++) error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); - break; - - default: - BUG(); - } + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + for (i = 0; i < 8; i++) + error->fence[i+8] = I915_READ(FENCE_REG_945_8 + + (i * 4)); + } else if (IS_GEN5(dev) || IS_GEN4(dev)) + for (i = 0; i < 16; i++) + error->fence[i] = I915_READ64(FENCE_REG_965_0 + + (i * 8)); + else if (INTEL_INFO(dev)->gen >= 6) + for (i = 0; i < dev_priv->num_fence_regs; i++) + error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + + (i * 8)); } -- cgit v0.10.2 From 1eb0f0061d8234ed204a1c6ed9e8bb8dcefa2789 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 3 Dec 2014 04:55:26 -0800 Subject: drm/i915: Organize PPGTT init Let's be optimistic that for future platforms memory management doesn't change that much and reuse gen8 function for PPGTT init. Cc: Damien Lespiau Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 75a29a3..82cb566 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1165,10 +1165,8 @@ static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) if (INTEL_INFO(dev)->gen < 8) return gen6_ppgtt_init(ppgtt); - else if (IS_GEN8(dev) || IS_GEN9(dev)) - return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total); else - BUG(); + return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total); } int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) { -- cgit v0.10.2 From 74745b093889aee5887e327b0108d56ba3ab9629 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 3 Dec 2014 04:55:27 -0800 Subject: drm/i915: Organize PDP regs report for future. Let's be optimistic that for future platforms this will remain the same and reorg a bit. This reorg in if blocks instead of switch make life easier for future platform support addition. Cc: Damien Lespiau Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 010f57f..d172d13 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -912,9 +912,13 @@ static void i915_record_ring_state(struct drm_device *dev, ering->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(ring)); - switch (INTEL_INFO(dev)->gen) { - case 9: - case 8: + if (IS_GEN6(dev)) + ering->vm_info.pp_dir_base = + I915_READ(RING_PP_DIR_BASE_READ(ring)); + else if (IS_GEN7(dev)) + ering->vm_info.pp_dir_base = + I915_READ(RING_PP_DIR_BASE(ring)); + else if (INTEL_INFO(dev)->gen >= 8) for (i = 0; i < 4; i++) { ering->vm_info.pdp[i] = I915_READ(GEN8_RING_PDP_UDW(ring, i)); @@ -922,16 +926,6 @@ static void i915_record_ring_state(struct drm_device *dev, ering->vm_info.pdp[i] |= I915_READ(GEN8_RING_PDP_LDW(ring, i)); } - break; - case 7: - ering->vm_info.pp_dir_base = - I915_READ(RING_PP_DIR_BASE(ring)); - break; - case 6: - ering->vm_info.pp_dir_base = - I915_READ(RING_PP_DIR_BASE_READ(ring)); - break; - } } } -- cgit v0.10.2 From 563f94f6faefe8cb497245a3511b272587ebd85b Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 3 Dec 2014 04:55:28 -0800 Subject: drm/i915: Organize INSTDONE report for future. Let's be optimistic that for future platforms this will remain the same and reorg a bit. This reorg in if blocks instead of switch make life easier for future platform support addition. Cc: Damien Lespiau Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index d172d13..be5c990 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1356,26 +1356,15 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone) struct drm_i915_private *dev_priv = dev->dev_private; memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG); - switch (INTEL_INFO(dev)->gen) { - case 2: - case 3: + if (IS_GEN2(dev) || IS_GEN3(dev)) instdone[0] = I915_READ(INSTDONE); - break; - case 4: - case 5: - case 6: + else if (IS_GEN4(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { instdone[0] = I915_READ(INSTDONE_I965); instdone[1] = I915_READ(INSTDONE1); - break; - default: - WARN_ONCE(1, "Unsupported platform\n"); - case 7: - case 8: - case 9: + } else if (INTEL_INFO(dev)->gen >= 7) { instdone[0] = I915_READ(GEN7_INSTDONE_1); instdone[1] = I915_READ(GEN7_SC_INSTDONE); instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE); instdone[3] = I915_READ(GEN7_ROW_INSTDONE); - break; } } -- cgit v0.10.2 From b1252bcfe53f8ced80ce4e07d761304e755594db Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 3 Dec 2014 04:55:29 -0800 Subject: drm/i915: Organize bind_vma funcs Let's be optimistic that for future platforms this will remain the same and reorg a bit. This reorg in if blocks instead of switch make life easier for future platform support addition. Cc: Damien Lespiau Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 82cb566..746f77f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2243,11 +2243,7 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, vma->obj = obj; vma->ggtt_view = *view; - switch (INTEL_INFO(vm->dev)->gen) { - case 9: - case 8: - case 7: - case 6: + if (INTEL_INFO(vm->dev)->gen >= 6) { if (i915_is_ggtt(vm)) { vma->unbind_vma = ggtt_unbind_vma; vma->bind_vma = ggtt_bind_vma; @@ -2255,17 +2251,10 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, vma->unbind_vma = ppgtt_unbind_vma; vma->bind_vma = ppgtt_bind_vma; } - break; - case 5: - case 4: - case 3: - case 2: + } else { BUG_ON(!i915_is_ggtt(vm)); vma->unbind_vma = i915_ggtt_unbind_vma; vma->bind_vma = i915_ggtt_bind_vma; - break; - default: - BUG(); } list_add_tail(&vma->vma_link, &obj->vma_list); -- cgit v0.10.2 From 05acaec334fcc1132d1e48c5042e044651e0b75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 17 Dec 2014 13:56:22 +0200 Subject: drm: Reorganize probed mode validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make drm_mode_validate_size() and drm_mode_validate_flag() deal with a single mode instead of having each iterate through the mode list. The hope is that in the future we might be able to share various mode validation functions between modeset and get_modes. Signed-off-by: Ville Syrjälä Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 6d8b941..1918866 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -907,8 +907,7 @@ EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo); /** * drm_mode_validate_size - make sure modes adhere to size constraints - * @dev: DRM device - * @mode_list: list of modes to check + * @mode: mode to check * @maxX: maximum width * @maxY: maximum height * @@ -916,20 +915,21 @@ EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo); * limitations of the DRM device/connector. If a mode is too big its status * member is updated with the appropriate validation failure code. The list * itself is not changed. + * + * Returns: + * The mode status */ -void drm_mode_validate_size(struct drm_device *dev, - struct list_head *mode_list, - int maxX, int maxY) +enum drm_mode_status +drm_mode_validate_size(const struct drm_display_mode *mode, + int maxX, int maxY) { - struct drm_display_mode *mode; + if (maxX > 0 && mode->hdisplay > maxX) + return MODE_VIRTUAL_X; - list_for_each_entry(mode, mode_list, head) { - if (maxX > 0 && mode->hdisplay > maxX) - mode->status = MODE_VIRTUAL_X; + if (maxY > 0 && mode->vdisplay > maxY) + return MODE_VIRTUAL_Y; - if (maxY > 0 && mode->vdisplay > maxY) - mode->status = MODE_VIRTUAL_Y; - } + return MODE_OK; } EXPORT_SYMBOL(drm_mode_validate_size); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 7483a47..2161d8e 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -58,28 +58,23 @@ static bool drm_kms_helper_poll = true; module_param_named(poll, drm_kms_helper_poll, bool, 0600); -static void drm_mode_validate_flag(struct drm_connector *connector, - int flags) +static enum drm_mode_status +drm_mode_validate_flag(const struct drm_display_mode *mode, + int flags) { - struct drm_display_mode *mode; + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && + !(flags & DRM_MODE_FLAG_INTERLACE)) + return MODE_NO_INTERLACE; - if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE | - DRM_MODE_FLAG_3D_MASK)) - return; + if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && + !(flags & DRM_MODE_FLAG_DBLSCAN)) + return MODE_NO_DBLESCAN; - list_for_each_entry(mode, &connector->modes, head) { - if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && - !(flags & DRM_MODE_FLAG_INTERLACE)) - mode->status = MODE_NO_INTERLACE; - if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && - !(flags & DRM_MODE_FLAG_DBLSCAN)) - mode->status = MODE_NO_DBLESCAN; - if ((mode->flags & DRM_MODE_FLAG_3D_MASK) && - !(flags & DRM_MODE_FLAG_3D_MASK)) - mode->status = MODE_NO_STEREO; - } + if ((mode->flags & DRM_MODE_FLAG_3D_MASK) && + !(flags & DRM_MODE_FLAG_3D_MASK)) + return MODE_NO_STEREO; - return; + return MODE_OK; } static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector) @@ -164,18 +159,19 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect drm_mode_connector_list_update(connector, merge_type_bits); - if (maxX && maxY) - drm_mode_validate_size(dev, &connector->modes, maxX, maxY); - if (connector->interlace_allowed) mode_flags |= DRM_MODE_FLAG_INTERLACE; if (connector->doublescan_allowed) mode_flags |= DRM_MODE_FLAG_DBLSCAN; if (connector->stereo_allowed) mode_flags |= DRM_MODE_FLAG_3D_MASK; - drm_mode_validate_flag(connector, mode_flags); list_for_each_entry(mode, &connector->modes, head) { + mode->status = drm_mode_validate_size(mode, maxX, maxY); + + if (mode->status == MODE_OK) + mode->status = drm_mode_validate_flag(mode, mode_flags); + if (mode->status == MODE_OK && connector_funcs->mode_valid) mode->status = connector_funcs->mode_valid(connector, mode); diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 91d0582..6c53114 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -217,9 +217,8 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); /* for use by the crtc helper probe functions */ -void drm_mode_validate_size(struct drm_device *dev, - struct list_head *mode_list, - int maxX, int maxY); +enum drm_mode_status drm_mode_validate_size(const struct drm_display_mode *mode, + int maxX, int maxY); void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose); void drm_mode_sort(struct list_head *mode_list); -- cgit v0.10.2 From abc0b1447d4974963548777a5ba4a4457c82c426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 17 Dec 2014 13:56:23 +0200 Subject: drm: Perform basic sanity checks on probed modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure the timings of probed modes at least pass some very basic sanity checks. The checks include: - clock,hdisplay,vdisplay are non zero - sync pulse fits within the blanking period - htotal,vtotal are big enough I have not checked all the drivers to see if the modes the generate might violate these constraints. I'm hoping not, because that would mean either abandoning the idea of doing this from the core code, or fixing the drivers. I'm not entirely sure about limiting the sync pulse to the blanking period. Intel hardware doesn't support such things, but some other hardware might. However at least HDMI doesn't allow having sync pulse edges within the active period, so I'm thinking the check is probably OK to have in the common code. Signed-off-by: Ville Syrjälä Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 1918866..11cc4de 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -906,6 +906,38 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo); /** + * drm_mode_validate_basic - make sure the mode is somewhat sane + * @mode: mode to check + * + * Check that the mode timings are at least somewhat reasonable. + * Any hardware specific limits are left up for each driver to check. + * + * Returns: + * The mode status + */ +enum drm_mode_status +drm_mode_validate_basic(const struct drm_display_mode *mode) +{ + if (mode->clock == 0) + return MODE_CLOCK_LOW; + + if (mode->hdisplay == 0 || + mode->hsync_start < mode->hdisplay || + mode->hsync_end < mode->hsync_start || + mode->htotal < mode->hsync_end) + return MODE_H_ILLEGAL; + + if (mode->vdisplay == 0 || + mode->vsync_start < mode->vdisplay || + mode->vsync_end < mode->vsync_start || + mode->vtotal < mode->vsync_end) + return MODE_V_ILLEGAL; + + return MODE_OK; +} +EXPORT_SYMBOL(drm_mode_validate_basic); + +/** * drm_mode_validate_size - make sure modes adhere to size constraints * @mode: mode to check * @maxX: maximum width diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 2161d8e..2fbdcca 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -167,7 +167,10 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect mode_flags |= DRM_MODE_FLAG_3D_MASK; list_for_each_entry(mode, &connector->modes, head) { - mode->status = drm_mode_validate_size(mode, maxX, maxY); + mode->status = drm_mode_validate_basic(mode); + + if (mode->status == MODE_OK) + mode->status = drm_mode_validate_size(mode, maxX, maxY); if (mode->status == MODE_OK) mode->status = drm_mode_validate_flag(mode, mode_flags); diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 6c53114..a36a5bf 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -217,6 +217,7 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); /* for use by the crtc helper probe functions */ +enum drm_mode_status drm_mode_validate_basic(const struct drm_display_mode *mode); enum drm_mode_status drm_mode_validate_size(const struct drm_display_mode *mode, int maxX, int maxY); void drm_mode_prune_invalid(struct drm_device *dev, -- cgit v0.10.2 From 23e1ce89af5404c7a35dbd008ca85fb6adb16aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 17 Dec 2014 13:56:24 +0200 Subject: drm: Do basic sanity checks for user modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently userspace is allowed to pass in basiclly any kind of garbage to setcrtc. Try to catch the cases where the timings make no sense by passing the mode through drm_mode_validate_basic(). One concern here is that we now start to block some modes that have worked in the past. It's at least possible with when using i915 with LVDS/eDP. Previously we've just ignored everything but hdisplay/vdisplay from the user mode and just overwritten the rest with the panel fixed mode. So if someone has been passing a mode with just those populated that would now stop working. If that is a real problem, we can't add these checks to the core code and each driver would have to have its own sanity checks. So fingers crossed... Signed-off-by: Ville Syrjälä Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 6700eba..e3140c1 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2673,6 +2673,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } + mode->status = drm_mode_validate_basic(mode); + if (mode->status != MODE_OK) { + ret = -EINVAL; + goto out; + } + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, -- cgit v0.10.2 From 261ea74f3689a997502f1264494f1749951a05a8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 17 Dec 2014 16:41:40 +0100 Subject: drm: Remove stale comment The struct drm_connector_funcs kerneldoc refers to a part of struct drm_crtc_funcs that no longer exists. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index dd2c16e..eb32b09 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -455,7 +455,7 @@ struct drm_connector_state { /** * struct drm_connector_funcs - control connectors on a given device - * @dpms: set power state (see drm_crtc_funcs above) + * @dpms: set power state * @save: save connector state * @restore: restore connector state * @reset: reset connector after state has been invalidated (e.g. resume) -- cgit v0.10.2 From d9b13620fa09d2652008f96e083592c772532fd1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 26 Nov 2014 16:57:41 +0100 Subject: drm/atomic-helper: Export both plane and modeset check helpers The default call sequence for these two parts won't fit for all drivers. So export the two pieces and explain with a bit of kerneldoc when each should be called. v2: Squash in fixup from Rob to actually add the newly exported functions to headers Cc: Rob Clark Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index bbdbe47..0cd71da 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -330,7 +330,29 @@ mode_fixup(struct drm_atomic_state *state) return 0; } -static int +/** + * drm_atomic_helper_check - validate state object for modeset changes + * @dev: DRM device + * @state: the driver state object + * + * Check the state object to see if the requested state is physically possible. + * This does all the crtc and connector related computations for an atomic + * update. It computes and updates crtc_state->mode_changed, adds any additional + * connectors needed for full modesets and calls down into ->mode_fixup + * functions of the driver backend. + * + * IMPORTANT: + * + * Drivers which update ->mode_changed (e.g. in their ->atomic_check hooks if a + * plane update can't be done without a full modeset) _must_ call this function + * afterwards after that change. It is permitted to call this function multiple + * times for the same update, e.g. when the ->atomic_check functions depend upon + * the adjusted dotclock for fifo space allocation and watermark computation. + * + * RETURNS + * Zero for success or -errno + */ +int drm_atomic_helper_check_modeset(struct drm_device *dev, struct drm_atomic_state *state) { @@ -406,23 +428,23 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, return mode_fixup(state); } +EXPORT_SYMBOL(drm_atomic_helper_check_modeset); /** - * drm_atomic_helper_check - validate state object + * drm_atomic_helper_check - validate state object for modeset changes * @dev: DRM device * @state: the driver state object * * Check the state object to see if the requested state is physically possible. - * Only crtcs and planes have check callbacks, so for any additional (global) - * checking that a driver needs it can simply wrap that around this function. - * Drivers without such needs can directly use this as their ->atomic_check() - * callback. + * This does all the plane update related checks using by calling into the + * ->atomic_check hooks provided by the driver. * * RETURNS * Zero for success or -errno */ -int drm_atomic_helper_check(struct drm_device *dev, - struct drm_atomic_state *state) +int +drm_atomic_helper_check_planes(struct drm_device *dev, + struct drm_atomic_state *state) { int nplanes = dev->mode_config.num_total_plane; int ncrtcs = dev->mode_config.num_crtc; @@ -471,6 +493,33 @@ int drm_atomic_helper_check(struct drm_device *dev, } } + return ret; +} +EXPORT_SYMBOL(drm_atomic_helper_check_planes); + +/** + * drm_atomic_helper_check - validate state object + * @dev: DRM device + * @state: the driver state object + * + * Check the state object to see if the requested state is physically possible. + * Only crtcs and planes have check callbacks, so for any additional (global) + * checking that a driver needs it can simply wrap that around this function. + * Drivers without such needs can directly use this as their ->atomic_check() + * callback. + * + * RETURNS + * Zero for success or -errno + */ +int drm_atomic_helper_check(struct drm_device *dev, + struct drm_atomic_state *state) +{ + int ret; + + ret = drm_atomic_helper_check_planes(dev, state); + if (ret) + return ret; + ret = drm_atomic_helper_check_modeset(dev, state); if (ret) return ret; diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index f956b41..2095917 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -30,6 +30,10 @@ #include +int drm_atomic_helper_check_modeset(struct drm_device *dev, + struct drm_atomic_state *state); +int drm_atomic_helper_check_planes(struct drm_device *dev, + struct drm_atomic_state *state); int drm_atomic_helper_check(struct drm_device *dev, struct drm_atomic_state *state); int drm_atomic_helper_commit(struct drm_device *dev, diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index b863298..4ee7821 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -238,6 +238,7 @@ struct drm_atomic_state; /** * struct drm_crtc_state - mutable CRTC state * @enable: whether the CRTC should be enabled, gates all other state + * @active: whether the CRTC is actively displaying (used for DPMS) * @mode_changed: for use by helpers and drivers when computing state updates * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes * @last_vblank_count: for helpers and drivers to capture the vblank of the @@ -248,9 +249,16 @@ struct drm_atomic_state; * @event: optional pointer to a DRM event to signal upon completion of the * state update * @state: backpointer to global drm_atomic_state + * + * Note that the distinction between @enable and @active is rather subtile: + * Flipping @active while @enable is set without changing anything else may + * never return in a failure from the ->atomic_check callback. Userspace assumes + * that a DPMS On will always succeed. In other words: @enable controls resource + * assignment, @active controls the actual hardware state. */ struct drm_crtc_state { bool enable; + bool active; /* computed state bits used by helpers and drivers */ bool planes_changed : 1; -- cgit v0.10.2 From b4274fbee6fc7ca3dd1cc786456ec6fbc14f864d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 26 Nov 2014 17:02:18 +0100 Subject: drm/atomic-helper: Again check modeset *before* plane states This essentially reverts commit 934ce1c23624526d9d784e0499190bb48113e6f4 Author: Rob Clark Date: Wed Nov 19 16:41:33 2014 -0500 drm/atomic: check mode_changed *after* atomic_check Depending upon the driver both orders (or maybe even interleaving) is required: - If ->atomic_check updates ->mode_changed then helper_check_modeset must be run afters. - If ->atomic_check depends upon accurate adjusted dotclock values for e.g. watermarks, then helper_check_modeset must be run first. The failure mode in the first case is usually a totally angry hw because the pixel format switching doesn't happen. The failure mode in the later case is usually nothing, since in most cases the old adjusted mode from the previous modeset wont be too far off to be a problem. So just underruns and perhaps even just suboptimal (from a power consumption) watermarks. Furthermore in the transitional helpers we only call ->atomic_check after the new modeset state has been fully set up (and hence computed). Given that asymmetry in expected failure modes I think it's safer to go back to the older order. So do that and give msm a special check function to compensate. Also update kerneldoc to explain this a bit. v2: Actually add the missing hunk Rob spotted. v3: Move msm_atomic_check into msm_atomic.c, requested by Rob. Cc: Rob Clark Reviewed-by: Rob Clark Tested-by: Rob Clark Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0cd71da..eb380ee 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -508,6 +508,12 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes); * Drivers without such needs can directly use this as their ->atomic_check() * callback. * + * This just wraps the two parts of the state checking for planes and modeset + * state in the default order: First it calls drm_atomic_helper_check_modeset() + * and then drm_atomic_helper_check_planes(). The assumption is that the + * ->atomic_check functions depend upon an updated adjusted_mode.clock to + * e.g. properly compute watermarks. + * * RETURNS * Zero for success or -errno */ @@ -516,11 +522,11 @@ int drm_atomic_helper_check(struct drm_device *dev, { int ret; - ret = drm_atomic_helper_check_planes(dev, state); + ret = drm_atomic_helper_check_modeset(dev, state); if (ret) return ret; - ret = drm_atomic_helper_check_modeset(dev, state); + ret = drm_atomic_helper_check_planes(dev, state); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index f0de412..f8f18e8 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -81,6 +81,26 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb) } +int msm_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) +{ + int ret; + + /* + * msm ->atomic_check can update ->mode_changed for pixel format + * changes, hence must be run before we check the modeset changes. + */ + ret = drm_atomic_helper_check_planes(dev, state); + if (ret) + return ret; + + ret = drm_atomic_helper_check_modeset(dev, state); + if (ret) + return ret; + + return ret; +} + /** * drm_atomic_helper_commit - commit validated state object * @dev: DRM device diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index d3b791b..473e4d6 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -29,7 +29,7 @@ static void msm_fb_output_poll_changed(struct drm_device *dev) static const struct drm_mode_config_funcs mode_config_funcs = { .fb_create = msm_framebuffer_create, .output_poll_changed = msm_fb_output_poll_changed, - .atomic_check = drm_atomic_helper_check, + .atomic_check = msm_atomic_check, .atomic_commit = msm_atomic_commit, }; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 1363038..d408e02 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -144,6 +144,8 @@ void __msm_fence_worker(struct work_struct *work); (_cb)->func = _func; \ } while (0) +int msm_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state); int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async); -- cgit v0.10.2 From 07cc0ef67fa873c8d21e0b626d57753bfd190095 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Nov 2014 15:49:39 +0100 Subject: drm/atomic: Introduce state->obj backpointers Useful since this way we can pass around just the state objects and will get ther real object, too. Specifically this allows us to again simplify the parameters for set_crtc_for_plane. v2: msm already has it's own specific plane_reset hook, don't forget that one! v3: Fixup kerneldoc, reported by 0-day builder. Cc: Rob Clark Reviewed-by: Rob Clark (v2) Tested-by: Rob Clark (v2) Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index ff5f034..cbd5e72 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -344,8 +344,7 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state); /** * drm_atomic_set_crtc_for_plane - set crtc for plane - * @state: the incoming atomic state - * @plane: the plane whose incoming state to update + * @plane_state: the plane whose incoming state to update * @crtc: crtc to use for the plane * * Changing the assigned crtc for a plane requires us to grab the lock and state @@ -358,16 +357,12 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state); * sequence must be restarted. All other errors are fatal. */ int -drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state, - struct drm_plane *plane, struct drm_crtc *crtc) +drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, + struct drm_crtc *crtc) { - struct drm_plane_state *plane_state = - drm_atomic_get_plane_state(state, plane); + struct drm_plane *plane = plane_state->plane; struct drm_crtc_state *crtc_state; - if (WARN_ON(IS_ERR(plane_state))) - return PTR_ERR(plane_state); - if (plane_state->crtc) { crtc_state = drm_atomic_get_crtc_state(plane_state->state, plane_state->crtc); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index eb380ee..379d37a 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1277,7 +1277,7 @@ retry: goto fail; } - ret = drm_atomic_set_crtc_for_plane(state, plane, crtc); + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); if (ret != 0) goto fail; drm_atomic_set_fb_for_plane(plane_state, fb); @@ -1356,7 +1356,7 @@ retry: goto fail; } - ret = drm_atomic_set_crtc_for_plane(state, plane, NULL); + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); if (ret != 0) goto fail; drm_atomic_set_fb_for_plane(plane_state, NULL); @@ -1519,7 +1519,7 @@ retry: crtc_state->enable = false; - ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, NULL); + ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); if (ret != 0) goto fail; @@ -1534,7 +1534,7 @@ retry: crtc_state->enable = true; drm_mode_copy(&crtc_state->mode, set->mode); - ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc); + ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); if (ret != 0) goto fail; drm_atomic_set_fb_for_plane(primary_state, set->fb); @@ -1806,7 +1806,7 @@ retry: goto fail; } - ret = drm_atomic_set_crtc_for_plane(state, plane, crtc); + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); if (ret != 0) goto fail; drm_atomic_set_fb_for_plane(plane_state, fb); @@ -1869,6 +1869,9 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) { kfree(crtc->state); crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); + + if (crtc->state) + crtc->state->crtc = crtc; } EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); @@ -1928,6 +1931,9 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane) kfree(plane->state); plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); + + if (plane->state) + plane->state->plane = plane; } EXPORT_SYMBOL(drm_atomic_helper_plane_reset); @@ -1985,6 +1991,9 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector) { kfree(connector->state); connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL); + + if (connector->state) + connector->state->connector = connector; } EXPORT_SYMBOL(drm_atomic_helper_connector_reset); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index d552708..b1979e7 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -946,6 +946,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); if (!crtc_state) return -ENOMEM; + crtc_state->crtc = crtc; crtc_state->enable = true; crtc_state->planes_changed = true; @@ -1005,6 +1006,7 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); if (!plane_state) return -ENOMEM; + plane_state->plane = plane; plane_state->crtc = crtc; drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb); diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 18a1ac6..ae61fb2 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -517,6 +517,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); if (!plane_state) return -ENOMEM; + plane_state->plane = plane; plane_state->crtc = crtc; drm_atomic_set_fb_for_plane(plane_state, fb); @@ -563,6 +564,7 @@ int drm_plane_helper_disable(struct drm_plane *plane) plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); if (!plane_state) return -ENOMEM; + plane_state->plane = plane; plane_state->crtc = NULL; drm_atomic_set_fb_for_plane(plane_state, NULL); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 26e5fde..fc76f63 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -113,6 +113,7 @@ static void mdp5_plane_reset(struct drm_plane *plane) } else { mdp5_state->zpos = 1 + drm_plane_index(plane); } + mdp5_state->base.plane = plane; plane->state = &mdp5_state->base; } diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index ad22295..e224ccf 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -46,8 +46,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, struct drm_connector *connector); int __must_check -drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state, - struct drm_plane *plane, struct drm_crtc *crtc); +drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, + struct drm_crtc *crtc); void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, struct drm_framebuffer *fb); int __must_check diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 4ee7821..fd8139c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -237,6 +237,7 @@ struct drm_atomic_state; /** * struct drm_crtc_state - mutable CRTC state + * @crtc: backpointer to the CRTC * @enable: whether the CRTC should be enabled, gates all other state * @active: whether the CRTC is actively displaying (used for DPMS) * @mode_changed: for use by helpers and drivers when computing state updates @@ -257,6 +258,8 @@ struct drm_atomic_state; * assignment, @active controls the actual hardware state. */ struct drm_crtc_state { + struct drm_crtc *crtc; + bool enable; bool active; @@ -457,11 +460,14 @@ struct drm_crtc { /** * struct drm_connector_state - mutable connector state + * @connector: backpointer to the connector * @crtc: CRTC to connect connector to, NULL if disabled * @best_encoder: can be used by helpers and drivers to select the encoder * @state: backpointer to global drm_atomic_state */ struct drm_connector_state { + struct drm_connector *connector; + struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_connector() */ struct drm_encoder *best_encoder; @@ -701,6 +707,7 @@ struct drm_connector { /** * struct drm_plane_state - mutable plane state + * @plane: backpointer to the plane * @crtc: currently bound CRTC, NULL if disabled * @fb: currently bound framebuffer * @fence: optional fence to wait for before scanning out @fb @@ -717,6 +724,8 @@ struct drm_connector { * @state: backpointer to global drm_atomic_state */ struct drm_plane_state { + struct drm_plane *plane; + struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */ struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */ struct fence *fence; -- cgit v0.10.2 From 3843e71f9882c9e2e965cf025f3a7d4de19ce823 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 16 Dec 2014 18:05:29 -0500 Subject: drm: allow property validation for refcnted props We can already have object properties, which technically can be fb's. Switch the property validation logic over to a get/put style interface so it can take a ref to refcnt'd objects, and then drop that ref after the driver has a chance to take it's own ref. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5213da4..5ee4b88 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4193,12 +4193,22 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, } EXPORT_SYMBOL(drm_mode_connector_update_edid_property); -static bool drm_property_change_is_valid(struct drm_property *property, - uint64_t value) +/* Some properties could refer to dynamic refcnt'd objects, or things that + * need special locking to handle lifetime issues (ie. to ensure the prop + * value doesn't become invalid part way through the property update due to + * race). The value returned by reference via 'obj' should be passed back + * to drm_property_change_valid_put() after the property is set (and the + * object to which the property is attached has a chance to take it's own + * reference). + */ +static bool drm_property_change_valid_get(struct drm_property *property, + uint64_t value, struct drm_mode_object **ref) { if (property->flags & DRM_MODE_PROP_IMMUTABLE) return false; + *ref = NULL; + if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { if (value < property->values[0] || value > property->values[1]) return false; @@ -4219,19 +4229,23 @@ static bool drm_property_change_is_valid(struct drm_property *property, /* Only the driver knows */ return true; } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { - struct drm_mode_object *obj; /* a zero value for an object property translates to null: */ if (value == 0) return true; - /* - * NOTE: use _object_find() directly to bypass restriction on - * looking up refcnt'd objects (ie. fb's). For a refcnt'd - * object this could race against object finalization, so it - * simply tells us that the object *was* valid. Which is good - * enough. - */ - obj = _object_find(property->dev, value, property->values[0]); - return obj != NULL; + + /* handle refcnt'd objects specially: */ + if (property->values[0] == DRM_MODE_OBJECT_FB) { + struct drm_framebuffer *fb; + fb = drm_framebuffer_lookup(property->dev, value); + if (fb) { + *ref = &fb->base; + return true; + } else { + return false; + } + } else { + return _object_find(property->dev, value, property->values[0]) != NULL; + } } else { int i; for (i = 0; i < property->num_values; i++) @@ -4241,6 +4255,18 @@ static bool drm_property_change_is_valid(struct drm_property *property, } } +static void drm_property_change_valid_put(struct drm_property *property, + struct drm_mode_object *ref) +{ + if (!ref) + return; + + if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { + if (property->values[0] == DRM_MODE_OBJECT_FB) + drm_framebuffer_unreference(obj_to_fb(ref)); + } +} + /** * drm_mode_connector_property_set_ioctl - set the current value of a connector property * @dev: DRM device @@ -4429,8 +4455,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, struct drm_mode_object *arg_obj; struct drm_mode_object *prop_obj; struct drm_property *property; - int ret = -EINVAL; - int i; + int i, ret = -EINVAL; + struct drm_mode_object *ref; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -4460,7 +4486,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, } property = obj_to_property(prop_obj); - if (!drm_property_change_is_valid(property, arg->value)) + if (!drm_property_change_valid_get(property, arg->value, &ref)) goto out; switch (arg_obj->type) { @@ -4477,6 +4503,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, break; } + drm_property_change_valid_put(property, ref); + out: drm_modeset_unlock_all(dev); return ret; -- cgit v0.10.2 From b17cd757a3f61e4519b70b4673f0467ec0153a10 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 16 Dec 2014 18:05:30 -0500 Subject: drm: store property instead of id in obj attachment Keep property pointer, instead of id, in per mode-object attachments. This will simplify things in later patches. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5ee4b88..2780a08 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2105,12 +2105,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr); prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); for (i = 0; i < connector->properties.count; i++) { - if (put_user(connector->properties.ids[i], - prop_ptr + copied)) { + struct drm_property *prop = connector->properties.properties[i]; + if (put_user(prop->base.id, prop_ptr + copied)) { ret = -EFAULT; goto out; } - if (put_user(connector->properties.values[i], prop_values + copied)) { ret = -EFAULT; @@ -3822,7 +3821,7 @@ void drm_object_attach_property(struct drm_mode_object *obj, return; } - obj->properties->ids[count] = property->base.id; + obj->properties->properties[count] = property; obj->properties->values[count] = init_val; obj->properties->count++; } @@ -3847,7 +3846,7 @@ int drm_object_property_set_value(struct drm_mode_object *obj, int i; for (i = 0; i < obj->properties->count; i++) { - if (obj->properties->ids[i] == property->base.id) { + if (obj->properties->properties[i] == property) { obj->properties->values[i] = val; return 0; } @@ -3877,7 +3876,7 @@ int drm_object_property_get_value(struct drm_mode_object *obj, int i; for (i = 0; i < obj->properties->count; i++) { - if (obj->properties->ids[i] == property->base.id) { + if (obj->properties->properties[i] == property) { *val = obj->properties->values[i]; return 0; } @@ -4413,8 +4412,8 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, prop_values_ptr = (uint64_t __user *)(unsigned long) (arg->prop_values_ptr); for (i = 0; i < props_count; i++) { - if (put_user(obj->properties->ids[i], - props_ptr + copied)) { + struct drm_property *prop = obj->properties->properties[i]; + if (put_user(prop->base.id, props_ptr + copied)) { ret = -EFAULT; goto out; } @@ -4472,7 +4471,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, goto out; for (i = 0; i < arg_obj->properties->count; i++) - if (arg_obj->properties->ids[i] == arg->prop_id) + if (arg_obj->properties->properties[i]->base.id == arg->prop_id) break; if (i == arg_obj->properties->count) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index fd8139c..265f90a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -64,7 +64,12 @@ struct drm_mode_object { #define DRM_OBJECT_MAX_PROPERTY 24 struct drm_object_properties { int count; - uint32_t ids[DRM_OBJECT_MAX_PROPERTY]; + /* NOTE: if we ever start dynamically destroying properties (ie. + * not at drm_mode_config_cleanup() time), then we'd have to do + * a better job of detaching property from mode objects to avoid + * dangling property pointers: + */ + struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY]; uint64_t values[DRM_OBJECT_MAX_PROPERTY]; }; -- cgit v0.10.2 From 22b8b13b6f436ffbb6e540f5f8039b1084a72794 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 16 Dec 2014 18:05:31 -0500 Subject: drm: get rid of direct property value access For atomic drivers, we won't use the values array but instead shunt things off to obj->atomic_get_property(). So to simplify things make all read/write of properties values go through the accessors. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2780a08..481bb25 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2106,12 +2106,17 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); for (i = 0; i < connector->properties.count; i++) { struct drm_property *prop = connector->properties.properties[i]; + uint64_t val; + + ret = drm_object_property_get_value(&connector->base, prop, &val); + if (ret) + goto out; + if (put_user(prop->base.id, prop_ptr + copied)) { ret = -EFAULT; goto out; } - if (put_user(connector->properties.values[i], - prop_values + copied)) { + if (put_user(val, prop_values + copied)) { ret = -EFAULT; goto out; } @@ -4413,12 +4418,18 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, (arg->prop_values_ptr); for (i = 0; i < props_count; i++) { struct drm_property *prop = obj->properties->properties[i]; + uint64_t val; + + ret = drm_object_property_get_value(obj, prop, &val); + if (ret) + goto out; + if (put_user(prop->base.id, props_ptr + copied)) { ret = -EFAULT; goto out; } - if (put_user(obj->properties->values[i], - prop_values_ptr + copied)) { + + if (put_user(val, prop_values_ptr + copied)) { ret = -EFAULT; goto out; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 265f90a..f7c0b7b 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -70,6 +70,9 @@ struct drm_object_properties { * dangling property pointers: */ struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY]; + /* do not read/write values directly, but use drm_object_property_get_value() + * and drm_object_property_set_value(): + */ uint64_t values[DRM_OBJECT_MAX_PROPERTY]; }; -- cgit v0.10.2 From 140fd38dc4962ae3694f81900b51c567df1b6d33 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 15 Dec 2014 10:11:53 -0800 Subject: drm/i915: Hold runtime PM during plane commit During plane operations, we read/write some registers that only operate properly if we're not runtime suspended. At the moment we're not holding the runtime PM reference across the whole plane operation, so there's a potential for problems. This issue was already partially addressed by commit commit d6dd6843ff4a57c662dbc378b9f99a9c034b0956 Author: Paulo Zanoni Date: Fri Aug 15 15:59:32 2014 -0300 drm/i915: fix plane/cursor handling when runtime suspended which took care of holding the runtime PM reference during the pin and fence operations for plane updates. However there are still a few actual plane registers that we also need to hold the runtime PM reference for. Recent refactoring patches in preparation for atomic have rearranged the code and made it increasingly likely that the hardware will have time to suspend between the pin/fence operation and the actual register writes. Examples of such registers are the stuff touched by ivb_get_colorkey. The solution here grabs the runtime PM reference around the 'commit' operation for planes, which should cover all the relevant register reads/writes. Note that this has only been exposed with commit 6beb8c23ebcc3d3287d8a247d11b73d7d0eaa475 Author: Matt Roper Date: Mon Dec 1 15:40:14 2014 -0800 drm/i915: Consolidate plane 'prepare' functions (v2) so doesn't need to be ported to 3.19. Cc: Paulo Zanoni Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=87180 Signed-off-by: Matt Roper Testcase: igt/pm-rpm/legacy-planes Reviewed-by: Paulo Zanoni [danvet: Augment commit message with information Paulo supplied.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0a09473..a1dbe74 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11864,6 +11864,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_w, uint32_t src_h) { struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_framebuffer *old_fb = plane->fb; struct intel_plane_state state; struct intel_plane *intel_plane = to_intel_plane(plane); @@ -11903,7 +11904,9 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, return ret; } + intel_runtime_pm_get(dev_priv); intel_plane->commit_plane(plane, &state); + intel_runtime_pm_put(dev_priv); if (fb != old_fb && old_fb) { if (intel_crtc->active) -- cgit v0.10.2 From b46004b70367974d5318caeabfd435017adf9e2a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 17 Dec 2014 16:41:41 +0100 Subject: drm: Move IRQ related fields to proper section The .irq and .irq_enabled fields are part of the VBLANK interrupt handling infrastructure, so move them to the appropriate section within the structure. Signed-off-by: Thierry Reding Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 8ba35c6..7cd1c68 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -744,8 +744,6 @@ struct drm_device { /** \name Context support */ /*@{ */ - bool irq_enabled; /**< True if irq handler is enabled */ - int irq; __volatile__ long context_flag; /**< Context swapping flag */ int last_context; /**< Last current context */ @@ -753,6 +751,8 @@ struct drm_device { /** \name VBLANK IRQ support */ /*@{ */ + bool irq_enabled; + int irq; /* * At load time, disabling the vblank interrupt won't be allowed since -- cgit v0.10.2 From 6d11a2f00724d52b988b5fedc6e6a050e1a46389 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 17 Dec 2014 16:41:42 +0100 Subject: drm: Make drm_crtc_helper.h standalone includible The file refers to a bunch of structure declared in drm_crtc.h, so include it to make sure the drm_crtc_helper.h header can be included standalone. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 7adbb65..8608897 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -39,6 +39,8 @@ #include +#include + enum mode_set_atomic { LEAVE_ATOMIC_MODE_SET, ENTER_ATOMIC_MODE_SET, -- cgit v0.10.2 From 7552e7dd9527c41f891c87854418896eaf309c20 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 17 Dec 2014 16:41:43 +0100 Subject: drm: Include drm_crtc_helper.h in DocBook There is already a section that describes the helpers implemented by this module. Add the kerneldoc-generated structure descriptions to this section. While at it, add missing kerneldoc for the structures to avoid warnings when generating the documentation. Signed-off-by: Thierry Reding Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index d45b267..7af413f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2362,6 +2362,7 @@ void intel_crt_init(struct drm_device *dev) Modeset Helper Functions Reference +!Iinclude/drm/drm_crtc_helper.h !Edrivers/gpu/drm/drm_crtc_helper.c !Pdrivers/gpu/drm/drm_crtc_helper.c overview diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 8608897..e76828d 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -47,9 +47,20 @@ enum mode_set_atomic { }; /** - * drm_crtc_helper_funcs - helper operations for CRTCs - * @mode_fixup: try to fixup proposed mode for this connector + * struct drm_crtc_helper_funcs - helper operations for CRTCs + * @dpms: set power state + * @prepare: prepare the CRTC, called before @mode_set + * @commit: commit changes to CRTC, called after @mode_set + * @mode_fixup: try to fixup proposed mode for this CRTC * @mode_set: set this mode + * @mode_set_nofb: set mode only (no scanout buffer attached) + * @mode_set_base: update the scanout buffer + * @mode_set_base_atomic: non-blocking mode set (used for kgdb support) + * @load_lut: load color palette + * @disable: disable CRTC when no longer in use + * @atomic_check: check for validity of an atomic state + * @atomic_begin: begin atomic update + * @atomic_flush: flush atomic update * * The helper operations are called by the mid-layer CRTC helper. */ @@ -93,9 +104,17 @@ struct drm_crtc_helper_funcs { }; /** - * drm_encoder_helper_funcs - helper operations for encoders + * struct drm_encoder_helper_funcs - helper operations for encoders + * @dpms: set power state + * @save: save connector state + * @restore: restore connector state * @mode_fixup: try to fixup proposed mode for this connector + * @prepare: part of the disable sequence, called before the CRTC modeset + * @commit: called after the CRTC modeset * @mode_set: set this mode + * @get_crtc: return CRTC that the encoder is currently attached to + * @detect: connection status detection + * @disable: disable encoder when not in use (overrides DPMS off) * * The helper operations are called by the mid-layer CRTC helper. */ @@ -121,9 +140,10 @@ struct drm_encoder_helper_funcs { }; /** - * drm_connector_helper_funcs - helper operations for connectors + * struct drm_connector_helper_funcs - helper operations for connectors * @get_modes: get mode list for this connector - * @mode_valid (optional): is this mode valid on the given connector? + * @mode_valid: is this mode valid on the given connector? (optional) + * @best_encoder: return the preferred encoder for this connector * * The helper operations are called by the mid-layer CRTC helper. */ -- cgit v0.10.2 From 40ecc694e114a06b9ed77e3e94641b0f5490693c Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:46 -0500 Subject: drm: add atomic_set_property wrappers As we add properties for all the standard plane/crtc/connector attributes (in preperation for the atomic ioctl), we are going to want to handle core state in core (rather than per driver). Intercepting the core properties will be easier if the atomic_set_property vfuncs are not called directly, but instead have a mandatory wrapper function (which will later serve as the point to intercept core properties). v2: more verbose comments and copypasta comment fix Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index cbd5e72..6f729d1 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -217,6 +217,32 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_get_crtc_state); /** + * drm_atomic_crtc_set_property - set property on CRTC + * @crtc: the drm CRTC to set a property on + * @state: the state object to update with the new property value + * @property: the property to set + * @val: the new property value + * + * Use this instead of calling crtc->atomic_set_property directly. + * This function handles generic/core properties and calls out to + * driver's ->atomic_set_property() for driver properties. To ensure + * consistent behavior you must call this function rather than the + * driver hook directly. + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_atomic_crtc_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, struct drm_property *property, + uint64_t val) +{ + if (crtc->funcs->atomic_set_property) + return crtc->funcs->atomic_set_property(crtc, state, property, val); + return -EINVAL; +} +EXPORT_SYMBOL(drm_atomic_crtc_set_property); + +/** * drm_atomic_get_plane_state - get plane state * @state: global atomic state object * @plane: plane to get state object for @@ -272,6 +298,32 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_get_plane_state); /** + * drm_atomic_plane_set_property - set property on plane + * @plane: the drm plane to set a property on + * @state: the state object to update with the new property value + * @property: the property to set + * @val: the new property value + * + * Use this instead of calling plane->atomic_set_property directly. + * This function handles generic/core properties and calls out to + * driver's ->atomic_set_property() for driver properties. To ensure + * consistent behavior you must call this function rather than the + * driver hook directly. + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_atomic_plane_set_property(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_property *property, + uint64_t val) +{ + if (plane->funcs->atomic_set_property) + return plane->funcs->atomic_set_property(plane, state, property, val); + return -EINVAL; +} +EXPORT_SYMBOL(drm_atomic_plane_set_property); + +/** * drm_atomic_get_connector_state - get connector state * @state: global atomic state object * @connector: connector to get state object for @@ -343,6 +395,44 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_get_connector_state); /** + * drm_atomic_connector_set_property - set property on connector. + * @connector: the drm connector to set a property on + * @state: the state object to update with the new property value + * @property: the property to set + * @val: the new property value + * + * Use this instead of calling connector->atomic_set_property directly. + * This function handles generic/core properties and calls out to + * driver's ->atomic_set_property() for driver properties. To ensure + * consistent behavior you must call this function rather than the + * driver hook directly. + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_atomic_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = connector->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->dpms_property) { + /* setting DPMS property requires special handling, which + * is done in legacy setprop path for us. Disallow (for + * now?) atomic writes to DPMS property: + */ + return -EINVAL; + } else if (connector->funcs->atomic_set_property) { + return connector->funcs->atomic_set_property(connector, + state, property, val); + } else { + return -EINVAL; + } +} +EXPORT_SYMBOL(drm_atomic_connector_set_property); + +/** * drm_atomic_set_crtc_for_plane - set crtc for plane * @plane_state: the plane whose incoming state to update * @crtc: crtc to use for the plane diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 379d37a..57e5540 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1613,8 +1613,8 @@ retry: goto fail; } - ret = crtc->funcs->atomic_set_property(crtc, crtc_state, - property, val); + ret = drm_atomic_crtc_set_property(crtc, crtc_state, + property, val); if (ret) goto fail; @@ -1672,8 +1672,8 @@ retry: goto fail; } - ret = plane->funcs->atomic_set_property(plane, plane_state, - property, val); + ret = drm_atomic_plane_set_property(plane, plane_state, + property, val); if (ret) goto fail; @@ -1731,8 +1731,8 @@ retry: goto fail; } - ret = connector->funcs->atomic_set_property(connector, connector_state, - property, val); + ret = drm_atomic_connector_set_property(connector, connector_state, + property, val); if (ret) goto fail; diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index e224ccf..51168a8 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -38,12 +38,21 @@ void drm_atomic_state_free(struct drm_atomic_state *state); struct drm_crtc_state * __must_check drm_atomic_get_crtc_state(struct drm_atomic_state *state, struct drm_crtc *crtc); +int drm_atomic_crtc_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, struct drm_property *property, + uint64_t val); struct drm_plane_state * __must_check drm_atomic_get_plane_state(struct drm_atomic_state *state, struct drm_plane *plane); +int drm_atomic_plane_set_property(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_property *property, + uint64_t val); struct drm_connector_state * __must_check drm_atomic_get_connector_state(struct drm_atomic_state *state, struct drm_connector *connector); +int drm_atomic_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, struct drm_property *property, + uint64_t val); int __must_check drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f7c0b7b..7f15896 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -311,6 +311,7 @@ struct drm_crtc_state { * @atomic_duplicate_state: duplicate the atomic state for this CRTC * @atomic_destroy_state: destroy an atomic state for this CRTC * @atomic_set_property: set a property on an atomic state for this CRTC + * (do not call directly, use drm_atomic_crtc_set_property()) * * The drm_crtc_funcs structure is the central CRTC management structure * in the DRM. Each CRTC controls one or more connectors (note that the name @@ -497,6 +498,7 @@ struct drm_connector_state { * @atomic_duplicate_state: duplicate the atomic state for this connector * @atomic_destroy_state: destroy an atomic state for this connector * @atomic_set_property: set a property on an atomic state for this connector + * (do not call directly, use drm_atomic_connector_set_property()) * * Each CRTC may have one or more connectors attached to it. The functions * below allow the core DRM code to control connectors, enumerate available modes, @@ -760,6 +762,7 @@ struct drm_plane_state { * @atomic_duplicate_state: duplicate the atomic state for this plane * @atomic_destroy_state: destroy an atomic state for this plane * @atomic_set_property: set a property on an atomic state for this plane + * (do not call directly, use drm_atomic_plane_set_property()) */ struct drm_plane_funcs { int (*update_plane)(struct drm_plane *plane, -- cgit v0.10.2 From ac9c925616028f1f03f631f229bca49b3a92ce9a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:47 -0500 Subject: drm: add atomic_get_property Since we won't be using the obj->properties->values[] array to shadow property values for atomic drivers, we are going to need a vfunc for getting prop values. Add that along w/ mandatory wrapper fxns. v2: more comments and copypasta comment typo fix Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 6f729d1..9c4e149 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -243,6 +243,32 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, EXPORT_SYMBOL(drm_atomic_crtc_set_property); /** + * drm_atomic_crtc_get_property - get property on CRTC + * @crtc: the drm CRTC to get a property on + * @state: the state object with the property value to read + * @property: the property to get + * @val: the property value (returned by reference) + * + * Use this instead of calling crtc->atomic_get_property directly. + * This function handles generic/core properties and calls out to + * driver's ->atomic_get_property() for driver properties. To ensure + * consistent behavior you must call this function rather than the + * driver hook directly. + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_atomic_crtc_get_property(struct drm_crtc *crtc, + const struct drm_crtc_state *state, + struct drm_property *property, uint64_t *val) +{ + if (crtc->funcs->atomic_get_property) + return crtc->funcs->atomic_get_property(crtc, state, property, val); + return -EINVAL; +} +EXPORT_SYMBOL(drm_atomic_crtc_get_property); + +/** * drm_atomic_get_plane_state - get plane state * @state: global atomic state object * @plane: plane to get state object for @@ -324,6 +350,32 @@ int drm_atomic_plane_set_property(struct drm_plane *plane, EXPORT_SYMBOL(drm_atomic_plane_set_property); /** + * drm_atomic_plane_get_property - get property on plane + * @plane: the drm plane to get a property on + * @state: the state object with the property value to read + * @property: the property to get + * @val: the property value (returned by reference) + * + * Use this instead of calling plane->atomic_get_property directly. + * This function handles generic/core properties and calls out to + * driver's ->atomic_get_property() for driver properties. To ensure + * consistent behavior you must call this function rather than the + * driver hook directly. + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_atomic_plane_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, + struct drm_property *property, uint64_t *val) +{ + if (plane->funcs->atomic_get_property) + return plane->funcs->atomic_get_property(plane, state, property, val); + return -EINVAL; +} +EXPORT_SYMBOL(drm_atomic_plane_get_property); + +/** * drm_atomic_get_connector_state - get connector state * @state: global atomic state object * @connector: connector to get state object for @@ -433,6 +485,42 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, EXPORT_SYMBOL(drm_atomic_connector_set_property); /** + * drm_atomic_connector_get_property - get property on connector + * @connector: the drm connector to get a property on + * @state: the state object with the property value to read + * @property: the property to get + * @val: the property value (returned by reference) + * + * Use this instead of calling connector->atomic_get_property directly. + * This function handles generic/core properties and calls out to + * driver's ->atomic_get_property() for driver properties. To ensure + * consistent behavior you must call this function rather than the + * driver hook directly. + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_atomic_connector_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, uint64_t *val) +{ + struct drm_device *dev = connector->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->dpms_property) { + *val = connector->dpms; + } else if (connector->funcs->atomic_get_property) { + return connector->funcs->atomic_get_property(connector, + state, property, val); + } else { + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_connector_get_property); + +/** * drm_atomic_set_crtc_for_plane - set crtc for plane * @plane_state: the plane whose incoming state to update * @crtc: crtc to use for the plane diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 51168a8..d41233c 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -41,18 +41,27 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val); +int drm_atomic_crtc_get_property(struct drm_crtc *crtc, + const struct drm_crtc_state *state, + struct drm_property *property, uint64_t *val); struct drm_plane_state * __must_check drm_atomic_get_plane_state(struct drm_atomic_state *state, struct drm_plane *plane); int drm_atomic_plane_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val); +int drm_atomic_plane_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, + struct drm_property *property, uint64_t *val); struct drm_connector_state * __must_check drm_atomic_get_connector_state(struct drm_atomic_state *state, struct drm_connector *connector); int drm_atomic_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, struct drm_property *property, uint64_t val); +int drm_atomic_connector_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, uint64_t *val); int __must_check drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 7f15896..e1f3469 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -312,6 +312,8 @@ struct drm_crtc_state { * @atomic_destroy_state: destroy an atomic state for this CRTC * @atomic_set_property: set a property on an atomic state for this CRTC * (do not call directly, use drm_atomic_crtc_set_property()) + * @atomic_get_property: get a property on an atomic state for this CRTC + * (do not call directly, use drm_atomic_crtc_get_property()) * * The drm_crtc_funcs structure is the central CRTC management structure * in the DRM. Each CRTC controls one or more connectors (note that the name @@ -371,6 +373,10 @@ struct drm_crtc_funcs { struct drm_crtc_state *state, struct drm_property *property, uint64_t val); + int (*atomic_get_property)(struct drm_crtc *crtc, + const struct drm_crtc_state *state, + struct drm_property *property, + uint64_t *val); }; /** @@ -499,6 +505,8 @@ struct drm_connector_state { * @atomic_destroy_state: destroy an atomic state for this connector * @atomic_set_property: set a property on an atomic state for this connector * (do not call directly, use drm_atomic_connector_set_property()) + * @atomic_get_property: get a property on an atomic state for this connector + * (do not call directly, use drm_atomic_connector_get_property()) * * Each CRTC may have one or more connectors attached to it. The functions * below allow the core DRM code to control connectors, enumerate available modes, @@ -532,6 +540,10 @@ struct drm_connector_funcs { struct drm_connector_state *state, struct drm_property *property, uint64_t val); + int (*atomic_get_property)(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val); }; /** @@ -763,6 +775,8 @@ struct drm_plane_state { * @atomic_destroy_state: destroy an atomic state for this plane * @atomic_set_property: set a property on an atomic state for this plane * (do not call directly, use drm_atomic_plane_set_property()) + * @atomic_get_property: get a property on an atomic state for this plane + * (do not call directly, use drm_atomic_plane_get_property()) */ struct drm_plane_funcs { int (*update_plane)(struct drm_plane *plane, @@ -786,6 +800,10 @@ struct drm_plane_funcs { struct drm_plane_state *state, struct drm_property *property, uint64_t val); + int (*atomic_get_property)(struct drm_plane *plane, + const struct drm_plane_state *state, + struct drm_property *property, + uint64_t *val); }; enum drm_plane_type { -- cgit v0.10.2 From ccfc08655d5fd5076828f45fb09194c070f2f63a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:48 -0500 Subject: drm: tweak getconnector locking We need to hold connection_mutex as we read the properties. Easiest thing is just widen the scope where connection_mutex is held. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 303c991..2031ead 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2031,6 +2031,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); connector = drm_connector_find(dev, out_resp->connector_id); if (!connector) { @@ -2062,14 +2063,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, out_resp->mm_height = connector->display_info.height_mm; out_resp->subpixel = connector->display_info.subpixel_order; out_resp->connection = connector->status; - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - encoder = drm_connector_get_encoder(connector); if (encoder) out_resp->encoder_id = encoder->base.id; else out_resp->encoder_id = 0; - drm_modeset_unlock(&dev->mode_config.connection_mutex); /* * This ioctl is called twice, once to determine how much space is @@ -2135,6 +2133,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, out_resp->count_encoders = encoders_count; out: + drm_modeset_unlock(&dev->mode_config.connection_mutex); mutex_unlock(&dev->mode_config.mutex); return ret; -- cgit v0.10.2 From 95cbf110756c21397946ded181cc5ea4ab568c11 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:49 -0500 Subject: drm: refactor getproperties/getconnector Both need to iterate a mode objects properties. Split that out into a helper shared by both ioctl handlers, since this is going to become more complicated when we add atomic properties (which will need filtering from legacy userspace). Signed-off-by: Rob Clark Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2031ead..f5f34d0 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1991,6 +1991,38 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne return connector->encoder; } +/* helper for getconnector and getproperties ioctls */ +static int get_properties(struct drm_mode_object *obj, + uint32_t __user *prop_ptr, uint64_t __user *prop_values, + uint32_t *arg_count_props) +{ + int props_count = obj->properties->count; + int i, ret, copied = 0; + + if ((*arg_count_props >= props_count) && props_count) { + copied = 0; + for (i = 0; i < props_count; i++) { + struct drm_property *prop = obj->properties->properties[i]; + uint64_t val; + + ret = drm_object_property_get_value(obj, prop, &val); + if (ret) + return ret; + + if (put_user(prop->base.id, prop_ptr + copied)) + return -EFAULT; + + if (put_user(val, prop_values + copied)) + return -EFAULT; + + copied++; + } + } + *arg_count_props = props_count; + + return 0; +} + /** * drm_mode_getconnector - get connector configuration * @dev: drm device for the ioctl @@ -2012,15 +2044,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_encoder *encoder; struct drm_display_mode *mode; int mode_count = 0; - int props_count = 0; int encoders_count = 0; int ret = 0; int copied = 0; int i; struct drm_mode_modeinfo u_mode; struct drm_mode_modeinfo __user *mode_ptr; - uint32_t __user *prop_ptr; - uint64_t __user *prop_values; uint32_t __user *encoder_ptr; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -2039,8 +2068,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, goto out; } - props_count = connector->properties.count; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) if (connector->encoder_ids[i] != 0) encoders_count++; @@ -2091,30 +2118,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, } out_resp->count_modes = mode_count; - if ((out_resp->count_props >= props_count) && props_count) { - copied = 0; - prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr); - prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); - for (i = 0; i < connector->properties.count; i++) { - struct drm_property *prop = connector->properties.properties[i]; - uint64_t val; - - ret = drm_object_property_get_value(&connector->base, prop, &val); - if (ret) - goto out; - - if (put_user(prop->base.id, prop_ptr + copied)) { - ret = -EFAULT; - goto out; - } - if (put_user(val, prop_values + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - out_resp->count_props = props_count; + ret = get_properties(&connector->base, + (uint32_t __user *)(unsigned long)(out_resp->props_ptr), + (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), + &out_resp->count_props); + if (ret) + goto out; if ((out_resp->count_encoders >= encoders_count) && encoders_count) { copied = 0; @@ -4388,11 +4397,6 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, struct drm_mode_obj_get_properties *arg = data; struct drm_mode_object *obj; int ret = 0; - int i; - int copied = 0; - int props_count = 0; - uint32_t __user *props_ptr; - uint64_t __user *prop_values_ptr; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -4409,36 +4413,11 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, goto out; } - props_count = obj->properties->count; - - /* This ioctl is called twice, once to determine how much space is - * needed, and the 2nd time to fill it. */ - if ((arg->count_props >= props_count) && props_count) { - copied = 0; - props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); - prop_values_ptr = (uint64_t __user *)(unsigned long) - (arg->prop_values_ptr); - for (i = 0; i < props_count; i++) { - struct drm_property *prop = obj->properties->properties[i]; - uint64_t val; - - ret = drm_object_property_get_value(obj, prop, &val); - if (ret) - goto out; + ret = get_properties(obj, + (uint32_t __user *)(unsigned long)(arg->props_ptr), + (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), + &arg->count_props); - if (put_user(prop->base.id, props_ptr + copied)) { - ret = -EFAULT; - goto out; - } - - if (put_user(val, prop_values_ptr + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - arg->count_props = props_count; out: drm_modeset_unlock_all(dev); return ret; -- cgit v0.10.2 From 0e2cfc005b376ed7b5c9a9fc466b5842fcc18cc7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Dec 2014 16:21:42 +0100 Subject: drm/i915: Update DRIVER_DATE to 20141219 Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f318529..387eb2d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -55,7 +55,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20141205" +#define DRIVER_DATE "20141219" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- cgit v0.10.2 From 3b2b36e5f0ba60f5a7a770ab1bae3264b8d090b8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 9 Dec 2014 17:37:44 +0200 Subject: drm: adv7511: Remove interlaced mode check The ADV7511 supports interlaced modes fine, there's no need to reject them. Signed-off-by: Laurent Pinchart diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c index faf1c0c..fa140e0 100644 --- a/drivers/gpu/drm/i2c/adv7511.c +++ b/drivers/gpu/drm/i2c/adv7511.c @@ -644,9 +644,6 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder, if (mode->clock > 165000) return MODE_CLOCK_HIGH; - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - return MODE_NO_INTERLACE; - return MODE_OK; } -- cgit v0.10.2 From 347d761c74f75d55a36350ae7505498bd56b33ec Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 11 Dec 2014 01:26:04 +0200 Subject: drm: rcar-du: Don't fail probe in case of partial encoder init error If an encoder fails to initialize the device can still be used without the failed encoder. Don't propagate the error out of the probe function but just skip the failed encoder. As a special case a deferred probe request from the encoder is still propagated out of the probe function in order not to break the deferred probing mechanism. Signed-off-by: Laurent Pinchart diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 34a122a..7c74ecf 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -193,32 +193,46 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, if (renc->lvds) { dev_err(rcdu->dev, "Chaining LVDS and HDMI encoders not supported\n"); - return -EINVAL; + ret = -EINVAL; + goto done; } ret = rcar_du_hdmienc_init(rcdu, renc, enc_node); if (ret < 0) - return ret; + goto done; } else { ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, encoder_type); if (ret < 0) - return ret; + goto done; drm_encoder_helper_add(encoder, &encoder_helper_funcs); } switch (encoder_type) { case DRM_MODE_ENCODER_LVDS: - return rcar_du_lvds_connector_init(rcdu, renc, con_node); + ret = rcar_du_lvds_connector_init(rcdu, renc, con_node); + break; case DRM_MODE_ENCODER_DAC: - return rcar_du_vga_connector_init(rcdu, renc); + ret = rcar_du_vga_connector_init(rcdu, renc); + break; case DRM_MODE_ENCODER_TMDS: - return rcar_du_hdmi_connector_init(rcdu, renc); + ret = rcar_du_hdmi_connector_init(rcdu, renc); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + +done: + if (ret < 0) { + if (encoder->name) + encoder->funcs->destroy(encoder); + devm_kfree(rcdu->dev, renc); + } + + return ret; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 0c5ee61..cc9136e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -346,8 +346,14 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu) /* Process the output pipeline. */ ret = rcar_du_encoders_init_one(rcdu, output, &ep); if (ret < 0) { - of_node_put(ep_node); - return ret; + if (ret == -EPROBE_DEFER) { + of_node_put(ep_node); + return ret; + } + + dev_info(rcdu->dev, + "encoder initialization failed, skipping\n"); + continue; } num_encoders += ret; @@ -413,6 +419,11 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) if (ret < 0) return ret; + if (ret == 0) { + dev_err(rcdu->dev, "error: no encoder could be initialized\n"); + return -EINVAL; + } + num_encoders = ret; /* Set the possible CRTCs and possible clones. There's always at least -- cgit v0.10.2 From 49785e25816b0567112ba599504c3b78901a7db4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 9 Dec 2014 22:45:11 +0200 Subject: drm: rcar-du: Configure pitch for chroma plane of multiplanar formats The PnMWR register containing the plane stride must be programmed with correct stride values for both the luma and chroma planes when using a multiplanar format. Fix it. Signed-off-by: Laurent Pinchart diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 72a7cb4..fb3ea4f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -130,6 +130,8 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane) if (plane->format->planes == 2) { index = (index + 1) % 8; + rcar_du_plane_write(rgrp, index, PnMWR, plane->pitch); + rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x); rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * (plane->format->bpp == 16 ? 2 : 1) / 2); -- cgit v0.10.2 From 5e433b6312d9d05ac83078bfd2e6371f24d6eb46 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 26 Oct 2014 01:14:27 +0300 Subject: drm: rcar-du: Remove LVDS and HDMI encoders chaining restriction The rcar-du driver refuses connecting an LVDS output to an HDMI encoder. There is not technical reason for that restriction, remove it. Signed-off-by: Laurent Pinchart diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 7c74ecf..243aba8 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -190,13 +190,6 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, } if (type == RCAR_DU_ENCODER_HDMI) { - if (renc->lvds) { - dev_err(rcdu->dev, - "Chaining LVDS and HDMI encoders not supported\n"); - ret = -EINVAL; - goto done; - } - ret = rcar_du_hdmienc_init(rcdu, renc, enc_node); if (ret < 0) goto done; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c index 359bc99..0d774a9 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c @@ -21,6 +21,7 @@ #include "rcar_du_drv.h" #include "rcar_du_encoder.h" #include "rcar_du_hdmienc.h" +#include "rcar_du_lvdsenc.h" struct rcar_du_hdmienc { struct rcar_du_encoder *renc; @@ -39,9 +40,15 @@ static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode) if (hdmienc->dpms == mode) return; + if (mode == DRM_MODE_DPMS_ON && hdmienc->renc->lvds) + rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode); + if (sfuncs->dpms) sfuncs->dpms(encoder, mode); + if (mode != DRM_MODE_DPMS_ON && hdmienc->renc->lvds) + rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode); + hdmienc->dpms = mode; } @@ -49,8 +56,16 @@ static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + /* The internal LVDS encoder has a clock frequency operating range of + * 30MHz to 150MHz. Clamp the clock accordingly. + */ + if (hdmienc->renc->lvds) + adjusted_mode->clock = clamp(adjusted_mode->clock, + 30000, 150000); + if (sfuncs->mode_fixup == NULL) return true; -- cgit v0.10.2 From 0c1c877681e73b87ef63634ed7da55a711de40a6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 9 Dec 2014 00:21:12 +0200 Subject: drm: rcar-du: Refactor DEFR8 feature Rename the feature from RCAR_DU_FEATURE_DEFR8 to RCAR_DU_FEATURE_EXT_CTRL_REGS to cover all extended control registers in addition to the DEFR8 register. Usage of the feature is refactored to optimize runtime operation and prepare for external clock support. Signed-off-by: Laurent Pinchart diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 23cc910..cf0dca1 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -139,9 +139,10 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc, */ rcrtc->outputs |= BIT(output); - /* Store RGB routing to DPAD0 for R8A7790. */ - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_DEFR8) && - output == RCAR_DU_OUTPUT_DPAD0) + /* Store RGB routing to DPAD0, the hardware will be configured when + * starting the CRTC. + */ + if (output == RCAR_DU_OUTPUT_DPAD0) rcdu->dpad0_source = rcrtc->index; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 967ae8f..4fb29b47 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -56,7 +56,8 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = { }; static const struct rcar_du_device_info rcar_du_r8a7790_info = { - .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8, + .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK + | RCAR_DU_FEATURE_EXT_CTRL_REGS, .quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES, .num_crtcs = 3, .routes = { @@ -83,7 +84,8 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = { }; static const struct rcar_du_device_info rcar_du_r8a7791_info = { - .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8, + .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK + | RCAR_DU_FEATURE_EXT_CTRL_REGS, .num_crtcs = 2, .routes = { /* R8A7791 has one RGB output, one LVDS output and one diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 0a72466..c5b9ea6 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -27,7 +27,7 @@ struct rcar_du_device; struct rcar_du_lvdsenc; #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ -#define RCAR_DU_FEATURE_DEFR8 (1 << 1) /* Has DEFR8 register */ +#define RCAR_DU_FEATURE_EXT_CTRL_REGS (1 << 1) /* Has extended control registers */ #define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ #define RCAR_DU_QUIRK_LVDS_LANES (1 << 1) /* LVDS lanes 1 and 3 inverted */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 4e7614b..7b64282 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -48,9 +48,6 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) { u32 defr8 = DEFR8_CODE | DEFR8_DEFE8; - if (!rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_DEFR8)) - return; - /* The DEFR8 register for the first group also controls RGB output * routing to DPAD0 */ @@ -69,7 +66,8 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp) rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE); rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5); - rcar_du_group_setup_defr8(rgrp); + if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) + rcar_du_group_setup_defr8(rgrp); /* Use DS1PR and DS2PR to configure planes priorities and connects the * superposition 0 to DU0 pins. DU1 pins will be configured dynamically. @@ -149,6 +147,9 @@ static int rcar_du_set_dpad0_routing(struct rcar_du_device *rcdu) { int ret; + if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS)) + return 0; + /* RGB output routing to DPAD0 is configured in the DEFR8 register of * the first group. As this function can be called with the DU0 and DU1 * CRTCs disabled, we need to enable the first group clock before -- cgit v0.10.2 From 1b30dbde8596ca8de2497c2a50d5381dfe62ee8c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 9 Dec 2014 00:24:49 +0200 Subject: drm: rcar-du: Add support for external pixel clock The DU uses the module functional clock as the default pixel clock, but supports using an externally supplied pixel clock instead. Support this by adding the external pixel clock to the DT bindings, and selecting the clock automatically at runtime based on the requested mode pixel frequency. The input clock pins to DU channels routing is configurable, but currently hardcoded to connect input clock i to channel i. Signed-off-by: Laurent Pinchart diff --git a/Documentation/devicetree/bindings/video/renesas,du.txt b/Documentation/devicetree/bindings/video/renesas,du.txt index 5102830..c902323 100644 --- a/Documentation/devicetree/bindings/video/renesas,du.txt +++ b/Documentation/devicetree/bindings/video/renesas,du.txt @@ -26,6 +26,10 @@ Required Properties: per LVDS encoder. The functional clocks must be named "du.x" with "x" being the channel numerical index. The LVDS clocks must be named "lvds.x" with "x" being the LVDS encoder numerical index. + - In addition to the functional and encoder clocks, all DU versions also + support externally supplied pixel clocks. Those clocks are optional. + When supplied they must be named "dclkin.x" with "x" being the input + clock numerical index. Required nodes: diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index cf0dca1..ce280bd 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -74,33 +74,71 @@ static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc) if (ret < 0) return ret; + ret = clk_prepare_enable(rcrtc->extclock); + if (ret < 0) + goto error_clock; + ret = rcar_du_group_get(rcrtc->group); if (ret < 0) - clk_disable_unprepare(rcrtc->clock); + goto error_group; + + return 0; +error_group: + clk_disable_unprepare(rcrtc->extclock); +error_clock: + clk_disable_unprepare(rcrtc->clock); return ret; } static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc) { rcar_du_group_put(rcrtc->group); + + clk_disable_unprepare(rcrtc->extclock); clk_disable_unprepare(rcrtc->clock); } static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) { const struct drm_display_mode *mode = &rcrtc->crtc.mode; + unsigned long mode_clock = mode->clock * 1000; unsigned long clk; u32 value; + u32 escr; u32 div; - /* Dot clock */ + /* Compute the clock divisor and select the internal or external dot + * clock based on the requested frequency. + */ clk = clk_get_rate(rcrtc->clock); - div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000); + div = DIV_ROUND_CLOSEST(clk, mode_clock); div = clamp(div, 1U, 64U) - 1; + escr = div | ESCR_DCLKSEL_CLKS; + + if (rcrtc->extclock) { + unsigned long extclk; + unsigned long extrate; + unsigned long rate; + u32 extdiv; + + extclk = clk_get_rate(rcrtc->extclock); + extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock); + extdiv = clamp(extdiv, 1U, 64U) - 1; + + rate = clk / (div + 1); + extrate = extclk / (extdiv + 1); + + if (abs((long)extrate - (long)mode_clock) < + abs((long)rate - (long)mode_clock)) { + dev_dbg(rcrtc->group->dev->dev, + "crtc%u: using external clock\n", rcrtc->index); + escr = extdiv | ESCR_DCLKSEL_DCLKIN; + } + } rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, - ESCR_DCLKSEL_CLKS | div); + escr); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0); /* Signal polarities */ @@ -543,12 +581,13 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index]; struct drm_crtc *crtc = &rcrtc->crtc; unsigned int irqflags; - char clk_name[5]; + struct clk *clk; + char clk_name[9]; char *name; int irq; int ret; - /* Get the CRTC clock. */ + /* Get the CRTC clock and the optional external clock. */ if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) { sprintf(clk_name, "du.%u", index); name = clk_name; @@ -562,6 +601,15 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) return PTR_ERR(rcrtc->clock); } + sprintf(clk_name, "dclkin.%u", index); + clk = devm_clk_get(rcdu->dev, clk_name); + if (!IS_ERR(clk)) { + rcrtc->extclock = clk; + } else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) { + dev_info(rcdu->dev, "can't get external clock %u\n", index); + return -EPROBE_DEFER; + } + rcrtc->group = rgrp; rcrtc->mmio_offset = mmio_offsets[index]; rcrtc->index = index; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 984e608..d2f89f7 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -26,6 +26,7 @@ struct rcar_du_crtc { struct drm_crtc crtc; struct clk *clock; + struct clk *extclock; unsigned int mmio_offset; unsigned int index; bool started; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 7b64282..1bdc0ee 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -66,9 +66,21 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp) rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE); rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5); - if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) + if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) { rcar_du_group_setup_defr8(rgrp); + /* Configure input dot clock routing. We currently hardcode the + * configuration to routing DOTCLKINn to DUn. + */ + rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE | + DIDSR_LCDS_DCLKIN(2) | + DIDSR_LCDS_DCLKIN(1) | + DIDSR_LCDS_DCLKIN(0) | + DIDSR_PDCS_CLK(2, 0) | + DIDSR_PDCS_CLK(1, 0) | + DIDSR_PDCS_CLK(0, 0)); + } + /* Use DS1PR and DS2PR to configure planes priorities and connects the * superposition 0 to DU0 pins. DU1 pins will be configured dynamically. */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h index 73f7347..c3639d1 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h @@ -256,8 +256,8 @@ #define DIDSR_LCDS_LVDS0(n) (2 << (8 + (n) * 2)) #define DIDSR_LCDS_LVDS1(n) (3 << (8 + (n) * 2)) #define DIDSR_LCDS_MASK(n) (3 << (8 + (n) * 2)) -#define DIDSR_PCDS_CLK(n, clk) (clk << ((n) * 2)) -#define DIDSR_PCDS_MASK(n) (3 << ((n) * 2)) +#define DIDSR_PDCS_CLK(n, clk) (clk << ((n) * 2)) +#define DIDSR_PDCS_MASK(n) (3 << ((n) * 2)) /* ----------------------------------------------------------------------------- * Display Timing Generation Registers -- cgit v0.10.2 From f67e1e058b722a2a2af4e40fa80936889f128b4c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 9 Dec 2014 00:40:59 +0200 Subject: drm: rcar-du: Output HSYNC instead of CSYNC The DU outputs by default a composite sync signal (XOR of the horizontal and vertical sync signals) on the HSYNC output pin. As this can confuse devices and isn't needed by any of the supported encoders, configure the HSYNC pin to output the horizontal sync signal. Signed-off-by: Laurent Pinchart diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index ce280bd..25b762b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -144,7 +144,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) /* Signal polarities */ value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL) | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL) - | DSMR_DIPM_DE; + | DSMR_DIPM_DE | DSMR_CSPM; rcar_du_crtc_write(rcrtc, DSMR, value); /* Display timings */ -- cgit v0.10.2 From 2d60762adebfa9fabca69fc2f2f2d51d4cfd7af5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 9 Dec 2014 01:18:36 +0200 Subject: drm: rcar-du: Enable hotplug detection on HDMI connector As HDMI support hotplug detection, enable HPD-based poll on HDMI connectors. Signed-off-by: Laurent Pinchart diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c index 4d7d4dd..322b720 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c @@ -95,6 +95,7 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, connector = &rcon->connector; connector->display_info.width_mm = 0; connector->display_info.height_mm = 0; + connector->polled = DRM_CONNECTOR_POLL_HPD; ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, DRM_MODE_CONNECTOR_HDMIA); -- cgit v0.10.2 From 3dbf11e42108d2c8a497923df959eb82388131f8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 9 Dec 2014 13:19:10 +0200 Subject: drm: rcar-du: Clamp DPMS states to on and off The intermediate DPMS standby and suspend states are a thing from the past. They only matter in practice for VGA CRT monitors, and are just a power saving vs. resume time optimization. Given that they have never been implemented properly in the rcar-du driver and that the Intel driver has dropped them on the vga port years ago, it's safe to only care about the on and off states. Signed-off-by: Laurent Pinchart diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 25b762b..86766cc 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -347,6 +347,9 @@ static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode) { struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + if (rcrtc->dpms == mode) return; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 243aba8..279167f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -46,6 +46,9 @@ static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode) { struct rcar_du_encoder *renc = to_rcar_encoder(encoder); + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + if (renc->lvds) rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode); } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c index 0d774a9..221f0a1 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c @@ -37,6 +37,9 @@ static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode) struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + if (hdmienc->dpms == mode) return; -- cgit v0.10.2 From 906eff7fcada4186cde54eb89572fb774ab294a0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 9 Dec 2014 19:11:18 +0200 Subject: drm: rcar-du: Implement support for interlaced modes Accept interlaced modes on the VGA and HDMI connectors and configure the hardware accordingly. Signed-off-by: Laurent Pinchart diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 86766cc..25c7a99 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -155,12 +155,15 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) mode->hsync_start - 1); rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1); - rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2); - rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end + - mode->vdisplay - 2); - rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end + - mode->vsync_start - 1); - rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1); + rcar_du_crtc_write(rcrtc, VDSR, mode->crtc_vtotal - + mode->crtc_vsync_end - 2); + rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal - + mode->crtc_vsync_end + + mode->crtc_vdisplay - 2); + rcar_du_crtc_write(rcrtc, VSPR, mode->crtc_vtotal - + mode->crtc_vsync_end + + mode->crtc_vsync_start - 1); + rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1); rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start); rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); @@ -256,6 +259,7 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc) static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) { struct drm_crtc *crtc = &rcrtc->crtc; + bool interlaced; unsigned int i; if (rcrtc->started) @@ -291,7 +295,10 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) * sync mode (with the HSYNC and VSYNC signals configured as outputs and * actively driven). */ - rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER); + interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE; + rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK, + (interlaced ? DSYSR_SCM_INT_VIDEO : 0) | + DSYSR_TVM_MASTER); rcar_du_group_start_stop(rcrtc->group, true); @@ -528,7 +535,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) status = rcar_du_crtc_read(rcrtc, DSSR); rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); - if (status & DSSR_VBK) { + if (status & DSSR_FRM) { drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index); rcar_du_crtc_finish_page_flip(rcrtc); ret = IRQ_HANDLED; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c index 322b720..ca94b02 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c @@ -95,6 +95,7 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, connector = &rcon->connector; connector->display_info.width_mm = 0; connector->display_info.height_mm = 0; + connector->interlace_allowed = true; connector->polled = DRM_CONNECTOR_POLL_HPD; ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index fb3ea4f..50f2f2b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -104,14 +104,22 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane) { struct rcar_du_group *rgrp = plane->group; unsigned int index = plane->hwindex; + bool interlaced; u32 mwr; - /* Memory pitch (expressed in pixels) */ + interlaced = plane->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE; + + /* Memory pitch (expressed in pixels). Must be doubled for interlaced + * operation with 32bpp formats. + */ if (plane->format->planes == 2) mwr = plane->pitch; else mwr = plane->pitch * 8 / plane->format->bpp; + if (interlaced && plane->format->bpp == 32) + mwr *= 2; + rcar_du_plane_write(rgrp, index, PnMWR, mwr); /* The Y position is expressed in raster line units and must be doubled @@ -119,12 +127,16 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane) * doubling the Y position is found in the R8A7779 datasheet, but the * rule seems to apply there as well. * + * Despite not being documented, doubling seem not to be needed when + * operating in interlaced mode. + * * Similarly, for the second plane, NV12 and NV21 formats seem to - * require a halved Y position value. + * require a halved Y position value, in both progressive and interlaced + * modes. */ rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x); rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * - (plane->format->bpp == 32 ? 2 : 1)); + (!interlaced && plane->format->bpp == 32 ? 2 : 1)); rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]); if (plane->format->planes == 2) { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h index c3639d1..70fcbc4 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h @@ -34,6 +34,7 @@ #define DSYSR_SCM_INT_NONE (0 << 4) #define DSYSR_SCM_INT_SYNC (2 << 4) #define DSYSR_SCM_INT_VIDEO (3 << 4) +#define DSYSR_SCM_MASK (3 << 4) #define DSMR 0x00004 #define DSMR_VSPM (1 << 28) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c index 752747a..9d48799 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c @@ -64,6 +64,7 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu, connector = &rcon->connector; connector->display_info.width_mm = 0; connector->display_info.height_mm = 0; + connector->interlace_allowed = true; ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, DRM_MODE_CONNECTOR_VGA); -- cgit v0.10.2 From f32c4c506f9b197f24d4be4ee7283bd549e3a30f Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 30 Dec 2014 15:08:16 +0100 Subject: drm: sti: add DVO output connector Digital Video Out connector driver LCD panels. Like HDMI and HDA it create bridge, encoder and connector drm object. Add binding description. Signed-off-by: Benjamin Gaignard diff --git a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt index c99eb34..6b1d75f 100644 --- a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt +++ b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt @@ -83,6 +83,22 @@ sti-hda: - clock-names: names of the clocks listed in clocks property in the same order. +sti-dvo: + Required properties: + must be a child of sti-tvout + - compatible: "st,stih-dvo" + - reg: Physical base address of the IP registers and length of memory mapped region. + - reg-names: names of the mapped memory regions listed in regs property in + the same order. + - clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend of the SoC type. + See ../clocks/clock-bindings.txt for details. + - clock-names: names of the clocks listed in clocks property in the same + order. + - pinctrl-0: pin control handle + - pinctrl-name: names of the pin control to use + - sti,panel: phandle of the panel connected to the DVO output + sti-hqvdp: must be a child of sti-display-subsystem Required properties: @@ -198,6 +214,19 @@ Example: clock-names = "pix", "hddac"; clocks = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>; }; + + sti-dvo@8d00400 { + compatible = "st,stih407-dvo"; + reg = <0x8d00400 0x200>; + reg-names = "dvo-reg"; + clock-names = "dvo_pix", "dvo", + "main_parent", "aux_parent"; + clocks = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>, + <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dvo>; + sti,panel = <&panel_dvo>; + }; }; sti-hqvdp@9c000000 { diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index 6ba9d27..f0f1e4e 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile @@ -12,6 +12,9 @@ stihdmi-y := sti_hdmi.o \ sti_hdmi_tx3g0c55phy.o \ sti_hdmi_tx3g4c28phy.o \ +stidvo-y := sti_dvo.o \ + sti_awg_utils.o + obj-$(CONFIG_DRM_STI) = \ sti_vtg.o \ sti_vtac.o \ @@ -20,4 +23,5 @@ obj-$(CONFIG_DRM_STI) = \ sti_tvout.o \ sticompositor.o \ sti_hqvdp.o \ + stidvo.o \ sti_drm_drv.o diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c new file mode 100644 index 0000000..9fde3ee --- /dev/null +++ b/drivers/gpu/drm/sti/sti_awg_utils.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Vincent Abriou for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include "sti_awg_utils.h" + +#define AWG_OPCODE_OFFSET 10 + +enum opcode { + SET, + RPTSET, + RPLSET, + SKIP, + STOP, + REPEAT, + REPLAY, + JUMP, + HOLD, +}; + +static int awg_generate_instr(enum opcode opcode, + long int arg, + long int mux_sel, + long int data_en, + struct awg_code_generation_params *fwparams) +{ + u32 instruction = 0; + u32 mux = (mux_sel << 8) & 0x1ff; + u32 data_enable = (data_en << 9) & 0x2ff; + long int arg_tmp = arg; + + /* skip, repeat and replay arg should not exceed 1023. + * If user wants to exceed this value, the instruction should be + * duplicate and arg should be adjust for each duplicated instruction. + */ + + while (arg_tmp > 0) { + arg = arg_tmp; + if (fwparams->instruction_offset >= AWG_MAX_INST) { + DRM_ERROR("too many number of instructions\n"); + return -EINVAL; + } + + switch (opcode) { + case SKIP: + /* leave 'arg' + 1 pixel elapsing without changing + * output bus */ + arg--; /* pixel adjustment */ + arg_tmp--; + + if (arg < 0) { + /* SKIP instruction not needed */ + return 0; + } + + if (arg == 0) { + /* SKIP 0 not permitted but we want to skip 1 + * pixel. So we transform SKIP into SET + * instruction */ + opcode = SET; + arg = (arg << 24) >> 24; + arg &= (0x0ff); + break; + } + + mux = 0; + data_enable = 0; + arg = (arg << 22) >> 22; + arg &= (0x3ff); + break; + case REPEAT: + case REPLAY: + if (arg == 0) { + /* REPEAT or REPLAY instruction not needed */ + return 0; + } + + mux = 0; + data_enable = 0; + arg = (arg << 22) >> 22; + arg &= (0x3ff); + break; + case JUMP: + mux = 0; + data_enable = 0; + arg |= 0x40; /* for jump instruction 7th bit is 1 */ + arg = (arg << 22) >> 22; + arg &= 0x3ff; + break; + case STOP: + arg = 0; + break; + case SET: + case RPTSET: + case RPLSET: + case HOLD: + arg = (arg << 24) >> 24; + arg &= (0x0ff); + break; + default: + DRM_ERROR("instruction %d does not exist\n", opcode); + return -EINVAL; + } + + arg_tmp = arg_tmp - arg; + + arg = ((arg + mux) + data_enable); + + instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg; + fwparams->ram_code[fwparams->instruction_offset] = + instruction & (0x3fff); + fwparams->instruction_offset++; + } + return 0; +} + +int sti_awg_generate_code_data_enable_mode( + struct awg_code_generation_params *fwparams, + struct awg_timing *timing) +{ + long int val; + long int data_en; + int ret = 0; + + if (timing->trailing_lines > 0) { + /* skip trailing lines */ + val = timing->blanking_level; + data_en = 0; + ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams); + + val = timing->trailing_lines - 1; + data_en = 0; + ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams); + } + + if (timing->trailing_pixels > 0) { + /* skip trailing pixel */ + val = timing->blanking_level; + data_en = 0; + ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams); + + val = timing->trailing_pixels - 1; + data_en = 0; + ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams); + } + + /* set DE signal high */ + val = timing->blanking_level; + data_en = 1; + ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET, + val, 0, data_en, fwparams); + + if (timing->blanking_pixels > 0) { + /* skip the number of active pixel */ + val = timing->active_pixels - 1; + data_en = 1; + ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams); + + /* set DE signal low */ + val = timing->blanking_level; + data_en = 0; + ret |= awg_generate_instr(SET, val, 0, data_en, fwparams); + } + + /* replay the sequence as many active lines defined */ + val = timing->active_lines - 1; + data_en = 0; + ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams); + + if (timing->blanking_lines > 0) { + /* skip blanking lines */ + val = timing->blanking_level; + data_en = 0; + ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams); + + val = timing->blanking_lines - 1; + data_en = 0; + ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams); + } + + return ret; +} diff --git a/drivers/gpu/drm/sti/sti_awg_utils.h b/drivers/gpu/drm/sti/sti_awg_utils.h new file mode 100644 index 0000000..45d599b --- /dev/null +++ b/drivers/gpu/drm/sti/sti_awg_utils.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Vincent Abriou for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_AWG_UTILS_H_ +#define _STI_AWG_UTILS_H_ + +#include + +#define AWG_MAX_INST 64 + +struct awg_code_generation_params { + u32 *ram_code; + u8 instruction_offset; +}; + +struct awg_timing { + u32 total_lines; + u32 active_lines; + u32 blanking_lines; + u32 trailing_lines; + u32 total_pixels; + u32 active_pixels; + u32 blanking_pixels; + u32 trailing_pixels; + u32 blanking_level; +}; + +int sti_awg_generate_code_data_enable_mode( + struct awg_code_generation_params *fw_gen_params, + struct awg_timing *timing); +#endif diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c new file mode 100644 index 0000000..651afad --- /dev/null +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -0,0 +1,551 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Vincent Abriou for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sti_awg_utils.h" +#include "sti_mixer.h" + +/* DVO registers */ +#define DVO_AWG_DIGSYNC_CTRL 0x0000 +#define DVO_DOF_CFG 0x0004 +#define DVO_LUT_PROG_LOW 0x0008 +#define DVO_LUT_PROG_MID 0x000C +#define DVO_LUT_PROG_HIGH 0x0010 +#define DVO_DIGSYNC_INSTR_I 0x0100 + +#define DVO_AWG_CTRL_EN BIT(0) +#define DVO_AWG_FRAME_BASED_SYNC BIT(2) + +#define DVO_DOF_EN_LOWBYTE BIT(0) +#define DVO_DOF_EN_MIDBYTE BIT(1) +#define DVO_DOF_EN_HIGHBYTE BIT(2) +#define DVO_DOF_EN BIT(6) +#define DVO_DOF_MOD_COUNT_SHIFT 8 + +#define DVO_LUT_ZERO 0 +#define DVO_LUT_Y_G 1 +#define DVO_LUT_Y_G_DEL 2 +#define DVO_LUT_CB_B 3 +#define DVO_LUT_CB_B_DEL 4 +#define DVO_LUT_CR_R 5 +#define DVO_LUT_CR_R_DEL 6 +#define DVO_LUT_HOLD 7 + +struct dvo_config { + u32 flags; + u32 lowbyte; + u32 midbyte; + u32 highbyte; + int (*awg_fwgen_fct)( + struct awg_code_generation_params *fw_gen_params, + struct awg_timing *timing); +}; + +static struct dvo_config rgb_24bit_de_cfg = { + .flags = (0L << DVO_DOF_MOD_COUNT_SHIFT), + .lowbyte = DVO_LUT_CR_R, + .midbyte = DVO_LUT_Y_G, + .highbyte = DVO_LUT_CB_B, + .awg_fwgen_fct = sti_awg_generate_code_data_enable_mode, +}; + +/** + * STI digital video output structure + * + * @dev: driver device + * @drm_dev: pointer to drm device + * @mode: current display mode selected + * @regs: dvo registers + * @clk_pix: pixel clock for dvo + * @clk: clock for dvo + * @clk_main_parent: dvo parent clock if main path used + * @clk_aux_parent: dvo parent clock if aux path used + * @panel_node: panel node reference from device tree + * @panel: reference to the panel connected to the dvo + * @enabled: true if dvo is enabled else false + * @encoder: drm_encoder it is bound + */ +struct sti_dvo { + struct device dev; + struct drm_device *drm_dev; + struct drm_display_mode mode; + void __iomem *regs; + struct clk *clk_pix; + struct clk *clk; + struct clk *clk_main_parent; + struct clk *clk_aux_parent; + struct device_node *panel_node; + struct drm_panel *panel; + struct dvo_config *config; + bool enabled; + struct drm_encoder *encoder; +}; + +struct sti_dvo_connector { + struct drm_connector drm_connector; + struct drm_encoder *encoder; + struct sti_dvo *dvo; +}; + +#define to_sti_dvo_connector(x) \ + container_of(x, struct sti_dvo_connector, drm_connector) + +#define BLANKING_LEVEL 16 +int dvo_awg_generate_code(struct sti_dvo *dvo, u8 *ram_size, u32 *ram_code) +{ + struct drm_display_mode *mode = &dvo->mode; + struct dvo_config *config = dvo->config; + struct awg_code_generation_params fw_gen_params; + struct awg_timing timing; + + fw_gen_params.ram_code = ram_code; + fw_gen_params.instruction_offset = 0; + + timing.total_lines = mode->vtotal; + timing.active_lines = mode->vdisplay; + timing.blanking_lines = mode->vsync_start - mode->vdisplay; + timing.trailing_lines = mode->vtotal - mode->vsync_start; + timing.total_pixels = mode->htotal; + timing.active_pixels = mode->hdisplay; + timing.blanking_pixels = mode->hsync_start - mode->hdisplay; + timing.trailing_pixels = mode->htotal - mode->hsync_start; + timing.blanking_level = BLANKING_LEVEL; + + if (config->awg_fwgen_fct(&fw_gen_params, &timing)) { + DRM_ERROR("AWG firmware not properly generated\n"); + return -EINVAL; + } + + *ram_size = fw_gen_params.instruction_offset; + + return 0; +} + +/* Configure AWG, writing instructions + * + * @dvo: pointer to DVO structure + * @awg_ram_code: pointer to AWG instructions table + * @nb: nb of AWG instructions + */ +static void dvo_awg_configure(struct sti_dvo *dvo, u32 *awg_ram_code, int nb) +{ + int i; + + DRM_DEBUG_DRIVER("\n"); + + for (i = 0; i < nb; i++) + writel(awg_ram_code[i], + dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4); + for (i = nb; i < AWG_MAX_INST; i++) + writel(0, dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4); + + writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL); +} + +static void sti_dvo_disable(struct drm_bridge *bridge) +{ + struct sti_dvo *dvo = bridge->driver_private; + + if (!dvo->enabled) + return; + + DRM_DEBUG_DRIVER("\n"); + + if (dvo->config->awg_fwgen_fct) + writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL); + + writel(0x00000000, dvo->regs + DVO_DOF_CFG); + + if (dvo->panel) + dvo->panel->funcs->disable(dvo->panel); + + /* Disable/unprepare dvo clock */ + clk_disable_unprepare(dvo->clk_pix); + clk_disable_unprepare(dvo->clk); + + dvo->enabled = false; +} + +static void sti_dvo_pre_enable(struct drm_bridge *bridge) +{ + struct sti_dvo *dvo = bridge->driver_private; + struct dvo_config *config = dvo->config; + u32 val; + + DRM_DEBUG_DRIVER("\n"); + + if (dvo->enabled) + return; + + /* Make sure DVO is disabled */ + writel(0x00000000, dvo->regs + DVO_DOF_CFG); + writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL); + + if (config->awg_fwgen_fct) { + u8 nb_instr; + u32 awg_ram_code[AWG_MAX_INST]; + /* Configure AWG */ + if (!dvo_awg_generate_code(dvo, &nb_instr, awg_ram_code)) + dvo_awg_configure(dvo, awg_ram_code, nb_instr); + else + return; + } + + /* Prepare/enable clocks */ + if (clk_prepare_enable(dvo->clk_pix)) + DRM_ERROR("Failed to prepare/enable dvo_pix clk\n"); + if (clk_prepare_enable(dvo->clk)) + DRM_ERROR("Failed to prepare/enable dvo clk\n"); + + if (dvo->panel) + dvo->panel->funcs->enable(dvo->panel); + + /* Set LUT */ + writel(config->lowbyte, dvo->regs + DVO_LUT_PROG_LOW); + writel(config->midbyte, dvo->regs + DVO_LUT_PROG_MID); + writel(config->highbyte, dvo->regs + DVO_LUT_PROG_HIGH); + + /* Digital output formatter config */ + val = (config->flags | DVO_DOF_EN); + writel(val, dvo->regs + DVO_DOF_CFG); + + dvo->enabled = true; +} + +static void sti_dvo_set_mode(struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct sti_dvo *dvo = bridge->driver_private; + struct sti_mixer *mixer = to_sti_mixer(dvo->encoder->crtc); + int rate = mode->clock * 1000; + struct clk *clkp; + int ret; + + DRM_DEBUG_DRIVER("\n"); + + memcpy(&dvo->mode, mode, sizeof(struct drm_display_mode)); + + /* According to the path used (main or aux), the dvo clocks should + * have a different parent clock. */ + if (mixer->id == STI_MIXER_MAIN) + clkp = dvo->clk_main_parent; + else + clkp = dvo->clk_aux_parent; + + if (clkp) { + clk_set_parent(dvo->clk_pix, clkp); + clk_set_parent(dvo->clk, clkp); + } + + /* DVO clocks = compositor clock */ + ret = clk_set_rate(dvo->clk_pix, rate); + if (ret < 0) { + DRM_ERROR("Cannot set rate (%dHz) for dvo_pix clk\n", rate); + return; + } + + ret = clk_set_rate(dvo->clk, rate); + if (ret < 0) { + DRM_ERROR("Cannot set rate (%dHz) for dvo clk\n", rate); + return; + } + + /* For now, we only support 24bit data enable (DE) synchro format */ + dvo->config = &rgb_24bit_de_cfg; +} + +static void sti_dvo_bridge_nope(struct drm_bridge *bridge) +{ + /* do nothing */ +} + +static void sti_dvo_brigde_destroy(struct drm_bridge *bridge) +{ + drm_bridge_cleanup(bridge); + kfree(bridge); +} + +static const struct drm_bridge_funcs sti_dvo_bridge_funcs = { + .pre_enable = sti_dvo_pre_enable, + .enable = sti_dvo_bridge_nope, + .disable = sti_dvo_disable, + .post_disable = sti_dvo_bridge_nope, + .mode_set = sti_dvo_set_mode, + .destroy = sti_dvo_brigde_destroy, +}; + +static int sti_dvo_connector_get_modes(struct drm_connector *connector) +{ + struct sti_dvo_connector *dvo_connector + = to_sti_dvo_connector(connector); + struct sti_dvo *dvo = dvo_connector->dvo; + + if (dvo->panel) + return dvo->panel->funcs->get_modes(dvo->panel); + + return 0; +} + +#define CLK_TOLERANCE_HZ 50 + +static int sti_dvo_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + int target = mode->clock * 1000; + int target_min = target - CLK_TOLERANCE_HZ; + int target_max = target + CLK_TOLERANCE_HZ; + int result; + struct sti_dvo_connector *dvo_connector + = to_sti_dvo_connector(connector); + struct sti_dvo *dvo = dvo_connector->dvo; + + result = clk_round_rate(dvo->clk_pix, target); + + DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n", + target, result); + + if ((result < target_min) || (result > target_max)) { + DRM_DEBUG_DRIVER("dvo pixclk=%d not supported\n", target); + return MODE_BAD; + } + + return MODE_OK; +} + +struct drm_encoder *sti_dvo_best_encoder(struct drm_connector *connector) +{ + struct sti_dvo_connector *dvo_connector + = to_sti_dvo_connector(connector); + + /* Best encoder is the one associated during connector creation */ + return dvo_connector->encoder; +} + +static struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = { + .get_modes = sti_dvo_connector_get_modes, + .mode_valid = sti_dvo_connector_mode_valid, + .best_encoder = sti_dvo_best_encoder, +}; + +static enum drm_connector_status +sti_dvo_connector_detect(struct drm_connector *connector, bool force) +{ + struct sti_dvo_connector *dvo_connector + = to_sti_dvo_connector(connector); + struct sti_dvo *dvo = dvo_connector->dvo; + + DRM_DEBUG_DRIVER("\n"); + + if (!dvo->panel) + dvo->panel = of_drm_find_panel(dvo->panel_node); + + if (dvo->panel) + if (!drm_panel_attach(dvo->panel, connector)) + return connector_status_connected; + + return connector_status_disconnected; +} + +static void sti_dvo_connector_destroy(struct drm_connector *connector) +{ + struct sti_dvo_connector *dvo_connector + = to_sti_dvo_connector(connector); + + drm_connector_unregister(connector); + drm_connector_cleanup(connector); + kfree(dvo_connector); +} + +static struct drm_connector_funcs sti_dvo_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = sti_dvo_connector_detect, + .destroy = sti_dvo_connector_destroy, +}; + +static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev) +{ + struct drm_encoder *encoder; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) + return encoder; + } + + return NULL; +} + +static int sti_dvo_bind(struct device *dev, struct device *master, void *data) +{ + struct sti_dvo *dvo = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + struct drm_encoder *encoder; + struct sti_dvo_connector *connector; + struct drm_connector *drm_connector; + struct drm_bridge *bridge; + int err; + + /* Set the drm device handle */ + dvo->drm_dev = drm_dev; + + encoder = sti_dvo_find_encoder(drm_dev); + if (!encoder) + return -ENOMEM; + + connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL); + if (!connector) + return -ENOMEM; + + connector->dvo = dvo; + + bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); + if (!bridge) + return -ENOMEM; + + bridge->driver_private = dvo; + drm_bridge_init(drm_dev, bridge, &sti_dvo_bridge_funcs); + + encoder->bridge = bridge; + connector->encoder = encoder; + dvo->encoder = encoder; + + drm_connector = (struct drm_connector *)connector; + + drm_connector->polled = DRM_CONNECTOR_POLL_HPD; + + drm_connector_init(drm_dev, drm_connector, + &sti_dvo_connector_funcs, DRM_MODE_CONNECTOR_LVDS); + drm_connector_helper_add(drm_connector, + &sti_dvo_connector_helper_funcs); + + err = drm_connector_register(drm_connector); + if (err) + goto err_connector; + + err = drm_mode_connector_attach_encoder(drm_connector, encoder); + if (err) { + DRM_ERROR("Failed to attach a connector to a encoder\n"); + goto err_sysfs; + } + + return 0; + +err_sysfs: + drm_connector_unregister(drm_connector); +err_connector: + drm_bridge_cleanup(bridge); + drm_connector_cleanup(drm_connector); + return -EINVAL; +} + +static void sti_dvo_unbind(struct device *dev, + struct device *master, void *data) +{ + /* do nothing */ +} + +static const struct component_ops sti_dvo_ops = { + .bind = sti_dvo_bind, + .unbind = sti_dvo_unbind, +}; + +static int sti_dvo_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sti_dvo *dvo; + struct resource *res; + struct device_node *np = dev->of_node; + + DRM_INFO("%s\n", __func__); + + dvo = devm_kzalloc(dev, sizeof(*dvo), GFP_KERNEL); + if (!dvo) { + DRM_ERROR("Failed to allocate memory for DVO\n"); + return -ENOMEM; + } + + dvo->dev = pdev->dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvo-reg"); + if (!res) { + DRM_ERROR("Invalid dvo resource\n"); + return -ENOMEM; + } + dvo->regs = devm_ioremap_nocache(dev, res->start, + resource_size(res)); + if (IS_ERR(dvo->regs)) + return PTR_ERR(dvo->regs); + + dvo->clk_pix = devm_clk_get(dev, "dvo_pix"); + if (IS_ERR(dvo->clk_pix)) { + DRM_ERROR("Cannot get dvo_pix clock\n"); + return PTR_ERR(dvo->clk_pix); + } + + dvo->clk = devm_clk_get(dev, "dvo"); + if (IS_ERR(dvo->clk)) { + DRM_ERROR("Cannot get dvo clock\n"); + return PTR_ERR(dvo->clk); + } + + dvo->clk_main_parent = devm_clk_get(dev, "main_parent"); + if (IS_ERR(dvo->clk_main_parent)) { + DRM_DEBUG_DRIVER("Cannot get main_parent clock\n"); + dvo->clk_main_parent = NULL; + } + + dvo->clk_aux_parent = devm_clk_get(dev, "aux_parent"); + if (IS_ERR(dvo->clk_aux_parent)) { + DRM_DEBUG_DRIVER("Cannot get aux_parent clock\n"); + dvo->clk_aux_parent = NULL; + } + + dvo->panel_node = of_parse_phandle(np, "sti,panel", 0); + if (!dvo->panel_node) + DRM_ERROR("No panel associated to the dvo output\n"); + + platform_set_drvdata(pdev, dvo); + + return component_add(&pdev->dev, &sti_dvo_ops); +} + +static int sti_dvo_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &sti_dvo_ops); + return 0; +} + +static struct of_device_id dvo_of_match[] = { + { .compatible = "st,stih407-dvo", }, + { /* end node */ } +}; +MODULE_DEVICE_TABLE(of, dvo_of_match); + +struct platform_driver sti_dvo_driver = { + .driver = { + .name = "sti-dvo", + .owner = THIS_MODULE, + .of_match_table = dvo_of_match, + }, + .probe = sti_dvo_probe, + .remove = sti_dvo_remove, +}; + +module_platform_driver(sti_dvo_driver); + +MODULE_AUTHOR("Benjamin Gaignard "); +MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index cb924aa..5cc5311 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -48,6 +48,9 @@ #define TVO_HDMI_CLIP_VALUE_R_CR 0x514 #define TVO_HDMI_SYNC_SEL 0x518 #define TVO_HDMI_DFV_OBS 0x540 +#define TVO_VIP_DVO 0x600 +#define TVO_DVO_SYNC_SEL 0x618 +#define TVO_DVO_CONFIG 0x620 #define TVO_IN_FMT_SIGNED BIT(0) #define TVO_SYNC_EXT BIT(4) @@ -98,6 +101,9 @@ #define TVO_SYNC_HD_DCS_SHIFT 8 +#define TVO_SYNC_DVO_PAD_HSYNC_SHIFT 8 +#define TVO_SYNC_DVO_PAD_VSYNC_SHIFT 16 + #define ENCODER_CRTC_MASK (BIT(0) | BIT(1)) /* enum listing the supported output data format */ @@ -113,6 +119,7 @@ struct sti_tvout { struct reset_control *reset; struct drm_encoder *hdmi; struct drm_encoder *hda; + struct drm_encoder *dvo; }; struct sti_tvout_encoder { @@ -262,6 +269,66 @@ static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout, } /** + * Start VIP block for DVO output + * + * @tvout: pointer on tvout structure + * @main_path: true if main path has to be used in the vip configuration + * else aux path is used. + */ +static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path) +{ + struct device_node *node = tvout->dev->of_node; + bool sel_input_logic_inverted = false; + u32 tvo_in_vid_format; + int val; + + dev_dbg(tvout->dev, "%s\n", __func__); + + if (main_path) { + DRM_DEBUG_DRIVER("main vip for DVO\n"); + /* Select the input sync for dvo = VTG set 4 */ + val = TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT; + val |= TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT; + val |= TVO_SYNC_MAIN_VTG_SET_4; + tvout_write(tvout, val, TVO_DVO_SYNC_SEL); + tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; + } else { + DRM_DEBUG_DRIVER("aux vip for DVO\n"); + /* Select the input sync for dvo = VTG set 4 */ + val = TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT; + val |= TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT; + val |= TVO_SYNC_AUX_VTG_SET_4; + tvout_write(tvout, val, TVO_DVO_SYNC_SEL); + tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; + } + + /* Set color channel order */ + tvout_vip_set_color_order(tvout, TVO_VIP_DVO, + TVO_VIP_REORDER_CR_R_SEL, + TVO_VIP_REORDER_Y_G_SEL, + TVO_VIP_REORDER_CB_B_SEL); + + /* Set clipping mode (Limited range RGB/Y) */ + tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO, + TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y); + + /* Set round mode (rounded to 8-bit per component) */ + tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED); + + if (of_device_is_compatible(node, "st,stih407-tvout")) { + /* Set input video format */ + tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, + TVO_IN_FMT_SIGNED); + sel_input_logic_inverted = true; + } + + /* Input selection */ + tvout_vip_set_sel_input(tvout, TVO_VIP_DVO, main_path, + sel_input_logic_inverted, + STI_TVOUT_VIDEO_OUT_RGB); +} + +/** * Start VIP block for HDMI output * * @tvout: pointer on tvout structure @@ -402,6 +469,56 @@ static const struct drm_encoder_funcs sti_tvout_encoder_funcs = { .destroy = sti_tvout_encoder_destroy, }; +static void sti_dvo_encoder_commit(struct drm_encoder *encoder) +{ + struct sti_tvout *tvout = to_sti_tvout(encoder); + + tvout_dvo_start(tvout, sti_drm_crtc_is_main(encoder->crtc)); +} + +static void sti_dvo_encoder_disable(struct drm_encoder *encoder) +{ + struct sti_tvout *tvout = to_sti_tvout(encoder); + + /* Reset VIP register */ + tvout_write(tvout, 0x0, TVO_VIP_DVO); +} + +static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = { + .dpms = sti_tvout_encoder_dpms, + .mode_fixup = sti_tvout_encoder_mode_fixup, + .mode_set = sti_tvout_encoder_mode_set, + .prepare = sti_tvout_encoder_prepare, + .commit = sti_dvo_encoder_commit, + .disable = sti_dvo_encoder_disable, +}; + +static struct drm_encoder * +sti_tvout_create_dvo_encoder(struct drm_device *dev, + struct sti_tvout *tvout) +{ + struct sti_tvout_encoder *encoder; + struct drm_encoder *drm_encoder; + + encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); + if (!encoder) + return NULL; + + encoder->tvout = tvout; + + drm_encoder = (struct drm_encoder *)encoder; + + drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; + drm_encoder->possible_clones = 1 << 0; + + drm_encoder_init(dev, drm_encoder, + &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_LVDS); + + drm_encoder_helper_add(drm_encoder, &sti_dvo_encoder_helper_funcs); + + return drm_encoder; +} + static void sti_hda_encoder_commit(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder); @@ -508,6 +625,7 @@ static void sti_tvout_create_encoders(struct drm_device *dev, { tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout); tvout->hda = sti_tvout_create_hda_encoder(dev, tvout); + tvout->dvo = sti_tvout_create_dvo_encoder(dev, tvout); } static void sti_tvout_destroy_encoders(struct sti_tvout *tvout) -- cgit v0.10.2 From 88a48e297b3a3bac6022c03babfb038f1a886cea Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:50 -0500 Subject: drm: add atomic properties Once a driver is using atomic helpers for modeset, the next step is to switch over to atomic properties. To do this, make sure that any modeset objects have their ->atomic_{get,set}_property() vfuncs suitably populated if they have custom properties (you did already remember to plug in atomic-helper func for the legacy ->set_property() vfuncs, right?), and then set DRIVER_ATOMIC bit in driver_features flag. A new cap is introduced, DRM_CLIENT_CAP_ATOMIC, for the purposes of shielding legacy userspace from atomic properties. Mostly for the benefit of legacy DDX drivers that do silly things like getting/setting each property at startup (since some of the new atomic properties will be able to trigger modeset). Signed-off-by: Rob Clark [danvet: Squash in fixup patch to check for DRM_MODE_PROP_ATOMIC instaed of the CAP define when filtering properties. Reported by Tvrtko Uruslin, acked by Rob.] Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 4b592ff..7fa4f98 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -239,6 +239,14 @@ Driver supports dedicated render nodes. + + DRIVER_ATOMIC + + Driver supports atomic properties. In this case the driver + must implement appropriate obj->atomic_get_property() vfuncs + for any modeset objects with driver specific properties. + + diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9c4e149..ce3c681 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -521,6 +521,51 @@ int drm_atomic_connector_get_property(struct drm_connector *connector, EXPORT_SYMBOL(drm_atomic_connector_get_property); /** + * drm_atomic_get_property - helper to read atomic property + * @obj: drm mode object whose property to read + * @property: the property to read + * @val: the read value, returned by reference + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_atomic_get_property(struct drm_mode_object *obj, + struct drm_property *property, uint64_t *val) +{ + struct drm_device *dev = property->dev; + int ret; + + switch (obj->type) { + case DRM_MODE_OBJECT_CONNECTOR: { + struct drm_connector *connector = obj_to_connector(obj); + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + ret = drm_atomic_connector_get_property(connector, + connector->state, property, val); + break; + } + case DRM_MODE_OBJECT_CRTC: { + struct drm_crtc *crtc = obj_to_crtc(obj); + WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); + ret = drm_atomic_crtc_get_property(crtc, + crtc->state, property, val); + break; + } + case DRM_MODE_OBJECT_PLANE: { + struct drm_plane *plane = obj_to_plane(obj); + WARN_ON(!drm_modeset_is_locked(&plane->mutex)); + ret = drm_atomic_plane_get_property(plane, + plane->state, property, val); + break; + } + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** * drm_atomic_set_crtc_for_plane - set crtc for plane * @plane_state: the plane whose incoming state to update * @crtc: crtc to use for the plane diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f5f34d0..3bac877 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "drm_crtc_internal.h" #include "drm_internal.h" @@ -1992,19 +1993,25 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne } /* helper for getconnector and getproperties ioctls */ -static int get_properties(struct drm_mode_object *obj, +static int get_properties(struct drm_mode_object *obj, bool atomic, uint32_t __user *prop_ptr, uint64_t __user *prop_values, uint32_t *arg_count_props) { - int props_count = obj->properties->count; - int i, ret, copied = 0; + int props_count; + int i, ret, copied; + + props_count = obj->properties->count; + if (!atomic) + props_count -= obj->properties->atomic_count; if ((*arg_count_props >= props_count) && props_count) { - copied = 0; - for (i = 0; i < props_count; i++) { + for (i = 0, copied = 0; copied < props_count; i++) { struct drm_property *prop = obj->properties->properties[i]; uint64_t val; + if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) + continue; + ret = drm_object_property_get_value(obj, prop, &val); if (ret) return ret; @@ -2118,7 +2125,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, } out_resp->count_modes = mode_count; - ret = get_properties(&connector->base, + ret = get_properties(&connector->base, file_priv->atomic, (uint32_t __user *)(unsigned long)(out_resp->props_ptr), (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), &out_resp->count_props); @@ -3832,6 +3839,8 @@ void drm_object_attach_property(struct drm_mode_object *obj, obj->properties->properties[count] = property; obj->properties->values[count] = init_val; obj->properties->count++; + if (property->flags & DRM_MODE_PROP_ATOMIC) + obj->properties->atomic_count++; } EXPORT_SYMBOL(drm_object_attach_property); @@ -3883,6 +3892,14 @@ int drm_object_property_get_value(struct drm_mode_object *obj, { int i; + /* read-only properties bypass atomic mechanism and still store + * their value in obj->properties->values[].. mostly to avoid + * having to deal w/ EDID and similar props in atomic paths: + */ + if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && + !(property->flags & DRM_MODE_PROP_IMMUTABLE)) + return drm_atomic_get_property(obj, property, val); + for (i = 0; i < obj->properties->count; i++) { if (obj->properties->properties[i] == property) { *val = obj->properties->values[i]; @@ -4413,7 +4430,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, goto out; } - ret = get_properties(obj, + ret = get_properties(obj, file_priv->atomic, (uint32_t __user *)(unsigned long)(arg->props_ptr), (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), &arg->count_props); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 4f41377..d512134 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -40,15 +40,19 @@ unsigned int drm_debug = 0; /* 1 to enable debug output */ EXPORT_SYMBOL(drm_debug); +bool drm_atomic = 0; + MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); MODULE_PARM_DESC(debug, "Enable debug output"); +MODULE_PARM_DESC(atomic, "Enable experimental atomic KMS API"); MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); module_param_named(debug, drm_debug, int, 0600); +module_param_named_unsafe(atomic, drm_atomic, bool, 0600); static DEFINE_SPINLOCK(drm_minor_lock); static struct idr drm_minors_idr; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 00587a1..adc8223 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -345,6 +345,16 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) return -EINVAL; file_priv->universal_planes = req->value; break; + case DRM_CLIENT_CAP_ATOMIC: + /* for now, hide behind experimental drm.atomic moduleparam */ + if (!drm_atomic) + return -EINVAL; + if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) + return -EINVAL; + if (req->value > 1) + return -EINVAL; + file_priv->atomic = req->value; + break; default: return -EINVAL; } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 8ba35c6..0f7115e 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -143,6 +143,7 @@ void drm_err(const char *format, ...); #define DRIVER_MODESET 0x2000 #define DRIVER_PRIME 0x4000 #define DRIVER_RENDER 0x8000 +#define DRIVER_ATOMIC 0x10000 /***********************************************************************/ /** \name Macros to make printk easier */ @@ -283,6 +284,8 @@ struct drm_file { * in the plane list */ unsigned universal_planes:1; + /* true if client understands atomic properties */ + unsigned atomic:1; struct pid *pid; kuid_t uid; @@ -950,6 +953,7 @@ extern void drm_master_put(struct drm_master **master); extern void drm_put_dev(struct drm_device *dev); extern void drm_unplug_dev(struct drm_device *dev); extern unsigned int drm_debug; +extern bool drm_atomic; /* Debugfs support */ #if defined(CONFIG_DEBUG_FS) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index d41233c..231fb48 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -63,6 +63,9 @@ int drm_atomic_connector_get_property(struct drm_connector *connector, const struct drm_connector_state *state, struct drm_property *property, uint64_t *val); +int drm_atomic_get_property(struct drm_mode_object *obj, + struct drm_property *property, uint64_t *val); + int __must_check drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, struct drm_crtc *crtc); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index e1f3469..b5ab673 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -63,7 +63,7 @@ struct drm_mode_object { #define DRM_OBJECT_MAX_PROPERTY 24 struct drm_object_properties { - int count; + int count, atomic_count; /* NOTE: if we ever start dynamically destroying properties (ie. * not at drm_mode_config_cleanup() time), then we'd have to do * a better job of detaching property from mode objects to avoid diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index b0b8556..f7b2baf7 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -654,6 +654,13 @@ struct drm_get_cap { */ #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 +/** + * DRM_CLIENT_CAP_ATOMIC + * + * If set to 1, the DRM core will expose atomic properties to userspace + */ +#define DRM_CLIENT_CAP_ATOMIC 3 + /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability; diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index aae71cb..b8f9c0f 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -272,6 +272,13 @@ struct drm_mode_get_connector { #define DRM_MODE_PROP_OBJECT DRM_MODE_PROP_TYPE(1) #define DRM_MODE_PROP_SIGNED_RANGE DRM_MODE_PROP_TYPE(2) +/* the PROP_ATOMIC flag is used to hide properties from userspace that + * is not aware of atomic properties. This is mostly to work around + * older userspace (DDX drivers) that read/write each prop they find, + * witout being aware that this could be triggering a lengthy modeset. + */ +#define DRM_MODE_PROP_ATOMIC 0x80000000 + struct drm_mode_property_enum { __u64 value; char name[DRM_PROP_NAME_LEN]; -- cgit v0.10.2 From 5e743737421fe9be9d7b25475427a3698e6f70a5 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:51 -0500 Subject: drm/atomic: atomic_check functions Add functions to check core plane/crtc state. v2: comments, int-overflow checks, call from core rather than helpers to be sure drivers can't find a way to bypass core checks Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index ce3c681..1c472b1 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -269,6 +269,29 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc, EXPORT_SYMBOL(drm_atomic_crtc_get_property); /** + * drm_atomic_crtc_check - check crtc state + * @crtc: crtc to check + * @state: crtc state to check + * + * Provides core sanity checks for crtc state. + * + * RETURNS: + * Zero on success, error code on failure + */ +static int drm_atomic_crtc_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + /* NOTE: we explicitly don't enforce constraints such as primary + * layer covering entire screen, since that is something we want + * to allow (on hw that supports it). For hw that does not, it + * should be checked in driver's crtc->atomic_check() vfunc. + * + * TODO: Add generic modeset state checks once we support those. + */ + return 0; +} + +/** * drm_atomic_get_plane_state - get plane state * @state: global atomic state object * @plane: plane to get state object for @@ -376,6 +399,82 @@ int drm_atomic_plane_get_property(struct drm_plane *plane, EXPORT_SYMBOL(drm_atomic_plane_get_property); /** + * drm_atomic_plane_check - check plane state + * @plane: plane to check + * @state: plane state to check + * + * Provides core sanity checks for plane state. + * + * RETURNS: + * Zero on success, error code on failure + */ +static int drm_atomic_plane_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + unsigned int fb_width, fb_height; + unsigned int i; + + /* either *both* CRTC and FB must be set, or neither */ + if (WARN_ON(state->crtc && !state->fb)) { + DRM_DEBUG_KMS("CRTC set but no FB\n"); + return -EINVAL; + } else if (WARN_ON(state->fb && !state->crtc)) { + DRM_DEBUG_KMS("FB set but no CRTC\n"); + return -EINVAL; + } + + /* if disabled, we don't care about the rest of the state: */ + if (!state->crtc) + return 0; + + /* Check whether this plane is usable on this CRTC */ + if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) { + DRM_DEBUG_KMS("Invalid crtc for plane\n"); + return -EINVAL; + } + + /* Check whether this plane supports the fb pixel format. */ + for (i = 0; i < plane->format_count; i++) + if (state->fb->pixel_format == plane->format_types[i]) + break; + if (i == plane->format_count) { + DRM_DEBUG_KMS("Invalid pixel format %s\n", + drm_get_format_name(state->fb->pixel_format)); + return -EINVAL; + } + + /* Give drivers some help against integer overflows */ + if (state->crtc_w > INT_MAX || + state->crtc_x > INT_MAX - (int32_t) state->crtc_w || + state->crtc_h > INT_MAX || + state->crtc_y > INT_MAX - (int32_t) state->crtc_h) { + DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", + state->crtc_w, state->crtc_h, + state->crtc_x, state->crtc_y); + return -ERANGE; + } + + fb_width = state->fb->width << 16; + fb_height = state->fb->height << 16; + + /* Make sure source coordinates are inside the fb. */ + if (state->src_w > fb_width || + state->src_x > fb_width - state->src_w || + state->src_h > fb_height || + state->src_y > fb_height - state->src_h) { + DRM_DEBUG_KMS("Invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", + state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, + state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, + state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, + state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); + return -ENOSPC; + } + + return 0; +} + +/** * drm_atomic_get_connector_state - get connector state * @state: global atomic state object * @connector: connector to get state object for @@ -801,14 +900,46 @@ EXPORT_SYMBOL(drm_atomic_legacy_backoff); */ int drm_atomic_check_only(struct drm_atomic_state *state) { - struct drm_mode_config *config = &state->dev->mode_config; + struct drm_device *dev = state->dev; + struct drm_mode_config *config = &dev->mode_config; + int nplanes = config->num_total_plane; + int ncrtcs = config->num_crtc; + int i, ret = 0; DRM_DEBUG_KMS("checking %p\n", state); + for (i = 0; i < nplanes; i++) { + struct drm_plane *plane = state->planes[i]; + + if (!plane) + continue; + + ret = drm_atomic_plane_check(plane, state->plane_states[i]); + if (ret) { + DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n", + plane->base.id); + return ret; + } + } + + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc *crtc = state->crtcs[i]; + + if (!crtc) + continue; + + ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]); + if (ret) { + DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n", + crtc->base.id); + return ret; + } + } + if (config->funcs->atomic_check) - return config->funcs->atomic_check(state->dev, state); - else - return 0; + ret = config->funcs->atomic_check(state->dev, state); + + return ret; } EXPORT_SYMBOL(drm_atomic_check_only); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 57e5540..541ba83 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -467,7 +467,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev, ret = funcs->atomic_check(plane, plane_state); if (ret) { - DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n", + DRM_DEBUG_KMS("[PLANE:%d] atomic driver check failed\n", plane->base.id); return ret; } @@ -487,7 +487,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev, ret = funcs->atomic_check(crtc, state->crtc_states[i]); if (ret) { - DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n", + DRM_DEBUG_KMS("[CRTC:%d] atomic driver check failed\n", crtc->base.id); return ret; } -- cgit v0.10.2 From 356af0e154467eb6844f25631a11940b462deca0 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:52 -0500 Subject: drm: small property creation cleanup Getting ready to add a lot more standard properties for atomic. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter [danvet: Realign function paramaters where the lines shrunk massively.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3bac877..f33863a 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1325,33 +1325,40 @@ EXPORT_SYMBOL(drm_plane_force_disable); static int drm_mode_create_standard_connector_properties(struct drm_device *dev) { - struct drm_property *edid; - struct drm_property *dpms; - struct drm_property *dev_path; + struct drm_property *prop; /* * Standard properties (apply to all connectors) */ - edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, "EDID", 0); - dev->mode_config.edid_property = edid; + if (!prop) + return -ENOMEM; + dev->mode_config.edid_property = prop; - dpms = drm_property_create_enum(dev, 0, + prop = drm_property_create_enum(dev, 0, "DPMS", drm_dpms_enum_list, ARRAY_SIZE(drm_dpms_enum_list)); - dev->mode_config.dpms_property = dpms; - - dev_path = drm_property_create(dev, - DRM_MODE_PROP_BLOB | - DRM_MODE_PROP_IMMUTABLE, - "PATH", 0); - dev->mode_config.path_property = dev_path; - - dev->mode_config.tile_property = drm_property_create(dev, - DRM_MODE_PROP_BLOB | - DRM_MODE_PROP_IMMUTABLE, - "TILE", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.dpms_property = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB | + DRM_MODE_PROP_IMMUTABLE, + "PATH", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.path_property = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB | + DRM_MODE_PROP_IMMUTABLE, + "TILE", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.tile_property = prop; return 0; } -- cgit v0.10.2 From 6b4959f43a04e12d39c5700607727f2cbcfeac31 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:53 -0500 Subject: drm/atomic: atomic plane properties Expose the core plane state as properties, so they can be updated via atomic ioctl. v2: atomic property flag Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 7fa4f98..8d8dc71 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2572,7 +2572,7 @@ void intel_crt_init(struct drm_device *dev) - + @@ -2602,7 +2602,7 @@ void intel_crt_init(struct drm_device *dev) - + @@ -2610,6 +2610,76 @@ void intel_crt_init(struct drm_device *dev) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 1c472b1..131d47f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -366,9 +366,41 @@ int drm_atomic_plane_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val) { - if (plane->funcs->atomic_set_property) - return plane->funcs->atomic_set_property(plane, state, property, val); - return -EINVAL; + struct drm_device *dev = plane->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_fb_id) { + struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, val); + drm_atomic_set_fb_for_plane(state, fb); + if (fb) + drm_framebuffer_unreference(fb); + } else if (property == config->prop_crtc_id) { + struct drm_crtc *crtc = drm_crtc_find(dev, val); + return drm_atomic_set_crtc_for_plane(state, crtc); + } else if (property == config->prop_crtc_x) { + state->crtc_x = U642I64(val); + } else if (property == config->prop_crtc_y) { + state->crtc_y = U642I64(val); + } else if (property == config->prop_crtc_w) { + state->crtc_w = val; + } else if (property == config->prop_crtc_h) { + state->crtc_h = val; + } else if (property == config->prop_src_x) { + state->src_x = val; + } else if (property == config->prop_src_y) { + state->src_y = val; + } else if (property == config->prop_src_w) { + state->src_w = val; + } else if (property == config->prop_src_h) { + state->src_h = val; + } else if (plane->funcs->atomic_set_property) { + return plane->funcs->atomic_set_property(plane, state, + property, val); + } else { + return -EINVAL; + } + + return 0; } EXPORT_SYMBOL(drm_atomic_plane_set_property); @@ -392,9 +424,36 @@ int drm_atomic_plane_get_property(struct drm_plane *plane, const struct drm_plane_state *state, struct drm_property *property, uint64_t *val) { - if (plane->funcs->atomic_get_property) + struct drm_device *dev = plane->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_fb_id) { + *val = (state->fb) ? state->fb->base.id : 0; + } else if (property == config->prop_crtc_id) { + *val = (state->crtc) ? state->crtc->base.id : 0; + } else if (property == config->prop_crtc_x) { + *val = I642U64(state->crtc_x); + } else if (property == config->prop_crtc_y) { + *val = I642U64(state->crtc_y); + } else if (property == config->prop_crtc_w) { + *val = state->crtc_w; + } else if (property == config->prop_crtc_h) { + *val = state->crtc_h; + } else if (property == config->prop_src_x) { + *val = state->src_x; + } else if (property == config->prop_src_y) { + *val = state->src_y; + } else if (property == config->prop_src_w) { + *val = state->src_w; + } else if (property == config->prop_src_h) { + *val = state->src_h; + } else if (plane->funcs->atomic_get_property) { return plane->funcs->atomic_get_property(plane, state, property, val); - return -EINVAL; + } else { + return -EINVAL; + } + + return 0; } EXPORT_SYMBOL(drm_atomic_plane_get_property); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f33863a..46fa094 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1169,6 +1169,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, const uint32_t *formats, uint32_t format_count, enum drm_plane_type type) { + struct drm_mode_config *config = &dev->mode_config; int ret; ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); @@ -1193,15 +1194,28 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, plane->possible_crtcs = possible_crtcs; plane->type = type; - list_add_tail(&plane->head, &dev->mode_config.plane_list); - dev->mode_config.num_total_plane++; + list_add_tail(&plane->head, &config->plane_list); + config->num_total_plane++; if (plane->type == DRM_PLANE_TYPE_OVERLAY) - dev->mode_config.num_overlay_plane++; + config->num_overlay_plane++; drm_object_attach_property(&plane->base, - dev->mode_config.plane_type_property, + config->plane_type_property, plane->type); + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { + drm_object_attach_property(&plane->base, config->prop_fb_id, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); + drm_object_attach_property(&plane->base, config->prop_src_x, 0); + drm_object_attach_property(&plane->base, config->prop_src_y, 0); + drm_object_attach_property(&plane->base, config->prop_src_w, 0); + drm_object_attach_property(&plane->base, config->prop_src_h, 0); + } + return 0; } EXPORT_SYMBOL(drm_universal_plane_init); @@ -1323,7 +1337,7 @@ void drm_plane_force_disable(struct drm_plane *plane) } EXPORT_SYMBOL(drm_plane_force_disable); -static int drm_mode_create_standard_connector_properties(struct drm_device *dev) +static int drm_mode_create_standard_properties(struct drm_device *dev) { struct drm_property *prop; @@ -1360,20 +1374,72 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.tile_property = prop; - return 0; -} - -static int drm_mode_create_standard_plane_properties(struct drm_device *dev) -{ - struct drm_property *type; - - /* - * Standard properties (apply to all planes) - */ - type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, + prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, "type", drm_plane_type_enum_list, ARRAY_SIZE(drm_plane_type_enum_list)); - dev->mode_config.plane_type_property = type; + if (!prop) + return -ENOMEM; + dev->mode_config.plane_type_property = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "SRC_X", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_src_x = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "SRC_Y", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_src_y = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "SRC_W", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_src_w = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "SRC_H", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_src_h = prop; + + prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_X", INT_MIN, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_x = prop; + + prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_Y", INT_MIN, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_y = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_W", 0, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_w = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_H", 0, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_h = prop; + + prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, + "FB_ID", DRM_MODE_OBJECT_FB); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_fb_id = prop; + + prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_ID", DRM_MODE_OBJECT_CRTC); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_id = prop; return 0; } @@ -5264,8 +5330,7 @@ void drm_mode_config_init(struct drm_device *dev) idr_init(&dev->mode_config.tile_idr); drm_modeset_lock_all(dev); - drm_mode_create_standard_connector_properties(dev); - drm_mode_create_standard_plane_properties(dev); + drm_mode_create_standard_properties(dev); drm_modeset_unlock_all(dev); /* Just to be sure */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index b5ab673..fc4767f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1099,6 +1099,16 @@ struct drm_mode_config { struct drm_property *tile_property; struct drm_property *plane_type_property; struct drm_property *rotation_property; + struct drm_property *prop_src_x; + struct drm_property *prop_src_y; + struct drm_property *prop_src_w; + struct drm_property *prop_src_h; + struct drm_property *prop_crtc_x; + struct drm_property *prop_crtc_y; + struct drm_property *prop_crtc_w; + struct drm_property *prop_crtc_h; + struct drm_property *prop_fb_id; + struct drm_property *prop_crtc_id; /* DVI-I properties */ struct drm_property *dvi_i_subconnector_property; -- cgit v0.10.2 From ae16c597b61ae4613b13a0c3fac302e8d8827ac7 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:54 -0500 Subject: drm/atomic: atomic connector properties Expose the core connector state as properties so it can be updated via atomic ioctl. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 8d8dc71..2f4a299 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2572,8 +2572,8 @@ void intel_crt_init(struct drm_device *dev) - - + + @@ -2602,6 +2602,13 @@ void intel_crt_init(struct drm_device *dev) + + + + + + + diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 131d47f..57cc681 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -627,7 +627,10 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, struct drm_device *dev = connector->dev; struct drm_mode_config *config = &dev->mode_config; - if (property == config->dpms_property) { + if (property == config->prop_crtc_id) { + struct drm_crtc *crtc = drm_crtc_find(dev, val); + return drm_atomic_set_crtc_for_connector(state, crtc); + } else if (property == config->dpms_property) { /* setting DPMS property requires special handling, which * is done in legacy setprop path for us. Disallow (for * now?) atomic writes to DPMS property: @@ -665,7 +668,9 @@ int drm_atomic_connector_get_property(struct drm_connector *connector, struct drm_device *dev = connector->dev; struct drm_mode_config *config = &dev->mode_config; - if (property == config->dpms_property) { + if (property == config->prop_crtc_id) { + *val = (state->crtc) ? state->crtc->base.id : 0; + } else if (property == config->dpms_property) { *val = connector->dpms; } else if (connector->funcs->atomic_get_property) { return connector->funcs->atomic_get_property(connector, diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 46fa094..3cb1fa0 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -831,6 +831,7 @@ int drm_connector_init(struct drm_device *dev, const struct drm_connector_funcs *funcs, int connector_type) { + struct drm_mode_config *config = &dev->mode_config; int ret; struct ida *connector_ida = &drm_connector_enum_list[connector_type].ida; @@ -869,16 +870,20 @@ int drm_connector_init(struct drm_device *dev, /* We should add connectors at the end to avoid upsetting the connector * index too much. */ - list_add_tail(&connector->head, &dev->mode_config.connector_list); - dev->mode_config.num_connector++; + list_add_tail(&connector->head, &config->connector_list); + config->num_connector++; if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) drm_object_attach_property(&connector->base, - dev->mode_config.edid_property, + config->edid_property, 0); drm_object_attach_property(&connector->base, - dev->mode_config.dpms_property, 0); + config->dpms_property, 0); + + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { + drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); + } connector->debugfs_entry = NULL; -- cgit v0.10.2 From d34f20d6e2f21bd3531b969dc40913181a8ae31a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:56 -0500 Subject: drm: Atomic modeset ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The atomic modeset ioctl can be used to push any number of new values for object properties. The driver can then check the full device configuration as single unit, and try to apply the changes atomically. The ioctl simply takes a list of object IDs and property IDs and their values. Originally based on a patch from Ville Syrjälä, although it has mutated (mutilated?) enough since then that you probably shouldn't blame it on him ;-) The atomic support is hidden behind the DRM_CLIENT_CAP_ATOMIC cap (to protect legacy userspace) and drm.atomic module param (for now). v2: Check for file_priv->atomic to make sure we only allow userspace in-the-know to use atomic. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 57cc681..67f64bd 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -56,6 +56,11 @@ drm_atomic_state_alloc(struct drm_device *dev) if (!state) return NULL; + /* TODO legacy paths should maybe do a better job about + * setting this appropriately? + */ + state->allow_modeset = true; + state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); state->crtcs = kcalloc(dev->mode_config.num_crtc, @@ -1003,6 +1008,22 @@ int drm_atomic_check_only(struct drm_atomic_state *state) if (config->funcs->atomic_check) ret = config->funcs->atomic_check(state->dev, state); + if (!state->allow_modeset) { + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc *crtc = state->crtcs[i]; + struct drm_crtc_state *crtc_state = state->crtc_states[i]; + + if (!crtc) + continue; + + if (crtc_state->mode_changed) { + DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", + crtc->base.id); + return -EINVAL; + } + } + } + return ret; } EXPORT_SYMBOL(drm_atomic_check_only); @@ -1068,3 +1089,313 @@ int drm_atomic_async_commit(struct drm_atomic_state *state) return config->funcs->atomic_commit(state->dev, state, true); } EXPORT_SYMBOL(drm_atomic_async_commit); + +/* + * The big monstor ioctl + */ + +static struct drm_pending_vblank_event *create_vblank_event( + struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data) +{ + struct drm_pending_vblank_event *e = NULL; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + if (file_priv->event_space < sizeof e->event) { + spin_unlock_irqrestore(&dev->event_lock, flags); + goto out; + } + file_priv->event_space -= sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + + e = kzalloc(sizeof *e, GFP_KERNEL); + if (e == NULL) { + spin_lock_irqsave(&dev->event_lock, flags); + file_priv->event_space += sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + goto out; + } + + e->event.base.type = DRM_EVENT_FLIP_COMPLETE; + e->event.base.length = sizeof e->event; + e->event.user_data = user_data; + e->base.event = &e->event.base; + e->base.file_priv = file_priv; + e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; + +out: + return e; +} + +static void destroy_vblank_event(struct drm_device *dev, + struct drm_file *file_priv, struct drm_pending_vblank_event *e) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + file_priv->event_space += sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + kfree(e); +} + +static int atomic_set_prop(struct drm_atomic_state *state, + struct drm_mode_object *obj, struct drm_property *prop, + uint64_t prop_value) +{ + struct drm_mode_object *ref; + int ret; + + if (!drm_property_change_valid_get(prop, prop_value, &ref)) + return -EINVAL; + + switch (obj->type) { + case DRM_MODE_OBJECT_CONNECTOR: { + struct drm_connector *connector = obj_to_connector(obj); + struct drm_connector_state *connector_state; + + connector_state = drm_atomic_get_connector_state(state, connector); + if (IS_ERR(connector_state)) { + ret = PTR_ERR(connector_state); + break; + } + + ret = drm_atomic_connector_set_property(connector, + connector_state, prop, prop_value); + break; + } + case DRM_MODE_OBJECT_CRTC: { + struct drm_crtc *crtc = obj_to_crtc(obj); + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + break; + } + + ret = drm_atomic_crtc_set_property(crtc, + crtc_state, prop, prop_value); + break; + } + case DRM_MODE_OBJECT_PLANE: { + struct drm_plane *plane = obj_to_plane(obj); + struct drm_plane_state *plane_state; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + break; + } + + ret = drm_atomic_plane_set_property(plane, + plane_state, prop, prop_value); + break; + } + default: + ret = -EINVAL; + break; + } + + drm_property_change_valid_put(prop, ref); + return ret; +} + +int drm_mode_atomic_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_atomic *arg = data; + uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr); + uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr); + uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); + uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr); + unsigned int copied_objs, copied_props; + struct drm_atomic_state *state; + struct drm_modeset_acquire_ctx ctx; + struct drm_plane *plane; + unsigned plane_mask = 0; + int ret = 0; + unsigned int i, j; + + /* disallow for drivers not supporting atomic: */ + if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) + return -EINVAL; + + /* disallow for userspace that has not enabled atomic cap (even + * though this may be a bit overkill, since legacy userspace + * wouldn't know how to call this ioctl) + */ + if (!file_priv->atomic) + return -EINVAL; + + if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) + return -EINVAL; + + if (arg->reserved) + return -EINVAL; + + if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) && + !dev->mode_config.async_page_flip) + return -EINVAL; + + /* can't test and expect an event at the same time. */ + if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) && + (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) + return -EINVAL; + + drm_modeset_acquire_init(&ctx, 0); + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + state->acquire_ctx = &ctx; + state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); + +retry: + copied_objs = 0; + copied_props = 0; + + for (i = 0; i < arg->count_objs; i++) { + uint32_t obj_id, count_props; + struct drm_mode_object *obj; + + if (get_user(obj_id, objs_ptr + copied_objs)) { + ret = -EFAULT; + goto fail; + } + + obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY); + if (!obj || !obj->properties) { + ret = -ENOENT; + goto fail; + } + + if (obj->type == DRM_MODE_OBJECT_PLANE) { + plane = obj_to_plane(obj); + plane_mask |= (1 << drm_plane_index(plane)); + plane->old_fb = plane->fb; + } + + if (get_user(count_props, count_props_ptr + copied_objs)) { + ret = -EFAULT; + goto fail; + } + + copied_objs++; + + for (j = 0; j < count_props; j++) { + uint32_t prop_id; + uint64_t prop_value; + struct drm_property *prop; + + if (get_user(prop_id, props_ptr + copied_props)) { + ret = -EFAULT; + goto fail; + } + + prop = drm_property_find(dev, prop_id); + if (!prop) { + ret = -ENOENT; + goto fail; + } + + if (get_user(prop_value, prop_values_ptr + copied_props)) { + ret = -EFAULT; + goto fail; + } + + ret = atomic_set_prop(state, obj, prop, prop_value); + if (ret) + goto fail; + + copied_props++; + } + } + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + int ncrtcs = dev->mode_config.num_crtc; + + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc_state *crtc_state = state->crtc_states[i]; + struct drm_pending_vblank_event *e; + + if (!crtc_state) + continue; + + e = create_vblank_event(dev, file_priv, arg->user_data); + if (!e) { + ret = -ENOMEM; + goto fail; + } + + crtc_state->event = e; + } + } + + if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { + ret = drm_atomic_check_only(state); + /* _check_only() does not free state, unlike _commit() */ + drm_atomic_state_free(state); + } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { + ret = drm_atomic_async_commit(state); + } else { + ret = drm_atomic_commit(state); + } + + /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping + * locks (ie. while it is still safe to deref plane->state). We + * need to do this here because the driver entry points cannot + * distinguish between legacy and atomic ioctls. + */ + drm_for_each_plane_mask(plane, dev, plane_mask) { + if (ret == 0) { + struct drm_framebuffer *new_fb = plane->state->fb; + if (new_fb) + drm_framebuffer_reference(new_fb); + plane->fb = new_fb; + plane->crtc = plane->state->crtc; + } else { + plane->old_fb = NULL; + } + if (plane->old_fb) { + drm_framebuffer_unreference(plane->old_fb); + plane->old_fb = NULL; + } + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; + +fail: + if (ret == -EDEADLK) + goto backoff; + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + int ncrtcs = dev->mode_config.num_crtc; + + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc_state *crtc_state = state->crtc_states[i]; + + if (!crtc_state) + continue; + + destroy_vblank_event(dev, file_priv, crtc_state->event); + crtc_state->event = NULL; + } + } + + drm_atomic_state_free(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; + +backoff: + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + + goto retry; +} diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3cb1fa0..2059642 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4303,7 +4303,7 @@ EXPORT_SYMBOL(drm_mode_connector_update_edid_property); * object to which the property is attached has a chance to take it's own * reference). */ -static bool drm_property_change_valid_get(struct drm_property *property, +bool drm_property_change_valid_get(struct drm_property *property, uint64_t value, struct drm_mode_object **ref) { int i; @@ -4365,7 +4365,7 @@ static bool drm_property_change_valid_get(struct drm_property *property, return false; } -static void drm_property_change_valid_put(struct drm_property *property, +void drm_property_change_valid_put(struct drm_property *property, struct drm_mode_object *ref) { if (!ref) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index adc8223..a28c0ab 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -630,6 +630,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index fc4767f..1dcfb685 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -902,7 +902,7 @@ struct drm_bridge { /** * struct struct drm_atomic_state - the global state object for atomic updates * @dev: parent DRM device - * @flags: state flags like async update + * @allow_modeset: allow full modeset * @planes: pointer to array of plane pointers * @plane_states: pointer to array of plane states pointers * @crtcs: pointer to array of CRTC pointers @@ -914,7 +914,7 @@ struct drm_bridge { */ struct drm_atomic_state { struct drm_device *dev; - uint32_t flags; + bool allow_modeset : 1; struct drm_plane **planes; struct drm_plane_state **plane_states; struct drm_crtc **crtcs; @@ -1346,6 +1346,10 @@ extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev); extern int drm_mode_create_dirty_info_property(struct drm_device *dev); extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev); +extern bool drm_property_change_valid_get(struct drm_property *property, + uint64_t value, struct drm_mode_object **ref); +extern void drm_property_change_valid_put(struct drm_property *property, + struct drm_mode_object *ref); extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); @@ -1437,6 +1441,8 @@ extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane, struct drm_property *property, uint64_t value); +extern int drm_mode_atomic_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index f7b2baf7..01b2d6d 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -784,6 +784,7 @@ struct drm_prime_handle { #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) #define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) #define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2) +#define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xBC, struct drm_mode_atomic) /** * Device specific ioctls should only be in their respective headers diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index b8f9c0f..ca788e0 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -526,4 +526,27 @@ struct drm_mode_destroy_dumb { uint32_t handle; }; +/* page-flip flags are valid, plus: */ +#define DRM_MODE_ATOMIC_TEST_ONLY 0x0100 +#define DRM_MODE_ATOMIC_NONBLOCK 0x0200 +#define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 + +#define DRM_MODE_ATOMIC_FLAGS (\ + DRM_MODE_PAGE_FLIP_EVENT |\ + DRM_MODE_PAGE_FLIP_ASYNC |\ + DRM_MODE_ATOMIC_TEST_ONLY |\ + DRM_MODE_ATOMIC_NONBLOCK |\ + DRM_MODE_ATOMIC_ALLOW_MODESET) + +struct drm_mode_atomic { + __u32 flags; + __u32 count_objs; + __u64 objs_ptr; + __u64 count_props_ptr; + __u64 props_ptr; + __u64 prop_values_ptr; + __u64 reserved; + __u64 user_data; +}; + #endif -- cgit v0.10.2 From a97df1ccd3c30f16385696964767adf854878021 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Dec 2014 22:49:02 +0100 Subject: drm/atomic: Hide drm.ko internal interfaces This is just a bit fallout from patch polishing and moving the get_prop logic fully into the core: - Drop EXPORT_SYMBOL and make the helpers static. - Drop kerneldoc since not used by drivers. - Move the cross-file function declarations only used by drm.ko internally to an internal header. v2: keep the gist of the comments, requested by Rob. Cc: Rob Clark Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 67f64bd..1e38dfc 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -247,21 +247,11 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, } EXPORT_SYMBOL(drm_atomic_crtc_set_property); -/** - * drm_atomic_crtc_get_property - get property on CRTC - * @crtc: the drm CRTC to get a property on - * @state: the state object with the property value to read - * @property: the property to get - * @val: the property value (returned by reference) - * - * Use this instead of calling crtc->atomic_get_property directly. +/* * This function handles generic/core properties and calls out to * driver's ->atomic_get_property() for driver properties. To ensure * consistent behavior you must call this function rather than the * driver hook directly. - * - * RETURNS: - * Zero on success, error code on failure */ int drm_atomic_crtc_get_property(struct drm_crtc *crtc, const struct drm_crtc_state *state, @@ -271,7 +261,6 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc, return crtc->funcs->atomic_get_property(crtc, state, property, val); return -EINVAL; } -EXPORT_SYMBOL(drm_atomic_crtc_get_property); /** * drm_atomic_crtc_check - check crtc state @@ -409,23 +398,14 @@ int drm_atomic_plane_set_property(struct drm_plane *plane, } EXPORT_SYMBOL(drm_atomic_plane_set_property); -/** - * drm_atomic_plane_get_property - get property on plane - * @plane: the drm plane to get a property on - * @state: the state object with the property value to read - * @property: the property to get - * @val: the property value (returned by reference) - * - * Use this instead of calling plane->atomic_get_property directly. +/* * This function handles generic/core properties and calls out to * driver's ->atomic_get_property() for driver properties. To ensure * consistent behavior you must call this function rather than the * driver hook directly. - * - * RETURNS: - * Zero on success, error code on failure */ -int drm_atomic_plane_get_property(struct drm_plane *plane, +static int +drm_atomic_plane_get_property(struct drm_plane *plane, const struct drm_plane_state *state, struct drm_property *property, uint64_t *val) { @@ -460,7 +440,6 @@ int drm_atomic_plane_get_property(struct drm_plane *plane, return 0; } -EXPORT_SYMBOL(drm_atomic_plane_get_property); /** * drm_atomic_plane_check - check plane state @@ -650,23 +629,14 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, } EXPORT_SYMBOL(drm_atomic_connector_set_property); -/** - * drm_atomic_connector_get_property - get property on connector - * @connector: the drm connector to get a property on - * @state: the state object with the property value to read - * @property: the property to get - * @val: the property value (returned by reference) - * - * Use this instead of calling connector->atomic_get_property directly. +/* * This function handles generic/core properties and calls out to * driver's ->atomic_get_property() for driver properties. To ensure * consistent behavior you must call this function rather than the * driver hook directly. - * - * RETURNS: - * Zero on success, error code on failure */ -int drm_atomic_connector_get_property(struct drm_connector *connector, +static int +drm_atomic_connector_get_property(struct drm_connector *connector, const struct drm_connector_state *state, struct drm_property *property, uint64_t *val) { @@ -686,17 +656,7 @@ int drm_atomic_connector_get_property(struct drm_connector *connector, return 0; } -EXPORT_SYMBOL(drm_atomic_connector_get_property); -/** - * drm_atomic_get_property - helper to read atomic property - * @obj: drm mode object whose property to read - * @property: the property to read - * @val: the read value, returned by reference - * - * RETURNS: - * Zero on success, error code on failure - */ int drm_atomic_get_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val) { diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index a2945ee..247dc8b 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -36,3 +36,9 @@ int drm_mode_object_get(struct drm_device *dev, void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object *object); +/* drm_atomic.c */ +int drm_atomic_get_property(struct drm_mode_object *obj, + struct drm_property *property, uint64_t *val); +int drm_mode_atomic_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); + diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index a28c0ab..5cb4058 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -32,6 +32,7 @@ #include #include "drm_legacy.h" #include "drm_internal.h" +#include "drm_crtc_internal.h" #include #include diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 231fb48..51168a8 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -41,30 +41,18 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val); -int drm_atomic_crtc_get_property(struct drm_crtc *crtc, - const struct drm_crtc_state *state, - struct drm_property *property, uint64_t *val); struct drm_plane_state * __must_check drm_atomic_get_plane_state(struct drm_atomic_state *state, struct drm_plane *plane); int drm_atomic_plane_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val); -int drm_atomic_plane_get_property(struct drm_plane *plane, - const struct drm_plane_state *state, - struct drm_property *property, uint64_t *val); struct drm_connector_state * __must_check drm_atomic_get_connector_state(struct drm_atomic_state *state, struct drm_connector *connector); int drm_atomic_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, struct drm_property *property, uint64_t val); -int drm_atomic_connector_get_property(struct drm_connector *connector, - const struct drm_connector_state *state, - struct drm_property *property, uint64_t *val); - -int drm_atomic_get_property(struct drm_mode_object *obj, - struct drm_property *property, uint64_t *val); int __must_check drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, -- cgit v0.10.2 From 179f158ccf15fb9425f53d589d1b48eab90449a6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Dec 2014 10:33:52 +0100 Subject: drm: Ensure universal_planes is set for atomic Atomic doesn't really work without universal planes anyway. But make sure that evil userspace doesn't pull the kernel over the table because we didn't consider a cornercase that just doesn't make sense, just for safety. v2: Just force ->universal_planes to the same value to avoid imposing restrictions on userspace. Cc: Rob Clark Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 5cb4058..3785d66 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -355,6 +355,7 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) if (req->value > 1) return -EINVAL; file_priv->atomic = req->value; + file_priv->universal_planes = req->value; break; default: return -EINVAL; -- cgit v0.10.2 From 944115934436b1ff6cf773a9e9123858ea9ef3da Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Wed, 31 Dec 2014 16:23:00 -0800 Subject: drm/i915: Make sample_c messages go faster on Haswell. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Haswell significantly improved the performance of sampler_c messages, but the optimization appears to be off by default. Later platforms remove this bit, and apparently always enable the optimization. Improves performance in "Counter Strike: Global Offensive" by 18% at default settings on Iris Pro. This may break sampling of paletted formats (P8/A8P8/P8A8). It's unclear whether it affects sampling of paletted formats in general, or just the sample_c message (which is never used). While libva does have support for using paletted formats (primarily for OSDs), that support appears to have been broken for at least a year, so I couldn't observe a regression from this: I tried to get libva-intel to use paletted formats, and observe a regression...but the only thing I found that used it was mplayer's OSD (on screen display). Even without my patch, the colors were totally wrong with that, and it's according to a few distro wikis, that's been the case for over a year. If libva's code for paletted formats /is/ broken, they could always add code to disable this bit using the command validator when fixing it. Further investigation from Haihao shows that libva mplayer OSD seems to work at least on his setup (still unclear what's wron with Ken's), and that it's not affected by this patch. Quoting the discussion between Haihao and Ken: > > > If you use "-vo gl" or "-vo xv", the OSD is solid white text with a black > > > border around it. I presume that it's supposed to be white with vaapi as > > > well, but I guess I'm not entirely sure. > > > > > > It's possible that the optimization doesn't affect the palette as long as > > > you never use sample_c with the paletted textures. > > > > I verified the palette takes effect in the following way: > > > > 1. Only support P8A8 format in the driver > > > > 2. ran the above command and I saw white OSD text > > > > 3. Only support P4A4 format in the driver and don't use > > 3DSTATE_SAMPLER_PALETTE_LOAD0 to load the value to the texture palette, > > so the palette keeps unchanged. > > > > 4. ran the above command and I saw black OSD text. > > > > 5. Load the right value to the texture palette and ran the above command > > again, I saw white OSD text. > > > > Hence I think sample_c with the paletted textures is used in the driver. > > That sounds like the palette is actually working, then. Great :) > > I doubt that libva would use sample_c - sampling with a shadow comparison? > It looks like it just uses sample and sample+killpix. You are right, libva driver doesn't use sample_c message. > I'm pretty sure the sample_c optimization just uses the palette memory as > storage for some stuff, so it's quite possible it just works if you're > only using sample and sample+killpix. Thanks for the explanation, it makes sense to me. Signed-off-by: Kenneth Graunke [danvet: Add wa name from Ville's review to the comment and copypaste the explanation why we don't care about libva (already broken) from Ken. Also add conclusion from libva devs that&why this is all fine.] Reviewed-by: Ville Syrjälä Cc: "Xiang, Haihao" Cc: libva@lists.freedesktop.org Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1fdda42..0cb0067 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6152,6 +6152,7 @@ enum punit_power_well { #define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6) #define HALF_SLICE_CHICKEN3 0xe184 +#define HSW_SAMPLE_C_PERFORMANCE (1<<9) #define GEN8_CENTROID_PIXEL_OPT_DIS (1<<8) #define GEN8_SAMPLER_POWER_BYPASS_DIS (1<<1) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4254e91..0918604 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5972,6 +5972,10 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_GT_MODE, GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4); + /* WaSampleCChickenBitEnable:hsw */ + I915_WRITE(HALF_SLICE_CHICKEN3, + _MASKED_BIT_ENABLE(HSW_SAMPLE_C_PERFORMANCE)); + /* WaSwitchSolVfFArbitrationPriority:hsw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); -- cgit v0.10.2 From 7838a63a53f69c4cdfd450b60f0d58ed6641076e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 5 Jan 2015 14:36:59 +0100 Subject: drm/i915: Include i915_gem_evict.c kerneldoc into the drm docbook I've written these long before we've had a reasonable docbook structure, and naturally they've gone stale. Fix this up asap. Signed-off-by: Daniel Vetter diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index bd1456a..38f7ef3 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4048,6 +4048,17 @@ int num_ioctls; !Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views !Idrivers/gpu/drm/i915/i915_gem_gtt.c + + Buffer Object Eviction + + This section documents the interface function for evicting buffer + objects to make space available in the virtual gpu address spaces. + Note that this is mostly orthogonal to shrinking buffer objects + caches, which has the goal to make main memory (shared with the gpu + through the unified memory architecture) available. + +!Idrivers/gpu/drm/i915/i915_gem_evict.c + diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 886ff2e..d104c91 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -50,11 +50,12 @@ mark_free(struct i915_vma *vma, struct list_head *unwind) * i915_gem_evict_something - Evict vmas to make room for binding a new one * @dev: drm_device * @vm: address space to evict from - * @size: size of the desired free space + * @min_size: size of the desired free space * @alignment: alignment constraint of the desired free space * @cache_level: cache_level for the desired space - * @mappable: whether the free space must be mappable - * @nonblocking: whether evicting active objects is allowed or not + * @start: start (inclusive) of the range from which to evict objects + * @end: end (exclusive) of the range from which to evict objects + * @flags: additional flags to control the eviction algorithm * * This function will try to evict vmas until a free space satisfying the * requirements is found. Callers must check first whether any such hole exists @@ -196,7 +197,6 @@ found: /** * i915_gem_evict_vm - Evict all idle vmas from a vm - * * @vm: Address space to cleanse * @do_idle: Boolean directing whether to idle first. * -- cgit v0.10.2 From b9b5dce5e767a07604b5debb169472f15b4b57a7 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 23 Dec 2014 17:16:04 +0000 Subject: drm/i915: Add some extra guards in evict_vm v2: Use WARN_ONs (Daniel) Cc: Daniel Vetter Signed-off-by: Ben Widawsky Signed-off-by: Michel Thierry Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index d104c91..e3a49d9 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -214,6 +214,7 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) struct i915_vma *vma, *next; int ret; + WARN_ON(!mutex_is_locked(&vm->dev->struct_mutex)); trace_i915_gem_evict_vm(vm); if (do_idle) { @@ -222,6 +223,8 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) return ret; i915_gem_retire_requests(vm->dev); + + WARN_ON(!list_empty(&vm->active_list)); } list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list) -- cgit v0.10.2 From 43566dedde54f9729113f5f9fde77d53e75e61e9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 2 Jan 2015 16:29:29 +0530 Subject: drm/i915: Broaden application of set-domain(GTT) Previously, this was restricted to only operate on bound objects - to make pointer access through the GTT to the object coherent with writes to and from the GPU. A second usecase is drm_intel_bo_wait_rendering() which at present does not function unless the object also happens to be bound into the GGTT (on current systems that is becoming increasingly rare, especially for the typical requests from mesa). A third usecase is a future patch wishing to extend the coverage of the GTT domain to include objects not bound into the GGTT but still in its coherent cache domain. For the latter pair of requests, we need to operate on the object regardless of its bind state. v2: After discussion with Akash, we came to the conclusion that the get-pages was required in order for accurate domain tracking in the corner cases (like the shrinker) and also useful for ensuring memory coherency with earlier cached CPU mmaps in case userspace uses exotic cache bypass (non-temporal) instructions. v3: Fix the inactive object check. v4: Rebase to latest drm-intel-nightly codebase Signed-off-by: Chris Wilson Reviewed-by: Akash Goel Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f678017..a2c64a6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -153,12 +153,6 @@ int i915_mutex_lock_interruptible(struct drm_device *dev) return 0; } -static inline bool -i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) -{ - return i915_gem_obj_bound_any(obj) && !obj->active; -} - int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file) @@ -1472,18 +1466,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, if (ret) goto unref; - if (read_domains & I915_GEM_DOMAIN_GTT) { + if (read_domains & I915_GEM_DOMAIN_GTT) ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); - - /* Silently promote "you're not bound, there was nothing to do" - * to success, since the client was just asking us to - * make sure everything was done. - */ - if (ret == -EINVAL) - ret = 0; - } else { + else ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); - } unref: drm_gem_object_unreference(&obj->base); @@ -3699,15 +3685,10 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj, int i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - struct i915_vma *vma = i915_gem_obj_to_ggtt(obj); uint32_t old_write_domain, old_read_domains; + struct i915_vma *vma; int ret; - /* Not valid to be called on unbound objects. */ - if (vma == NULL) - return -EINVAL; - if (obj->base.write_domain == I915_GEM_DOMAIN_GTT) return 0; @@ -3716,6 +3697,19 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) return ret; i915_gem_object_retire(obj); + + /* Flush and acquire obj->pages so that we are coherent through + * direct access in memory with previous cached writes through + * shmemfs and that our cache domain tracking remains valid. + * For example, if the obj->filp was moved to swap without us + * being notified and releasing the pages, we would mistakenly + * continue to assume that the obj remained out of the CPU cached + * domain. + */ + ret = i915_gem_object_get_pages(obj); + if (ret) + return ret; + i915_gem_object_flush_cpu_write_domain(obj, false); /* Serialise direct access to this object with the barriers for @@ -3747,9 +3741,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) old_write_domain); /* And bump the LRU for this access */ - if (i915_gem_object_is_inactive(obj)) + vma = i915_gem_obj_to_ggtt(obj); + if (vma && drm_mm_node_allocated(&vma->node) && !obj->active) list_move_tail(&vma->mm_list, - &dev_priv->gtt.base.inactive_list); + &to_i915(obj->base.dev)->gtt.base.inactive_list); return 0; } -- cgit v0.10.2 From 1816f92363036600f2387bb8273b1e5e1f5b304e Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Fri, 2 Jan 2015 16:29:30 +0530 Subject: drm/i915: Support creation of unbound wc user mappings for objects This patch provides support to create write-combining virtual mappings of GEM object. It intends to provide the same funtionality of 'mmap_gtt' interface without the constraints and contention of a limited aperture space, but requires clients handles the linear to tile conversion on their own. This is for improving the CPU write operation performance, as with such mapping, writes and reads are almost 50% faster than with mmap_gtt. Similar to the GTT mmapping, unlike the regular CPU mmapping, it avoids the cache flush after update from CPU side, when object is passed onto GPU. This type of mapping is specially useful in case of sub-region update, i.e. when only a portion of the object is to be updated. Using a CPU mmap in such cases would normally incur a clflush of the whole object, and using a GTT mmapping would likely require eviction of an active object or fence and thus stall. The write-combining CPU mmap avoids both. To ensure the cache coherency, before using this mapping, the GTT domain has been reused here. This provides the required cache flush if the object is in CPU domain or synchronization against the concurrent rendering. Although the access through an uncached mmap should automatically invalidate the cache lines, this may not be true for non-temporal write instructions and also not all pages of the object may be updated at any given point of time through this mapping. Having a call to get_pages in set_to_gtt_domain function, as added in the earlier patch 'drm/i915: Broaden application of set-domain(GTT)', would guarantee the clflush and so there will be no cachelines holding the data for the object before it is accessed through this map. The drm_i915_gem_mmap structure (for the DRM_I915_GEM_MMAP_IOCTL) has been extended with a new flags field (defaulting to 0 for existent users). In order for userspace to detect the extended ioctl, a new parameter I915_PARAM_MMAP_VERSION has been added for versioning the ioctl interface. v2: Fix error handling, invalid flag detection, renaming (ickle) v3: Rebase to latest drm-intel-nightly codebase The new mmapping is exercised by igt/gem_mmap_wc, igt/gem_concurrent_blit and igt/gem_gtt_speed. Change-Id: Ie883942f9e689525f72fe9a8d3780c3a9faa769a Signed-off-by: Akash Goel Signed-off-by: Chris Wilson Cc: Daniel Vetter Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 52730ed..7fad6b8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -143,6 +143,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_COHERENT_PHYS_GTT: value = 1; break; + case I915_PARAM_MMAP_VERSION: + value = 1; + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a2c64a6..9cd457a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1534,6 +1534,12 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; unsigned long addr; + if (args->flags & ~(I915_MMAP_WC)) + return -EINVAL; + + if (args->flags & I915_MMAP_WC && !cpu_has_pat) + return -ENODEV; + obj = drm_gem_object_lookup(dev, file, args->handle); if (obj == NULL) return -ENOENT; @@ -1549,6 +1555,19 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, addr = vm_mmap(obj->filp, 0, args->size, PROT_READ | PROT_WRITE, MAP_SHARED, args->offset); + if (args->flags & I915_MMAP_WC) { + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + + down_write(&mm->mmap_sem); + vma = find_vma(mm, addr); + if (vma) + vma->vm_page_prot = + pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + else + addr = -ENOMEM; + up_write(&mm->mmap_sem); + } drm_gem_object_unreference_unlocked(obj); if (IS_ERR((void *)addr)) return addr; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 2502622..c155a03 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -341,6 +341,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_WT 27 #define I915_PARAM_CMD_PARSER_VERSION 28 #define I915_PARAM_HAS_COHERENT_PHYS_GTT 29 +#define I915_PARAM_MMAP_VERSION 30 typedef struct drm_i915_getparam { int param; @@ -488,6 +489,14 @@ struct drm_i915_gem_mmap { * This is a fixed-size type for 32/64 compatibility. */ __u64 addr_ptr; + + /** + * Flags for extended behaviour. + * + * Added in version 2. + */ + __u64 flags; +#define I915_MMAP_WC 0x1 }; struct drm_i915_gem_mmap_gtt { -- cgit v0.10.2 From dcbc9eb1919359719be0ef652afe1d90b0fa98ed Mon Sep 17 00:00:00 2001 From: Peter Seiderer Date: Sun, 8 Dec 2013 22:03:58 +0100 Subject: drm/imx: parallel-display: fix imxpd-->edid memleak If edid was allocated during bind, it must be freed again during unbind. Signed-off-by: Peter Seiderer Acked-by: Sascha Hauer Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 796c3c1..88cf7ca 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -257,6 +257,8 @@ static void imx_pd_unbind(struct device *dev, struct device *master, imxpd->encoder.funcs->destroy(&imxpd->encoder); imxpd->connector.funcs->destroy(&imxpd->connector); + + kfree(imxpd->edid); } static const struct component_ops imx_pd_ops = { @@ -272,6 +274,7 @@ static int imx_pd_probe(struct platform_device *pdev) static int imx_pd_remove(struct platform_device *pdev) { component_del(&pdev->dev, &imx_pd_ops); + return 0; } -- cgit v0.10.2 From f4876ffea6f310e1c7ee015687f913248a0d5f9c Mon Sep 17 00:00:00 2001 From: Peter Seiderer Date: Sun, 8 Dec 2013 22:03:57 +0100 Subject: drm/imx: imx-ldb: fix channel->edid memleak If edid was allocated during bind, it must be freed again during unbind. Signed-off-by: Peter Seiderer Acked-by: Sascha Hauer Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index c604600..4ff62a5 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -574,6 +574,8 @@ static void imx_ldb_unbind(struct device *dev, struct device *master, channel->connector.funcs->destroy(&channel->connector); channel->encoder.funcs->destroy(&channel->encoder); + + kfree(channel->edid); } } -- cgit v0.10.2 From 6457b9716bca99b95a07e85ff8b00f9bf471ac2c Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 3 Jul 2014 17:52:57 +0100 Subject: drm/imx: convert imx-drm to use the generic DRM OF helper Use the generic DRM OF helper to locate the possible CRTCs for the encoder, thereby shrinking the imx-drm driver some more. Signed-off-by: Russell King Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index b250130..06cd2e5 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "imx-drm.h" @@ -46,7 +47,6 @@ struct imx_drm_crtc { struct drm_crtc *crtc; int pipe; struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; - struct device_node *port; }; static int legacyfb_depth = 16; @@ -365,9 +365,10 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; imx_drm_crtc->pipe = imxdrm->pipes++; - imx_drm_crtc->port = port; imx_drm_crtc->crtc = crtc; + crtc->port = port; + imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc; *new_crtc = imx_drm_crtc; @@ -408,33 +409,28 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) } EXPORT_SYMBOL_GPL(imx_drm_remove_crtc); -/* - * Find the DRM CRTC possible mask for the connected endpoint. - * - * The encoder possible masks are defined by their position in the - * mode_config crtc_list. This means that CRTCs must not be added - * or removed once the DRM device has been fully initialised. - */ -static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm, - struct device_node *endpoint) +int imx_drm_encoder_parse_of(struct drm_device *drm, + struct drm_encoder *encoder, struct device_node *np) { - struct device_node *port; - unsigned i; + uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np); - port = of_graph_get_remote_port(endpoint); - if (!port) - return 0; - of_node_put(port); + /* + * If we failed to find the CRTC(s) which this encoder is + * supposed to be connected to, it's because the CRTC has + * not been registered yet. Defer probing, and hope that + * the required CRTC is added later. + */ + if (crtc_mask == 0) + return -EPROBE_DEFER; - for (i = 0; i < MAX_CRTC; i++) { - struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i]; + encoder->possible_crtcs = crtc_mask; - if (imx_drm_crtc && imx_drm_crtc->port == port) - return drm_crtc_mask(imx_drm_crtc->crtc); - } + /* FIXME: this is the mask of outputs which can clone this output. */ + encoder->possible_clones = ~0; return 0; } +EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); static struct device_node *imx_drm_of_get_next_endpoint( const struct device_node *parent, struct device_node *prev) @@ -445,48 +441,6 @@ static struct device_node *imx_drm_of_get_next_endpoint( return node; } -int imx_drm_encoder_parse_of(struct drm_device *drm, - struct drm_encoder *encoder, struct device_node *np) -{ - struct imx_drm_device *imxdrm = drm->dev_private; - struct device_node *ep = NULL; - uint32_t crtc_mask = 0; - int i; - - for (i = 0; ; i++) { - u32 mask; - - ep = imx_drm_of_get_next_endpoint(np, ep); - if (!ep) - break; - - mask = imx_drm_find_crtc_mask(imxdrm, ep); - - /* - * If we failed to find the CRTC(s) which this encoder is - * supposed to be connected to, it's because the CRTC has - * not been registered yet. Defer probing, and hope that - * the required CRTC is added later. - */ - if (mask == 0) - return -EPROBE_DEFER; - - crtc_mask |= mask; - } - - of_node_put(ep); - if (i == 0) - return -ENOENT; - - encoder->possible_crtcs = crtc_mask; - - /* FIXME: this is the mask of outputs which can clone this output. */ - encoder->possible_clones = ~0; - - return 0; -} -EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); - /* * @node: device tree node containing encoder input ports * @encoder: drm_encoder @@ -510,7 +464,7 @@ int imx_drm_encoder_get_mux_id(struct device_node *node, port = of_graph_get_remote_port(ep); of_node_put(port); - if (port == imx_crtc->port) { + if (port == imx_crtc->crtc->port) { ret = of_graph_parse_endpoint(ep, &endpoint); return ret ? ret : endpoint.port; } -- cgit v0.10.2 From f853f3daac748daa339bc8b64ba39db82160524a Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Mon, 26 Aug 2013 11:42:09 -0700 Subject: gpu: ipu-v3: Implement use counter for ipu_dc_enable(), ipu_dc_disable() The functions ipu_dc_enable() and ipu_dc_disable() enable/disable the DC globally in the IPU_CONF register, but the DC is used by multiple clients on different DC channels. So make sure to only disable/enable the DC globally based on a use counter. Signed-off-by: Steve Longerbeam Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index 2326c75..323203d 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c @@ -114,6 +114,7 @@ struct ipu_dc_priv { struct completion comp; int dc_irq; int dp_irq; + int use_count; }; static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority) @@ -232,7 +233,16 @@ EXPORT_SYMBOL_GPL(ipu_dc_init_sync); void ipu_dc_enable(struct ipu_soc *ipu) { - ipu_module_enable(ipu, IPU_CONF_DC_EN); + struct ipu_dc_priv *priv = ipu->dc_priv; + + mutex_lock(&priv->mutex); + + if (!priv->use_count) + ipu_module_enable(priv->ipu, IPU_CONF_DC_EN); + + priv->use_count++; + + mutex_unlock(&priv->mutex); } EXPORT_SYMBOL_GPL(ipu_dc_enable); @@ -294,7 +304,18 @@ EXPORT_SYMBOL_GPL(ipu_dc_disable_channel); void ipu_dc_disable(struct ipu_soc *ipu) { - ipu_module_disable(ipu, IPU_CONF_DC_EN); + struct ipu_dc_priv *priv = ipu->dc_priv; + + mutex_lock(&priv->mutex); + + priv->use_count--; + if (!priv->use_count) + ipu_module_disable(priv->ipu, IPU_CONF_DC_EN); + + if (priv->use_count < 0) + priv->use_count = 0; + + mutex_unlock(&priv->mutex); } EXPORT_SYMBOL_GPL(ipu_dc_disable); -- cgit v0.10.2 From b587833933de39e21b314e3b392ac0f1ec94a97e Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 5 Dec 2014 14:23:52 +0800 Subject: drm: imx: imx-hdmi: make checkpatch happy CHECK: Alignment should match open parenthesis + if ((hdmi->vic == 10) || (hdmi->vic == 11) || + (hdmi->vic == 12) || (hdmi->vic == 13) || CHECK: braces {} should be used on all arms of this statement + if (hdmi->hdmi_data.video_mode.mdvi) [...] + else { [...] Signed-off-by: Andy Yan Reviewed-by: Daniel Kurtz Tested-by: Russell King Acked-by: Russell King Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/drm/imx/imx-hdmi.c b/drivers/gpu/drm/imx/imx-hdmi.c index ddc53e0..3f96a5e 100644 --- a/drivers/gpu/drm/imx/imx-hdmi.c +++ b/drivers/gpu/drm/imx/imx-hdmi.c @@ -163,7 +163,7 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg) } static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg, - u8 shift, u8 mask) + u8 shift, u8 mask) { hdmi_modb(hdmi, data << shift, mask, reg); } @@ -327,7 +327,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk, } static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, - unsigned long pixel_clk) + unsigned long pixel_clk) { unsigned int clk_n, clk_cts; @@ -338,7 +338,7 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, if (!clk_cts) { dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", - __func__, pixel_clk); + __func__, pixel_clk); return; } @@ -477,13 +477,11 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) u16 coeff_b = (*csc_coeff)[1][i]; u16 coeff_c = (*csc_coeff)[2][i]; - hdmi_writeb(hdmi, coeff_a & 0xff, - HDMI_CSC_COEF_A1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2); hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2); hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2); hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2); - hdmi_writeb(hdmi, coeff_c & 0xff, - HDMI_CSC_COEF_C1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2); hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2); } @@ -535,21 +533,22 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; u8 val, vp_conf; - if (hdmi_data->enc_out_format == RGB - || hdmi_data->enc_out_format == YCBCR444) { - if (!hdmi_data->enc_color_depth) + if (hdmi_data->enc_out_format == RGB || + hdmi_data->enc_out_format == YCBCR444) { + if (!hdmi_data->enc_color_depth) { output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; - else if (hdmi_data->enc_color_depth == 8) { + } else if (hdmi_data->enc_color_depth == 8) { color_depth = 4; output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; - } else if (hdmi_data->enc_color_depth == 10) + } else if (hdmi_data->enc_color_depth == 10) { color_depth = 5; - else if (hdmi_data->enc_color_depth == 12) + } else if (hdmi_data->enc_color_depth == 12) { color_depth = 6; - else if (hdmi_data->enc_color_depth == 16) + } else if (hdmi_data->enc_color_depth == 16) { color_depth = 7; - else + } else { return; + } } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) { if (!hdmi_data->enc_color_depth || hdmi_data->enc_color_depth == 8) @@ -561,8 +560,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) else return; output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422; - } else + } else { return; + } /* set the packetizer registers */ val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & @@ -623,34 +623,34 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) } static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET, HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET, HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET, HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_writeb(hdmi, bit, HDMI_PHY_TST1); } static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_writeb(hdmi, bit, HDMI_PHY_TST2); } @@ -666,21 +666,21 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec) } static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, - unsigned char addr) + unsigned char addr) { hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0); hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR); hdmi_writeb(hdmi, (unsigned char)(data >> 8), - HDMI_PHY_I2CM_DATAO_1_ADDR); + HDMI_PHY_I2CM_DATAO_1_ADDR); hdmi_writeb(hdmi, (unsigned char)(data >> 0), - HDMI_PHY_I2CM_DATAO_0_ADDR); + HDMI_PHY_I2CM_DATAO_0_ADDR); hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE, - HDMI_PHY_I2CM_OPERATION_ADDR); + HDMI_PHY_I2CM_OPERATION_ADDR); hdmi_phy_wait_i2c_done(hdmi, 1000); } static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, - unsigned char addr) + unsigned char addr) { __hdmi_phy_i2c_write(hdmi, data, addr); return 0; @@ -839,7 +839,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, hdmi_phy_test_clear(hdmi, 1); hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2, - HDMI_PHY_I2CM_SLAVE_ADDR); + HDMI_PHY_I2CM_SLAVE_ADDR); hdmi_phy_test_clear(hdmi, 0); /* PLL/MPLL Cfg - always match on final entry */ @@ -857,9 +857,8 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, break; if (i >= ARRAY_SIZE(curr_ctrl)) { - dev_err(hdmi->dev, - "Pixel clock %d - unsupported by HDMI\n", - hdmi->hdmi_data.video_mode.mpixelclock); + dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", + hdmi->hdmi_data.video_mode.mpixelclock); return -EINVAL; } @@ -1223,21 +1222,21 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) } if ((hdmi->vic == 6) || (hdmi->vic == 7) || - (hdmi->vic == 21) || (hdmi->vic == 22) || - (hdmi->vic == 2) || (hdmi->vic == 3) || - (hdmi->vic == 17) || (hdmi->vic == 18)) + (hdmi->vic == 21) || (hdmi->vic == 22) || + (hdmi->vic == 2) || (hdmi->vic == 3) || + (hdmi->vic == 17) || (hdmi->vic == 18)) hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; else hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; if ((hdmi->vic == 10) || (hdmi->vic == 11) || - (hdmi->vic == 12) || (hdmi->vic == 13) || - (hdmi->vic == 14) || (hdmi->vic == 15) || - (hdmi->vic == 25) || (hdmi->vic == 26) || - (hdmi->vic == 27) || (hdmi->vic == 28) || - (hdmi->vic == 29) || (hdmi->vic == 30) || - (hdmi->vic == 35) || (hdmi->vic == 36) || - (hdmi->vic == 37) || (hdmi->vic == 38)) + (hdmi->vic == 12) || (hdmi->vic == 13) || + (hdmi->vic == 14) || (hdmi->vic == 15) || + (hdmi->vic == 25) || (hdmi->vic == 26) || + (hdmi->vic == 27) || (hdmi->vic == 28) || + (hdmi->vic == 29) || (hdmi->vic == 30) || + (hdmi->vic == 35) || (hdmi->vic == 36) || + (hdmi->vic == 37) || (hdmi->vic == 38)) hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1; else hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; @@ -1266,9 +1265,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) imx_hdmi_enable_video_path(hdmi); /* not for DVI mode */ - if (hdmi->hdmi_data.video_mode.mdvi) + if (hdmi->hdmi_data.video_mode.mdvi) { dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); - else { + } else { dev_dbg(hdmi->dev, "%s CEA mode\n", __func__); /* HDMI Initialization Step E - Configure audio */ @@ -1525,7 +1524,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) dev_dbg(hdmi->dev, "EVENT=plugout\n"); hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, - HDMI_PHY_POL0); + HDMI_PHY_POL0); imx_hdmi_poweroff(hdmi); } @@ -1554,7 +1553,7 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) DRM_MODE_ENCODER_TMDS); drm_connector_helper_add(&hdmi->connector, - &imx_hdmi_connector_helper_funcs); + &imx_hdmi_connector_helper_funcs); drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); @@ -1642,40 +1641,36 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); if (IS_ERR(hdmi->isfr_clk)) { ret = PTR_ERR(hdmi->isfr_clk); - dev_err(hdmi->dev, - "Unable to get HDMI isfr clk: %d\n", ret); + dev_err(hdmi->dev, "Unable to get HDMI isfr clk: %d\n", ret); return ret; } ret = clk_prepare_enable(hdmi->isfr_clk); if (ret) { - dev_err(hdmi->dev, - "Cannot enable HDMI isfr clock: %d\n", ret); + dev_err(hdmi->dev, "Cannot enable HDMI isfr clock: %d\n", ret); return ret; } hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); if (IS_ERR(hdmi->iahb_clk)) { ret = PTR_ERR(hdmi->iahb_clk); - dev_err(hdmi->dev, - "Unable to get HDMI iahb clk: %d\n", ret); + dev_err(hdmi->dev, "Unable to get HDMI iahb clk: %d\n", ret); goto err_isfr; } ret = clk_prepare_enable(hdmi->iahb_clk); if (ret) { - dev_err(hdmi->dev, - "Cannot enable HDMI iahb clock: %d\n", ret); + dev_err(hdmi->dev, "Cannot enable HDMI iahb clock: %d\n", ret); goto err_isfr; } /* Product and revision IDs */ dev_info(dev, - "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", - hdmi_readb(hdmi, HDMI_DESIGN_ID), - hdmi_readb(hdmi, HDMI_REVISION_ID), - hdmi_readb(hdmi, HDMI_PRODUCT_ID0), - hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); + "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", + hdmi_readb(hdmi, HDMI_DESIGN_ID), + hdmi_readb(hdmi, HDMI_REVISION_ID), + hdmi_readb(hdmi, HDMI_PRODUCT_ID0), + hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); initialize_hdmi_ih_mutes(hdmi); -- cgit v0.10.2 From c2c3848851a723a0e5e0fec22df395a885edf459 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 5 Dec 2014 14:24:28 +0800 Subject: drm: imx: imx-hdmi: return defer if can't get ddc i2c adapter drm driver may probe before the i2c bus, so the driver should defer probing until it is available Signed-off-by: Andy Yan Reviewed-by: Daniel Kurtz Tested-by: Russell King Acked-by: Russell King Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/drm/imx/imx-hdmi.c b/drivers/gpu/drm/imx/imx-hdmi.c index 3f96a5e..3118dde 100644 --- a/drivers/gpu/drm/imx/imx-hdmi.c +++ b/drivers/gpu/drm/imx/imx-hdmi.c @@ -1611,10 +1611,12 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); if (ddc_node) { hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); - if (!hdmi->ddc) + of_node_put(ddc_node); + if (!hdmi->ddc) { dev_dbg(hdmi->dev, "failed to read ddc node\n"); + return -EPROBE_DEFER; + } - of_node_put(ddc_node); } else { dev_dbg(hdmi->dev, "no ddc property found\n"); } -- cgit v0.10.2 From 3d1b35a3d9f3d6de690b237995d5aa858e349648 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 5 Dec 2014 14:25:05 +0800 Subject: drm: imx: imx-hdmi: convert imx-hdmi to drm_bridge mode IMX6 and Rockchip RK3288 and JZ4780 (Ingenic Xburst/MIPS) use the interface compatible Designware HDMI IP, but they also have some lightly differences, such as phy pll configuration, register width, 4K support, clk useage, and the crtc mux configuration is also platform specific. To reuse the imx hdmi driver, convert it to drm_bridge handle encoder in imx-hdmi_pltfm.c, as most of the encoder operation are platform specific such as crtc select and panel format set This patch depends on Russell King's patch: drm: imx: convert imx-drm to use the generic DRM OF helper http://driverdev.linuxdriverproject.org/pipermail/driverdev-devel/2014-July/053484.html Signed-off-by: Andy Yan Signed-off-by: Yakir Yang Tested-by: Russell King Acked-by: Russell King Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile index 582c438..63cf56a 100644 --- a/drivers/gpu/drm/imx/Makefile +++ b/drivers/gpu/drm/imx/Makefile @@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o -obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o +obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o imx-hdmi_pltfm.o diff --git a/drivers/gpu/drm/imx/imx-hdmi.c b/drivers/gpu/drm/imx/imx-hdmi.c index 3118dde..9f2f0fe 100644 --- a/drivers/gpu/drm/imx/imx-hdmi.c +++ b/drivers/gpu/drm/imx/imx-hdmi.c @@ -12,25 +12,20 @@ * Copyright (C) 2010, Guennadi Liakhovetski */ -#include #include #include #include #include #include -#include -#include -#include #include +#include #include #include #include #include -#include
Description/Restrictions
DRMDRM Generic “EDID” BLOB | IMMUTABLEContains tiling information for a connector.
PlanePlane “type” ENUM | IMMUTABLE { "Overlay", "Primary", "Cursor" }Plane type
“SRC_X”RANGEMin=0, Max=UINT_MAXPlaneScanout source x coordinate in 16.16 fixed point (atomic)
“SRC_Y”RANGEMin=0, Max=UINT_MAXPlaneScanout source y coordinate in 16.16 fixed point (atomic)
“SRC_W”RANGEMin=0, Max=UINT_MAXPlaneScanout source width in 16.16 fixed point (atomic)
“SRC_H”RANGEMin=0, Max=UINT_MAXPlaneScanout source height in 16.16 fixed point (atomic)
“CRTC_X”SIGNED_RANGEMin=INT_MIN, Max=INT_MAXPlaneScanout CRTC (destination) x coordinate (atomic)
“CRTC_Y”SIGNED_RANGEMin=INT_MIN, Max=INT_MAXPlaneScanout CRTC (destination) y coordinate (atomic)
“CRTC_W”RANGEMin=0, Max=UINT_MAXPlaneScanout CRTC (destination) width (atomic)
“CRTC_H”RANGEMin=0, Max=UINT_MAXPlaneScanout CRTC (destination) height (atomic)
“FB_ID”OBJECTDRM_MODE_OBJECT_FBPlaneScanout framebuffer (atomic)
“CRTC_ID”OBJECTDRM_MODE_OBJECT_CRTCPlaneCRTC that plane is attached to (atomic)
DVI-I “subconnector” ENUMDescription/Restrictions
DRMGenericDRMConnector “EDID” BLOB | IMMUTABLE 0Contains tiling information for a connector.
“CRTC_ID”OBJECTDRM_MODE_OBJECT_CRTCConnectorCRTC that connector is attached to (atomic)
Plane “type” ENUM | IMMUTABLE