Merge branch 'ics_HWA' of git://github.com/securecrt/android_kernel_htcleo-2.6.32-ics into ics_HWA
update the KGSL driver to the latest version
This commit is contained in:
commit
47e7119196
2
arch/arm/mach-msm/board-htcleo.c
Normal file → Executable file
2
arch/arm/mach-msm/board-htcleo.c
Normal file → Executable file
@ -755,7 +755,7 @@ static struct android_pmem_platform_data mdp_pmem_pdata = {
|
||||
.start = MSM_PMEM_MDP_BASE,
|
||||
.size = MSM_PMEM_MDP_SIZE,
|
||||
#ifdef CONFIG_MSM_KGSL
|
||||
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
|
||||
.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
|
||||
#else
|
||||
.no_allocator = 0,
|
||||
#endif
|
||||
|
3
arch/arm/mach-msm/board-htcleo.h
Normal file → Executable file
3
arch/arm/mach-msm/board-htcleo.h
Normal file → Executable file
@ -26,6 +26,7 @@
|
||||
#define MSM_EBI1_BANK0_SIZE 0x1E7C0000 /* 488MB - 0x00040000 RAM CONSOLE*/
|
||||
#endif
|
||||
|
||||
|
||||
/* Don't change that */
|
||||
#define MSM_SMI_BASE 0x00000000
|
||||
#define MSM_SMI_SIZE 0x04000000
|
||||
@ -42,7 +43,7 @@
|
||||
#define MSM_PMEM_MDP_SIZE 0x02000000
|
||||
|
||||
#define MSM_PMEM_ADSP_BASE 0x3D700000
|
||||
#define MSM_PMEM_ADSP_SIZE 0x02900000
|
||||
#define MSM_PMEM_ADSP_SIZE 0x01800000
|
||||
|
||||
#define MSM_GPU_PHYS_BASE (MSM_PMEM_SMI_BASE + MSM_FB_SIZE)
|
||||
#define MSM_GPU_PHYS_SIZE 0x00800000
|
||||
|
23
arch/arm/mach-msm/include/mach/ion.h
Executable file
23
arch/arm/mach-msm/include/mach/ion.h
Executable file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
*
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_ION_H_
|
||||
#define __MACH_ION_H_
|
||||
|
||||
enum ion_memory_types {
|
||||
ION_EBI_TYPE,
|
||||
ION_SMI_TYPE,
|
||||
};
|
||||
|
||||
#endif
|
15
arch/arm/mach-msm/qdsp6_1550/msm_q6vdec.c
Normal file → Executable file
15
arch/arm/mach-msm/qdsp6_1550/msm_q6vdec.c
Normal file → Executable file
@ -61,7 +61,7 @@
|
||||
#define VDEC_GET_MAJOR_VERSION(version) (((version)&MAJOR_MASK)>>16)
|
||||
|
||||
#define VDEC_GET_MINOR_VERSION(version) ((version)&MINOR_MASK)
|
||||
|
||||
//#define DEBUG_TRACE_VDEC
|
||||
#ifdef DEBUG_TRACE_VDEC
|
||||
#define TRACE(fmt,x...) \
|
||||
do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
|
||||
@ -69,6 +69,8 @@
|
||||
#define TRACE(fmt,x...) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* the version check will cause vdec hang up!!! */
|
||||
#define VERSION_CHECK 0
|
||||
|
||||
static DEFINE_MUTEX(idlecount_lock);
|
||||
static int idlecount;
|
||||
@ -696,7 +698,7 @@ static long vdec_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("%s: invalid ioctl!\n", __func__);
|
||||
pr_err("%s: invalid ioctl! cmd= %08x \n", __func__,cmd);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
@ -799,8 +801,9 @@ static int vdec_open(struct inode *inode, struct file *file)
|
||||
int i;
|
||||
struct vdec_msg_list *l;
|
||||
struct vdec_data *vd;
|
||||
#if VERSION_CHECK
|
||||
struct dal_info version_info;
|
||||
|
||||
#endif
|
||||
pr_info("q6vdec_open()\n");
|
||||
mutex_lock(&vdec_ref_lock);
|
||||
if (ref_cnt >= MAX_SUPPORTED_INSTANCES) {
|
||||
@ -845,6 +848,7 @@ static int vdec_open(struct inode *inode, struct file *file)
|
||||
ret = -EIO;
|
||||
goto vdec_open_err_handle_list;
|
||||
}
|
||||
#if VERSION_CHECK
|
||||
ret = dal_call_f9(vd->vdec_handle, DAL_OP_INFO,
|
||||
&version_info, sizeof(struct dal_info));
|
||||
|
||||
@ -859,12 +863,15 @@ static int vdec_open(struct inode *inode, struct file *file)
|
||||
pr_err("%s: driver version mismatch !\n", __func__);
|
||||
goto vdec_open_err_handle_version;
|
||||
}
|
||||
|
||||
#endif
|
||||
vd->running = 1;
|
||||
prevent_sleep();
|
||||
return 0;
|
||||
|
||||
#if VERSION_CHECK
|
||||
vdec_open_err_handle_version:
|
||||
dal_detach(vd->vdec_handle);
|
||||
#endif
|
||||
vdec_open_err_handle_list:
|
||||
{
|
||||
struct vdec_msg_list *l, *n;
|
||||
|
1
drivers/gpu/msm/Makefile
Normal file → Executable file
1
drivers/gpu/msm/Makefile
Normal file → Executable file
@ -19,6 +19,7 @@ msm_adreno-y += \
|
||||
adreno_drawctxt.o \
|
||||
adreno_postmortem.o \
|
||||
adreno_a2xx.o \
|
||||
adreno_a3xx.o \
|
||||
adreno.o
|
||||
|
||||
msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o
|
||||
|
22
drivers/gpu/msm/a2xx_reg.h
Normal file → Executable file
22
drivers/gpu/msm/a2xx_reg.h
Normal file → Executable file
@ -140,24 +140,9 @@ union reg_rb_edram_info {
|
||||
struct rb_edram_info_t f;
|
||||
};
|
||||
|
||||
#define RBBM_READ_ERROR_UNUSED0_SIZE 2
|
||||
#define RBBM_READ_ERROR_READ_ADDRESS_SIZE 15
|
||||
#define RBBM_READ_ERROR_UNUSED1_SIZE 13
|
||||
#define RBBM_READ_ERROR_READ_REQUESTER_SIZE 1
|
||||
#define RBBM_READ_ERROR_READ_ERROR_SIZE 1
|
||||
|
||||
struct rbbm_read_error_t {
|
||||
unsigned int unused0:RBBM_READ_ERROR_UNUSED0_SIZE;
|
||||
unsigned int read_address:RBBM_READ_ERROR_READ_ADDRESS_SIZE;
|
||||
unsigned int unused1:RBBM_READ_ERROR_UNUSED1_SIZE;
|
||||
unsigned int read_requester:RBBM_READ_ERROR_READ_REQUESTER_SIZE;
|
||||
unsigned int read_error:RBBM_READ_ERROR_READ_ERROR_SIZE;
|
||||
};
|
||||
|
||||
union rbbm_read_error_u {
|
||||
unsigned int val:32;
|
||||
struct rbbm_read_error_t f;
|
||||
};
|
||||
#define RBBM_READ_ERROR_ADDRESS_MASK 0x0001fffc
|
||||
#define RBBM_READ_ERROR_REQUESTER (1<<30)
|
||||
#define RBBM_READ_ERROR_ERROR (1<<31)
|
||||
|
||||
#define CP_RB_CNTL_RB_BUFSZ_SIZE 6
|
||||
#define CP_RB_CNTL_UNUSED0_SIZE 2
|
||||
@ -278,6 +263,7 @@ union reg_cp_rb_cntl {
|
||||
#define REG_CP_ME_CNTL 0x01F6
|
||||
#define REG_CP_ME_RAM_DATA 0x01FA
|
||||
#define REG_CP_ME_RAM_WADDR 0x01F8
|
||||
#define REG_CP_ME_RAM_RADDR 0x01F9
|
||||
#define REG_CP_ME_STATUS 0x01F7
|
||||
#define REG_CP_PFP_UCODE_ADDR 0x00C0
|
||||
#define REG_CP_PFP_UCODE_DATA 0x00C1
|
||||
|
453
drivers/gpu/msm/a3xx_reg.h
Executable file
453
drivers/gpu/msm/a3xx_reg.h
Executable file
@ -0,0 +1,453 @@
|
||||
/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _A300_REG_H
|
||||
#define _A300_REG_H
|
||||
|
||||
/* Interrupt bit positions within RBBM_INT_0 */
|
||||
|
||||
#define A3XX_INT_RBBM_GPU_IDLE 0
|
||||
#define A3XX_INT_RBBM_AHB_ERROR 1
|
||||
#define A3XX_INT_RBBM_REG_TIMEOUT 2
|
||||
#define A3XX_INT_RBBM_ME_MS_TIMEOUT 3
|
||||
#define A3XX_INT_RBBM_PFP_MS_TIMEOUT 4
|
||||
#define A3XX_INT_RBBM_ATB_BUS_OVERFLOW 5
|
||||
#define A3XX_INT_VFD_ERROR 6
|
||||
#define A3XX_INT_CP_SW_INT 7
|
||||
#define A3XX_INT_CP_T0_PACKET_IN_IB 8
|
||||
#define A3XX_INT_CP_OPCODE_ERROR 9
|
||||
#define A3XX_INT_CP_RESERVED_BIT_ERROR 10
|
||||
#define A3XX_INT_CP_HW_FAULT 11
|
||||
#define A3xx_INT_CP_DMA 12
|
||||
#define A3XX_INT_CP_IB2_INT 13
|
||||
#define A3XX_INT_CP_IB1_INT 14
|
||||
#define A3XX_INT_CP_RB_INT 15
|
||||
#define A3XX_INT_CP_REG_PROTECT_FAULT 16
|
||||
#define A3XX_INT_CP_RB_DONE_TS 17
|
||||
#define A3XX_INT_CP_VS_DONE_TS 18
|
||||
#define A3XX_INT_CP_PS_DONE_TS 19
|
||||
#define A3XX_INT_CACHE_FLUSH_TS 20
|
||||
#define A3XX_INT_CP_AHB_ERROR_HALT 21
|
||||
#define A3XX_INT_MISC_HANG_DETECT 24
|
||||
#define A3XX_INT_UCHE_OOB_ACCESS 25
|
||||
|
||||
/* Register definitions */
|
||||
|
||||
#define A3XX_RBBM_HW_VERSION 0x000
|
||||
#define A3XX_RBBM_HW_RELEASE 0x001
|
||||
#define A3XX_RBBM_HW_CONFIGURATION 0x002
|
||||
#define A3XX_RBBM_SW_RESET_CMD 0x018
|
||||
#define A3XX_RBBM_AHB_CTL0 0x020
|
||||
#define A3XX_RBBM_AHB_CTL1 0x021
|
||||
#define A3XX_RBBM_AHB_CMD 0x022
|
||||
#define A3XX_RBBM_AHB_ERROR_STATUS 0x027
|
||||
#define A3XX_RBBM_GPR0_CTL 0x02E
|
||||
/* This the same register as on A2XX, just in a different place */
|
||||
#define A3XX_RBBM_STATUS 0x030
|
||||
#define A3XX_RBBM_INTERFACE_HANG_INT_CTL 0x50
|
||||
#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL0 0x51
|
||||
#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL1 0x54
|
||||
#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL2 0x57
|
||||
#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL3 0x5A
|
||||
#define A3XX_RBBM_INT_CLEAR_CMD 0x061
|
||||
#define A3XX_RBBM_INT_0_MASK 0x063
|
||||
#define A3XX_RBBM_INT_0_STATUS 0x064
|
||||
#define A3XX_RBBM_GPU_BUSY_MASKED 0x88
|
||||
#define A3XX_RBBM_RBBM_CTL 0x100
|
||||
#define A3XX_RBBM_RBBM_CTL 0x100
|
||||
#define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC
|
||||
#define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED
|
||||
/* Following two are same as on A2XX, just in a different place */
|
||||
#define A3XX_CP_PFP_UCODE_ADDR 0x1C9
|
||||
#define A3XX_CP_PFP_UCODE_DATA 0x1CA
|
||||
#define A3XX_CP_HW_FAULT 0x45C
|
||||
#define A3XX_CP_AHB_FAULT 0x54D
|
||||
#define A3XX_CP_PROTECT_CTRL 0x45E
|
||||
#define A3XX_CP_PROTECT_STATUS 0x45F
|
||||
#define A3XX_CP_PROTECT_REG_0 0x460
|
||||
#define A3XX_CP_PROTECT_REG_1 0x461
|
||||
#define A3XX_CP_PROTECT_REG_2 0x462
|
||||
#define A3XX_CP_PROTECT_REG_3 0x463
|
||||
#define A3XX_CP_PROTECT_REG_4 0x464
|
||||
#define A3XX_CP_PROTECT_REG_5 0x465
|
||||
#define A3XX_CP_PROTECT_REG_6 0x466
|
||||
#define A3XX_CP_PROTECT_REG_7 0x467
|
||||
#define A3XX_CP_PROTECT_REG_8 0x468
|
||||
#define A3XX_CP_PROTECT_REG_9 0x469
|
||||
#define A3XX_CP_PROTECT_REG_A 0x46A
|
||||
#define A3XX_CP_PROTECT_REG_B 0x46B
|
||||
#define A3XX_CP_PROTECT_REG_C 0x46C
|
||||
#define A3XX_CP_PROTECT_REG_D 0x46D
|
||||
#define A3XX_CP_PROTECT_REG_E 0x46E
|
||||
#define A3XX_CP_PROTECT_REG_F 0x46F
|
||||
#define A3XX_CP_SCRATCH_REG2 0x57A
|
||||
#define A3XX_CP_SCRATCH_REG3 0x57B
|
||||
#define A3XX_VSC_BIN_SIZE 0xC01
|
||||
#define A3XX_VSC_SIZE_ADDRESS 0xC02
|
||||
#define A3XX_VSC_PIPE_CONFIG_0 0xC06
|
||||
#define A3XX_VSC_PIPE_DATA_ADDRESS_0 0xC07
|
||||
#define A3XX_VSC_PIPE_DATA_LENGTH_0 0xC08
|
||||
#define A3XX_VSC_PIPE_CONFIG_1 0xC09
|
||||
#define A3XX_VSC_PIPE_DATA_ADDRESS_1 0xC0A
|
||||
#define A3XX_VSC_PIPE_DATA_LENGTH_1 0xC0B
|
||||
#define A3XX_VSC_PIPE_CONFIG_2 0xC0C
|
||||
#define A3XX_VSC_PIPE_DATA_ADDRESS_2 0xC0D
|
||||
#define A3XX_VSC_PIPE_DATA_LENGTH_2 0xC0E
|
||||
#define A3XX_VSC_PIPE_CONFIG_3 0xC0F
|
||||
#define A3XX_VSC_PIPE_DATA_ADDRESS_3 0xC10
|
||||
#define A3XX_VSC_PIPE_DATA_LENGTH_3 0xC11
|
||||
#define A3XX_VSC_PIPE_CONFIG_4 0xC12
|
||||
#define A3XX_VSC_PIPE_DATA_ADDRESS_4 0xC13
|
||||
#define A3XX_VSC_PIPE_DATA_LENGTH_4 0xC14
|
||||
#define A3XX_VSC_PIPE_CONFIG_5 0xC15
|
||||
#define A3XX_VSC_PIPE_DATA_ADDRESS_5 0xC16
|
||||
#define A3XX_VSC_PIPE_DATA_LENGTH_5 0xC17
|
||||
#define A3XX_VSC_PIPE_CONFIG_6 0xC18
|
||||
#define A3XX_VSC_PIPE_DATA_ADDRESS_6 0xC19
|
||||
#define A3XX_VSC_PIPE_DATA_LENGTH_6 0xC1A
|
||||
#define A3XX_VSC_PIPE_CONFIG_7 0xC1B
|
||||
#define A3XX_VSC_PIPE_DATA_ADDRESS_7 0xC1C
|
||||
#define A3XX_VSC_PIPE_DATA_LENGTH_7 0xC1D
|
||||
#define A3XX_GRAS_CL_USER_PLANE_X0 0xCA0
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Y0 0xCA1
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Z0 0xCA2
|
||||
#define A3XX_GRAS_CL_USER_PLANE_W0 0xCA3
|
||||
#define A3XX_GRAS_CL_USER_PLANE_X1 0xCA4
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Y1 0xCA5
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Z1 0xCA6
|
||||
#define A3XX_GRAS_CL_USER_PLANE_W1 0xCA7
|
||||
#define A3XX_GRAS_CL_USER_PLANE_X2 0xCA8
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Y2 0xCA9
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Z2 0xCAA
|
||||
#define A3XX_GRAS_CL_USER_PLANE_W2 0xCAB
|
||||
#define A3XX_GRAS_CL_USER_PLANE_X3 0xCAC
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Y3 0xCAD
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Z3 0xCAE
|
||||
#define A3XX_GRAS_CL_USER_PLANE_W3 0xCAF
|
||||
#define A3XX_GRAS_CL_USER_PLANE_X4 0xCB0
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Y4 0xCB1
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Z4 0xCB2
|
||||
#define A3XX_GRAS_CL_USER_PLANE_W4 0xCB3
|
||||
#define A3XX_GRAS_CL_USER_PLANE_X5 0xCB4
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Y5 0xCB5
|
||||
#define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
|
||||
#define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
|
||||
#define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
|
||||
#define A3XX_GRAS_CL_CLIP_CNTL 0x2040
|
||||
#define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
|
||||
#define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
|
||||
#define A3XX_GRAS_CL_VPORT_ZOFFSET 0x204C
|
||||
#define A3XX_GRAS_CL_VPORT_ZSCALE 0x204D
|
||||
#define A3XX_GRAS_SU_POINT_MINMAX 0x2068
|
||||
#define A3XX_GRAS_SU_POINT_SIZE 0x2069
|
||||
#define A3XX_GRAS_SU_POLY_OFFSET_SCALE 0x206C
|
||||
#define A3XX_GRAS_SU_POLY_OFFSET_OFFSET 0x206D
|
||||
#define A3XX_GRAS_SU_MODE_CONTROL 0x2070
|
||||
#define A3XX_GRAS_SC_CONTROL 0x2072
|
||||
#define A3XX_GRAS_SC_SCREEN_SCISSOR_TL 0x2074
|
||||
#define A3XX_GRAS_SC_SCREEN_SCISSOR_BR 0x2075
|
||||
#define A3XX_GRAS_SC_WINDOW_SCISSOR_TL 0x2079
|
||||
#define A3XX_GRAS_SC_WINDOW_SCISSOR_BR 0x207A
|
||||
#define A3XX_RB_MODE_CONTROL 0x20C0
|
||||
#define A3XX_RB_RENDER_CONTROL 0x20C1
|
||||
#define A3XX_RB_MSAA_CONTROL 0x20C2
|
||||
#define A3XX_RB_MRT_CONTROL0 0x20C4
|
||||
#define A3XX_RB_MRT_BUF_INFO0 0x20C5
|
||||
#define A3XX_RB_MRT_BLEND_CONTROL0 0x20C7
|
||||
#define A3XX_RB_MRT_BLEND_CONTROL1 0x20CB
|
||||
#define A3XX_RB_MRT_BLEND_CONTROL2 0x20CF
|
||||
#define A3XX_RB_MRT_BLEND_CONTROL3 0x20D3
|
||||
#define A3XX_RB_BLEND_RED 0x20E4
|
||||
#define A3XX_RB_COPY_CONTROL 0x20EC
|
||||
#define A3XX_RB_COPY_DEST_INFO 0x20EF
|
||||
#define A3XX_RB_DEPTH_CONTROL 0x2100
|
||||
#define A3XX_RB_STENCIL_CONTROL 0x2104
|
||||
#define A3XX_PC_VSTREAM_CONTROL 0x21E4
|
||||
#define A3XX_PC_VERTEX_REUSE_BLOCK_CNTL 0x21EA
|
||||
#define A3XX_PC_PRIM_VTX_CNTL 0x21EC
|
||||
#define A3XX_PC_RESTART_INDEX 0x21ED
|
||||
#define A3XX_HLSQ_CONTROL_0_REG 0x2200
|
||||
#define A3XX_HLSQ_VS_CONTROL_REG 0x2204
|
||||
#define A3XX_HLSQ_CONST_FSPRESV_RANGE_REG 0x2207
|
||||
#define A3XX_HLSQ_CL_NDRANGE_0_REG 0x220A
|
||||
#define A3XX_HLSQ_CL_NDRANGE_2_REG 0x220C
|
||||
#define A3XX_HLSQ_CL_CONTROL_0_REG 0x2211
|
||||
#define A3XX_HLSQ_CL_CONTROL_1_REG 0x2212
|
||||
#define A3XX_HLSQ_CL_KERNEL_CONST_REG 0x2214
|
||||
#define A3XX_HLSQ_CL_KERNEL_GROUP_X_REG 0x2215
|
||||
#define A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG 0x2217
|
||||
#define A3XX_HLSQ_CL_WG_OFFSET_REG 0x221A
|
||||
#define A3XX_VFD_CONTROL_0 0x2240
|
||||
#define A3XX_VFD_INDEX_MIN 0x2242
|
||||
#define A3XX_VFD_FETCH_INSTR_0_0 0x2246
|
||||
#define A3XX_VFD_FETCH_INSTR_0_4 0x224E
|
||||
#define A3XX_VFD_DECODE_INSTR_0 0x2266
|
||||
#define A3XX_VFD_VS_THREADING_THRESHOLD 0x227E
|
||||
#define A3XX_VPC_ATTR 0x2280
|
||||
#define A3XX_VPC_VARY_CYLWRAP_ENABLE_1 0x228B
|
||||
#define A3XX_SP_SP_CTRL_REG 0x22C0
|
||||
#define A3XX_SP_VS_CTRL_REG0 0x22C4
|
||||
#define A3XX_SP_VS_CTRL_REG1 0x22C5
|
||||
#define A3XX_SP_VS_PARAM_REG 0x22C6
|
||||
#define A3XX_SP_VS_OUT_REG_7 0x22CE
|
||||
#define A3XX_SP_VS_VPC_DST_REG_0 0x22D0
|
||||
#define A3XX_SP_VS_OBJ_OFFSET_REG 0x22D4
|
||||
#define A3XX_SP_VS_PVT_MEM_SIZE_REG 0x22D8
|
||||
#define A3XX_SP_VS_LENGTH_REG 0x22DF
|
||||
#define A3XX_SP_FS_CTRL_REG0 0x22E0
|
||||
#define A3XX_SP_FS_CTRL_REG1 0x22E1
|
||||
#define A3XX_SP_FS_OBJ_OFFSET_REG 0x22E2
|
||||
#define A3XX_SP_FS_PVT_MEM_SIZE_REG 0x22E6
|
||||
#define A3XX_SP_FS_FLAT_SHAD_MODE_REG_0 0x22E8
|
||||
#define A3XX_SP_FS_FLAT_SHAD_MODE_REG_1 0x22E9
|
||||
#define A3XX_SP_FS_OUTPUT_REG 0x22EC
|
||||
#define A3XX_SP_FS_MRT_REG_0 0x22F0
|
||||
#define A3XX_SP_FS_IMAGE_OUTPUT_REG_0 0x22F4
|
||||
#define A3XX_SP_FS_IMAGE_OUTPUT_REG_3 0x22F7
|
||||
#define A3XX_SP_FS_LENGTH_REG 0x22FF
|
||||
#define A3XX_TPL1_TP_VS_TEX_OFFSET 0x2340
|
||||
#define A3XX_TPL1_TP_FS_TEX_OFFSET 0x2342
|
||||
#define A3XX_TPL1_TP_FS_BORDER_COLOR_BASE_ADDR 0x2343
|
||||
#define A3XX_VBIF_FIXED_SORT_EN 0x300C
|
||||
#define A3XX_VBIF_FIXED_SORT_SEL0 0x300D
|
||||
#define A3XX_VBIF_FIXED_SORT_SEL1 0x300E
|
||||
|
||||
/* Bit flags for RBBM_CTL */
|
||||
#define RBBM_RBBM_CTL_RESET_PWR_CTR1 (1 << 1)
|
||||
#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1 (17 << 1)
|
||||
|
||||
/* Various flags used by the context switch code */
|
||||
|
||||
#define SP_MULTI 0
|
||||
#define SP_BUFFER_MODE 1
|
||||
#define SP_TWO_VTX_QUADS 0
|
||||
#define SP_PIXEL_BASED 0
|
||||
#define SP_R8G8B8A8_UNORM 8
|
||||
#define SP_FOUR_PIX_QUADS 1
|
||||
|
||||
#define HLSQ_DIRECT 0
|
||||
#define HLSQ_BLOCK_ID_SP_VS 4
|
||||
#define HLSQ_SP_VS_INSTR 0
|
||||
#define HLSQ_SP_FS_INSTR 0
|
||||
#define HLSQ_BLOCK_ID_SP_FS 6
|
||||
#define HLSQ_TWO_PIX_QUADS 0
|
||||
#define HLSQ_TWO_VTX_QUADS 0
|
||||
#define HLSQ_BLOCK_ID_TP_TEX 2
|
||||
#define HLSQ_TP_TEX_SAMPLERS 0
|
||||
#define HLSQ_TP_TEX_MEMOBJ 1
|
||||
#define HLSQ_BLOCK_ID_TP_MIPMAP 3
|
||||
#define HLSQ_TP_MIPMAP_BASE 1
|
||||
#define HLSQ_FOUR_PIX_QUADS 1
|
||||
|
||||
#define RB_FACTOR_ONE 1
|
||||
#define RB_BLEND_OP_ADD 0
|
||||
#define RB_FACTOR_ZERO 0
|
||||
#define RB_DITHER_DISABLE 0
|
||||
#define RB_DITHER_ALWAYS 1
|
||||
#define RB_FRAG_NEVER 0
|
||||
#define RB_ENDIAN_NONE 0
|
||||
#define RB_R8G8B8A8_UNORM 8
|
||||
#define RB_RESOLVE_PASS 2
|
||||
#define RB_CLEAR_MODE_RESOLVE 1
|
||||
#define RB_TILINGMODE_LINEAR 0
|
||||
#define RB_REF_NEVER 0
|
||||
#define RB_STENCIL_KEEP 0
|
||||
#define RB_RENDERING_PASS 0
|
||||
#define RB_TILINGMODE_32X32 2
|
||||
|
||||
#define PC_DRAW_TRIANGLES 2
|
||||
#define PC_DI_PT_RECTLIST 8
|
||||
#define PC_DI_SRC_SEL_AUTO_INDEX 2
|
||||
#define PC_DI_INDEX_SIZE_16_BIT 0
|
||||
#define PC_DI_IGNORE_VISIBILITY 0
|
||||
#define PC_DI_PT_TRILIST 4
|
||||
#define PC_DI_SRC_SEL_IMMEDIATE 1
|
||||
#define PC_DI_INDEX_SIZE_32_BIT 1
|
||||
|
||||
#define UCHE_ENTIRE_CACHE 1
|
||||
#define UCHE_OP_INVALIDATE 1
|
||||
|
||||
/*
|
||||
* The following are bit field shifts within some of the registers defined
|
||||
* above. These are used in the context switch code in conjunction with the
|
||||
* _SET macro
|
||||
*/
|
||||
|
||||
#define GRAS_CL_CLIP_CNTL_CLIP_DISABLE 16
|
||||
#define GRAS_CL_CLIP_CNTL_IJ_PERSP_CENTER 12
|
||||
#define GRAS_CL_CLIP_CNTL_PERSP_DIVISION_DISABLE 21
|
||||
#define GRAS_CL_CLIP_CNTL_VP_CLIP_CODE_IGNORE 19
|
||||
#define GRAS_CL_CLIP_CNTL_VP_XFORM_DISABLE 20
|
||||
#define GRAS_CL_CLIP_CNTL_ZFAR_CLIP_DISABLE 17
|
||||
#define GRAS_CL_VPORT_XSCALE_VPORT_XSCALE 0
|
||||
#define GRAS_CL_VPORT_YSCALE_VPORT_YSCALE 0
|
||||
#define GRAS_CL_VPORT_ZSCALE_VPORT_ZSCALE 0
|
||||
#define GRAS_SC_CONTROL_RASTER_MODE 12
|
||||
#define GRAS_SC_CONTROL_RENDER_MODE 4
|
||||
#define GRAS_SC_SCREEN_SCISSOR_BR_BR_X 0
|
||||
#define GRAS_SC_SCREEN_SCISSOR_BR_BR_Y 16
|
||||
#define GRAS_SC_WINDOW_SCISSOR_BR_BR_X 0
|
||||
#define GRAS_SC_WINDOW_SCISSOR_BR_BR_Y 16
|
||||
#define HLSQ_CONSTFSPRESERVEDRANGEREG_ENDENTRY 16
|
||||
#define HLSQ_CONSTFSPRESERVEDRANGEREG_STARTENTRY 0
|
||||
#define HLSQ_CTRL0REG_CHUNKDISABLE 26
|
||||
#define HLSQ_CTRL0REG_CONSTSWITCHMODE 27
|
||||
#define HLSQ_CTRL0REG_FSSUPERTHREADENABLE 6
|
||||
#define HLSQ_CTRL0REG_FSTHREADSIZE 4
|
||||
#define HLSQ_CTRL0REG_LAZYUPDATEDISABLE 28
|
||||
#define HLSQ_CTRL0REG_RESERVED2 10
|
||||
#define HLSQ_CTRL0REG_SPCONSTFULLUPDATE 29
|
||||
#define HLSQ_CTRL0REG_SPSHADERRESTART 9
|
||||
#define HLSQ_CTRL0REG_TPFULLUPDATE 30
|
||||
#define HLSQ_CTRL1REG_RESERVED1 9
|
||||
#define HLSQ_CTRL1REG_VSSUPERTHREADENABLE 8
|
||||
#define HLSQ_CTRL1REG_VSTHREADSIZE 6
|
||||
#define HLSQ_CTRL2REG_PRIMALLOCTHRESHOLD 26
|
||||
#define HLSQ_FSCTRLREG_FSCONSTLENGTH 0
|
||||
#define HLSQ_FSCTRLREG_FSCONSTSTARTOFFSET 12
|
||||
#define HLSQ_FSCTRLREG_FSINSTRLENGTH 24
|
||||
#define HLSQ_VSCTRLREG_VSINSTRLENGTH 24
|
||||
#define PC_PRIM_VTX_CONTROL_POLYMODE_BACK_PTYPE 8
|
||||
#define PC_PRIM_VTX_CONTROL_POLYMODE_FRONT_PTYPE 5
|
||||
#define PC_PRIM_VTX_CONTROL_PROVOKING_VTX_LAST 25
|
||||
#define PC_PRIM_VTX_CONTROL_STRIDE_IN_VPC 0
|
||||
#define PC_DRAW_INITIATOR_PRIM_TYPE 0
|
||||
#define PC_DRAW_INITIATOR_SOURCE_SELECT 6
|
||||
#define PC_DRAW_INITIATOR_VISIBILITY_CULLING_MODE 9
|
||||
#define PC_DRAW_INITIATOR_INDEX_SIZE 0x0B
|
||||
#define PC_DRAW_INITIATOR_SMALL_INDEX 0x0D
|
||||
#define PC_DRAW_INITIATOR_PRE_DRAW_INITIATOR_ENABLE 0x0E
|
||||
#define RB_COPYCONTROL_COPY_GMEM_BASE 14
|
||||
#define RB_COPYCONTROL_RESOLVE_CLEAR_MODE 4
|
||||
#define RB_COPYDESTBASE_COPY_DEST_BASE 4
|
||||
#define RB_COPYDESTINFO_COPY_COMPONENT_ENABLE 14
|
||||
#define RB_COPYDESTINFO_COPY_DEST_ENDIAN 18
|
||||
#define RB_COPYDESTINFO_COPY_DEST_FORMAT 2
|
||||
#define RB_COPYDESTINFO_COPY_DEST_TILE 0
|
||||
#define RB_COPYDESTPITCH_COPY_DEST_PITCH 0
|
||||
#define RB_DEPTHCONTROL_Z_TEST_FUNC 4
|
||||
#define RB_MODECONTROL_RENDER_MODE 8
|
||||
#define RB_MODECONTROL_MARB_CACHE_SPLIT_MODE 15
|
||||
#define RB_MODECONTROL_PACKER_TIMER_ENABLE 16
|
||||
#define RB_MRTBLENDCONTROL_ALPHA_BLEND_OPCODE 21
|
||||
#define RB_MRTBLENDCONTROL_ALPHA_DEST_FACTOR 24
|
||||
#define RB_MRTBLENDCONTROL_ALPHA_SRC_FACTOR 16
|
||||
#define RB_MRTBLENDCONTROL_CLAMP_ENABLE 29
|
||||
#define RB_MRTBLENDCONTROL_RGB_BLEND_OPCODE 5
|
||||
#define RB_MRTBLENDCONTROL_RGB_DEST_FACTOR 8
|
||||
#define RB_MRTBLENDCONTROL_RGB_SRC_FACTOR 0
|
||||
#define RB_MRTBUFBASE_COLOR_BUF_BASE 4
|
||||
#define RB_MRTBUFINFO_COLOR_BUF_PITCH 17
|
||||
#define RB_MRTBUFINFO_COLOR_FORMAT 0
|
||||
#define RB_MRTBUFINFO_COLOR_TILE_MODE 6
|
||||
#define RB_MRTCONTROL_COMPONENT_ENABLE 24
|
||||
#define RB_MRTCONTROL_DITHER_MODE 12
|
||||
#define RB_MRTCONTROL_READ_DEST_ENABLE 3
|
||||
#define RB_MRTCONTROL_ROP_CODE 8
|
||||
#define RB_MSAACONTROL_MSAA_DISABLE 10
|
||||
#define RB_MSAACONTROL_SAMPLE_MASK 16
|
||||
#define RB_RENDERCONTROL_ALPHA_TEST_FUNC 24
|
||||
#define RB_RENDERCONTROL_BIN_WIDTH 4
|
||||
#define RB_RENDERCONTROL_DISABLE_COLOR_PIPE 12
|
||||
#define RB_STENCILCONTROL_STENCIL_FAIL 11
|
||||
#define RB_STENCILCONTROL_STENCIL_FAIL_BF 23
|
||||
#define RB_STENCILCONTROL_STENCIL_FUNC 8
|
||||
#define RB_STENCILCONTROL_STENCIL_FUNC_BF 20
|
||||
#define RB_STENCILCONTROL_STENCIL_ZFAIL 17
|
||||
#define RB_STENCILCONTROL_STENCIL_ZFAIL_BF 29
|
||||
#define RB_STENCILCONTROL_STENCIL_ZPASS 14
|
||||
#define RB_STENCILCONTROL_STENCIL_ZPASS_BF 26
|
||||
#define SP_FSCTRLREG0_FSFULLREGFOOTPRINT 10
|
||||
#define SP_FSCTRLREG0_FSICACHEINVALID 2
|
||||
#define SP_FSCTRLREG0_FSINOUTREGOVERLAP 18
|
||||
#define SP_FSCTRLREG0_FSINSTRBUFFERMODE 1
|
||||
#define SP_FSCTRLREG0_FSLENGTH 24
|
||||
#define SP_FSCTRLREG0_FSSUPERTHREADMODE 21
|
||||
#define SP_FSCTRLREG0_FSTHREADMODE 0
|
||||
#define SP_FSCTRLREG0_FSTHREADSIZE 20
|
||||
#define SP_FSCTRLREG0_PIXLODENABLE 22
|
||||
#define SP_FSCTRLREG1_FSCONSTLENGTH 0
|
||||
#define SP_FSCTRLREG1_FSINITIALOUTSTANDING 20
|
||||
#define SP_FSCTRLREG1_HALFPRECVAROFFSET 24
|
||||
#define SP_FSMRTREG_REGID 0
|
||||
#define SP_FSOUTREG_PAD0 2
|
||||
#define SP_IMAGEOUTPUTREG_MRTFORMAT 0
|
||||
#define SP_IMAGEOUTPUTREG_PAD0 6
|
||||
#define SP_OBJOFFSETREG_CONSTOBJECTSTARTOFFSET 16
|
||||
#define SP_OBJOFFSETREG_SHADEROBJOFFSETINIC 25
|
||||
#define SP_SHADERLENGTH_LEN 0
|
||||
#define SP_SPCTRLREG_CONSTMODE 18
|
||||
#define SP_SPCTRLREG_SLEEPMODE 20
|
||||
#define SP_VSCTRLREG0_VSFULLREGFOOTPRINT 10
|
||||
#define SP_VSCTRLREG0_VSICACHEINVALID 2
|
||||
#define SP_VSCTRLREG0_VSINSTRBUFFERMODE 1
|
||||
#define SP_VSCTRLREG0_VSLENGTH 24
|
||||
#define SP_VSCTRLREG0_VSSUPERTHREADMODE 21
|
||||
#define SP_VSCTRLREG0_VSTHREADMODE 0
|
||||
#define SP_VSCTRLREG0_VSTHREADSIZE 20
|
||||
#define SP_VSCTRLREG1_VSINITIALOUTSTANDING 24
|
||||
#define SP_VSOUTREG_COMPMASK0 9
|
||||
#define SP_VSPARAMREG_POSREGID 0
|
||||
#define SP_VSPARAMREG_PSIZEREGID 8
|
||||
#define SP_VSPARAMREG_TOTALVSOUTVAR 20
|
||||
#define SP_VSVPCDSTREG_OUTLOC0 0
|
||||
#define TPL1_TPTEXOFFSETREG_BASETABLEPTR 16
|
||||
#define TPL1_TPTEXOFFSETREG_MEMOBJOFFSET 8
|
||||
#define TPL1_TPTEXOFFSETREG_SAMPLEROFFSET 0
|
||||
#define UCHE_INVALIDATE1REG_OPCODE 0x1C
|
||||
#define UCHE_INVALIDATE1REG_ALLORPORTION 0x1F
|
||||
#define VFD_BASEADDR_BASEADDR 0
|
||||
#define VFD_CTRLREG0_PACKETSIZE 18
|
||||
#define VFD_CTRLREG0_STRMDECINSTRCNT 22
|
||||
#define VFD_CTRLREG0_STRMFETCHINSTRCNT 27
|
||||
#define VFD_CTRLREG0_TOTALATTRTOVS 0
|
||||
#define VFD_CTRLREG1_MAXSTORAGE 0
|
||||
#define VFD_CTRLREG1_REGID4INST 24
|
||||
#define VFD_CTRLREG1_REGID4VTX 16
|
||||
#define VFD_DECODEINSTRUCTIONS_CONSTFILL 4
|
||||
#define VFD_DECODEINSTRUCTIONS_FORMAT 6
|
||||
#define VFD_DECODEINSTRUCTIONS_LASTCOMPVALID 29
|
||||
#define VFD_DECODEINSTRUCTIONS_REGID 12
|
||||
#define VFD_DECODEINSTRUCTIONS_SHIFTCNT 24
|
||||
#define VFD_DECODEINSTRUCTIONS_SWITCHNEXT 30
|
||||
#define VFD_DECODEINSTRUCTIONS_WRITEMASK 0
|
||||
#define VFD_FETCHINSTRUCTIONS_BUFSTRIDE 7
|
||||
#define VFD_FETCHINSTRUCTIONS_FETCHSIZE 0
|
||||
#define VFD_FETCHINSTRUCTIONS_INDEXDECODE 18
|
||||
#define VFD_FETCHINSTRUCTIONS_STEPRATE 24
|
||||
#define VFD_FETCHINSTRUCTIONS_SWITCHNEXT 17
|
||||
#define VFD_THREADINGTHRESHOLD_REGID_VTXCNT 8
|
||||
#define VFD_THREADINGTHRESHOLD_RESERVED6 4
|
||||
#define VPC_VPCATTR_LMSIZE 28
|
||||
#define VPC_VPCATTR_THRHDASSIGN 12
|
||||
#define VPC_VPCATTR_TOTALATTR 0
|
||||
#define VPC_VPCPACK_NUMFPNONPOSVAR 8
|
||||
#define VPC_VPCPACK_NUMNONPOSVSVAR 16
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT08 0
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT09 2
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT0A 4
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT0B 6
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT0C 8
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT0D 10
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT0E 12
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT0F 14
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT10 16
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT11 18
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT12 20
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT13 22
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT14 24
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT15 26
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT16 28
|
||||
#define VPC_VPCVARPSREPLMODE_COMPONENT17 30
|
||||
|
||||
#endif
|
406
drivers/gpu/msm/adreno.c
Normal file → Executable file
406
drivers/gpu/msm/adreno.c
Normal file → Executable file
@ -72,6 +72,7 @@
|
||||
| (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT))
|
||||
|
||||
static const struct kgsl_functable adreno_functable;
|
||||
unsigned int kgsl_cff_dump_enable=0;
|
||||
|
||||
static struct adreno_device device_3d0 = {
|
||||
.dev = {
|
||||
@ -120,8 +121,11 @@ static struct adreno_device device_3d0 = {
|
||||
},
|
||||
.pfp_fw = NULL,
|
||||
.pm4_fw = NULL,
|
||||
.wait_timeout = 10000, /* in milliseconds */
|
||||
.ib_check_level = 0,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This is the master list of all GPU cores that are supported by this
|
||||
* driver.
|
||||
@ -135,50 +139,47 @@ static const struct {
|
||||
const char *pm4fw;
|
||||
const char *pfpfw;
|
||||
struct adreno_gpudev *gpudev;
|
||||
unsigned int istore_size;
|
||||
unsigned int pix_shader_start;
|
||||
unsigned int instruction_size; /* Size of an instruction in dwords */
|
||||
unsigned int gmem_size; /* size of gmem for gpu*/
|
||||
} adreno_gpulist[] = {
|
||||
{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
|
||||
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev },
|
||||
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
|
||||
512, 384, 3, SZ_256K },
|
||||
{ ADRENO_REV_A203, 0, 1, 1, ANY_ID,
|
||||
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
|
||||
512, 384, 3, SZ_256K },
|
||||
{ ADRENO_REV_A205, 0, 1, 0, ANY_ID,
|
||||
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev },
|
||||
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
|
||||
512, 384, 3, SZ_256K },
|
||||
{ ADRENO_REV_A220, 2, 1, ANY_ID, ANY_ID,
|
||||
"leia_pm4_470.fw", "leia_pfp_470.fw", &adreno_a2xx_gpudev },
|
||||
"leia_pm4_470.fw", "leia_pfp_470.fw", &adreno_a2xx_gpudev,
|
||||
512, 384, 3, SZ_512K },
|
||||
/*
|
||||
* patchlevel 5 (8960v2) needs special pm4 firmware to work around
|
||||
* a hardware problem.
|
||||
*/
|
||||
{ ADRENO_REV_A225, 2, 2, 0, 5,
|
||||
"a225p5_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev },
|
||||
"a225p5_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
|
||||
1536, 768, 3, SZ_512K },
|
||||
{ ADRENO_REV_A225, 2, 2, 0, 6,
|
||||
"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
|
||||
1536, 768, 3, SZ_512K },
|
||||
{ ADRENO_REV_A225, 2, 2, ANY_ID, ANY_ID,
|
||||
"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev },
|
||||
"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
|
||||
1536, 768, 3, SZ_512K },
|
||||
/* A3XX doesn't use the pix_shader_start */
|
||||
{ ADRENO_REV_A305, 3, 1, ANY_ID, ANY_ID,
|
||||
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
|
||||
512, 0, 2, SZ_256K },
|
||||
/* A3XX doesn't use the pix_shader_start */
|
||||
{ ADRENO_REV_A320, 3, 1, ANY_ID, ANY_ID,
|
||||
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
|
||||
512, 0, 2, SZ_512K },
|
||||
|
||||
};
|
||||
|
||||
static void adreno_gmeminit(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = &adreno_dev->dev;
|
||||
union reg_rb_edram_info rb_edram_info;
|
||||
unsigned int gmem_size;
|
||||
unsigned int edram_value = 0;
|
||||
|
||||
/* make sure edram range is aligned to size */
|
||||
BUG_ON(adreno_dev->gmemspace.gpu_base &
|
||||
(adreno_dev->gmemspace.sizebytes - 1));
|
||||
|
||||
/* get edram_size value equivalent */
|
||||
gmem_size = (adreno_dev->gmemspace.sizebytes >> 14);
|
||||
while (gmem_size >>= 1)
|
||||
edram_value++;
|
||||
|
||||
rb_edram_info.val = 0;
|
||||
|
||||
rb_edram_info.f.edram_size = edram_value;
|
||||
rb_edram_info.f.edram_mapping_mode = 0; /* EDRAM_MAP_UPPER */
|
||||
|
||||
/* must be aligned to size */
|
||||
rb_edram_info.f.edram_range = (adreno_dev->gmemspace.gpu_base >> 14);
|
||||
|
||||
adreno_regwrite(device, REG_RB_EDRAM_INFO, rb_edram_info.val);
|
||||
}
|
||||
|
||||
static irqreturn_t adreno_isr(int irq, void *data)
|
||||
{
|
||||
irqreturn_t result;
|
||||
@ -268,10 +269,13 @@ static void adreno_setstate(struct kgsl_device *device,
|
||||
int sizedwords = 0;
|
||||
unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */
|
||||
|
||||
/* If possible, then set the state via the command stream to avoid
|
||||
a CPU idle. Otherwise, use the default setstate which uses register
|
||||
writes */
|
||||
if (adreno_dev->drawctxt_active) {
|
||||
/*
|
||||
* If possible, then set the state via the command stream to avoid
|
||||
* a CPU idle. Otherwise, use the default setstate which uses register
|
||||
* writes For CFF dump we must idle and use the registers so that it is
|
||||
* easier to filter out the mmu accesses from the dump
|
||||
*/
|
||||
if (!kgsl_cff_dump_enable && adreno_dev->drawctxt_active) {
|
||||
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
|
||||
/* wait for graphics pipe to be idle */
|
||||
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
|
||||
@ -419,6 +423,10 @@ adreno_identify_gpu(struct adreno_device *adreno_dev)
|
||||
adreno_dev->gpudev = adreno_gpulist[i].gpudev;
|
||||
adreno_dev->pfp_fwfile = adreno_gpulist[i].pfpfw;
|
||||
adreno_dev->pm4_fwfile = adreno_gpulist[i].pm4fw;
|
||||
adreno_dev->istore_size = adreno_gpulist[i].istore_size;
|
||||
adreno_dev->pix_shader_start = adreno_gpulist[i].pix_shader_start;
|
||||
adreno_dev->instruction_size = adreno_gpulist[i].instruction_size;
|
||||
adreno_dev->gmemspace.sizebytes = adreno_gpulist[i].gmem_size;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
@ -432,8 +440,6 @@ adreno_probe(struct platform_device *pdev)
|
||||
adreno_dev = ADRENO_DEVICE(device);
|
||||
device->parentdev = &pdev->dev;
|
||||
|
||||
adreno_dev->wait_timeout = 10000; /* default value in milliseconds */
|
||||
|
||||
init_completion(&device->recovery_gate);
|
||||
|
||||
status = adreno_ringbuffer_init(device);
|
||||
@ -480,7 +486,6 @@ static int adreno_start(struct kgsl_device *device, unsigned int init_ram)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
int init_reftimestamp = 0x7fffffff;
|
||||
|
||||
device->state = KGSL_STATE_INIT;
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
@ -508,80 +513,22 @@ static int adreno_start(struct kgsl_device *device, unsigned int init_ram)
|
||||
|
||||
kgsl_mh_start(device);
|
||||
|
||||
if (kgsl_mmu_start(device))
|
||||
status = kgsl_mmu_start(device);
|
||||
if (status)
|
||||
goto error_clk_off;
|
||||
|
||||
/*We need to make sure all blocks are powered up and clocked before
|
||||
*issuing a soft reset. The overrides will then be turned off (set to 0)
|
||||
*/
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0xfffffffe);
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xffffffff);
|
||||
|
||||
/* Only reset CP block if all blocks have previously been reset */
|
||||
if (!(device->flags & KGSL_FLAGS_SOFT_RESET) ||
|
||||
!adreno_is_a22x(adreno_dev)) {
|
||||
adreno_regwrite(device, REG_RBBM_SOFT_RESET, 0xFFFFFFFF);
|
||||
device->flags |= KGSL_FLAGS_SOFT_RESET;
|
||||
} else
|
||||
adreno_regwrite(device, REG_RBBM_SOFT_RESET, 0x00000001);
|
||||
|
||||
/* The core is in an indeterminate state until the reset completes
|
||||
* after 30ms.
|
||||
*/
|
||||
msleep(30);
|
||||
|
||||
adreno_regwrite(device, REG_RBBM_SOFT_RESET, 0x00000000);
|
||||
|
||||
adreno_regwrite(device, REG_RBBM_CNTL, 0x00004442);
|
||||
|
||||
if (adreno_is_a225(adreno_dev)) {
|
||||
/* Enable large instruction store for A225 */
|
||||
adreno_regwrite(device, REG_SQ_FLOW_CONTROL, 0x18000000);
|
||||
}
|
||||
|
||||
adreno_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
|
||||
adreno_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
|
||||
|
||||
if (cpu_is_msm8960() || cpu_is_msm8930())
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0x200);
|
||||
else
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0);
|
||||
|
||||
if (!adreno_is_a22x(adreno_dev))
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0);
|
||||
else
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0x80);
|
||||
|
||||
kgsl_sharedmem_set(&device->memstore, 0, 0, device->memstore.size);
|
||||
|
||||
kgsl_sharedmem_writel(&device->memstore,
|
||||
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
|
||||
init_reftimestamp);
|
||||
|
||||
adreno_regwrite(device, REG_RBBM_DEBUG, 0x00080000);
|
||||
|
||||
/* Make sure interrupts are disabled */
|
||||
|
||||
adreno_regwrite(device, REG_RBBM_INT_CNTL, 0);
|
||||
adreno_regwrite(device, REG_CP_INT_CNTL, 0);
|
||||
adreno_regwrite(device, REG_SQ_INT_CNTL, 0);
|
||||
|
||||
if (adreno_is_a22x(adreno_dev))
|
||||
adreno_dev->gmemspace.sizebytes = SZ_512K;
|
||||
else
|
||||
adreno_dev->gmemspace.sizebytes = SZ_256K;
|
||||
adreno_gmeminit(adreno_dev);
|
||||
/* Start the GPU */
|
||||
adreno_dev->gpudev->start(adreno_dev);
|
||||
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
|
||||
device->ftbl->irqctrl(device, 1);
|
||||
|
||||
status = adreno_ringbuffer_start(&adreno_dev->ringbuffer, init_ram);
|
||||
if (status != 0)
|
||||
goto error_irq_off;
|
||||
|
||||
if (status == 0) {
|
||||
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
error_irq_off:
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
|
||||
kgsl_mmu_stop(device);
|
||||
error_clk_off:
|
||||
@ -624,6 +571,8 @@ adreno_recover_hang(struct kgsl_device *device)
|
||||
unsigned int soptimestamp;
|
||||
unsigned int eoptimestamp;
|
||||
struct adreno_context *drawctxt;
|
||||
struct kgsl_context *context;
|
||||
int next = 0;
|
||||
|
||||
KGSL_DRV_ERR(device, "Starting recovery from 3D GPU hang....\n");
|
||||
rb_buffer = vmalloc(rb->buffer_desc.size);
|
||||
@ -692,6 +641,24 @@ adreno_recover_hang(struct kgsl_device *device)
|
||||
|
||||
drawctxt->flags |= CTXT_FLAGS_GPU_HANG;
|
||||
|
||||
/*
|
||||
* Set the reset status of all contexts to
|
||||
* INNOCENT_CONTEXT_RESET_EXT except for the bad context
|
||||
* since thats the guilty party
|
||||
*/
|
||||
while ((context = idr_get_next(&device->context_idr, &next))) {
|
||||
if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
|
||||
context->reset_status) {
|
||||
if (context->devctxt != drawctxt)
|
||||
context->reset_status =
|
||||
KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
|
||||
else
|
||||
context->reset_status =
|
||||
KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
|
||||
}
|
||||
next = next + 1;
|
||||
}
|
||||
|
||||
/* Restore valid commands in ringbuffer */
|
||||
adreno_ringbuffer_restore(rb, rb_buffer, num_rb_contents);
|
||||
rb->timestamp = timestamp;
|
||||
@ -834,6 +801,12 @@ static int adreno_getproperty(struct kgsl_device *device,
|
||||
return status;
|
||||
}
|
||||
|
||||
static inline void adreno_poke(struct kgsl_device *device)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
adreno_regwrite(device, REG_CP_RB_WPTR, adreno_dev->ringbuffer.wptr);
|
||||
}
|
||||
|
||||
/* Caller must hold the device mutex. */
|
||||
int adreno_idle(struct kgsl_device *device, unsigned int timeout)
|
||||
{
|
||||
@ -842,16 +815,32 @@ int adreno_idle(struct kgsl_device *device, unsigned int timeout)
|
||||
unsigned int rbbm_status;
|
||||
unsigned long wait_timeout =
|
||||
msecs_to_jiffies(adreno_dev->wait_timeout);
|
||||
unsigned long wait_time = jiffies + wait_timeout;
|
||||
unsigned long wait_time;
|
||||
unsigned long wait_time_part;
|
||||
unsigned int msecs;
|
||||
unsigned int msecs_first;
|
||||
unsigned int msecs_part;
|
||||
|
||||
kgsl_cffdump_regpoll(device->id, REG_RBBM_STATUS << 2,
|
||||
kgsl_cffdump_regpoll(device->id,
|
||||
adreno_dev->gpudev->reg_rbbm_status << 2,
|
||||
0x00000000, 0x80000000);
|
||||
/* first, wait until the CP has consumed all the commands in
|
||||
* the ring buffer
|
||||
*/
|
||||
retry:
|
||||
if (rb->flags & KGSL_FLAGS_STARTED) {
|
||||
msecs = adreno_dev->wait_timeout;
|
||||
msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
|
||||
msecs_part = (msecs - msecs_first + 3) / 4;
|
||||
wait_time = jiffies + wait_timeout;
|
||||
wait_time_part = jiffies + msecs_to_jiffies(msecs_first);
|
||||
adreno_poke(device);
|
||||
do {
|
||||
if (time_after(jiffies, wait_time_part)) {
|
||||
adreno_poke(device);
|
||||
wait_time_part = jiffies +
|
||||
msecs_to_jiffies(msecs_part);
|
||||
}
|
||||
GSL_RB_GET_READPTR(rb, &rb->rptr);
|
||||
if (time_after(jiffies, wait_time)) {
|
||||
KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
|
||||
@ -864,7 +853,8 @@ retry:
|
||||
/* now, wait for the GPU to finish its operations */
|
||||
wait_time = jiffies + wait_timeout;
|
||||
while (time_before(jiffies, wait_time)) {
|
||||
adreno_regread(device, REG_RBBM_STATUS, &rbbm_status);
|
||||
adreno_regread(device, adreno_dev->gpudev->reg_rbbm_status,
|
||||
&rbbm_status);
|
||||
if (rbbm_status == 0x110)
|
||||
return 0;
|
||||
}
|
||||
@ -918,58 +908,70 @@ static int adreno_suspend_context(struct kgsl_device *device)
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t *kgsl_sharedmem_convertaddr(struct kgsl_device *device,
|
||||
unsigned int pt_base, unsigned int gpuaddr, unsigned int *size)
|
||||
struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
|
||||
unsigned int pt_base,
|
||||
unsigned int gpuaddr,
|
||||
unsigned int size)
|
||||
{
|
||||
uint8_t *result = NULL;
|
||||
struct kgsl_memdesc *result = NULL;
|
||||
struct kgsl_mem_entry *entry;
|
||||
struct kgsl_process_private *priv;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct adreno_ringbuffer *ringbuffer = &adreno_dev->ringbuffer;
|
||||
struct kgsl_context *context;
|
||||
int next = 0;
|
||||
|
||||
if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr)) {
|
||||
return kgsl_gpuaddr_to_vaddr(&ringbuffer->buffer_desc,
|
||||
gpuaddr, size);
|
||||
}
|
||||
if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr, size))
|
||||
return &ringbuffer->buffer_desc;
|
||||
|
||||
if (kgsl_gpuaddr_in_memdesc(&ringbuffer->memptrs_desc, gpuaddr)) {
|
||||
return kgsl_gpuaddr_to_vaddr(&ringbuffer->memptrs_desc,
|
||||
gpuaddr, size);
|
||||
}
|
||||
if (kgsl_gpuaddr_in_memdesc(&ringbuffer->memptrs_desc, gpuaddr, size))
|
||||
return &ringbuffer->memptrs_desc;
|
||||
|
||||
if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr)) {
|
||||
return kgsl_gpuaddr_to_vaddr(&device->memstore,
|
||||
gpuaddr, size);
|
||||
}
|
||||
if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
|
||||
return &device->memstore;
|
||||
|
||||
mutex_lock(&kgsl_driver.process_mutex);
|
||||
list_for_each_entry(priv, &kgsl_driver.process_list, list) {
|
||||
if (!kgsl_mmu_pt_equal(priv->pagetable, pt_base))
|
||||
continue;
|
||||
spin_lock(&priv->mem_lock);
|
||||
entry = kgsl_sharedmem_find_region(priv, gpuaddr,
|
||||
sizeof(unsigned int));
|
||||
if (entry) {
|
||||
result = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
|
||||
gpuaddr, size);
|
||||
spin_unlock(&priv->mem_lock);
|
||||
mutex_unlock(&kgsl_driver.process_mutex);
|
||||
return result;
|
||||
}
|
||||
spin_unlock(&priv->mem_lock);
|
||||
}
|
||||
mutex_unlock(&kgsl_driver.process_mutex);
|
||||
entry = kgsl_get_mem_entry(pt_base, gpuaddr, size);
|
||||
|
||||
BUG_ON(!mutex_is_locked(&device->mutex));
|
||||
list_for_each_entry(entry, &device->memqueue, list) {
|
||||
if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr)) {
|
||||
result = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
|
||||
gpuaddr, size);
|
||||
if (entry)
|
||||
return &entry->memdesc;
|
||||
|
||||
while (1) {
|
||||
struct adreno_context *adreno_context = NULL;
|
||||
context = idr_get_next(&device->context_idr, &next);
|
||||
if (context == NULL)
|
||||
break;
|
||||
|
||||
adreno_context = (struct adreno_context *)context->devctxt;
|
||||
|
||||
if (kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base)) {
|
||||
struct kgsl_memdesc *desc;
|
||||
|
||||
desc = &adreno_context->gpustate;
|
||||
if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) {
|
||||
result = desc;
|
||||
return result;
|
||||
}
|
||||
|
||||
desc = &adreno_context->context_gmem_shadow.gmemshadow;
|
||||
if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) {
|
||||
result = desc;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
next = next + 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
uint8_t *adreno_convertaddr(struct kgsl_device *device, unsigned int pt_base,
|
||||
unsigned int gpuaddr, unsigned int size)
|
||||
{
|
||||
struct kgsl_memdesc *memdesc;
|
||||
|
||||
memdesc = adreno_find_region(device, pt_base, gpuaddr, size);
|
||||
|
||||
return memdesc ? kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr) : NULL;
|
||||
}
|
||||
|
||||
void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
|
||||
@ -1047,7 +1049,8 @@ static int kgsl_check_interrupt_timestamp(struct kgsl_device *device,
|
||||
* get an interrupt */
|
||||
cmds[0] = cp_type3_packet(CP_NOP, 1);
|
||||
cmds[1] = 0;
|
||||
adreno_ringbuffer_issuecmds(device, 0, &cmds[0], 2);
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
|
||||
&cmds[0], 2);
|
||||
}
|
||||
mutex_unlock(&device->mutex);
|
||||
}
|
||||
@ -1078,8 +1081,12 @@ static int adreno_waittimestamp(struct kgsl_device *device,
|
||||
{
|
||||
long status = 0;
|
||||
uint io = 1;
|
||||
static uint io_cnt;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
int retries;
|
||||
unsigned int msecs_first;
|
||||
unsigned int msecs_part;
|
||||
|
||||
/* Don't wait forever, set a max value for now */
|
||||
if (msecs == -1)
|
||||
@ -1092,47 +1099,65 @@ static int adreno_waittimestamp(struct kgsl_device *device,
|
||||
status = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (!kgsl_check_timestamp(device, timestamp)) {
|
||||
if (pwr->active_pwrlevel) {
|
||||
int low_pwrlevel = pwr->num_pwrlevels -
|
||||
KGSL_PWRLEVEL_LOW_OFFSET;
|
||||
if (pwr->active_pwrlevel == low_pwrlevel)
|
||||
io = 0;
|
||||
|
||||
/* Keep the first timeout as 100msecs before rewriting
|
||||
* the WPTR. Less visible impact if the WPTR has not
|
||||
* been updated properly.
|
||||
*/
|
||||
msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
|
||||
msecs_part = (msecs - msecs_first + 3) / 4;
|
||||
for (retries = 0; retries < 5; retries++) {
|
||||
if (kgsl_check_timestamp(device, timestamp)) {
|
||||
/* if the timestamp happens while we're not
|
||||
* waiting, there's a chance that an interrupt
|
||||
* will not be generated and thus the timestamp
|
||||
* work needs to be queued.
|
||||
*/
|
||||
queue_work(device->work_queue, &device->ts_expired_ws);
|
||||
status = 0;
|
||||
goto done;
|
||||
}
|
||||
adreno_poke(device);
|
||||
// the QSD8X50 don't support io_fraction ?? // SecureCRT 2012-06-20
|
||||
// io_cnt = (io_cnt + 1) % 100;
|
||||
// if (io_cnt <
|
||||
// pwr->pwrlevels[pwr->active_pwrlevel].o_fraction)
|
||||
// io = 0;
|
||||
mutex_unlock(&device->mutex);
|
||||
/* We need to make sure that the process is placed in wait-q
|
||||
* before its condition is called */
|
||||
/* We need to make sure that the process is
|
||||
* placed in wait-q before its condition is called
|
||||
*/
|
||||
status = kgsl_wait_event_interruptible_timeout(
|
||||
device->wait_queue,
|
||||
kgsl_check_interrupt_timestamp(device,
|
||||
timestamp),
|
||||
msecs_to_jiffies(msecs), io);
|
||||
msecs_to_jiffies(retries ?
|
||||
msecs_part : msecs_first), io);
|
||||
mutex_lock(&device->mutex);
|
||||
|
||||
if (status > 0)
|
||||
status = 0;
|
||||
else if (status == 0) {
|
||||
if (!kgsl_check_timestamp(device, timestamp)) {
|
||||
if (status > 0) {
|
||||
/*completed before the wait finished */
|
||||
status = 0;
|
||||
goto done;
|
||||
} else if (status < 0) {
|
||||
/*an error occurred*/
|
||||
goto done;
|
||||
}
|
||||
/*this wait timed out*/
|
||||
}
|
||||
status = -ETIMEDOUT;
|
||||
KGSL_DRV_ERR(device,
|
||||
"Device hang detected while waiting "
|
||||
"for timestamp: %x, last "
|
||||
"submitted(rb->timestamp): %x, wptr: "
|
||||
"%x\n", timestamp,
|
||||
adreno_dev->ringbuffer.timestamp,
|
||||
"Device hang detected while waiting for timestamp: %x,"
|
||||
"last submitted(rb->timestamp): %x, wptr: %x\n",
|
||||
timestamp, adreno_dev->ringbuffer.timestamp,
|
||||
adreno_dev->ringbuffer.wptr);
|
||||
if (!adreno_dump_and_recover(device)) {
|
||||
/* wait for idle after recovery as the
|
||||
* timestamp that this process wanted
|
||||
* to wait on may be invalid */
|
||||
if (!adreno_idle(device,
|
||||
KGSL_TIMEOUT_DEFAULT))
|
||||
status = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!adreno_idle(device, KGSL_TIMEOUT_DEFAULT))
|
||||
status = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
return (int)status;
|
||||
}
|
||||
@ -1179,7 +1204,7 @@ static long adreno_ioctl(struct kgsl_device_private *dev_priv,
|
||||
default:
|
||||
KGSL_DRV_INFO(dev_priv->device,
|
||||
"invalid ioctl code %08x\n", cmd);
|
||||
result = -EINVAL;
|
||||
result = -ENOIOCTLCMD;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
@ -1195,44 +1220,29 @@ static inline s64 adreno_ticks_to_us(u32 ticks, u32 gpu_freq)
|
||||
static void adreno_power_stats(struct kgsl_device *device,
|
||||
struct kgsl_power_stats *stats)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
unsigned int cycles;
|
||||
|
||||
/* Get the busy cycles counted since the counter was last reset */
|
||||
/* Calling this function also resets and restarts the counter */
|
||||
|
||||
cycles = adreno_dev->gpudev->busy_cycles(adreno_dev);
|
||||
|
||||
/* In order to calculate idle you have to have run the algorithm *
|
||||
* at least once to get a start time. */
|
||||
if (pwr->time != 0) {
|
||||
s64 tmp;
|
||||
/* Stop the performance moniter and read the current *
|
||||
* busy cycles. */
|
||||
adreno_regwrite(device,
|
||||
REG_CP_PERFMON_CNTL,
|
||||
REG_PERF_MODE_CNT |
|
||||
REG_PERF_STATE_FREEZE);
|
||||
adreno_regread(device, REG_RBBM_PERFCOUNTER1_LO, ®);
|
||||
tmp = ktime_to_us(ktime_get());
|
||||
s64 tmp = ktime_to_us(ktime_get());
|
||||
stats->total_time = tmp - pwr->time;
|
||||
pwr->time = tmp;
|
||||
stats->busy_time = adreno_ticks_to_us(reg, device->pwrctrl.
|
||||
stats->busy_time = adreno_ticks_to_us(cycles, device->pwrctrl.
|
||||
pwrlevels[device->pwrctrl.active_pwrlevel].
|
||||
gpu_freq);
|
||||
|
||||
adreno_regwrite(device,
|
||||
REG_CP_PERFMON_CNTL,
|
||||
REG_PERF_MODE_CNT |
|
||||
REG_PERF_STATE_RESET);
|
||||
} else {
|
||||
stats->total_time = 0;
|
||||
stats->busy_time = 0;
|
||||
pwr->time = ktime_to_us(ktime_get());
|
||||
}
|
||||
|
||||
/* re-enable the performance moniters */
|
||||
adreno_regread(device, REG_RBBM_PM_OVERRIDE2, ®);
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, (reg | 0x40));
|
||||
adreno_regwrite(device, REG_RBBM_PERFCOUNTER1_SELECT, 0x1);
|
||||
adreno_regwrite(device,
|
||||
REG_CP_PERFMON_CNTL,
|
||||
REG_PERF_MODE_CNT | REG_PERF_STATE_ENABLE);
|
||||
}
|
||||
|
||||
void adreno_irqctrl(struct kgsl_device *device, int state)
|
||||
|
85
drivers/gpu/msm/adreno.h
Normal file → Executable file
85
drivers/gpu/msm/adreno.h
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -24,13 +24,16 @@
|
||||
KGSL_CONTAINER_OF(device, struct adreno_device, dev)
|
||||
|
||||
/* Flags to control command packet settings */
|
||||
#define KGSL_CMD_FLAGS_NONE 0x00000000
|
||||
#define KGSL_CMD_FLAGS_PMODE 0x00000001
|
||||
#define KGSL_CMD_FLAGS_NO_TS_CMP 0x00000002
|
||||
#define KGSL_CMD_FLAGS_NOT_KERNEL_CMD 0x00000004
|
||||
|
||||
/* Command identifiers */
|
||||
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0xDEADBEEF
|
||||
#define KGSL_CMD_IDENTIFIER 0xFEEDFACE
|
||||
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
|
||||
#define KGSL_CMD_IDENTIFIER 0x2EEDFACE
|
||||
#define KGSL_START_OF_IB_IDENTIFIER 0x2EADEABE
|
||||
#define KGSL_END_OF_IB_IDENTIFIER 0x2ABEDEAD
|
||||
|
||||
#ifdef CONFIG_MSM_SCM
|
||||
#define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_tz)
|
||||
@ -38,12 +41,17 @@
|
||||
#define ADRENO_DEFAULT_PWRSCALE_POLICY NULL
|
||||
#endif
|
||||
|
||||
#define ADRENO_ISTORE_START 0x5000 /* Istore offset */
|
||||
|
||||
enum adreno_gpurev {
|
||||
ADRENO_REV_UNKNOWN = 0,
|
||||
ADRENO_REV_A200 = 200,
|
||||
ADRENO_REV_A203 = 203,
|
||||
ADRENO_REV_A205 = 205,
|
||||
ADRENO_REV_A220 = 220,
|
||||
ADRENO_REV_A225 = 225,
|
||||
ADRENO_REV_A305 = 305,
|
||||
ADRENO_REV_A320 = 320,
|
||||
};
|
||||
|
||||
struct adreno_gpudev;
|
||||
@ -64,20 +72,34 @@ struct adreno_device {
|
||||
unsigned int mharb;
|
||||
struct adreno_gpudev *gpudev;
|
||||
unsigned int wait_timeout;
|
||||
unsigned int istore_size;
|
||||
unsigned int pix_shader_start;
|
||||
unsigned int instruction_size;
|
||||
unsigned int ib_check_level;
|
||||
};
|
||||
|
||||
struct adreno_gpudev {
|
||||
int (*ctxt_gpustate_shadow)(struct adreno_device *,
|
||||
struct adreno_context *);
|
||||
int (*ctxt_gmem_shadow)(struct adreno_device *,
|
||||
struct adreno_context *);
|
||||
/*
|
||||
* These registers are in a different location on A3XX, so define
|
||||
* them in the structure and use them as variables.
|
||||
*/
|
||||
unsigned int reg_rbbm_status;
|
||||
unsigned int reg_cp_pfp_ucode_data;
|
||||
unsigned int reg_cp_pfp_ucode_addr;
|
||||
|
||||
/* GPU specific function hooks */
|
||||
int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
|
||||
void (*ctxt_save)(struct adreno_device *, struct adreno_context *);
|
||||
void (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
|
||||
irqreturn_t (*irq_handler)(struct adreno_device *);
|
||||
void (*irq_control)(struct adreno_device *, int);
|
||||
void (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
|
||||
void (*start)(struct adreno_device *);
|
||||
unsigned int (*busy_cycles)(struct adreno_device *);
|
||||
};
|
||||
|
||||
extern struct adreno_gpudev adreno_a2xx_gpudev;
|
||||
extern struct adreno_gpudev adreno_a3xx_gpudev;
|
||||
|
||||
int adreno_idle(struct kgsl_device *device, unsigned int timeout);
|
||||
void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
|
||||
@ -85,23 +107,32 @@ void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
|
||||
void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
|
||||
unsigned int value);
|
||||
|
||||
uint8_t *kgsl_sharedmem_convertaddr(struct kgsl_device *device,
|
||||
unsigned int pt_base, unsigned int gpuaddr, unsigned int *size);
|
||||
struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
|
||||
unsigned int pt_base,
|
||||
unsigned int gpuaddr,
|
||||
unsigned int size);
|
||||
|
||||
uint8_t *adreno_convertaddr(struct kgsl_device *device,
|
||||
unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
|
||||
|
||||
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
|
||||
{
|
||||
return (adreno_dev->gpurev == ADRENO_REV_A200);
|
||||
}
|
||||
|
||||
static inline int adreno_is_a203(struct adreno_device *adreno_dev)
|
||||
{
|
||||
return (adreno_dev->gpurev == ADRENO_REV_A203);
|
||||
}
|
||||
|
||||
static inline int adreno_is_a205(struct adreno_device *adreno_dev)
|
||||
{
|
||||
return (adreno_dev->gpurev == ADRENO_REV_A200);
|
||||
return (adreno_dev->gpurev == ADRENO_REV_A205);
|
||||
}
|
||||
|
||||
static inline int adreno_is_a20x(struct adreno_device *adreno_dev)
|
||||
{
|
||||
return (adreno_dev->gpurev == ADRENO_REV_A200 ||
|
||||
adreno_dev->gpurev == ADRENO_REV_A205);
|
||||
return (adreno_dev->gpurev <= 209);
|
||||
}
|
||||
|
||||
static inline int adreno_is_a220(struct adreno_device *adreno_dev)
|
||||
@ -122,8 +153,36 @@ static inline int adreno_is_a22x(struct adreno_device *adreno_dev)
|
||||
|
||||
static inline int adreno_is_a2xx(struct adreno_device *adreno_dev)
|
||||
{
|
||||
return (adreno_dev->gpurev <= ADRENO_REV_A225);
|
||||
return (adreno_dev->gpurev <= 299);
|
||||
}
|
||||
|
||||
static inline int adreno_is_a3xx(struct adreno_device *adreno_dev)
|
||||
{
|
||||
return (adreno_dev->gpurev >= 300);
|
||||
}
|
||||
|
||||
/**
|
||||
* adreno_encode_istore_size - encode istore size in CP format
|
||||
* @adreno_dev - The 3D device.
|
||||
*
|
||||
* Encode the istore size into the format expected that the
|
||||
* CP_SET_SHADER_BASES and CP_ME_INIT commands:
|
||||
* bits 31:29 - istore size as encoded by this function
|
||||
* bits 27:16 - vertex shader start offset in instructions
|
||||
* bits 11:0 - pixel shader start offset in instructions.
|
||||
*/
|
||||
static inline int adreno_encode_istore_size(struct adreno_device *adreno_dev)
|
||||
{
|
||||
unsigned int size;
|
||||
/* in a225 the CP microcode multiplies the encoded
|
||||
* value by 3 while decoding.
|
||||
*/
|
||||
if (adreno_is_a225(adreno_dev))
|
||||
size = adreno_dev->istore_size/3;
|
||||
else
|
||||
size = adreno_dev->istore_size;
|
||||
|
||||
return (ilog2(size) - 5) << 29;
|
||||
}
|
||||
|
||||
#endif /*__ADRENO_H */
|
||||
|
396
drivers/gpu/msm/adreno_a2xx.c
Normal file → Executable file
396
drivers/gpu/msm/adreno_a2xx.c
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -11,6 +11,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "kgsl.h"
|
||||
#include "kgsl_sharedmem.h"
|
||||
#include "kgsl_cffdump.h"
|
||||
@ -72,10 +74,6 @@
|
||||
#define TEX_CONSTANTS (32*6) /* DWORDS */
|
||||
#define BOOL_CONSTANTS 8 /* DWORDS */
|
||||
#define LOOP_CONSTANTS 56 /* DWORDS */
|
||||
#define SHADER_INSTRUCT_LOG2 9U /* 2^n == SHADER_INSTRUCTIONS */
|
||||
|
||||
/* 96-bit instructions */
|
||||
#define SHADER_INSTRUCT (1<<SHADER_INSTRUCT_LOG2)
|
||||
|
||||
/* LOAD_CONSTANT_CONTEXT shadow size */
|
||||
#define LCC_SHADOW_SIZE 0x2000 /* 8KB */
|
||||
@ -88,14 +86,22 @@
|
||||
#define CMD_BUFFER_SIZE 0x3000 /* 12KB */
|
||||
#endif
|
||||
#define TEX_SHADOW_SIZE (TEX_CONSTANTS*4) /* 768 bytes */
|
||||
#define SHADER_SHADOW_SIZE (SHADER_INSTRUCT*12) /* 6KB */
|
||||
|
||||
#define REG_OFFSET LCC_SHADOW_SIZE
|
||||
#define CMD_OFFSET (REG_OFFSET + REG_SHADOW_SIZE)
|
||||
#define TEX_OFFSET (CMD_OFFSET + CMD_BUFFER_SIZE)
|
||||
#define SHADER_OFFSET ((TEX_OFFSET + TEX_SHADOW_SIZE + 32) & ~31)
|
||||
|
||||
#define CONTEXT_SIZE (SHADER_OFFSET + 3 * SHADER_SHADOW_SIZE)
|
||||
static inline int _shader_shadow_size(struct adreno_device *adreno_dev)
|
||||
{
|
||||
return adreno_dev->istore_size *
|
||||
(adreno_dev->instruction_size * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
static inline int _context_size(struct adreno_device *adreno_dev)
|
||||
{
|
||||
return SHADER_OFFSET + 3*_shader_shadow_size(adreno_dev);
|
||||
}
|
||||
|
||||
/* A scratchpad used to build commands during context create */
|
||||
|
||||
@ -546,6 +552,7 @@ static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev,
|
||||
unsigned int addr = shadow->gmemshadow.gpuaddr;
|
||||
unsigned int offset = (addr - (addr & 0xfffff000)) / bytesperpixel;
|
||||
|
||||
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
/* Store TP0_CHICKEN register */
|
||||
*cmds++ = cp_type3_packet(CP_REG_TO_MEM, 2);
|
||||
*cmds++ = REG_TP0_CHICKEN;
|
||||
@ -554,6 +561,7 @@ static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev,
|
||||
|
||||
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
|
||||
*cmds++ = 0;
|
||||
}
|
||||
|
||||
/* Set TP0_CHICKEN to zero */
|
||||
*cmds++ = cp_type0_packet(REG_TP0_CHICKEN, 1);
|
||||
@ -601,7 +609,8 @@ static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev,
|
||||
*cmds++ = 0x00003F00;
|
||||
|
||||
*cmds++ = cp_type3_packet(CP_SET_SHADER_BASES, 1);
|
||||
*cmds++ = (0x80000000) | 0x180;
|
||||
*cmds++ = adreno_encode_istore_size(adreno_dev)
|
||||
| adreno_dev->pix_shader_start;
|
||||
|
||||
/* load the patched vertex shader stream */
|
||||
cmds = program_shader(cmds, 0, gmem2sys_vtx_pgm, GMEM2SYS_VTX_PGM_LEN);
|
||||
@ -755,6 +764,7 @@ static unsigned int *build_sys2gmem_cmds(struct adreno_device *adreno_dev,
|
||||
unsigned int *cmds = shadow->gmem_restore_commands;
|
||||
unsigned int *start = cmds;
|
||||
|
||||
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
/* Store TP0_CHICKEN register */
|
||||
*cmds++ = cp_type3_packet(CP_REG_TO_MEM, 2);
|
||||
*cmds++ = REG_TP0_CHICKEN;
|
||||
@ -762,6 +772,7 @@ static unsigned int *build_sys2gmem_cmds(struct adreno_device *adreno_dev,
|
||||
|
||||
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
|
||||
*cmds++ = 0;
|
||||
}
|
||||
|
||||
/* Set TP0_CHICKEN to zero */
|
||||
*cmds++ = cp_type0_packet(REG_TP0_CHICKEN, 1);
|
||||
@ -802,7 +813,8 @@ static unsigned int *build_sys2gmem_cmds(struct adreno_device *adreno_dev,
|
||||
*cmds++ = 0x00000300; /* 0x100 = Vertex, 0x200 = Pixel */
|
||||
|
||||
*cmds++ = cp_type3_packet(CP_SET_SHADER_BASES, 1);
|
||||
*cmds++ = (0x80000000) | 0x180;
|
||||
*cmds++ = adreno_encode_istore_size(adreno_dev)
|
||||
| adreno_dev->pix_shader_start;
|
||||
|
||||
/* Load the patched fragment shader stream */
|
||||
cmds =
|
||||
@ -1089,7 +1101,8 @@ static void build_regrestore_cmds(struct adreno_device *adreno_dev,
|
||||
}
|
||||
|
||||
static void
|
||||
build_shader_save_restore_cmds(struct adreno_context *drawctxt)
|
||||
build_shader_save_restore_cmds(struct adreno_device *adreno_dev,
|
||||
struct adreno_context *drawctxt)
|
||||
{
|
||||
unsigned int *cmd = tmp_ctx.cmd;
|
||||
unsigned int *save, *restore, *fixup;
|
||||
@ -1099,8 +1112,10 @@ build_shader_save_restore_cmds(struct adreno_context *drawctxt)
|
||||
|
||||
/* compute vertex, pixel and shared instruction shadow GPU addresses */
|
||||
tmp_ctx.shader_vertex = drawctxt->gpustate.gpuaddr + SHADER_OFFSET;
|
||||
tmp_ctx.shader_pixel = tmp_ctx.shader_vertex + SHADER_SHADOW_SIZE;
|
||||
tmp_ctx.shader_shared = tmp_ctx.shader_pixel + SHADER_SHADOW_SIZE;
|
||||
tmp_ctx.shader_pixel = tmp_ctx.shader_vertex
|
||||
+ _shader_shadow_size(adreno_dev);
|
||||
tmp_ctx.shader_shared = tmp_ctx.shader_pixel
|
||||
+ _shader_shadow_size(adreno_dev);
|
||||
|
||||
/* restore shader partitioning and instructions */
|
||||
|
||||
@ -1156,8 +1171,8 @@ build_shader_save_restore_cmds(struct adreno_context *drawctxt)
|
||||
*cmd++ = REG_SCRATCH_REG2;
|
||||
/* AND off invalid bits. */
|
||||
*cmd++ = 0x0FFF0FFF;
|
||||
/* OR in instruction memory size */
|
||||
*cmd++ = (unsigned int)((SHADER_INSTRUCT_LOG2 - 5U) << 29);
|
||||
/* OR in instruction memory size. */
|
||||
*cmd++ = adreno_encode_istore_size(adreno_dev);
|
||||
|
||||
/* write the computed value to the SET_SHADER_BASES data field */
|
||||
*cmd++ = cp_type3_packet(CP_REG_TO_MEM, 2);
|
||||
@ -1219,45 +1234,22 @@ build_shader_save_restore_cmds(struct adreno_context *drawctxt)
|
||||
}
|
||||
|
||||
/* create buffers for saving/restoring registers, constants, & GMEM */
|
||||
static int a2xx_ctxt_gpustate_shadow(struct adreno_device *adreno_dev,
|
||||
static int a2xx_create_gpustate_shadow(struct adreno_device *adreno_dev,
|
||||
struct adreno_context *drawctxt)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Allocate vmalloc memory to store the gpustate */
|
||||
result = kgsl_allocate(&drawctxt->gpustate,
|
||||
drawctxt->pagetable, CONTEXT_SIZE);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
drawctxt->flags |= CTXT_FLAGS_STATE_SHADOW;
|
||||
|
||||
/* Blank out h/w register, constant, and command buffer shadows. */
|
||||
kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0, CONTEXT_SIZE);
|
||||
|
||||
/* set-up command and vertex buffer pointers */
|
||||
tmp_ctx.cmd = tmp_ctx.start
|
||||
= (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
|
||||
|
||||
/* build indirect command buffers to save & restore regs/constants */
|
||||
adreno_idle(&adreno_dev->dev, KGSL_TIMEOUT_DEFAULT);
|
||||
build_regrestore_cmds(adreno_dev, drawctxt);
|
||||
build_regsave_cmds(adreno_dev, drawctxt);
|
||||
|
||||
build_shader_save_restore_cmds(drawctxt);
|
||||
build_shader_save_restore_cmds(adreno_dev, drawctxt);
|
||||
|
||||
kgsl_cache_range_op(&drawctxt->gpustate,
|
||||
KGSL_CACHE_OP_FLUSH);
|
||||
|
||||
kgsl_cffdump_syncmem(NULL, &drawctxt->gpustate,
|
||||
drawctxt->gpustate.gpuaddr,
|
||||
drawctxt->gpustate.size, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create buffers for saving/restoring registers, constants, & GMEM */
|
||||
static int a2xx_ctxt_gmem_shadow(struct adreno_device *adreno_dev,
|
||||
static int a2xx_create_gmem_shadow(struct adreno_device *adreno_dev,
|
||||
struct adreno_context *drawctxt)
|
||||
{
|
||||
int result;
|
||||
@ -1272,8 +1264,8 @@ static int a2xx_ctxt_gmem_shadow(struct adreno_device *adreno_dev,
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* we've allocated the shadow, when swapped out, GMEM must be saved. */
|
||||
drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW | CTXT_FLAGS_GMEM_SAVE;
|
||||
/* set the gmem shadow flag for the context */
|
||||
drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW;
|
||||
|
||||
/* blank out gmem shadow. */
|
||||
kgsl_sharedmem_set(&drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
|
||||
@ -1284,6 +1276,7 @@ static int a2xx_ctxt_gmem_shadow(struct adreno_device *adreno_dev,
|
||||
&tmp_ctx.cmd);
|
||||
|
||||
/* build TP0_CHICKEN register restore command buffer */
|
||||
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE))
|
||||
tmp_ctx.cmd = build_chicken_restore_cmds(drawctxt);
|
||||
|
||||
/* build indirect command buffers to save & restore gmem */
|
||||
@ -1309,7 +1302,61 @@ static int a2xx_ctxt_gmem_shadow(struct adreno_device *adreno_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void a2xx_ctxt_save(struct adreno_device *adreno_dev,
|
||||
static int a2xx_drawctxt_create(struct adreno_device *adreno_dev,
|
||||
struct adreno_context *drawctxt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Allocate memory for the GPU state and the context commands.
|
||||
* Despite the name, this is much more then just storage for
|
||||
* the gpustate. This contains command space for gmem save
|
||||
* and texture and vertex buffer storage too
|
||||
*/
|
||||
|
||||
ret = kgsl_allocate(&drawctxt->gpustate,
|
||||
drawctxt->pagetable, _context_size(adreno_dev));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0,
|
||||
_context_size(adreno_dev));
|
||||
|
||||
tmp_ctx.cmd = tmp_ctx.start
|
||||
= (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
|
||||
|
||||
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
ret = a2xx_create_gpustate_shadow(adreno_dev, drawctxt);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
drawctxt->flags |= CTXT_FLAGS_SHADER_SAVE;
|
||||
}
|
||||
|
||||
if (!(drawctxt->flags & CTXT_FLAGS_NOGMEMALLOC)) {
|
||||
ret = a2xx_create_gmem_shadow(adreno_dev, drawctxt);
|
||||
if (ret)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Flush and sync the gpustate memory */
|
||||
|
||||
kgsl_cache_range_op(&drawctxt->gpustate,
|
||||
KGSL_CACHE_OP_FLUSH);
|
||||
|
||||
kgsl_cffdump_syncmem(NULL, &drawctxt->gpustate,
|
||||
drawctxt->gpustate.gpuaddr,
|
||||
drawctxt->gpustate.size, false);
|
||||
|
||||
done:
|
||||
if (ret)
|
||||
kgsl_sharedmem_free(&drawctxt->gpustate);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
|
||||
struct adreno_context *context)
|
||||
{
|
||||
struct kgsl_device *device = &adreno_dev->dev;
|
||||
@ -1321,25 +1368,28 @@ static void a2xx_ctxt_save(struct adreno_device *adreno_dev,
|
||||
KGSL_CTXT_WARN(device,
|
||||
"Current active context has caused gpu hang\n");
|
||||
|
||||
KGSL_CTXT_INFO(device,
|
||||
"active context flags %08x\n", context->flags);
|
||||
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
|
||||
/* save registers and constants. */
|
||||
adreno_ringbuffer_issuecmds(device, 0, context->reg_save, 3);
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
|
||||
context->reg_save, 3);
|
||||
|
||||
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
|
||||
/* save shader partitioning and instructions. */
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
|
||||
adreno_ringbuffer_issuecmds(device,
|
||||
KGSL_CMD_FLAGS_PMODE,
|
||||
context->shader_save, 3);
|
||||
|
||||
/* fixup shader partitioning parameter for
|
||||
/*
|
||||
* fixup shader partitioning parameter for
|
||||
* SET_SHADER_BASES.
|
||||
*/
|
||||
adreno_ringbuffer_issuecmds(device, 0,
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
|
||||
context->shader_fixup, 3);
|
||||
|
||||
context->flags |= CTXT_FLAGS_SHADER_RESTORE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((context->flags & CTXT_FLAGS_GMEM_SAVE) &&
|
||||
(context->flags & CTXT_FLAGS_GMEM_SHADOW)) {
|
||||
@ -1350,14 +1400,16 @@ static void a2xx_ctxt_save(struct adreno_device *adreno_dev,
|
||||
context->context_gmem_shadow.gmem_save, 3);
|
||||
|
||||
/* Restore TP0_CHICKEN */
|
||||
adreno_ringbuffer_issuecmds(device, 0,
|
||||
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
|
||||
context->chicken_restore, 3);
|
||||
}
|
||||
|
||||
context->flags |= CTXT_FLAGS_GMEM_RESTORE;
|
||||
}
|
||||
}
|
||||
|
||||
static void a2xx_ctxt_restore(struct adreno_device *adreno_dev,
|
||||
static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
|
||||
struct adreno_context *context)
|
||||
{
|
||||
struct kgsl_device *device = &adreno_dev->dev;
|
||||
@ -1377,7 +1429,7 @@ static void a2xx_ctxt_restore(struct adreno_device *adreno_dev,
|
||||
cmds[3] = device->memstore.gpuaddr +
|
||||
KGSL_DEVICE_MEMSTORE_OFFSET(current_context);
|
||||
cmds[4] = (unsigned int) context;
|
||||
adreno_ringbuffer_issuecmds(device, 0, cmds, 5);
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
|
||||
kgsl_mmu_setstate(device, context->pagetable);
|
||||
|
||||
#ifndef CONFIG_MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP
|
||||
@ -1393,27 +1445,34 @@ static void a2xx_ctxt_restore(struct adreno_device *adreno_dev,
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
|
||||
context->context_gmem_shadow.gmem_restore, 3);
|
||||
|
||||
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
/* Restore TP0_CHICKEN */
|
||||
adreno_ringbuffer_issuecmds(device, 0,
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
|
||||
context->chicken_restore, 3);
|
||||
}
|
||||
|
||||
context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
|
||||
}
|
||||
|
||||
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
|
||||
/* restore registers and constants. */
|
||||
adreno_ringbuffer_issuecmds(device, 0,
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
|
||||
context->reg_restore, 3);
|
||||
|
||||
/* restore shader instructions & partitioning. */
|
||||
if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
|
||||
adreno_ringbuffer_issuecmds(device, 0,
|
||||
adreno_ringbuffer_issuecmds(device,
|
||||
KGSL_CMD_FLAGS_NONE,
|
||||
context->shader_restore, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (adreno_is_a20x(adreno_dev)) {
|
||||
cmds[0] = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1);
|
||||
cmds[1] = context->bin_base_offset;
|
||||
adreno_ringbuffer_issuecmds(device, 0, cmds, 2);
|
||||
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
|
||||
cmds, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1532,21 +1591,33 @@ static void a2xx_rbbm_intrcallback(struct kgsl_device *device)
|
||||
{
|
||||
unsigned int status = 0;
|
||||
unsigned int rderr = 0;
|
||||
unsigned int addr = 0;
|
||||
const char *source;
|
||||
|
||||
adreno_regread(device, REG_RBBM_INT_STATUS, &status);
|
||||
|
||||
if (status & RBBM_INT_CNTL__RDERR_INT_MASK) {
|
||||
union rbbm_read_error_u rerr;
|
||||
adreno_regread(device, REG_RBBM_READ_ERROR, &rderr);
|
||||
rerr.val = rderr;
|
||||
if (rerr.f.read_address == REG_CP_INT_STATUS &&
|
||||
rerr.f.read_error &&
|
||||
rerr.f.read_requester)
|
||||
source = (rderr & RBBM_READ_ERROR_REQUESTER)
|
||||
? "host" : "cp";
|
||||
/* convert to dword address */
|
||||
addr = (rderr & RBBM_READ_ERROR_ADDRESS_MASK) >> 2;
|
||||
|
||||
/*
|
||||
* Log CP_INT_STATUS interrupts from the CP at a
|
||||
* lower level because they can happen frequently
|
||||
* and are worked around in a2xx_irq_handler.
|
||||
*/
|
||||
if (addr == REG_CP_INT_STATUS &&
|
||||
rderr & RBBM_READ_ERROR_ERROR &&
|
||||
rderr & RBBM_READ_ERROR_REQUESTER)
|
||||
KGSL_DRV_WARN(device,
|
||||
"rbbm read error interrupt: %08x\n", rderr);
|
||||
"rbbm read error interrupt: %s reg: %04X\n",
|
||||
source, addr);
|
||||
else
|
||||
KGSL_DRV_CRIT(device,
|
||||
"rbbm read error interrupt: %08x\n", rderr);
|
||||
"rbbm read error interrupt: %s reg: %04X\n",
|
||||
source, addr);
|
||||
}
|
||||
|
||||
status &= RBBM_INT_MASK;
|
||||
@ -1597,11 +1668,202 @@ static void a2xx_irq_control(struct adreno_device *adreno_dev, int state)
|
||||
wmb();
|
||||
}
|
||||
|
||||
static void a2xx_rb_init(struct adreno_device *adreno_dev,
|
||||
struct adreno_ringbuffer *rb)
|
||||
{
|
||||
unsigned int *cmds, cmds_gpu;
|
||||
|
||||
/* ME_INIT */
|
||||
cmds = adreno_ringbuffer_allocspace(rb, 19);
|
||||
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-19);
|
||||
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 18));
|
||||
/* All fields present (bits 9:0) */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x000003ff);
|
||||
/* Disable/Enable Real-Time Stream processing (present but ignored) */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
/* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_RB_SURFACE_INFO));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_PA_SC_WINDOW_OFFSET));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_VGT_MAX_VTX_INDX));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_SQ_PROGRAM_CNTL));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_RB_DEPTHCONTROL));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_PA_SU_POINT_SIZE));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_PA_SC_LINE_CNTL));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_PA_SU_POLY_OFFSET_FRONT_SCALE));
|
||||
|
||||
/* Instruction memory size: */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
(adreno_encode_istore_size(adreno_dev)
|
||||
| adreno_dev->pix_shader_start));
|
||||
/* Maximum Contexts */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000001);
|
||||
/* Write Confirm Interval and The CP will wait the
|
||||
* wait_interval * 16 clocks between polling */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
|
||||
/* NQ and External Memory Swap */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
/* Protected mode error checking */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
|
||||
/* Disable header dumping and Header dump address */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
/* Header dump size */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
|
||||
adreno_ringbuffer_submit(rb);
|
||||
}
|
||||
|
||||
static unsigned int a2xx_busy_cycles(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = &adreno_dev->dev;
|
||||
unsigned int reg, val;
|
||||
|
||||
/* Freeze the counter */
|
||||
adreno_regwrite(device, REG_CP_PERFMON_CNTL,
|
||||
REG_PERF_MODE_CNT | REG_PERF_STATE_FREEZE);
|
||||
|
||||
/* Get the value */
|
||||
adreno_regread(device, REG_RBBM_PERFCOUNTER1_LO, &val);
|
||||
|
||||
/* Reset the counter */
|
||||
adreno_regwrite(device, REG_CP_PERFMON_CNTL,
|
||||
REG_PERF_MODE_CNT | REG_PERF_STATE_RESET);
|
||||
|
||||
/* Re-Enable the performance monitors */
|
||||
adreno_regread(device, REG_RBBM_PM_OVERRIDE2, ®);
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, (reg | 0x40));
|
||||
adreno_regwrite(device, REG_RBBM_PERFCOUNTER1_SELECT, 0x1);
|
||||
adreno_regwrite(device, REG_CP_PERFMON_CNTL,
|
||||
REG_PERF_MODE_CNT | REG_PERF_STATE_ENABLE);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void a2xx_gmeminit(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = &adreno_dev->dev;
|
||||
union reg_rb_edram_info rb_edram_info;
|
||||
unsigned int gmem_size;
|
||||
unsigned int edram_value = 0;
|
||||
|
||||
/* make sure edram range is aligned to size */
|
||||
BUG_ON(adreno_dev->gmemspace.gpu_base &
|
||||
(adreno_dev->gmemspace.sizebytes - 1));
|
||||
|
||||
/* get edram_size value equivalent */
|
||||
gmem_size = (adreno_dev->gmemspace.sizebytes >> 14);
|
||||
while (gmem_size >>= 1)
|
||||
edram_value++;
|
||||
|
||||
rb_edram_info.val = 0;
|
||||
|
||||
rb_edram_info.f.edram_size = edram_value;
|
||||
rb_edram_info.f.edram_mapping_mode = 0; /* EDRAM_MAP_UPPER */
|
||||
|
||||
/* must be aligned to size */
|
||||
rb_edram_info.f.edram_range = (adreno_dev->gmemspace.gpu_base >> 14);
|
||||
|
||||
adreno_regwrite(device, REG_RB_EDRAM_INFO, rb_edram_info.val);
|
||||
}
|
||||
|
||||
static void a2xx_start(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = &adreno_dev->dev;
|
||||
int init_reftimestamp = 0x7fffffff;
|
||||
|
||||
/*
|
||||
* We need to make sure all blocks are powered up and clocked
|
||||
* before issuing a soft reset. The overrides will then be
|
||||
* turned off (set to 0)
|
||||
*/
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0xfffffffe);
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xffffffff);
|
||||
|
||||
/*
|
||||
* Only reset CP block if all blocks have previously been
|
||||
* reset
|
||||
*/
|
||||
if (!(device->flags & KGSL_FLAGS_SOFT_RESET) ||
|
||||
!adreno_is_a22x(adreno_dev)) {
|
||||
adreno_regwrite(device, REG_RBBM_SOFT_RESET,
|
||||
0xFFFFFFFF);
|
||||
device->flags |= KGSL_FLAGS_SOFT_RESET;
|
||||
} else {
|
||||
adreno_regwrite(device, REG_RBBM_SOFT_RESET,
|
||||
0x00000001);
|
||||
}
|
||||
/*
|
||||
* The core is in an indeterminate state until the reset
|
||||
* completes after 30ms.
|
||||
*/
|
||||
msleep(30);
|
||||
|
||||
adreno_regwrite(device, REG_RBBM_SOFT_RESET, 0x00000000);
|
||||
|
||||
if (adreno_is_a225(adreno_dev)) {
|
||||
/* Enable large instruction store for A225 */
|
||||
adreno_regwrite(device, REG_SQ_FLOW_CONTROL,
|
||||
0x18000000);
|
||||
}
|
||||
|
||||
adreno_regwrite(device, REG_RBBM_CNTL, 0x00004442);
|
||||
|
||||
adreno_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
|
||||
adreno_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
|
||||
|
||||
// if (cpu_is_msm8960() || cpu_is_msm8930())
|
||||
if(0)
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0x200);
|
||||
else
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0);
|
||||
|
||||
if (!adreno_is_a22x(adreno_dev))
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0);
|
||||
else
|
||||
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0x80);
|
||||
|
||||
kgsl_sharedmem_set(&device->memstore, 0, 0, device->memstore.size);
|
||||
|
||||
kgsl_sharedmem_writel(&device->memstore,
|
||||
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
|
||||
init_reftimestamp);
|
||||
|
||||
adreno_regwrite(device, REG_RBBM_DEBUG, 0x00080000);
|
||||
|
||||
/* Make sure interrupts are disabled */
|
||||
adreno_regwrite(device, REG_RBBM_INT_CNTL, 0);
|
||||
adreno_regwrite(device, REG_CP_INT_CNTL, 0);
|
||||
adreno_regwrite(device, REG_SQ_INT_CNTL, 0);
|
||||
|
||||
a2xx_gmeminit(adreno_dev);
|
||||
}
|
||||
|
||||
/* Defined in adreno_a2xx_snapshot.c */
|
||||
void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
|
||||
int *remain, int hang);
|
||||
|
||||
struct adreno_gpudev adreno_a2xx_gpudev = {
|
||||
.ctxt_gpustate_shadow = a2xx_ctxt_gpustate_shadow,
|
||||
.ctxt_gmem_shadow = a2xx_ctxt_gmem_shadow,
|
||||
.ctxt_save = a2xx_ctxt_save,
|
||||
.ctxt_restore = a2xx_ctxt_restore,
|
||||
.reg_rbbm_status = REG_RBBM_STATUS,
|
||||
.reg_cp_pfp_ucode_addr = REG_CP_PFP_UCODE_ADDR,
|
||||
.reg_cp_pfp_ucode_data = REG_CP_PFP_UCODE_DATA,
|
||||
|
||||
.ctxt_create = a2xx_drawctxt_create,
|
||||
.ctxt_save = a2xx_drawctxt_save,
|
||||
.ctxt_restore = a2xx_drawctxt_restore,
|
||||
.irq_handler = a2xx_irq_handler,
|
||||
.irq_control = a2xx_irq_control,
|
||||
.rb_init = a2xx_rb_init,
|
||||
.busy_cycles = a2xx_busy_cycles,
|
||||
.start = a2xx_start,
|
||||
};
|
||||
|
2547
drivers/gpu/msm/adreno_a3xx.c
Executable file
2547
drivers/gpu/msm/adreno_a3xx.c
Executable file
File diff suppressed because it is too large
Load Diff
14
drivers/gpu/msm/adreno_debugfs.c
Normal file → Executable file
14
drivers/gpu/msm/adreno_debugfs.c
Normal file → Executable file
@ -223,21 +223,24 @@ static int kgsl_regread_nolock(struct kgsl_device *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define KGSL_ISTORE_START 0x5000
|
||||
#define KGSL_ISTORE_LENGTH 0x600
|
||||
#define ADRENO_ISTORE_START 0x5000
|
||||
static ssize_t kgsl_istore_read(
|
||||
struct file *file,
|
||||
char __user *buff,
|
||||
size_t buff_count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
int i, count = KGSL_ISTORE_LENGTH, remaining, pos = 0, tot = 0;
|
||||
int i, count, remaining, pos = 0, tot = 0;
|
||||
struct kgsl_device *device = file->private_data;
|
||||
const int rowc = 8;
|
||||
struct adreno_device *adreno_dev;
|
||||
|
||||
if (!ppos || !device)
|
||||
return 0;
|
||||
|
||||
adreno_dev = ADRENO_DEVICE(device);
|
||||
count = adreno_dev->istore_size * adreno_dev->instruction_size;
|
||||
|
||||
remaining = count;
|
||||
for (i = 0; i < count; i += rowc) {
|
||||
unsigned int vals[rowc];
|
||||
@ -248,7 +251,8 @@ static ssize_t kgsl_istore_read(
|
||||
if (pos >= *ppos) {
|
||||
for (j = 0; j < linec; ++j)
|
||||
kgsl_regread_nolock(device,
|
||||
KGSL_ISTORE_START+i+j, vals+j);
|
||||
ADRENO_ISTORE_START + i + j,
|
||||
vals + j);
|
||||
} else
|
||||
memset(vals, 0, sizeof(vals));
|
||||
|
||||
@ -440,6 +444,8 @@ void adreno_debugfs_init(struct kgsl_device *device)
|
||||
&kgsl_cff_dump_enable_fops);
|
||||
debugfs_create_u32("wait_timeout", 0644, device->d_debugfs,
|
||||
&adreno_dev->wait_timeout);
|
||||
debugfs_create_u32("ib_check", 0644, device->d_debugfs,
|
||||
&adreno_dev->ib_check_level);
|
||||
|
||||
/* Create post mortem control files */
|
||||
|
||||
|
51
drivers/gpu/msm/adreno_drawctxt.c
Normal file → Executable file
51
drivers/gpu/msm/adreno_drawctxt.c
Normal file → Executable file
@ -19,6 +19,7 @@
|
||||
|
||||
/* quad for copying GMEM to context shadow */
|
||||
#define QUAD_LEN 12
|
||||
#define QUAD_RESTORE_LEN 14
|
||||
|
||||
static unsigned int gmem_copy_quad[QUAD_LEN] = {
|
||||
0x00000000, 0x00000000, 0x3f800000,
|
||||
@ -27,6 +28,14 @@ static unsigned int gmem_copy_quad[QUAD_LEN] = {
|
||||
0x00000000, 0x00000000, 0x3f800000
|
||||
};
|
||||
|
||||
static unsigned int gmem_restore_quad[QUAD_RESTORE_LEN] = {
|
||||
0x00000000, 0x3f800000, 0x3f800000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x3f800000, 0x00000000, 0x00000000,
|
||||
0x3f800000, 0x00000000, 0x00000000,
|
||||
0x3f800000, 0x3f800000,
|
||||
};
|
||||
|
||||
#define TEXCOORD_LEN 8
|
||||
|
||||
static unsigned int gmem_copy_texcoord[TEXCOORD_LEN] = {
|
||||
@ -73,12 +82,12 @@ static void set_gmem_copy_quad(struct gmem_shadow_t *shadow)
|
||||
gmem_copy_quad[4] = uint2float(shadow->height);
|
||||
gmem_copy_quad[9] = uint2float(shadow->width);
|
||||
|
||||
gmem_copy_quad[0] = 0;
|
||||
gmem_copy_quad[6] = 0;
|
||||
gmem_copy_quad[7] = 0;
|
||||
gmem_copy_quad[10] = 0;
|
||||
gmem_restore_quad[5] = uint2float(shadow->height);
|
||||
gmem_restore_quad[7] = uint2float(shadow->width);
|
||||
|
||||
memcpy(shadow->quad_vertices.hostptr, gmem_copy_quad, QUAD_LEN << 2);
|
||||
memcpy(shadow->quad_vertices_restore.hostptr, gmem_copy_quad,
|
||||
QUAD_RESTORE_LEN << 2);
|
||||
|
||||
memcpy(shadow->quad_texcoords.hostptr, gmem_copy_texcoord,
|
||||
TEXCOORD_LEN << 2);
|
||||
@ -103,6 +112,13 @@ void build_quad_vtxbuff(struct adreno_context *drawctxt,
|
||||
|
||||
cmd += QUAD_LEN;
|
||||
|
||||
/* Used by A3XX, but define for both to make the code easier */
|
||||
shadow->quad_vertices_restore.hostptr = cmd;
|
||||
shadow->quad_vertices_restore.gpuaddr =
|
||||
virt2gpu(cmd, &drawctxt->gpustate);
|
||||
|
||||
cmd += QUAD_RESTORE_LEN;
|
||||
|
||||
/* tex coord buffer location (in GPU space) */
|
||||
shadow->quad_texcoords.hostptr = cmd;
|
||||
shadow->quad_texcoords.gpuaddr = virt2gpu(cmd, &drawctxt->gpustate);
|
||||
@ -139,27 +155,19 @@ int adreno_drawctxt_create(struct kgsl_device *device,
|
||||
drawctxt->pagetable = pagetable;
|
||||
drawctxt->bin_base_offset = 0;
|
||||
|
||||
/* FIXME: Deal with preambles */
|
||||
if (flags & KGSL_CONTEXT_PREAMBLE)
|
||||
drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
|
||||
|
||||
ret = adreno_dev->gpudev->ctxt_gpustate_shadow(adreno_dev, drawctxt);
|
||||
if (flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
|
||||
drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;
|
||||
|
||||
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* Save the shader instruction memory on context switching */
|
||||
drawctxt->flags |= CTXT_FLAGS_SHADER_SAVE;
|
||||
|
||||
if (!(flags & KGSL_CONTEXT_NO_GMEM_ALLOC)) {
|
||||
/* create gmem shadow */
|
||||
ret = adreno_dev->gpudev->ctxt_gmem_shadow(adreno_dev,
|
||||
drawctxt);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
context->devctxt = drawctxt;
|
||||
return 0;
|
||||
err:
|
||||
kgsl_sharedmem_free(&drawctxt->gpustate);
|
||||
kfree(drawctxt);
|
||||
return ret;
|
||||
}
|
||||
@ -179,11 +187,12 @@ void adreno_drawctxt_destroy(struct kgsl_device *device,
|
||||
struct kgsl_context *context)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct adreno_context *drawctxt = context->devctxt;
|
||||
struct adreno_context *drawctxt;
|
||||
|
||||
if (drawctxt == NULL)
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
drawctxt = context->devctxt;
|
||||
/* deactivate context */
|
||||
if (adreno_dev->drawctxt_active == drawctxt) {
|
||||
/* no need to save GMEM or shader, the context is
|
||||
@ -261,6 +270,6 @@ void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
|
||||
adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
|
||||
|
||||
/* Set the new context */
|
||||
adreno_dev->drawctxt_active = drawctxt;
|
||||
adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
|
||||
adreno_dev->drawctxt_active = drawctxt;
|
||||
}
|
||||
|
47
drivers/gpu/msm/adreno_drawctxt.h
Normal file → Executable file
47
drivers/gpu/msm/adreno_drawctxt.h
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -30,12 +30,16 @@
|
||||
#define CTXT_FLAGS_GMEM_SAVE 0x00000200
|
||||
/* gmem can be restored from shadow */
|
||||
#define CTXT_FLAGS_GMEM_RESTORE 0x00000400
|
||||
/* preamble packed in cmdbuffer for context switching */
|
||||
#define CTXT_FLAGS_PREAMBLE 0x00000800
|
||||
/* shader must be copied to shadow */
|
||||
#define CTXT_FLAGS_SHADER_SAVE 0x00002000
|
||||
/* shader can be restored from shadow */
|
||||
#define CTXT_FLAGS_SHADER_RESTORE 0x00004000
|
||||
/* Context has caused a GPU hang */
|
||||
#define CTXT_FLAGS_GPU_HANG 0x00008000
|
||||
/* Specifies there is no need to save GMEM */
|
||||
#define CTXT_FLAGS_NOGMEMALLOC 0x00010000
|
||||
|
||||
struct kgsl_device;
|
||||
struct adreno_device;
|
||||
@ -46,37 +50,56 @@ struct kgsl_context;
|
||||
struct gmem_shadow_t {
|
||||
struct kgsl_memdesc gmemshadow; /* Shadow buffer address */
|
||||
|
||||
/* 256 KB GMEM surface = 4 bytes-per-pixel x 256 pixels/row x
|
||||
* 256 rows. */
|
||||
/* width & height must be a multiples of 32, in case tiled textures
|
||||
* are used. */
|
||||
enum COLORFORMATX format;
|
||||
/*
|
||||
* 256 KB GMEM surface = 4 bytes-per-pixel x 256 pixels/row x
|
||||
* 256 rows. Width & height must be multiples of 32 in case tiled
|
||||
* textures are used
|
||||
*/
|
||||
|
||||
enum COLORFORMATX format; /* Unused on A3XX */
|
||||
unsigned int size; /* Size of surface used to store GMEM */
|
||||
unsigned int width; /* Width of surface used to store GMEM */
|
||||
unsigned int height; /* Height of surface used to store GMEM */
|
||||
unsigned int pitch; /* Pitch of surface used to store GMEM */
|
||||
unsigned int gmem_pitch; /* Pitch value used for GMEM */
|
||||
unsigned int *gmem_save_commands;
|
||||
unsigned int *gmem_restore_commands;
|
||||
unsigned int *gmem_save_commands; /* Unused on A3XX */
|
||||
unsigned int *gmem_restore_commands; /* Unused on A3XX */
|
||||
unsigned int gmem_save[3];
|
||||
unsigned int gmem_restore[3];
|
||||
struct kgsl_memdesc quad_vertices;
|
||||
struct kgsl_memdesc quad_texcoords;
|
||||
struct kgsl_memdesc quad_vertices_restore;
|
||||
};
|
||||
|
||||
struct adreno_context {
|
||||
uint32_t flags;
|
||||
struct kgsl_pagetable *pagetable;
|
||||
struct kgsl_memdesc gpustate;
|
||||
unsigned int reg_save[3];
|
||||
unsigned int reg_restore[3];
|
||||
unsigned int shader_save[3];
|
||||
unsigned int shader_fixup[3];
|
||||
unsigned int shader_restore[3];
|
||||
unsigned int chicken_restore[3];
|
||||
unsigned int bin_base_offset;
|
||||
|
||||
/* Information of the GMEM shadow that is created in context create */
|
||||
struct gmem_shadow_t context_gmem_shadow;
|
||||
|
||||
/* A2XX specific items */
|
||||
unsigned int reg_save[3];
|
||||
unsigned int shader_fixup[3];
|
||||
unsigned int chicken_restore[3];
|
||||
unsigned int bin_base_offset;
|
||||
|
||||
/* A3XX specific items */
|
||||
unsigned int regconstant_save[3];
|
||||
unsigned int constant_restore[3];
|
||||
unsigned int hlsqcontrol_restore[3];
|
||||
unsigned int save_fixup[3];
|
||||
unsigned int restore_fixup[3];
|
||||
struct kgsl_memdesc shader_load_commands[2];
|
||||
struct kgsl_memdesc shader_save_commands[4];
|
||||
struct kgsl_memdesc constant_save_commands[3];
|
||||
struct kgsl_memdesc constant_load_commands[3];
|
||||
struct kgsl_memdesc cond_execs[4];
|
||||
struct kgsl_memdesc hlsqcontrol_restore_commands[1];
|
||||
};
|
||||
|
||||
int adreno_drawctxt_create(struct kgsl_device *device,
|
||||
|
50
drivers/gpu/msm/adreno_pm4types.h
Normal file → Executable file
50
drivers/gpu/msm/adreno_pm4types.h
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -29,11 +29,6 @@
|
||||
/* skip N 32-bit words to get to the next packet */
|
||||
#define CP_NOP 0x10
|
||||
|
||||
/* indirect buffer dispatch. prefetch parser uses this packet type to determine
|
||||
* whether to pre-fetch the IB
|
||||
*/
|
||||
#define CP_INDIRECT_BUFFER 0x3f
|
||||
|
||||
/* indirect buffer dispatch. same as IB, but init is pipelined */
|
||||
#define CP_INDIRECT_BUFFER_PFD 0x37
|
||||
|
||||
@ -117,6 +112,9 @@
|
||||
/* load constants from a location in memory */
|
||||
#define CP_LOAD_CONSTANT_CONTEXT 0x2e
|
||||
|
||||
/* (A2x) sets binning configuration registers */
|
||||
#define CP_SET_BIN_DATA 0x2f
|
||||
|
||||
/* selective invalidation of state pointers */
|
||||
#define CP_INVALIDATE_STATE 0x3b
|
||||
|
||||
@ -157,6 +155,25 @@
|
||||
|
||||
#define CP_SET_PROTECTED_MODE 0x5f /* sets the register protection mode */
|
||||
|
||||
/*
|
||||
* for a3xx
|
||||
*/
|
||||
|
||||
#define CP_LOAD_STATE 0x30 /* load high level sequencer command */
|
||||
|
||||
/* Conditionally load a IB based on a flag */
|
||||
#define CP_COND_INDIRECT_BUFFER_PFE 0x3A /* prefetch enabled */
|
||||
#define CP_COND_INDIRECT_BUFFER_PFD 0x32 /* prefetch disabled */
|
||||
|
||||
/* Load a buffer with pre-fetch enabled */
|
||||
#define CP_INDIRECT_BUFFER_PFE 0x3F
|
||||
|
||||
#define CP_LOADSTATE_DSTOFFSET_SHIFT 0x00000000
|
||||
#define CP_LOADSTATE_STATESRC_SHIFT 0x00000010
|
||||
#define CP_LOADSTATE_STATEBLOCKID_SHIFT 0x00000013
|
||||
#define CP_LOADSTATE_NUMOFUNITS_SHIFT 0x00000016
|
||||
#define CP_LOADSTATE_STATETYPE_SHIFT 0x00000000
|
||||
#define CP_LOADSTATE_EXTSRCADDR_SHIFT 0x00000002
|
||||
|
||||
/* packet header building macros */
|
||||
#define cp_type0_packet(regindx, cnt) \
|
||||
@ -178,11 +195,20 @@
|
||||
#define cp_nop_packet(cnt) \
|
||||
(CP_TYPE3_PKT | (((cnt)-1) << 16) | (CP_NOP << 8))
|
||||
|
||||
#define pkt_is_type0(pkt) (((pkt) & 0XC0000000) == CP_TYPE0_PKT)
|
||||
|
||||
#define type0_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
|
||||
#define type0_pkt_offset(pkt) ((pkt) & 0x7FFF)
|
||||
|
||||
#define pkt_is_type3(pkt) (((pkt) & 0xC0000000) == CP_TYPE3_PKT)
|
||||
|
||||
#define cp_type3_opcode(pkt) (((pkt) >> 8) & 0xFF)
|
||||
#define type3_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
|
||||
|
||||
/* packet headers */
|
||||
#define CP_HDR_ME_INIT cp_type3_packet(CP_ME_INIT, 18)
|
||||
#define CP_HDR_INDIRECT_BUFFER_PFD cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)
|
||||
#define CP_HDR_INDIRECT_BUFFER cp_type3_packet(CP_INDIRECT_BUFFER, 2)
|
||||
#define CP_HDR_INDIRECT_BUFFER_PFE cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2)
|
||||
|
||||
/* dword base address of the GFX decode space */
|
||||
#define SUBBLOCK_OFFSET(reg) ((unsigned int)((reg) - (0x2000)))
|
||||
@ -190,4 +216,14 @@
|
||||
/* gmem command buffer length */
|
||||
#define CP_REG(reg) ((0x4 << 16) | (SUBBLOCK_OFFSET(reg)))
|
||||
|
||||
|
||||
/* Return 1 if the command is an indirect buffer of any kind */
|
||||
static inline int adreno_cmd_is_ib(unsigned int cmd)
|
||||
{
|
||||
return (cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2) ||
|
||||
cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2) ||
|
||||
cmd == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFE, 2) ||
|
||||
cmd == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFD, 2));
|
||||
}
|
||||
|
||||
#endif /* __ADRENO_PM4TYPES_H */
|
||||
|
32
drivers/gpu/msm/adreno_postmortem.c
Normal file → Executable file
32
drivers/gpu/msm/adreno_postmortem.c
Normal file → Executable file
@ -52,7 +52,7 @@ static const struct pm_id_name pm3_types[] = {
|
||||
{CP_IM_LOAD, "IN__LOAD"},
|
||||
{CP_IM_LOAD_IMMEDIATE, "IM_LOADI"},
|
||||
{CP_IM_STORE, "IM_STORE"},
|
||||
{CP_INDIRECT_BUFFER, "IND_BUF_"},
|
||||
{CP_INDIRECT_BUFFER_PFE, "IND_BUF_"},
|
||||
{CP_INDIRECT_BUFFER_PFD, "IND_BUFP"},
|
||||
{CP_INTERRUPT, "PM4_INTR"},
|
||||
{CP_INVALIDATE_STATE, "INV_STAT"},
|
||||
@ -247,9 +247,8 @@ static void adreno_dump_regs(struct kgsl_device *device,
|
||||
static void dump_ib(struct kgsl_device *device, char* buffId, uint32_t pt_base,
|
||||
uint32_t base_offset, uint32_t ib_base, uint32_t ib_size, bool dump)
|
||||
{
|
||||
unsigned int memsize;
|
||||
uint8_t *base_addr = kgsl_sharedmem_convertaddr(device, pt_base,
|
||||
ib_base, &memsize);
|
||||
uint8_t *base_addr = adreno_convertaddr(device, pt_base,
|
||||
ib_base, ib_size*sizeof(uint32_t));
|
||||
|
||||
if (base_addr && dump)
|
||||
print_hex_dump(KERN_ERR, buffId, DUMP_PREFIX_OFFSET,
|
||||
@ -277,20 +276,19 @@ static void dump_ib1(struct kgsl_device *device, uint32_t pt_base,
|
||||
int i, j;
|
||||
uint32_t value;
|
||||
uint32_t *ib1_addr;
|
||||
unsigned int memsize;
|
||||
|
||||
dump_ib(device, "IB1:", pt_base, base_offset, ib1_base,
|
||||
ib1_size, dump);
|
||||
|
||||
/* fetch virtual address for given IB base */
|
||||
ib1_addr = (uint32_t *)kgsl_sharedmem_convertaddr(device, pt_base,
|
||||
ib1_base, &memsize);
|
||||
ib1_addr = (uint32_t *)adreno_convertaddr(device, pt_base,
|
||||
ib1_base, ib1_size*sizeof(uint32_t));
|
||||
if (!ib1_addr)
|
||||
return;
|
||||
|
||||
for (i = 0; i+3 < ib1_size; ) {
|
||||
value = ib1_addr[i++];
|
||||
if (value == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
|
||||
if (adreno_cmd_is_ib(value)) {
|
||||
uint32_t ib2_base = ib1_addr[i++];
|
||||
uint32_t ib2_size = ib1_addr[i++];
|
||||
|
||||
@ -466,7 +464,7 @@ static int adreno_dump(struct kgsl_device *device)
|
||||
const uint32_t *rb_vaddr;
|
||||
int num_item = 0;
|
||||
int read_idx, write_idx;
|
||||
unsigned int ts_processed, rb_memsize;
|
||||
unsigned int ts_processed;
|
||||
|
||||
static struct ib_list ib_list;
|
||||
|
||||
@ -681,11 +679,16 @@ static int adreno_dump(struct kgsl_device *device)
|
||||
|
||||
KGSL_LOG_DUMP(device, "RB: rd_addr:%8.8x rb_size:%d num_item:%d\n",
|
||||
cp_rb_base, rb_count<<2, num_item);
|
||||
rb_vaddr = (const uint32_t *)kgsl_sharedmem_convertaddr(device,
|
||||
cur_pt_base, cp_rb_base, &rb_memsize);
|
||||
|
||||
if (adreno_dev->ringbuffer.buffer_desc.gpuaddr != cp_rb_base)
|
||||
KGSL_LOG_POSTMORTEM_WRITE(device,
|
||||
"rb address mismatch, should be 0x%08x\n",
|
||||
adreno_dev->ringbuffer.buffer_desc.gpuaddr);
|
||||
|
||||
rb_vaddr = adreno_dev->ringbuffer.buffer_desc.hostptr;
|
||||
if (!rb_vaddr) {
|
||||
KGSL_LOG_POSTMORTEM_WRITE(device,
|
||||
"Can't fetch vaddr for CP_RB_BASE\n");
|
||||
"rb has no kernel mapping!\n");
|
||||
goto error_vfree;
|
||||
}
|
||||
|
||||
@ -711,7 +714,7 @@ static int adreno_dump(struct kgsl_device *device)
|
||||
i = 0;
|
||||
for (read_idx = 0; read_idx < num_item; ) {
|
||||
uint32_t this_cmd = rb_copy[read_idx++];
|
||||
if (this_cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
|
||||
if (adreno_cmd_is_ib(this_cmd)) {
|
||||
uint32_t ib_addr = rb_copy[read_idx++];
|
||||
uint32_t ib_size = rb_copy[read_idx++];
|
||||
dump_ib1(device, cur_pt_base, (read_idx-3)<<2, ib_addr,
|
||||
@ -743,8 +746,7 @@ static int adreno_dump(struct kgsl_device *device)
|
||||
for (read_idx = NUM_DWORDS_OF_RINGBUFFER_HISTORY;
|
||||
read_idx >= 0; --read_idx) {
|
||||
uint32_t this_cmd = rb_copy[read_idx];
|
||||
if (this_cmd == cp_type3_packet(
|
||||
CP_INDIRECT_BUFFER_PFD, 2)) {
|
||||
if (adreno_cmd_is_ib(this_cmd)) {
|
||||
uint32_t ib_addr = rb_copy[read_idx+1];
|
||||
uint32_t ib_size = rb_copy[read_idx+2];
|
||||
if (ib_size && cp_ib1_base == ib_addr) {
|
||||
|
422
drivers/gpu/msm/adreno_ringbuffer.c
Normal file → Executable file
422
drivers/gpu/msm/adreno_ringbuffer.c
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -22,30 +22,14 @@
|
||||
#include "adreno.h"
|
||||
#include "adreno_pm4types.h"
|
||||
#include "adreno_ringbuffer.h"
|
||||
#include "adreno_debugfs.h"
|
||||
|
||||
#include "a2xx_reg.h"
|
||||
#include "a3xx_reg.h"
|
||||
|
||||
#define GSL_RB_NOP_SIZEDWORDS 2
|
||||
/* protected mode error checking below register address 0x800
|
||||
* note: if CP_INTERRUPT packet is used then checking needs
|
||||
* to change to below register address 0x7C8
|
||||
*/
|
||||
#define GSL_RB_PROTECTED_MODE_CONTROL 0x200001F2
|
||||
|
||||
/* Firmware file names
|
||||
* Legacy names must remain but replacing macro names to
|
||||
* match current kgsl model.
|
||||
* a200 is yamato
|
||||
* a220 is leia
|
||||
*/
|
||||
#define A200_PFP_FW "yamato_pfp.fw"
|
||||
#define A200_PM4_FW "yamato_pm4.fw"
|
||||
#define A220_PFP_470_FW "leia_pfp_470.fw"
|
||||
#define A220_PM4_470_FW "leia_pm4_470.fw"
|
||||
#define A225_PFP_FW "a225_pfp.fw"
|
||||
#define A225_PM4_FW "a225_pm4.fw"
|
||||
|
||||
static void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb)
|
||||
void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb)
|
||||
{
|
||||
BUG_ON(rb->wptr == 0);
|
||||
|
||||
@ -104,8 +88,7 @@ adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, unsigned int numcmds,
|
||||
} while ((freecmds != 0) && (freecmds <= numcmds));
|
||||
}
|
||||
|
||||
|
||||
static unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
|
||||
unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
|
||||
unsigned int numcmds)
|
||||
{
|
||||
unsigned int *ptr = NULL;
|
||||
@ -231,9 +214,10 @@ static int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
|
||||
KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
|
||||
adreno_dev->pfp_fw[0]);
|
||||
|
||||
adreno_regwrite(device, REG_CP_PFP_UCODE_ADDR, 0);
|
||||
adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
|
||||
for (i = 1; i < adreno_dev->pfp_fw_size; i++)
|
||||
adreno_regwrite(device, REG_CP_PFP_UCODE_DATA,
|
||||
adreno_regwrite(device,
|
||||
adreno_dev->gpudev->reg_cp_pfp_ucode_data,
|
||||
adreno_dev->pfp_fw[i]);
|
||||
err:
|
||||
return ret;
|
||||
@ -244,9 +228,9 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
|
||||
int status;
|
||||
/*cp_rb_cntl_u cp_rb_cntl; */
|
||||
union reg_cp_rb_cntl cp_rb_cntl;
|
||||
unsigned int *cmds, rb_cntl;
|
||||
unsigned int rb_cntl;
|
||||
struct kgsl_device *device = rb->device;
|
||||
uint cmds_gpu;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
|
||||
if (rb->flags & KGSL_FLAGS_STARTED)
|
||||
return 0;
|
||||
@ -262,12 +246,15 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
|
||||
kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
|
||||
(rb->sizedwords << 2));
|
||||
|
||||
if (adreno_is_a2xx(adreno_dev)) {
|
||||
adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
|
||||
(rb->memptrs_desc.gpuaddr
|
||||
+ GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
|
||||
|
||||
/* setup WPTR delay */
|
||||
adreno_regwrite(device, REG_CP_RB_WPTR_DELAY, 0 /*0x70000010 */);
|
||||
adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
|
||||
0 /*0x70000010 */);
|
||||
}
|
||||
|
||||
/*setup REG_CP_RB_CNTL */
|
||||
adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
|
||||
@ -286,7 +273,11 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
|
||||
*/
|
||||
cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);
|
||||
|
||||
cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN; /* WPTR polling */
|
||||
if (adreno_is_a2xx(adreno_dev)) {
|
||||
/* WPTR polling */
|
||||
cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
|
||||
}
|
||||
|
||||
/* mem RPTR writebacks */
|
||||
cp_rb_cntl.f.rb_no_update = GSL_RB_CNTL_NO_UPDATE;
|
||||
|
||||
@ -298,8 +289,36 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
|
||||
rb->memptrs_desc.gpuaddr +
|
||||
GSL_RB_MEMPTRS_RPTR_OFFSET);
|
||||
|
||||
if (adreno_is_a3xx(adreno_dev)) {
|
||||
/* enable access protection to privileged registers */
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
|
||||
|
||||
/* RBBM registers */
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
|
||||
|
||||
/* CP registers */
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
|
||||
|
||||
/* RB registers */
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
|
||||
|
||||
/* VBIF registers */
|
||||
adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
|
||||
}
|
||||
|
||||
if (adreno_is_a2xx(adreno_dev)) {
|
||||
/* explicitly clear all cp interrupts */
|
||||
adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
/* setup scratch/timestamp */
|
||||
adreno_regwrite(device, REG_SCRATCH_ADDR,
|
||||
@ -309,6 +328,11 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
|
||||
adreno_regwrite(device, REG_SCRATCH_UMSK,
|
||||
GSL_RB_MEMPTRS_SCRATCH_MASK);
|
||||
|
||||
/* update the eoptimestamp field with the last retired timestamp */
|
||||
kgsl_sharedmem_writel(&device->memstore,
|
||||
KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp),
|
||||
rb->timestamp);
|
||||
|
||||
/* load the CP ucode */
|
||||
|
||||
status = adreno_ringbuffer_load_pm4_ucode(device);
|
||||
@ -328,54 +352,8 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
|
||||
/* clear ME_HALT to start micro engine */
|
||||
adreno_regwrite(device, REG_CP_ME_CNTL, 0);
|
||||
|
||||
/* ME_INIT */
|
||||
cmds = adreno_ringbuffer_allocspace(rb, 19);
|
||||
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-19);
|
||||
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, CP_HDR_ME_INIT);
|
||||
/* All fields present (bits 9:0) */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x000003ff);
|
||||
/* Disable/Enable Real-Time Stream processing (present but ignored) */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
/* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_RB_SURFACE_INFO));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_PA_SC_WINDOW_OFFSET));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_VGT_MAX_VTX_INDX));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_SQ_PROGRAM_CNTL));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_RB_DEPTHCONTROL));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_PA_SU_POINT_SIZE));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_PA_SC_LINE_CNTL));
|
||||
GSL_RB_WRITE(cmds, cmds_gpu,
|
||||
SUBBLOCK_OFFSET(REG_PA_SU_POLY_OFFSET_FRONT_SCALE));
|
||||
|
||||
/* Vertex and Pixel Shader Start Addresses in instructions
|
||||
* (3 DWORDS per instruction) */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x80000180);
|
||||
/* Maximum Contexts */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000001);
|
||||
/* Write Confirm Interval and The CP will wait the
|
||||
* wait_interval * 16 clocks between polling */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
|
||||
/* NQ and External Memory Swap */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
/* Protected mode error checking */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
|
||||
/* Disable header dumping and Header dump address */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
/* Header dump size */
|
||||
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
|
||||
|
||||
adreno_ringbuffer_submit(rb);
|
||||
/* ME init is GPU specific, so jump into the sub-function */
|
||||
adreno_dev->gpudev->rb_init(adreno_dev, rb);
|
||||
|
||||
/* idle device to validate ME INIT */
|
||||
status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
|
||||
@ -391,7 +369,6 @@ void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
|
||||
if (rb->flags & KGSL_FLAGS_STARTED) {
|
||||
/* ME_HALT */
|
||||
adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
|
||||
|
||||
rb->flags &= ~KGSL_FLAGS_STARTED;
|
||||
}
|
||||
}
|
||||
@ -457,6 +434,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
|
||||
unsigned int flags, unsigned int *cmds,
|
||||
int sizedwords)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
|
||||
unsigned int *ringcmds;
|
||||
unsigned int timestamp;
|
||||
unsigned int total_sizedwords = sizedwords + 6;
|
||||
@ -470,6 +448,9 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
|
||||
total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 7 : 0;
|
||||
total_sizedwords += !(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD) ? 2 : 0;
|
||||
|
||||
if (adreno_is_a3xx(adreno_dev))
|
||||
total_sizedwords += 7;
|
||||
|
||||
ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
|
||||
rcmd_gpu = rb->buffer_desc.gpuaddr
|
||||
+ sizeof(uint)*(rb->wptr-total_sizedwords);
|
||||
@ -503,6 +484,21 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
|
||||
/* start-of-pipeline and end-of-pipeline timestamps */
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp);
|
||||
|
||||
if (adreno_is_a3xx(adreno_dev)) {
|
||||
/*
|
||||
* FLush HLSQ lazy updates to make sure there are no
|
||||
* rsources pending for indirect loads after the timestamp
|
||||
*/
|
||||
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu,
|
||||
cp_type3_packet(CP_EVENT_WRITE, 1));
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x07); /* HLSQ_FLUSH */
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu,
|
||||
cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
|
||||
}
|
||||
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_EVENT_WRITE, 3));
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu,
|
||||
@ -526,6 +522,15 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
|
||||
}
|
||||
|
||||
if (adreno_is_a3xx(adreno_dev)) {
|
||||
/* Dummy set-constant to trigger context rollover */
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu,
|
||||
cp_type3_packet(CP_SET_CONSTANT, 2));
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu,
|
||||
(0x4<<16)|(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG - 0x2000));
|
||||
GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
|
||||
}
|
||||
|
||||
adreno_ringbuffer_submit(rb);
|
||||
|
||||
/* return timestamp of issued coREG_ands */
|
||||
@ -546,6 +551,198 @@ adreno_ringbuffer_issuecmds(struct kgsl_device *device,
|
||||
adreno_ringbuffer_addcmds(rb, flags, cmds, sizedwords);
|
||||
}
|
||||
|
||||
static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
|
||||
int sizedwords);
|
||||
|
||||
static bool
|
||||
_handle_type3(struct kgsl_device_private *dev_priv, uint *hostaddr)
|
||||
{
|
||||
unsigned int opcode = cp_type3_opcode(*hostaddr);
|
||||
switch (opcode) {
|
||||
case CP_INDIRECT_BUFFER_PFD:
|
||||
case CP_INDIRECT_BUFFER_PFE:
|
||||
case CP_COND_INDIRECT_BUFFER_PFE:
|
||||
case CP_COND_INDIRECT_BUFFER_PFD:
|
||||
return _parse_ibs(dev_priv, hostaddr[1], hostaddr[2]);
|
||||
case CP_NOP:
|
||||
case CP_WAIT_FOR_IDLE:
|
||||
case CP_WAIT_REG_MEM:
|
||||
case CP_WAIT_REG_EQ:
|
||||
case CP_WAT_REG_GTE:
|
||||
case CP_WAIT_UNTIL_READ:
|
||||
case CP_WAIT_IB_PFD_COMPLETE:
|
||||
case CP_REG_RMW:
|
||||
case CP_REG_TO_MEM:
|
||||
case CP_MEM_WRITE:
|
||||
case CP_MEM_WRITE_CNTR:
|
||||
case CP_COND_EXEC:
|
||||
case CP_COND_WRITE:
|
||||
case CP_EVENT_WRITE:
|
||||
case CP_EVENT_WRITE_SHD:
|
||||
case CP_EVENT_WRITE_CFL:
|
||||
case CP_EVENT_WRITE_ZPD:
|
||||
case CP_DRAW_INDX:
|
||||
case CP_DRAW_INDX_2:
|
||||
case CP_DRAW_INDX_BIN:
|
||||
case CP_DRAW_INDX_2_BIN:
|
||||
case CP_VIZ_QUERY:
|
||||
case CP_SET_STATE:
|
||||
case CP_SET_CONSTANT:
|
||||
case CP_IM_LOAD:
|
||||
case CP_IM_LOAD_IMMEDIATE:
|
||||
case CP_LOAD_CONSTANT_CONTEXT:
|
||||
case CP_INVALIDATE_STATE:
|
||||
case CP_SET_SHADER_BASES:
|
||||
case CP_SET_BIN_MASK:
|
||||
case CP_SET_BIN_SELECT:
|
||||
case CP_SET_BIN_BASE_OFFSET:
|
||||
case CP_SET_BIN_DATA:
|
||||
case CP_CONTEXT_UPDATE:
|
||||
case CP_INTERRUPT:
|
||||
case CP_IM_STORE:
|
||||
case CP_LOAD_STATE:
|
||||
break;
|
||||
/* these shouldn't come from userspace */
|
||||
case CP_ME_INIT:
|
||||
case CP_SET_PROTECTED_MODE:
|
||||
default:
|
||||
KGSL_CMD_ERR(dev_priv->device, "bad CP opcode %0x\n", opcode);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_handle_type0(struct kgsl_device_private *dev_priv, uint *hostaddr)
|
||||
{
|
||||
unsigned int reg = type0_pkt_offset(*hostaddr);
|
||||
unsigned int cnt = type0_pkt_size(*hostaddr);
|
||||
if (reg < 0x0192 || (reg + cnt) >= 0x8000) {
|
||||
KGSL_CMD_ERR(dev_priv->device, "bad type0 reg: 0x%0x cnt: %d\n",
|
||||
reg, cnt);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Traverse IBs and dump them to test vector. Detect swap by inspecting
|
||||
* register writes, keeping note of the current state, and dump
|
||||
* framebuffer config to test vector
|
||||
*/
|
||||
static bool _parse_ibs(struct kgsl_device_private *dev_priv,
|
||||
uint gpuaddr, int sizedwords)
|
||||
{
|
||||
static uint level; /* recursion level */
|
||||
bool ret = false;
|
||||
uint *hostaddr, *hoststart;
|
||||
int dwords_left = sizedwords; /* dwords left in the current command
|
||||
buffer */
|
||||
struct kgsl_mem_entry *entry;
|
||||
|
||||
spin_lock(&dev_priv->process_priv->mem_lock);
|
||||
entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
|
||||
gpuaddr, sizedwords * sizeof(uint));
|
||||
spin_unlock(&dev_priv->process_priv->mem_lock);
|
||||
if (entry == NULL) {
|
||||
KGSL_CMD_ERR(dev_priv->device,
|
||||
"no mapping for gpuaddr: 0x%08x\n", gpuaddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(&entry->memdesc, gpuaddr);
|
||||
if (hostaddr == NULL) {
|
||||
KGSL_CMD_ERR(dev_priv->device,
|
||||
"no mapping for gpuaddr: 0x%08x\n", gpuaddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hoststart = hostaddr;
|
||||
|
||||
level++;
|
||||
|
||||
KGSL_CMD_INFO(dev_priv->device, "ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
|
||||
gpuaddr, sizedwords, hostaddr);
|
||||
|
||||
mb();
|
||||
while (dwords_left > 0) {
|
||||
bool cur_ret = true;
|
||||
int count = 0; /* dword count including packet header */
|
||||
|
||||
switch (*hostaddr >> 30) {
|
||||
case 0x0: /* type-0 */
|
||||
count = (*hostaddr >> 16)+2;
|
||||
cur_ret = _handle_type0(dev_priv, hostaddr);
|
||||
break;
|
||||
case 0x1: /* type-1 */
|
||||
count = 2;
|
||||
break;
|
||||
case 0x3: /* type-3 */
|
||||
count = ((*hostaddr >> 16) & 0x3fff) + 2;
|
||||
cur_ret = _handle_type3(dev_priv, hostaddr);
|
||||
break;
|
||||
default:
|
||||
KGSL_CMD_ERR(dev_priv->device, "unexpected type: "
|
||||
"type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
|
||||
*hostaddr >> 30, *hostaddr, hostaddr,
|
||||
gpuaddr+4*(sizedwords-dwords_left));
|
||||
cur_ret = false;
|
||||
count = dwords_left;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cur_ret) {
|
||||
KGSL_CMD_ERR(dev_priv->device,
|
||||
"bad sub-type: #:%d/%d, v:0x%08x"
|
||||
" @ 0x%p[gb:0x%08x], level:%d\n",
|
||||
sizedwords-dwords_left, sizedwords, *hostaddr,
|
||||
hostaddr, gpuaddr+4*(sizedwords-dwords_left),
|
||||
level);
|
||||
|
||||
if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
|
||||
>= 2)
|
||||
print_hex_dump(KERN_ERR,
|
||||
level == 1 ? "IB1:" : "IB2:",
|
||||
DUMP_PREFIX_OFFSET, 32, 4, hoststart,
|
||||
sizedwords*4, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* jump to next packet */
|
||||
dwords_left -= count;
|
||||
hostaddr += count;
|
||||
if (dwords_left < 0) {
|
||||
KGSL_CMD_ERR(dev_priv->device,
|
||||
"bad count: c:%d, #:%d/%d, "
|
||||
"v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
|
||||
count, sizedwords-(dwords_left+count),
|
||||
sizedwords, *(hostaddr-count), hostaddr-count,
|
||||
gpuaddr+4*(sizedwords-(dwords_left+count)),
|
||||
level);
|
||||
if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
|
||||
>= 2)
|
||||
print_hex_dump(KERN_ERR,
|
||||
level == 1 ? "IB1:" : "IB2:",
|
||||
DUMP_PREFIX_OFFSET, 32, 4, hoststart,
|
||||
sizedwords*4, 0);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ret = true;
|
||||
done:
|
||||
if (!ret)
|
||||
KGSL_DRV_ERR(dev_priv->device,
|
||||
"parsing failed: gpuaddr:0x%08x, "
|
||||
"host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
|
||||
|
||||
level--;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
struct kgsl_context *context,
|
||||
@ -560,6 +757,7 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
unsigned int *cmds;
|
||||
unsigned int i;
|
||||
struct adreno_context *drawctxt;
|
||||
unsigned int start_index = 0;
|
||||
|
||||
if (device->state & KGSL_STATE_HUNG)
|
||||
return -EBUSY;
|
||||
@ -575,22 +773,48 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
drawctxt);
|
||||
return -EDEADLK;
|
||||
}
|
||||
link = kzalloc(sizeof(unsigned int) * numibs * 3, GFP_KERNEL);
|
||||
cmds = link;
|
||||
|
||||
cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
|
||||
GFP_KERNEL);
|
||||
if (!link) {
|
||||
KGSL_MEM_ERR(device, "Failed to allocate memory for for command"
|
||||
" submission, size %x\n", numibs * 3);
|
||||
KGSL_CORE_ERR("kzalloc(%d) failed\n",
|
||||
sizeof(unsigned int) * (numibs * 3 + 4));
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (i = 0; i < numibs; i++) {
|
||||
(void)kgsl_cffdump_parse_ibs(dev_priv, NULL,
|
||||
ibdesc[i].gpuaddr, ibdesc[i].sizedwords, false);
|
||||
|
||||
/*When preamble is enabled, the preamble buffer with state restoration
|
||||
commands are stored in the first node of the IB chain. We can skip that
|
||||
if a context switch hasn't occured */
|
||||
|
||||
if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
|
||||
adreno_dev->drawctxt_active == drawctxt)
|
||||
start_index = 1;
|
||||
|
||||
if (!start_index) {
|
||||
*cmds++ = cp_nop_packet(1);
|
||||
*cmds++ = KGSL_START_OF_IB_IDENTIFIER;
|
||||
} else {
|
||||
*cmds++ = cp_nop_packet(4);
|
||||
*cmds++ = KGSL_START_OF_IB_IDENTIFIER;
|
||||
*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
|
||||
*cmds++ = ibdesc[0].gpuaddr;
|
||||
*cmds++ = ibdesc[0].sizedwords;
|
||||
}
|
||||
for (i = start_index; i < numibs; i++) {
|
||||
if (unlikely(adreno_dev->ib_check_level >= 1 &&
|
||||
!_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
|
||||
ibdesc[i].sizedwords))) {
|
||||
kfree(link);
|
||||
return -EINVAL;
|
||||
}
|
||||
*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
|
||||
*cmds++ = ibdesc[i].gpuaddr;
|
||||
*cmds++ = ibdesc[i].sizedwords;
|
||||
}
|
||||
|
||||
*cmds++ = cp_nop_packet(1);
|
||||
*cmds++ = KGSL_END_OF_IB_IDENTIFIER;
|
||||
|
||||
kgsl_setstate(device,
|
||||
kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
|
||||
device->id));
|
||||
@ -632,7 +856,6 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
|
||||
unsigned int val3;
|
||||
unsigned int copy_rb_contents = 0;
|
||||
unsigned int cur_context;
|
||||
unsigned int j;
|
||||
|
||||
GSL_RB_GET_READPTR(rb, &rb->rptr);
|
||||
|
||||
@ -739,8 +962,20 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
|
||||
kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
|
||||
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
|
||||
rb->buffer_desc.size);
|
||||
BUG_ON((copy_rb_contents == 0) &&
|
||||
(value == cur_context));
|
||||
|
||||
/*
|
||||
* If other context switches were already lost and
|
||||
* and the current context is the one that is hanging,
|
||||
* then we cannot recover. Print an error message
|
||||
* and leave.
|
||||
*/
|
||||
|
||||
if ((copy_rb_contents == 0) && (value == cur_context)) {
|
||||
KGSL_DRV_ERR(device, "GPU recovery could not "
|
||||
"find the previous context\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we were copying the commands and got to this point
|
||||
* then we need to remove the 3 commands that appear
|
||||
@ -771,19 +1006,6 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
|
||||
}
|
||||
|
||||
*rb_size = temp_idx;
|
||||
KGSL_DRV_ERR(device, "Extracted rb contents, size: %x\n", *rb_size);
|
||||
for (temp_idx = 0; temp_idx < *rb_size;) {
|
||||
char str[80];
|
||||
int idx = 0;
|
||||
if ((temp_idx + 8) <= *rb_size)
|
||||
j = 8;
|
||||
else
|
||||
j = *rb_size - temp_idx;
|
||||
for (; j != 0; j--)
|
||||
idx += scnprintf(str + idx, 80 - idx,
|
||||
"%8.8X ", temp_rb_buffer[temp_idx++]);
|
||||
printk(KERN_ALERT "%s", str);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
45
drivers/gpu/msm/adreno_ringbuffer.h
Normal file → Executable file
45
drivers/gpu/msm/adreno_ringbuffer.h
Normal file → Executable file
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
|
||||
* Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
|
||||
/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -14,10 +13,6 @@
|
||||
#ifndef __ADRENO_RINGBUFFER_H
|
||||
#define __ADRENO_RINGBUFFER_H
|
||||
|
||||
#define GSL_RB_USE_MEM_RPTR
|
||||
#define GSL_RB_USE_MEM_TIMESTAMP
|
||||
#define GSL_DEVICE_SHADOW_MEMSTORE_TO_USER
|
||||
|
||||
/*
|
||||
* Adreno ringbuffer sizes in bytes - these are converted to
|
||||
* the appropriate log2 values in the code
|
||||
@ -62,49 +57,36 @@ struct adreno_ringbuffer {
|
||||
uint32_t timestamp;
|
||||
};
|
||||
|
||||
|
||||
#define GSL_RB_WRITE(ring, gpuaddr, data) \
|
||||
do { \
|
||||
writel_relaxed(data, ring); \
|
||||
*ring = data; \
|
||||
wmb(); \
|
||||
kgsl_cffdump_setmem(gpuaddr, data, 4); \
|
||||
ring++; \
|
||||
gpuaddr += sizeof(uint); \
|
||||
} while (0)
|
||||
|
||||
/* timestamp */
|
||||
#ifdef GSL_DEVICE_SHADOW_MEMSTORE_TO_USER
|
||||
#define GSL_RB_USE_MEM_TIMESTAMP
|
||||
#endif /* GSL_DEVICE_SHADOW_MEMSTORE_TO_USER */
|
||||
|
||||
#ifdef GSL_RB_USE_MEM_TIMESTAMP
|
||||
/* enable timestamp (...scratch0) memory shadowing */
|
||||
#define GSL_RB_MEMPTRS_SCRATCH_MASK 0x1
|
||||
#define GSL_RB_INIT_TIMESTAMP(rb)
|
||||
|
||||
#else
|
||||
#define GSL_RB_MEMPTRS_SCRATCH_MASK 0x0
|
||||
#define GSL_RB_INIT_TIMESTAMP(rb) \
|
||||
adreno_regwrite((rb)->device->id, REG_CP_TIMESTAMP, 0)
|
||||
|
||||
#endif /* GSL_RB_USE_MEMTIMESTAMP */
|
||||
|
||||
/* mem rptr */
|
||||
#ifdef GSL_RB_USE_MEM_RPTR
|
||||
#define GSL_RB_CNTL_NO_UPDATE 0x0 /* enable */
|
||||
#define GSL_RB_GET_READPTR(rb, data) \
|
||||
do { \
|
||||
*(data) = readl_relaxed(&(rb)->memptrs->rptr); \
|
||||
*(data) = rb->memptrs->rptr; \
|
||||
} while (0)
|
||||
#else
|
||||
#define GSL_RB_CNTL_NO_UPDATE 0x1 /* disable */
|
||||
#define GSL_RB_GET_READPTR(rb, data) \
|
||||
do { \
|
||||
adreno_regread((rb)->device->id, REG_CP_RB_RPTR, (data)); \
|
||||
} while (0)
|
||||
#endif /* GSL_RB_USE_MEMRPTR */
|
||||
|
||||
#define GSL_RB_CNTL_POLL_EN 0x0 /* disable */
|
||||
|
||||
/*
|
||||
* protected mode error checking below register address 0x800
|
||||
* note: if CP_INTERRUPT packet is used then checking needs
|
||||
* to change to below register address 0x7C8
|
||||
*/
|
||||
#define GSL_RB_PROTECTED_MODE_CONTROL 0x200001F2
|
||||
|
||||
int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
struct kgsl_context *context,
|
||||
struct kgsl_ibdesc *ibdesc,
|
||||
@ -126,6 +108,8 @@ void adreno_ringbuffer_issuecmds(struct kgsl_device *device,
|
||||
unsigned int *cmdaddr,
|
||||
int sizedwords);
|
||||
|
||||
void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb);
|
||||
|
||||
void kgsl_cp_intrcallback(struct kgsl_device *device);
|
||||
|
||||
int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
|
||||
@ -136,6 +120,9 @@ void
|
||||
adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
|
||||
int num_rb_contents);
|
||||
|
||||
unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
|
||||
unsigned int numcmds);
|
||||
|
||||
static inline int adreno_ringbuffer_count(struct adreno_ringbuffer *rb,
|
||||
unsigned int rptr)
|
||||
{
|
||||
|
414
drivers/gpu/msm/kgsl.c
Normal file → Executable file
414
drivers/gpu/msm/kgsl.c
Normal file → Executable file
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
|
||||
* Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
|
||||
/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -25,6 +24,7 @@
|
||||
|
||||
#include <linux/ashmem.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/ion.h>
|
||||
|
||||
#include "kgsl.h"
|
||||
#include "kgsl_debugfs.h"
|
||||
@ -45,7 +45,7 @@ module_param_named(mmutype, ksgl_mmu_type, charp, 0);
|
||||
MODULE_PARM_DESC(ksgl_mmu_type,
|
||||
"Type of MMU to be used for graphics. Valid values are 'iommu' or 'gpummu' or 'nommu'");
|
||||
|
||||
#ifdef CONFIG_GENLOCK
|
||||
static struct ion_client *kgsl_ion_client;
|
||||
|
||||
/**
|
||||
* kgsl_add_event - Add a new timstamp event for the KGSL device
|
||||
@ -53,12 +53,14 @@ MODULE_PARM_DESC(ksgl_mmu_type,
|
||||
* @ts - the timestamp to trigger the event on
|
||||
* @cb - callback function to call when the timestamp expires
|
||||
* @priv - private data for the specific event type
|
||||
* @owner - driver instance that owns this event
|
||||
*
|
||||
* @returns - 0 on success or error code on failure
|
||||
*/
|
||||
|
||||
static int kgsl_add_event(struct kgsl_device *device, u32 ts,
|
||||
void (*cb)(struct kgsl_device *, void *, u32), void *priv)
|
||||
void (*cb)(struct kgsl_device *, void *, u32), void *priv,
|
||||
struct kgsl_device_private *owner)
|
||||
{
|
||||
struct kgsl_event *event;
|
||||
struct list_head *n;
|
||||
@ -82,6 +84,7 @@ static int kgsl_add_event(struct kgsl_device *device, u32 ts,
|
||||
event->timestamp = ts;
|
||||
event->priv = priv;
|
||||
event->func = cb;
|
||||
event->owner = owner;
|
||||
|
||||
/* Add the event in order to the list */
|
||||
|
||||
@ -97,10 +100,73 @@ static int kgsl_add_event(struct kgsl_device *device, u32 ts,
|
||||
|
||||
if (n == &device->events)
|
||||
list_add_tail(&event->list, &device->events);
|
||||
|
||||
|
||||
queue_work(device->work_queue, &device->ts_expired_ws);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* kgsl_cancel_events - Cancel all events for a process
|
||||
* @device - KGSL device for the events to cancel
|
||||
* @owner - driver instance that owns the events to cancel
|
||||
*
|
||||
*/
|
||||
static void kgsl_cancel_events(struct kgsl_device *device,
|
||||
struct kgsl_device_private *owner)
|
||||
{
|
||||
struct kgsl_event *event, *event_tmp;
|
||||
unsigned int cur = device->ftbl->readtimestamp(device,
|
||||
KGSL_TIMESTAMP_RETIRED);
|
||||
|
||||
list_for_each_entry_safe(event, event_tmp, &device->events, list) {
|
||||
if (event->owner != owner)
|
||||
continue;
|
||||
/*
|
||||
* "cancel" the events by calling their callback.
|
||||
* Currently, events are used for lock and memory
|
||||
* management, so if the process is dying the right
|
||||
* thing to do is release or free.
|
||||
*/
|
||||
if (event->func)
|
||||
event->func(device, event->priv, cur);
|
||||
|
||||
list_del(&event->list);
|
||||
kfree(event);
|
||||
}
|
||||
}
|
||||
|
||||
/* kgsl_get_mem_entry - get the mem_entry structure for the specified object
|
||||
* @ptbase - the pagetable base of the object
|
||||
* @gpuaddr - the GPU address of the object
|
||||
* @size - Size of the region to search
|
||||
*/
|
||||
|
||||
struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
|
||||
unsigned int gpuaddr, unsigned int size)
|
||||
{
|
||||
struct kgsl_process_private *priv;
|
||||
struct kgsl_mem_entry *entry;
|
||||
|
||||
mutex_lock(&kgsl_driver.process_mutex);
|
||||
|
||||
list_for_each_entry(priv, &kgsl_driver.process_list, list) {
|
||||
if (!kgsl_mmu_pt_equal(priv->pagetable, ptbase))
|
||||
continue;
|
||||
spin_lock(&priv->mem_lock);
|
||||
entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
|
||||
|
||||
if (entry) {
|
||||
spin_unlock(&priv->mem_lock);
|
||||
mutex_unlock(&kgsl_driver.process_mutex);
|
||||
return entry;
|
||||
}
|
||||
spin_unlock(&priv->mem_lock);
|
||||
}
|
||||
mutex_unlock(&kgsl_driver.process_mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_get_mem_entry);
|
||||
|
||||
static inline struct kgsl_mem_entry *
|
||||
kgsl_mem_entry_create(void)
|
||||
@ -121,18 +187,32 @@ kgsl_mem_entry_destroy(struct kref *kref)
|
||||
struct kgsl_mem_entry *entry = container_of(kref,
|
||||
struct kgsl_mem_entry,
|
||||
refcount);
|
||||
size_t size = entry->memdesc.size;
|
||||
|
||||
if (entry->memtype != KGSL_MEM_ENTRY_KERNEL)
|
||||
kgsl_driver.stats.mapped -= entry->memdesc.size;
|
||||
|
||||
/*
|
||||
* Ion takes care of freeing the sglist for us (how nice </sarcasm>) so
|
||||
* unmap the dma before freeing the sharedmem so kgsl_sharedmem_free
|
||||
* doesn't try to free it again
|
||||
*/
|
||||
|
||||
if (entry->memtype == KGSL_MEM_ENTRY_ION) {
|
||||
ion_unmap_dma(kgsl_ion_client, entry->priv_data);
|
||||
entry->memdesc.sg = NULL;
|
||||
}
|
||||
|
||||
kgsl_sharedmem_free(&entry->memdesc);
|
||||
|
||||
if (entry->memtype == KGSL_USER_MEMORY)
|
||||
entry->priv->stats.user -= size;
|
||||
else if (entry->memtype == KGSL_MAPPED_MEMORY) {
|
||||
if (entry->file_ptr)
|
||||
fput(entry->file_ptr);
|
||||
|
||||
kgsl_driver.stats.mapped -= size;
|
||||
entry->priv->stats.mapped -= size;
|
||||
switch (entry->memtype) {
|
||||
case KGSL_MEM_ENTRY_PMEM:
|
||||
case KGSL_MEM_ENTRY_ASHMEM:
|
||||
if (entry->priv_data)
|
||||
fput(entry->priv_data);
|
||||
break;
|
||||
case KGSL_MEM_ENTRY_ION:
|
||||
ion_free(kgsl_ion_client, entry->priv_data);
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(entry);
|
||||
@ -150,6 +230,21 @@ void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
|
||||
entry->priv = process;
|
||||
}
|
||||
|
||||
/* Detach a memory entry from a process and unmap it from the MMU */
|
||||
|
||||
static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
|
||||
{
|
||||
if (entry == NULL)
|
||||
return;
|
||||
|
||||
entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
|
||||
entry->priv = NULL;
|
||||
|
||||
kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
|
||||
|
||||
kgsl_mem_entry_put(entry);
|
||||
}
|
||||
|
||||
/* Allocate a new context id */
|
||||
|
||||
static struct kgsl_context *
|
||||
@ -206,44 +301,10 @@ kgsl_destroy_context(struct kgsl_device_private *dev_priv,
|
||||
idr_remove(&dev_priv->device->context_idr, id);
|
||||
}
|
||||
|
||||
/* to be called when a process is destroyed, this walks the memqueue and
|
||||
* frees any entryies that belong to the dying process
|
||||
*/
|
||||
static void kgsl_memqueue_cleanup(struct kgsl_device *device,
|
||||
struct kgsl_process_private *private)
|
||||
{
|
||||
struct kgsl_mem_entry *entry, *entry_tmp;
|
||||
|
||||
if (!private)
|
||||
return;
|
||||
|
||||
BUG_ON(!mutex_is_locked(&device->mutex));
|
||||
|
||||
list_for_each_entry_safe(entry, entry_tmp, &device->memqueue, list) {
|
||||
if (entry->priv == private) {
|
||||
list_del(&entry->list);
|
||||
kgsl_mem_entry_put(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kgsl_memqueue_freememontimestamp(struct kgsl_device *device,
|
||||
struct kgsl_mem_entry *entry,
|
||||
uint32_t timestamp,
|
||||
enum kgsl_timestamp_type type)
|
||||
{
|
||||
BUG_ON(!mutex_is_locked(&device->mutex));
|
||||
|
||||
entry->free_timestamp = timestamp;
|
||||
|
||||
list_add_tail(&entry->list, &device->memqueue);
|
||||
}
|
||||
|
||||
static void kgsl_timestamp_expired(struct work_struct *work)
|
||||
{
|
||||
struct kgsl_device *device = container_of(work, struct kgsl_device,
|
||||
ts_expired_ws);
|
||||
struct kgsl_mem_entry *entry, *entry_tmp;
|
||||
struct kgsl_event *event, *event_tmp;
|
||||
uint32_t ts_processed;
|
||||
|
||||
@ -253,15 +314,6 @@ static void kgsl_timestamp_expired(struct work_struct *work)
|
||||
ts_processed = device->ftbl->readtimestamp(device,
|
||||
KGSL_TIMESTAMP_RETIRED);
|
||||
|
||||
/* Flush the freememontimestamp queue */
|
||||
list_for_each_entry_safe(entry, entry_tmp, &device->memqueue, list) {
|
||||
if (timestamp_cmp(ts_processed, entry->free_timestamp) < 0)
|
||||
break;
|
||||
|
||||
list_del(&entry->list);
|
||||
kgsl_mem_entry_put(entry);
|
||||
}
|
||||
|
||||
/* Process expired events */
|
||||
list_for_each_entry_safe(event, event_tmp, &device->events, list) {
|
||||
if (timestamp_cmp(ts_processed, event->timestamp) < 0)
|
||||
@ -585,18 +637,13 @@ kgsl_put_process_private(struct kgsl_device *device,
|
||||
if (--private->refcnt)
|
||||
goto unlock;
|
||||
|
||||
KGSL_MEM_INFO(device,
|
||||
"Memory usage: user (%d/%d) mapped (%d/%d)\n",
|
||||
private->stats.user, private->stats.user_max,
|
||||
private->stats.mapped, private->stats.mapped_max);
|
||||
|
||||
kgsl_process_uninit_sysfs(private);
|
||||
|
||||
list_del(&private->list);
|
||||
|
||||
list_for_each_entry_safe(entry, entry_tmp, &private->mem_list, list) {
|
||||
list_del(&entry->list);
|
||||
kgsl_mem_entry_put(entry);
|
||||
kgsl_mem_entry_detach_process(entry);
|
||||
}
|
||||
|
||||
kgsl_mmu_putpagetable(private->pagetable);
|
||||
@ -641,7 +688,7 @@ static int kgsl_release(struct inode *inodep, struct file *filep)
|
||||
/* clean up any to-be-freed entries that belong to this
|
||||
* process and this device
|
||||
*/
|
||||
kgsl_memqueue_cleanup(device, private);
|
||||
kgsl_cancel_events(device, dev_priv);
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
kfree(dev_priv);
|
||||
@ -758,9 +805,7 @@ kgsl_sharedmem_find_region(struct kgsl_process_private *private,
|
||||
BUG_ON(private == NULL);
|
||||
|
||||
list_for_each_entry(entry, &private->mem_list, list) {
|
||||
if (gpuaddr >= entry->memdesc.gpuaddr &&
|
||||
((gpuaddr + size) <=
|
||||
(entry->memdesc.gpuaddr + entry->memdesc.size))) {
|
||||
if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
|
||||
result = entry;
|
||||
break;
|
||||
}
|
||||
@ -770,20 +815,6 @@ kgsl_sharedmem_find_region(struct kgsl_process_private *private,
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_sharedmem_find_region);
|
||||
|
||||
uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
|
||||
unsigned int gpuaddr, unsigned int *size)
|
||||
{
|
||||
BUG_ON(memdesc->hostptr == NULL);
|
||||
|
||||
if (memdesc->gpuaddr == 0 || (gpuaddr < memdesc->gpuaddr ||
|
||||
gpuaddr >= memdesc->gpuaddr + memdesc->size))
|
||||
return NULL;
|
||||
|
||||
*size = memdesc->size - (gpuaddr - memdesc->gpuaddr);
|
||||
return memdesc->hostptr + (gpuaddr - memdesc->gpuaddr);
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_gpuaddr_to_vaddr);
|
||||
|
||||
/*call all ioctl sub functions with driver locked*/
|
||||
static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data)
|
||||
@ -810,6 +841,40 @@ static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
|
||||
|
||||
break;
|
||||
}
|
||||
case KGSL_PROP_GPU_RESET_STAT:
|
||||
{
|
||||
/* Return reset status of given context and clear it */
|
||||
uint32_t id;
|
||||
struct kgsl_context *context;
|
||||
|
||||
if (param->sizebytes != sizeof(unsigned int)) {
|
||||
result = -EINVAL;
|
||||
break;
|
||||
}
|
||||
/* We expect the value passed in to contain the context id */
|
||||
if (copy_from_user(&id, param->value,
|
||||
sizeof(unsigned int))) {
|
||||
result = -EFAULT;
|
||||
break;
|
||||
}
|
||||
context = kgsl_find_context(dev_priv, id);
|
||||
if (!context) {
|
||||
result = -EINVAL;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Copy the reset status to value which also serves as
|
||||
* the out parameter
|
||||
*/
|
||||
if (copy_to_user(param->value, &(context->reset_status),
|
||||
sizeof(unsigned int))) {
|
||||
result = -EFAULT;
|
||||
break;
|
||||
}
|
||||
/* Clear reset status once its been queried */
|
||||
context->reset_status = KGSL_CTX_STAT_NO_ERROR;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
result = dev_priv->device->ftbl->getproperty(
|
||||
dev_priv->device, param->type,
|
||||
@ -844,40 +909,6 @@ static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private
|
||||
|
||||
return result;
|
||||
}
|
||||
static bool check_ibdesc(struct kgsl_device_private *dev_priv,
|
||||
struct kgsl_ibdesc *ibdesc, unsigned int numibs,
|
||||
bool parse)
|
||||
{
|
||||
bool result = true;
|
||||
unsigned int i;
|
||||
for (i = 0; i < numibs; i++) {
|
||||
struct kgsl_mem_entry *entry;
|
||||
spin_lock(&dev_priv->process_priv->mem_lock);
|
||||
entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
|
||||
ibdesc[i].gpuaddr, ibdesc[i].sizedwords * sizeof(uint));
|
||||
spin_unlock(&dev_priv->process_priv->mem_lock);
|
||||
if (entry == NULL) {
|
||||
KGSL_DRV_ERR(dev_priv->device,
|
||||
"invalid cmd buffer gpuaddr %08x " \
|
||||
"sizedwords %d\n", ibdesc[i].gpuaddr,
|
||||
ibdesc[i].sizedwords);
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (parse && !kgsl_cffdump_parse_ibs(dev_priv, &entry->memdesc,
|
||||
ibdesc[i].gpuaddr, ibdesc[i].sizedwords, true)) {
|
||||
KGSL_DRV_ERR(dev_priv->device,
|
||||
"invalid cmd buffer gpuaddr %08x " \
|
||||
"sizedwords %d numibs %d/%d\n",
|
||||
ibdesc[i].gpuaddr,
|
||||
ibdesc[i].sizedwords, i+1, numibs);
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data)
|
||||
@ -947,12 +978,6 @@ static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
param->numibs = 1;
|
||||
}
|
||||
|
||||
if (!check_ibdesc(dev_priv, ibdesc, param->numibs, true)) {
|
||||
KGSL_DRV_ERR(dev_priv->device, "bad ibdesc");
|
||||
result = -EINVAL;
|
||||
goto free_ibdesc;
|
||||
}
|
||||
|
||||
result = dev_priv->device->ftbl->issueibcmds(dev_priv,
|
||||
context,
|
||||
ibdesc,
|
||||
@ -960,17 +985,6 @@ static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
¶m->timestamp,
|
||||
param->flags);
|
||||
|
||||
if (result != 0)
|
||||
goto free_ibdesc;
|
||||
|
||||
/* this is a check to try to detect if a command buffer was freed
|
||||
* during issueibcmds().
|
||||
*/
|
||||
if (!check_ibdesc(dev_priv, ibdesc, param->numibs, false)) {
|
||||
KGSL_DRV_ERR(dev_priv->device, "bad ibdesc AFTER issue");
|
||||
result = -EINVAL;
|
||||
goto free_ibdesc;
|
||||
}
|
||||
|
||||
free_ibdesc:
|
||||
kfree(ibdesc);
|
||||
@ -996,6 +1010,16 @@ static long kgsl_ioctl_cmdstream_readtimestamp(struct kgsl_device_private
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kgsl_freemem_event_cb(struct kgsl_device *device,
|
||||
void *priv, u32 timestamp)
|
||||
{
|
||||
struct kgsl_mem_entry *entry = priv;
|
||||
spin_lock(&entry->priv->mem_lock);
|
||||
list_del(&entry->list);
|
||||
spin_unlock(&entry->priv->mem_lock);
|
||||
kgsl_mem_entry_detach_process(entry);
|
||||
}
|
||||
|
||||
static long kgsl_ioctl_cmdstream_freememontimestamp(struct kgsl_device_private
|
||||
*dev_priv, unsigned int cmd,
|
||||
void *data)
|
||||
@ -1006,13 +1030,11 @@ static long kgsl_ioctl_cmdstream_freememontimestamp(struct kgsl_device_private
|
||||
|
||||
spin_lock(&dev_priv->process_priv->mem_lock);
|
||||
entry = kgsl_sharedmem_find(dev_priv->process_priv, param->gpuaddr);
|
||||
if (entry)
|
||||
list_del(&entry->list);
|
||||
spin_unlock(&dev_priv->process_priv->mem_lock);
|
||||
|
||||
if (entry) {
|
||||
kgsl_memqueue_freememontimestamp(dev_priv->device, entry,
|
||||
param->timestamp, param->type);
|
||||
result = kgsl_add_event(dev_priv->device, param->timestamp,
|
||||
kgsl_freemem_event_cb, entry, dev_priv);
|
||||
} else {
|
||||
KGSL_DRV_ERR(dev_priv->device,
|
||||
"invalid gpuaddr %08x\n", param->gpuaddr);
|
||||
@ -1089,7 +1111,7 @@ static long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv,
|
||||
spin_unlock(&private->mem_lock);
|
||||
|
||||
if (entry) {
|
||||
kgsl_mem_entry_put(entry);
|
||||
kgsl_mem_entry_detach_process(entry);
|
||||
} else {
|
||||
KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
|
||||
result = -EINVAL;
|
||||
@ -1169,7 +1191,7 @@ kgsl_ioctl_sharedmem_from_vmalloc(struct kgsl_device_private *dev_priv,
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = kgsl_sharedmem_vmalloc_user(&entry->memdesc,
|
||||
result = kgsl_sharedmem_page_alloc_user(&entry->memdesc,
|
||||
private->pagetable, len,
|
||||
param->flags);
|
||||
if (result != 0)
|
||||
@ -1177,26 +1199,25 @@ kgsl_ioctl_sharedmem_from_vmalloc(struct kgsl_device_private *dev_priv,
|
||||
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
|
||||
result = remap_vmalloc_range(vma, (void *) entry->memdesc.hostptr, 0);
|
||||
result = kgsl_sharedmem_map_vma(vma, &entry->memdesc);
|
||||
if (result) {
|
||||
KGSL_CORE_ERR("remap_vmalloc_range failed: %d\n", result);
|
||||
goto error_free_vmalloc;
|
||||
KGSL_CORE_ERR("kgsl_sharedmem_map_vma failed: %d\n", result);
|
||||
goto error_free_alloc;
|
||||
}
|
||||
|
||||
param->gpuaddr = entry->memdesc.gpuaddr;
|
||||
|
||||
entry->memtype = KGSL_USER_MEMORY;
|
||||
entry->memtype = KGSL_MEM_ENTRY_KERNEL;
|
||||
|
||||
kgsl_mem_entry_attach_process(entry, private);
|
||||
|
||||
/* Process specific statistics */
|
||||
KGSL_STATS_ADD(len, private->stats.user,
|
||||
private->stats.user_max);
|
||||
kgsl_process_add_stats(private, entry->memtype, len);
|
||||
|
||||
kgsl_check_idle(dev_priv->device);
|
||||
return 0;
|
||||
|
||||
error_free_vmalloc:
|
||||
error_free_alloc:
|
||||
kgsl_sharedmem_free(&entry->memdesc);
|
||||
|
||||
error_free_entry:
|
||||
@ -1292,7 +1313,7 @@ static int kgsl_setup_phys_file(struct kgsl_mem_entry *entry,
|
||||
|
||||
}
|
||||
|
||||
entry->file_ptr = filep;
|
||||
entry->priv_data = filep;
|
||||
|
||||
entry->memdesc.pagetable = pagetable;
|
||||
entry->memdesc.size = size;
|
||||
@ -1319,8 +1340,8 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc,
|
||||
int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
|
||||
unsigned long paddr = (unsigned long) addr;
|
||||
|
||||
memdesc->sg = kmalloc(sglen * sizeof(struct scatterlist),
|
||||
GFP_KERNEL);
|
||||
memdesc->sg = kgsl_sg_alloc(sglen);
|
||||
|
||||
if (memdesc->sg == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1360,7 +1381,7 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc,
|
||||
|
||||
err:
|
||||
spin_unlock(¤t->mm->page_table_lock);
|
||||
kfree(memdesc->sg);
|
||||
kgsl_sg_free(memdesc->sg, sglen);
|
||||
memdesc->sg = NULL;
|
||||
|
||||
return -EINVAL;
|
||||
@ -1464,7 +1485,7 @@ static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry,
|
||||
goto err;
|
||||
}
|
||||
|
||||
entry->file_ptr = filep;
|
||||
entry->priv_data = filep;
|
||||
entry->memdesc.pagetable = pagetable;
|
||||
entry->memdesc.size = ALIGN(size, PAGE_SIZE);
|
||||
entry->memdesc.hostptr = hostptr;
|
||||
@ -1488,6 +1509,51 @@ static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
|
||||
struct kgsl_pagetable *pagetable, int fd)
|
||||
{
|
||||
struct ion_handle *handle;
|
||||
struct scatterlist *s;
|
||||
unsigned long flags;
|
||||
|
||||
if (kgsl_ion_client == NULL) {
|
||||
kgsl_ion_client = msm_ion_client_create(UINT_MAX, KGSL_NAME);
|
||||
if (kgsl_ion_client == NULL)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
handle = ion_import_fd(kgsl_ion_client, fd);
|
||||
if (IS_ERR_OR_NULL(handle))
|
||||
return PTR_ERR(handle);
|
||||
|
||||
entry->memtype = KGSL_MEM_ENTRY_ION;
|
||||
entry->priv_data = handle;
|
||||
entry->memdesc.pagetable = pagetable;
|
||||
entry->memdesc.size = 0;
|
||||
|
||||
if (ion_handle_get_flags(kgsl_ion_client, handle, &flags))
|
||||
goto err;
|
||||
|
||||
entry->memdesc.sg = ion_map_dma(kgsl_ion_client, handle, flags);
|
||||
|
||||
if (IS_ERR_OR_NULL(entry->memdesc.sg))
|
||||
goto err;
|
||||
|
||||
/* Calculate the size of the memdesc from the sglist */
|
||||
|
||||
entry->memdesc.sglen = 0;
|
||||
|
||||
for (s = entry->memdesc.sg; s != NULL; s = sg_next(s)) {
|
||||
entry->memdesc.size += s->length;
|
||||
entry->memdesc.sglen++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
ion_free(kgsl_ion_client, handle);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data)
|
||||
{
|
||||
@ -1515,6 +1581,7 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
|
||||
result = kgsl_setup_phys_file(entry, private->pagetable,
|
||||
param->fd, param->offset,
|
||||
param->len);
|
||||
entry->memtype = KGSL_MEM_ENTRY_PMEM;
|
||||
break;
|
||||
|
||||
case KGSL_USER_MEM_TYPE_ADDR:
|
||||
@ -1531,6 +1598,7 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
|
||||
result = kgsl_setup_hostptr(entry, private->pagetable,
|
||||
(void *) param->hostptr,
|
||||
param->offset, param->len);
|
||||
entry->memtype = KGSL_MEM_ENTRY_USER;
|
||||
break;
|
||||
|
||||
case KGSL_USER_MEM_TYPE_ASHMEM:
|
||||
@ -1547,6 +1615,12 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
|
||||
result = kgsl_setup_ashmem(entry, private->pagetable,
|
||||
param->fd, (void *) param->hostptr,
|
||||
param->len);
|
||||
|
||||
entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
|
||||
break;
|
||||
case KGSL_USER_MEM_TYPE_ION:
|
||||
result = kgsl_setup_ion(entry, private->pagetable,
|
||||
param->fd);
|
||||
break;
|
||||
default:
|
||||
KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
|
||||
@ -1566,14 +1640,10 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
|
||||
/* Adjust the returned value for a non 4k aligned offset */
|
||||
param->gpuaddr = entry->memdesc.gpuaddr + (param->offset & ~PAGE_MASK);
|
||||
|
||||
entry->memtype = KGSL_MAPPED_MEMORY;
|
||||
|
||||
KGSL_STATS_ADD(param->len, kgsl_driver.stats.mapped,
|
||||
kgsl_driver.stats.mapped_max);
|
||||
|
||||
/* Statistics */
|
||||
KGSL_STATS_ADD(param->len, private->stats.mapped,
|
||||
private->stats.mapped_max);
|
||||
kgsl_process_add_stats(private, entry->memtype, param->len);
|
||||
|
||||
kgsl_mem_entry_attach_process(entry, private);
|
||||
|
||||
@ -1581,8 +1651,8 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
|
||||
return result;
|
||||
|
||||
error_put_file_ptr:
|
||||
if (entry->file_ptr)
|
||||
fput(entry->file_ptr);
|
||||
if (entry->priv_data)
|
||||
fput(entry->priv_data);
|
||||
|
||||
error:
|
||||
kfree(entry);
|
||||
@ -1608,10 +1678,6 @@ kgsl_ioctl_sharedmem_flush_cache(struct kgsl_device_private *dev_priv,
|
||||
result = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (!entry->memdesc.hostptr)
|
||||
entry->memdesc.hostptr =
|
||||
kgsl_gpuaddr_to_vaddr(&entry->memdesc,
|
||||
param->gpuaddr, &entry->memdesc.size);
|
||||
|
||||
if (!entry->memdesc.hostptr) {
|
||||
KGSL_CORE_ERR("invalid hostptr with gpuaddr %08x\n",
|
||||
@ -1620,9 +1686,6 @@ kgsl_ioctl_sharedmem_flush_cache(struct kgsl_device_private *dev_priv,
|
||||
}
|
||||
|
||||
kgsl_cache_range_op(&entry->memdesc, KGSL_CACHE_OP_CLEAN);
|
||||
|
||||
/* Statistics - keep track of how many flushes each process does */
|
||||
private->stats.flushes++;
|
||||
done:
|
||||
spin_unlock(&private->mem_lock);
|
||||
return result;
|
||||
@ -1645,12 +1708,11 @@ kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv,
|
||||
param->size, param->flags);
|
||||
|
||||
if (result == 0) {
|
||||
entry->memtype = KGSL_USER_MEMORY;
|
||||
entry->memtype = KGSL_MEM_ENTRY_KERNEL;
|
||||
kgsl_mem_entry_attach_process(entry, private);
|
||||
param->gpuaddr = entry->memdesc.gpuaddr;
|
||||
|
||||
KGSL_STATS_ADD(entry->memdesc.size, private->stats.user,
|
||||
private->stats.user_max);
|
||||
kgsl_process_add_stats(private, entry->memtype, param->size);
|
||||
} else
|
||||
kfree(entry);
|
||||
|
||||
@ -1724,6 +1786,7 @@ static void kgsl_genlock_event_cb(struct kgsl_device *device,
|
||||
* @timestamp - Timestamp to trigger the event
|
||||
* @data - User space buffer containing struct kgsl_genlock_event_priv
|
||||
* @len - length of the userspace buffer
|
||||
* @owner - driver instance that owns this event
|
||||
* @returns 0 on success or error code on error
|
||||
*
|
||||
* Attack to a genlock handle and register an event to release the
|
||||
@ -1731,7 +1794,8 @@ static void kgsl_genlock_event_cb(struct kgsl_device *device,
|
||||
*/
|
||||
|
||||
static int kgsl_add_genlock_event(struct kgsl_device *device,
|
||||
u32 timestamp, void __user *data, int len)
|
||||
u32 timestamp, void __user *data, int len,
|
||||
struct kgsl_device_private *owner)
|
||||
{
|
||||
struct kgsl_genlock_event_priv *event;
|
||||
struct kgsl_timestamp_event_genlock priv;
|
||||
@ -1756,7 +1820,8 @@ static int kgsl_add_genlock_event(struct kgsl_device *device,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kgsl_add_event(device, timestamp, kgsl_genlock_event_cb, event);
|
||||
ret = kgsl_add_event(device, timestamp, kgsl_genlock_event_cb, event,
|
||||
owner);
|
||||
if (ret)
|
||||
kfree(event);
|
||||
|
||||
@ -1764,7 +1829,8 @@ static int kgsl_add_genlock_event(struct kgsl_device *device,
|
||||
}
|
||||
#else
|
||||
static long kgsl_add_genlock_event(struct kgsl_device *device,
|
||||
u32 timestamp, void __user *data, int len)
|
||||
u32 timestamp, void __user *data, int len,
|
||||
struct kgsl_device_private *owner)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1787,7 +1853,8 @@ static long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv,
|
||||
switch (param->type) {
|
||||
case KGSL_TIMESTAMP_EVENT_GENLOCK:
|
||||
ret = kgsl_add_genlock_event(dev_priv->device,
|
||||
param->timestamp, param->priv, param->len);
|
||||
param->timestamp, param->priv, param->len,
|
||||
dev_priv);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
@ -1892,7 +1959,7 @@ static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
|
||||
if (!func) {
|
||||
KGSL_DRV_INFO(dev_priv->device,
|
||||
"invalid ioctl code %08x\n", cmd);
|
||||
ret = -EINVAL;
|
||||
ret = -ENOIOCTLCMD;
|
||||
goto done;
|
||||
}
|
||||
lock = 1;
|
||||
@ -2142,7 +2209,6 @@ kgsl_register_device(struct kgsl_device *device)
|
||||
INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
|
||||
INIT_WORK(&device->ts_expired_ws, kgsl_timestamp_expired);
|
||||
|
||||
INIT_LIST_HEAD(&device->memqueue);
|
||||
INIT_LIST_HEAD(&device->events);
|
||||
|
||||
ret = kgsl_mmu_init(device);
|
||||
|
61
drivers/gpu/msm/kgsl.h
Normal file → Executable file
61
drivers/gpu/msm/kgsl.h
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -21,9 +21,13 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#define KGSL_NAME "kgsl"
|
||||
|
||||
/* Timestamp window used to detect rollovers */
|
||||
#define KGSL_TIMESTAMP_WINDOW 0x80000000
|
||||
|
||||
/*cache coherency ops */
|
||||
#define DRM_KGSL_GEM_CACHE_OP_TO_DEV 0x0001
|
||||
#define DRM_KGSL_GEM_CACHE_OP_FROM_DEV 0x0002
|
||||
@ -91,6 +95,8 @@ struct kgsl_driver {
|
||||
struct {
|
||||
unsigned int vmalloc;
|
||||
unsigned int vmalloc_max;
|
||||
unsigned int page_alloc;
|
||||
unsigned int page_alloc_max;
|
||||
unsigned int coherent;
|
||||
unsigned int coherent_max;
|
||||
unsigned int mapped;
|
||||
@ -101,11 +107,18 @@ struct kgsl_driver {
|
||||
|
||||
extern struct kgsl_driver kgsl_driver;
|
||||
|
||||
#define KGSL_USER_MEMORY 1
|
||||
#define KGSL_MAPPED_MEMORY 2
|
||||
|
||||
struct kgsl_pagetable;
|
||||
struct kgsl_memdesc_ops;
|
||||
struct kgsl_memdesc;
|
||||
|
||||
struct kgsl_memdesc_ops {
|
||||
int (*vmflags)(struct kgsl_memdesc *);
|
||||
int (*vmfault)(struct kgsl_memdesc *, struct vm_area_struct *,
|
||||
struct vm_fault *);
|
||||
void (*free)(struct kgsl_memdesc *memdesc);
|
||||
int (*map_kernel_mem)(struct kgsl_memdesc *);
|
||||
};
|
||||
|
||||
#define KGSL_MEMDESC_GUARD_PAGE BIT(0)
|
||||
|
||||
/* shared memory allocation */
|
||||
struct kgsl_memdesc {
|
||||
@ -118,13 +131,23 @@ struct kgsl_memdesc {
|
||||
struct scatterlist *sg;
|
||||
unsigned int sglen;
|
||||
struct kgsl_memdesc_ops *ops;
|
||||
int flags;
|
||||
};
|
||||
|
||||
/* List of different memory entry types */
|
||||
|
||||
#define KGSL_MEM_ENTRY_KERNEL 0
|
||||
#define KGSL_MEM_ENTRY_PMEM 1
|
||||
#define KGSL_MEM_ENTRY_ASHMEM 2
|
||||
#define KGSL_MEM_ENTRY_USER 3
|
||||
#define KGSL_MEM_ENTRY_ION 4
|
||||
#define KGSL_MEM_ENTRY_MAX 5
|
||||
|
||||
struct kgsl_mem_entry {
|
||||
struct kref refcount;
|
||||
struct kgsl_memdesc memdesc;
|
||||
int memtype;
|
||||
struct file *file_ptr;
|
||||
void *priv_data;
|
||||
struct list_head list;
|
||||
uint32_t free_timestamp;
|
||||
/* back pointer to private structure under whose context this
|
||||
@ -139,8 +162,10 @@ struct kgsl_mem_entry {
|
||||
#endif
|
||||
|
||||
void kgsl_mem_entry_destroy(struct kref *kref);
|
||||
uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
|
||||
unsigned int gpuaddr, unsigned int *size);
|
||||
|
||||
struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
|
||||
unsigned int gpuaddr, unsigned int size);
|
||||
|
||||
struct kgsl_mem_entry *kgsl_sharedmem_find_region(
|
||||
struct kgsl_process_private *private, unsigned int gpuaddr,
|
||||
size_t size);
|
||||
@ -169,14 +194,26 @@ static inline void kgsl_drm_exit(void)
|
||||
#endif
|
||||
|
||||
static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
|
||||
unsigned int gpuaddr)
|
||||
unsigned int gpuaddr, unsigned int size)
|
||||
{
|
||||
if (gpuaddr >= memdesc->gpuaddr && (gpuaddr + sizeof(unsigned int)) <=
|
||||
(memdesc->gpuaddr + memdesc->size)) {
|
||||
if (gpuaddr >= memdesc->gpuaddr &&
|
||||
((gpuaddr + size) <= (memdesc->gpuaddr + memdesc->size))) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static inline uint8_t *kgsl_gpuaddr_to_vaddr(struct kgsl_memdesc *memdesc,
|
||||
unsigned int gpuaddr)
|
||||
{
|
||||
if (memdesc->gpuaddr == 0 ||
|
||||
gpuaddr < memdesc->gpuaddr ||
|
||||
gpuaddr >= (memdesc->gpuaddr + memdesc->size) ||
|
||||
(NULL == memdesc->hostptr && memdesc->ops->map_kernel_mem &&
|
||||
memdesc->ops->map_kernel_mem(memdesc)))
|
||||
return NULL;
|
||||
|
||||
return memdesc->hostptr + (gpuaddr - memdesc->gpuaddr);
|
||||
}
|
||||
|
||||
static inline int timestamp_cmp(unsigned int new, unsigned int old)
|
||||
{
|
||||
@ -185,7 +222,7 @@ static inline int timestamp_cmp(unsigned int new, unsigned int old)
|
||||
if (ts_diff == 0)
|
||||
return 0;
|
||||
|
||||
return ((ts_diff > 0) || (ts_diff < -20000)) ? 1 : -1;
|
||||
return ((ts_diff > 0) || (ts_diff < -KGSL_TIMESTAMP_WINDOW)) ? 1 : -1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
219
drivers/gpu/msm/kgsl_cffdump.c
Normal file → Executable file
219
drivers/gpu/msm/kgsl_cffdump.c
Normal file → Executable file
@ -20,7 +20,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/sched.h>
|
||||
#include <mach/socinfo.h>
|
||||
//#include <mach/socinfo.h>
|
||||
|
||||
#include "kgsl.h"
|
||||
#include "kgsl_cffdump.h"
|
||||
@ -231,8 +231,6 @@ static void cffdump_printline(int id, uint opcode, uint op1, uint op2,
|
||||
|
||||
spin_lock(&cffdump_lock);
|
||||
if (opcode == CFF_OP_WRITE_MEM) {
|
||||
if (op1 < 0x40000000 || op1 >= 0x60000000)
|
||||
KGSL_CORE_ERR("addr out-of-range: op1=%08x", op1);
|
||||
if ((cff_op_write_membuf.addr != op1 &&
|
||||
cff_op_write_membuf.count)
|
||||
|| (cff_op_write_membuf.count == MEMBUF_SIZE))
|
||||
@ -360,15 +358,7 @@ void kgsl_cffdump_destroy()
|
||||
|
||||
void kgsl_cffdump_open(enum kgsl_deviceid device_id)
|
||||
{
|
||||
/*TODO: move this to where we can report correct gmemsize*/
|
||||
unsigned int va_base;
|
||||
|
||||
if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_msm8930())
|
||||
va_base = 0x40000000;
|
||||
else
|
||||
va_base = 0x20000000;
|
||||
|
||||
kgsl_cffdump_memory_base(device_id, va_base,
|
||||
kgsl_cffdump_memory_base(device_id, KGSL_PAGETABLE_BASE,
|
||||
CONFIG_MSM_KGSL_PAGE_TABLE_SIZE, SZ_256K);
|
||||
}
|
||||
|
||||
@ -401,8 +391,6 @@ void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
|
||||
bool clean_cache)
|
||||
{
|
||||
const void *src;
|
||||
uint host_size;
|
||||
uint physaddr;
|
||||
|
||||
if (!kgsl_cff_dump_enable)
|
||||
return;
|
||||
@ -422,13 +410,9 @@ void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
|
||||
}
|
||||
memdesc = &entry->memdesc;
|
||||
}
|
||||
BUG_ON(memdesc->gpuaddr == 0);
|
||||
BUG_ON(gpuaddr == 0);
|
||||
physaddr = kgsl_get_realaddr(memdesc) + (gpuaddr - memdesc->gpuaddr);
|
||||
|
||||
src = kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr, &host_size);
|
||||
if (src == NULL || host_size < sizebytes) {
|
||||
KGSL_CORE_ERR("did not find mapping for "
|
||||
src = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
|
||||
if (memdesc->hostptr == NULL) {
|
||||
KGSL_CORE_ERR("no kernel mapping for "
|
||||
"gpuaddr: 0x%08x, m->host: 0x%p, phys: 0x%08x\n",
|
||||
gpuaddr, memdesc->hostptr, memdesc->physaddr);
|
||||
return;
|
||||
@ -444,7 +428,6 @@ void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
|
||||
KGSL_CACHE_OP_INV);
|
||||
}
|
||||
|
||||
BUG_ON(physaddr > 0x66000000 && physaddr < 0x66ffffff);
|
||||
while (sizebytes > 3) {
|
||||
cffdump_printline(-1, CFF_OP_WRITE_MEM, gpuaddr, *(uint *)src,
|
||||
0, 0, 0);
|
||||
@ -462,7 +445,6 @@ void kgsl_cffdump_setmem(uint addr, uint value, uint sizebytes)
|
||||
if (!kgsl_cff_dump_enable)
|
||||
return;
|
||||
|
||||
BUG_ON(addr > 0x66000000 && addr < 0x66ffffff);
|
||||
while (sizebytes > 3) {
|
||||
/* Use 32bit memory writes as long as there's at least
|
||||
* 4 bytes left */
|
||||
@ -515,197 +497,6 @@ int kgsl_cffdump_waitirq(void)
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_cffdump_waitirq);
|
||||
|
||||
#define ADDRESS_STACK_SIZE 256
|
||||
#define GET_PM4_TYPE3_OPCODE(x) ((*(x) >> 8) & 0xFF)
|
||||
static unsigned int kgsl_cffdump_addr_count;
|
||||
|
||||
static bool kgsl_cffdump_handle_type3(struct kgsl_device_private *dev_priv,
|
||||
uint *hostaddr, bool check_only)
|
||||
{
|
||||
static uint addr_stack[ADDRESS_STACK_SIZE];
|
||||
static uint size_stack[ADDRESS_STACK_SIZE];
|
||||
|
||||
switch (GET_PM4_TYPE3_OPCODE(hostaddr)) {
|
||||
case CP_INDIRECT_BUFFER_PFD:
|
||||
case CP_INDIRECT_BUFFER:
|
||||
{
|
||||
/* traverse indirect buffers */
|
||||
int i;
|
||||
uint ibaddr = hostaddr[1];
|
||||
uint ibsize = hostaddr[2];
|
||||
|
||||
/* is this address already in encountered? */
|
||||
for (i = 0;
|
||||
i < kgsl_cffdump_addr_count && addr_stack[i] != ibaddr;
|
||||
++i)
|
||||
;
|
||||
|
||||
if (kgsl_cffdump_addr_count == i) {
|
||||
addr_stack[kgsl_cffdump_addr_count] = ibaddr;
|
||||
size_stack[kgsl_cffdump_addr_count++] = ibsize;
|
||||
|
||||
if (kgsl_cffdump_addr_count >= ADDRESS_STACK_SIZE) {
|
||||
KGSL_CORE_ERR("stack overflow\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return kgsl_cffdump_parse_ibs(dev_priv, NULL,
|
||||
ibaddr, ibsize, check_only);
|
||||
} else if (size_stack[i] != ibsize) {
|
||||
KGSL_CORE_ERR("gpuaddr: 0x%08x, "
|
||||
"wc: %u, with size wc: %u already on the "
|
||||
"stack\n", ibaddr, ibsize, size_stack[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Traverse IBs and dump them to test vector. Detect swap by inspecting
|
||||
* register writes, keeping note of the current state, and dump
|
||||
* framebuffer config to test vector
|
||||
*/
|
||||
bool kgsl_cffdump_parse_ibs(struct kgsl_device_private *dev_priv,
|
||||
const struct kgsl_memdesc *memdesc, uint gpuaddr, int sizedwords,
|
||||
bool check_only)
|
||||
{
|
||||
static uint level; /* recursion level */
|
||||
bool ret = true;
|
||||
uint host_size;
|
||||
uint *hostaddr, *hoststart;
|
||||
int dwords_left = sizedwords; /* dwords left in the current command
|
||||
buffer */
|
||||
|
||||
if (level == 0)
|
||||
kgsl_cffdump_addr_count = 0;
|
||||
|
||||
if (memdesc == NULL) {
|
||||
struct kgsl_mem_entry *entry;
|
||||
spin_lock(&dev_priv->process_priv->mem_lock);
|
||||
entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
|
||||
gpuaddr, sizedwords * sizeof(uint));
|
||||
spin_unlock(&dev_priv->process_priv->mem_lock);
|
||||
if (entry == NULL) {
|
||||
KGSL_CORE_ERR("did not find mapping "
|
||||
"for gpuaddr: 0x%08x\n", gpuaddr);
|
||||
return true;
|
||||
}
|
||||
memdesc = &entry->memdesc;
|
||||
}
|
||||
|
||||
hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr, &host_size);
|
||||
if (hostaddr == NULL) {
|
||||
KGSL_CORE_ERR("did not find mapping for "
|
||||
"gpuaddr: 0x%08x\n", gpuaddr);
|
||||
return true;
|
||||
}
|
||||
|
||||
hoststart = hostaddr;
|
||||
|
||||
level++;
|
||||
|
||||
if (!memdesc->physaddr) {
|
||||
KGSL_CORE_ERR("no physaddr");
|
||||
} else {
|
||||
mb();
|
||||
kgsl_cache_range_op((struct kgsl_memdesc *)memdesc,
|
||||
KGSL_CACHE_OP_INV);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
pr_info("kgsl: cffdump: ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
|
||||
gpuaddr, sizedwords, hostaddr);
|
||||
#endif
|
||||
|
||||
while (dwords_left > 0) {
|
||||
int count = 0; /* dword count including packet header */
|
||||
bool cur_ret = true;
|
||||
|
||||
switch (*hostaddr >> 30) {
|
||||
case 0x0: /* type-0 */
|
||||
count = (*hostaddr >> 16)+2;
|
||||
break;
|
||||
case 0x1: /* type-1 */
|
||||
count = 2;
|
||||
break;
|
||||
case 0x3: /* type-3 */
|
||||
count = ((*hostaddr >> 16) & 0x3fff) + 2;
|
||||
cur_ret = kgsl_cffdump_handle_type3(dev_priv,
|
||||
hostaddr, check_only);
|
||||
break;
|
||||
default:
|
||||
pr_warn("kgsl: cffdump: parse-ib: unexpected type: "
|
||||
"type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
|
||||
*hostaddr >> 30, *hostaddr, hostaddr,
|
||||
gpuaddr+4*(sizedwords-dwords_left));
|
||||
cur_ret = false;
|
||||
count = dwords_left;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!cur_ret) {
|
||||
pr_info("kgsl: cffdump: bad sub-type: #:%d/%d, v:0x%08x"
|
||||
" @ 0x%p[gb:0x%08x], level:%d\n",
|
||||
sizedwords-dwords_left, sizedwords, *hostaddr,
|
||||
hostaddr, gpuaddr+4*(sizedwords-dwords_left),
|
||||
level);
|
||||
|
||||
print_hex_dump(KERN_ERR, level == 1 ? "IB1:" : "IB2:",
|
||||
DUMP_PREFIX_OFFSET, 32, 4, hoststart,
|
||||
sizedwords*4, 0);
|
||||
}
|
||||
#endif
|
||||
ret = ret && cur_ret;
|
||||
|
||||
/* jump to next packet */
|
||||
dwords_left -= count;
|
||||
hostaddr += count;
|
||||
cur_ret = dwords_left >= 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!cur_ret) {
|
||||
pr_info("kgsl: cffdump: bad count: c:%d, #:%d/%d, "
|
||||
"v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
|
||||
count, sizedwords-(dwords_left+count),
|
||||
sizedwords, *(hostaddr-count), hostaddr-count,
|
||||
gpuaddr+4*(sizedwords-(dwords_left+count)),
|
||||
level);
|
||||
|
||||
print_hex_dump(KERN_ERR, level == 1 ? "IB1:" : "IB2:",
|
||||
DUMP_PREFIX_OFFSET, 32, 4, hoststart,
|
||||
sizedwords*4, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = ret && cur_ret;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
pr_info("kgsl: cffdump: parsing failed: gpuaddr:0x%08x, "
|
||||
"host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
|
||||
|
||||
if (!check_only) {
|
||||
#ifdef DEBUG
|
||||
uint offset = gpuaddr - memdesc->gpuaddr;
|
||||
pr_info("kgsl: cffdump: ib-dump: hostptr:%p, gpuaddr:%08x, "
|
||||
"physaddr:%08x, offset:%d, size:%d", hoststart,
|
||||
gpuaddr, memdesc->physaddr + offset, offset,
|
||||
sizedwords*4);
|
||||
#endif
|
||||
kgsl_cffdump_syncmem(dev_priv, memdesc, gpuaddr, sizedwords*4,
|
||||
false);
|
||||
}
|
||||
|
||||
level--;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int subbuf_start_handler(struct rchan_buf *buf,
|
||||
void *subbuf, void *prev_subbuf, uint prev_padding)
|
||||
{
|
||||
|
26
drivers/gpu/msm/kgsl_device.h
Normal file → Executable file
26
drivers/gpu/msm/kgsl_device.h
Normal file → Executable file
@ -124,6 +124,7 @@ struct kgsl_event {
|
||||
void (*func)(struct kgsl_device *, void *, u32);
|
||||
void *priv;
|
||||
struct list_head list;
|
||||
struct kgsl_device_private *owner;
|
||||
};
|
||||
|
||||
|
||||
@ -152,7 +153,6 @@ struct kgsl_device {
|
||||
uint32_t state;
|
||||
uint32_t requested_state;
|
||||
|
||||
struct list_head memqueue;
|
||||
unsigned int active_cnt;
|
||||
struct completion suspend_gate;
|
||||
|
||||
@ -185,6 +185,11 @@ struct kgsl_context {
|
||||
|
||||
/* Pointer to the device specific context information */
|
||||
void *devctxt;
|
||||
/*
|
||||
* Status indicating whether a gpu reset occurred and whether this
|
||||
* context was responsible for causing it
|
||||
*/
|
||||
unsigned int reset_status;
|
||||
};
|
||||
|
||||
struct kgsl_process_private {
|
||||
@ -194,15 +199,12 @@ struct kgsl_process_private {
|
||||
struct list_head mem_list;
|
||||
struct kgsl_pagetable *pagetable;
|
||||
struct list_head list;
|
||||
struct kobject *kobj;
|
||||
struct kobject kobj;
|
||||
|
||||
struct {
|
||||
unsigned int user;
|
||||
unsigned int user_max;
|
||||
unsigned int mapped;
|
||||
unsigned int mapped_max;
|
||||
unsigned int flushes;
|
||||
} stats;
|
||||
unsigned int cur;
|
||||
unsigned int max;
|
||||
} stats[KGSL_MEM_ENTRY_MAX];
|
||||
};
|
||||
|
||||
struct kgsl_device_private {
|
||||
@ -217,6 +219,14 @@ struct kgsl_power_stats {
|
||||
|
||||
struct kgsl_device *kgsl_get_device(int dev_idx);
|
||||
|
||||
static inline void kgsl_process_add_stats(struct kgsl_process_private *priv,
|
||||
unsigned int type, size_t size)
|
||||
{
|
||||
priv->stats[type].cur += size;
|
||||
if (priv->stats[type].max < priv->stats[type].cur)
|
||||
priv->stats[type].max = priv->stats[type].cur;
|
||||
}
|
||||
|
||||
static inline void kgsl_regread(struct kgsl_device *device,
|
||||
unsigned int offsetwords,
|
||||
unsigned int *value)
|
||||
|
333
drivers/gpu/msm/kgsl_drm.c
Normal file → Executable file
333
drivers/gpu/msm/kgsl_drm.c
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -17,7 +17,6 @@
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include <linux/android_pmem.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#include "kgsl.h"
|
||||
#include "kgsl_device.h"
|
||||
@ -39,6 +38,9 @@
|
||||
#define ENTRY_EMPTY -1
|
||||
#define ENTRY_NEEDS_CLEANUP -2
|
||||
|
||||
#define DRM_KGSL_NOT_INITED -1
|
||||
#define DRM_KGSL_INITED 1
|
||||
|
||||
#define DRM_KGSL_NUM_FENCE_ENTRIES (DRM_KGSL_HANDLE_WAIT_ENTRIES << 2)
|
||||
#define DRM_KGSL_HANDLE_WAIT_ENTRIES 5
|
||||
|
||||
@ -127,6 +129,8 @@ struct drm_kgsl_gem_object {
|
||||
struct list_head wait_list;
|
||||
};
|
||||
|
||||
static int kgsl_drm_inited = DRM_KGSL_NOT_INITED;
|
||||
|
||||
/* This is a global list of all the memory currently mapped in the MMU */
|
||||
static struct list_head kgsl_mem_list;
|
||||
|
||||
@ -152,22 +156,6 @@ static void kgsl_gem_mem_flush(struct kgsl_memdesc *memdesc, int type, int op)
|
||||
kgsl_cache_range_op(memdesc, cacheop);
|
||||
}
|
||||
|
||||
/* Flush all the memory mapped in the MMU */
|
||||
|
||||
void kgsl_gpu_mem_flush(int op)
|
||||
{
|
||||
struct drm_kgsl_gem_object *entry;
|
||||
|
||||
list_for_each_entry(entry, &kgsl_mem_list, list) {
|
||||
kgsl_gem_mem_flush(&entry->memdesc, entry->type, op);
|
||||
}
|
||||
|
||||
/* Takes care of WT/WC case.
|
||||
* More useful when we go barrierless
|
||||
*/
|
||||
dmb();
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
* Add vsync wait */
|
||||
|
||||
@ -186,41 +174,6 @@ struct kgsl_drm_device_priv {
|
||||
struct kgsl_device_private *devpriv[KGSL_DEVICE_MAX];
|
||||
};
|
||||
|
||||
static int kgsl_ts_notifier_cb(struct notifier_block *blk,
|
||||
unsigned long code, void *_param);
|
||||
|
||||
static struct notifier_block kgsl_ts_nb[KGSL_DEVICE_MAX];
|
||||
|
||||
static int kgsl_drm_firstopen(struct drm_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < KGSL_DEVICE_MAX; i++) {
|
||||
struct kgsl_device *device = kgsl_get_device(i);
|
||||
|
||||
if (device == NULL)
|
||||
continue;
|
||||
|
||||
kgsl_ts_nb[i].notifier_call = kgsl_ts_notifier_cb;
|
||||
kgsl_register_ts_notifier(device, &kgsl_ts_nb[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kgsl_drm_lastclose(struct drm_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < KGSL_DEVICE_MAX; i++) {
|
||||
struct kgsl_device *device = kgsl_get_device(i);
|
||||
if (device == NULL)
|
||||
continue;
|
||||
|
||||
kgsl_unregister_ts_notifier(device, &kgsl_ts_nb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void kgsl_drm_preclose(struct drm_device *dev, struct drm_file *file_priv)
|
||||
{
|
||||
}
|
||||
@ -268,80 +221,71 @@ kgsl_gem_alloc_memory(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_kgsl_gem_object *priv = obj->driver_private;
|
||||
int index;
|
||||
int result = 0;
|
||||
|
||||
/* Return if the memory is already allocated */
|
||||
|
||||
if (kgsl_gem_memory_allocated(obj) || TYPE_IS_FD(priv->type))
|
||||
return 0;
|
||||
|
||||
if (priv->pagetable == NULL) {
|
||||
priv->pagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
|
||||
|
||||
if (priv->pagetable == NULL) {
|
||||
DRM_ERROR("Unable to get the GPU MMU pagetable\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (TYPE_IS_PMEM(priv->type)) {
|
||||
int type;
|
||||
|
||||
if (priv->type == DRM_KGSL_GEM_TYPE_EBI ||
|
||||
priv->type & DRM_KGSL_GEM_PMEM_EBI)
|
||||
type = PMEM_MEMTYPE_EBI1;
|
||||
else
|
||||
type = PMEM_MEMTYPE_SMI;
|
||||
|
||||
priv->memdesc.physaddr =
|
||||
pmem_kalloc(obj->size * priv->bufcount,
|
||||
type | PMEM_ALIGNMENT_4K);
|
||||
|
||||
if (IS_ERR((void *) priv->memdesc.physaddr)) {
|
||||
DRM_ERROR("Unable to allocate PMEM memory\n");
|
||||
return -ENOMEM;
|
||||
priv->type & DRM_KGSL_GEM_PMEM_EBI) {
|
||||
type = PMEM_MEMTYPE_EBI1;
|
||||
result = kgsl_sharedmem_ebimem_user(
|
||||
&priv->memdesc,
|
||||
priv->pagetable,
|
||||
obj->size * priv->bufcount,
|
||||
0);
|
||||
if (result) {
|
||||
DRM_ERROR(
|
||||
"Unable to allocate PMEM memory\n");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
priv->memdesc.size = obj->size * priv->bufcount;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
} else if (TYPE_IS_MEM(priv->type)) {
|
||||
priv->memdesc.hostptr =
|
||||
vmalloc_user(obj->size * priv->bufcount);
|
||||
|
||||
if (priv->memdesc.hostptr == NULL) {
|
||||
DRM_ERROR("Unable to allocate vmalloc memory\n");
|
||||
return -ENOMEM;
|
||||
if (priv->type == DRM_KGSL_GEM_TYPE_KMEM ||
|
||||
priv->type & DRM_KGSL_GEM_CACHE_MASK)
|
||||
list_add(&priv->list, &kgsl_mem_list);
|
||||
|
||||
result = kgsl_sharedmem_page_alloc_user(&priv->memdesc,
|
||||
priv->pagetable,
|
||||
obj->size * priv->bufcount, 0);
|
||||
|
||||
if (result != 0) {
|
||||
DRM_ERROR(
|
||||
"Unable to allocate Vmalloc user memory\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
priv->memdesc.size = obj->size * priv->bufcount;
|
||||
priv->memdesc.ops = &kgsl_vmalloc_ops;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
for (index = 0; index < priv->bufcount; index++)
|
||||
for (index = 0; index < priv->bufcount; index++) {
|
||||
priv->bufs[index].offset = index * obj->size;
|
||||
|
||||
priv->bufs[index].gpuaddr =
|
||||
priv->memdesc.gpuaddr +
|
||||
priv->bufs[index].offset;
|
||||
}
|
||||
priv->flags |= DRM_KGSL_GEM_FLAG_MAPPED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MSM_KGSL_MMU
|
||||
static void
|
||||
kgsl_gem_unmap(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_kgsl_gem_object *priv = obj->driver_private;
|
||||
|
||||
if (!priv->flags & DRM_KGSL_GEM_FLAG_MAPPED)
|
||||
return;
|
||||
|
||||
kgsl_mmu_unmap(priv->pagetable, &priv->memdesc);
|
||||
|
||||
kgsl_mmu_putpagetable(priv->pagetable);
|
||||
priv->pagetable = NULL;
|
||||
|
||||
if ((priv->type == DRM_KGSL_GEM_TYPE_KMEM) ||
|
||||
(priv->type & DRM_KGSL_GEM_CACHE_MASK))
|
||||
list_del(&priv->list);
|
||||
|
||||
priv->flags &= ~DRM_KGSL_GEM_FLAG_MAPPED;
|
||||
}
|
||||
#else
|
||||
static void
|
||||
kgsl_gem_unmap(struct drm_gem_object *obj)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
kgsl_gem_free_memory(struct drm_gem_object *obj)
|
||||
{
|
||||
@ -353,12 +297,17 @@ kgsl_gem_free_memory(struct drm_gem_object *obj)
|
||||
kgsl_gem_mem_flush(&priv->memdesc, priv->type,
|
||||
DRM_KGSL_GEM_CACHE_OP_FROM_DEV);
|
||||
|
||||
kgsl_gem_unmap(obj);
|
||||
|
||||
if (TYPE_IS_PMEM(priv->type))
|
||||
pmem_kfree(priv->memdesc.physaddr);
|
||||
|
||||
kgsl_sharedmem_free(&priv->memdesc);
|
||||
|
||||
kgsl_mmu_putpagetable(priv->pagetable);
|
||||
priv->pagetable = NULL;
|
||||
|
||||
if ((priv->type == DRM_KGSL_GEM_TYPE_KMEM) ||
|
||||
(priv->type & DRM_KGSL_GEM_CACHE_MASK))
|
||||
list_del(&priv->list);
|
||||
|
||||
priv->flags &= ~DRM_KGSL_GEM_FLAG_MAPPED;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
@ -454,7 +403,7 @@ kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
|
||||
|
||||
filp = fget(drm_fd);
|
||||
if (unlikely(filp == NULL)) {
|
||||
DRM_ERROR("Unable to ghet the DRM file descriptor\n");
|
||||
DRM_ERROR("Unable to get the DRM file descriptor\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
file_priv = filp->private_data;
|
||||
@ -527,7 +476,7 @@ kgsl_gem_init_obj(struct drm_device *dev,
|
||||
|
||||
ret = drm_gem_handle_create(file_priv, obj, handle);
|
||||
|
||||
drm_gem_object_handle_unreference(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
INIT_LIST_HEAD(&priv->wait_list);
|
||||
|
||||
for (i = 0; i < DRM_KGSL_HANDLE_WAIT_ENTRIES; i++) {
|
||||
@ -702,128 +651,14 @@ int
|
||||
kgsl_gem_unbind_gpu_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_kgsl_gem_bind_gpu *args = data;
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_kgsl_gem_object *priv;
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
|
||||
|
||||
if (obj == NULL) {
|
||||
DRM_ERROR("Invalid GEM handle %x\n", args->handle);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
priv = obj->driver_private;
|
||||
|
||||
if (--priv->bound == 0)
|
||||
kgsl_gem_unmap(obj);
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MSM_KGSL_MMU
|
||||
static int
|
||||
kgsl_gem_map(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_kgsl_gem_object *priv = obj->driver_private;
|
||||
int index;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (priv->flags & DRM_KGSL_GEM_FLAG_MAPPED)
|
||||
return 0;
|
||||
|
||||
/* Get the global page table */
|
||||
|
||||
if (priv->pagetable == NULL) {
|
||||
priv->pagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
|
||||
|
||||
if (priv->pagetable == NULL) {
|
||||
DRM_ERROR("Unable to get the GPU MMU pagetable\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
priv->memdesc.pagetable = priv->pagetable;
|
||||
|
||||
ret = kgsl_mmu_map(priv->pagetable, &priv->memdesc,
|
||||
GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
|
||||
|
||||
if (!ret) {
|
||||
for (index = 0; index < priv->bufcount; index++) {
|
||||
priv->bufs[index].gpuaddr =
|
||||
priv->memdesc.gpuaddr +
|
||||
priv->bufs[index].offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add cached memory to the list to be cached */
|
||||
|
||||
if (priv->type == DRM_KGSL_GEM_TYPE_KMEM ||
|
||||
priv->type & DRM_KGSL_GEM_CACHE_MASK)
|
||||
list_add(&priv->list, &kgsl_mem_list);
|
||||
|
||||
priv->flags |= DRM_KGSL_GEM_FLAG_MAPPED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
kgsl_gem_map(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_kgsl_gem_object *priv = obj->driver_private;
|
||||
int index;
|
||||
|
||||
if (TYPE_IS_PMEM(priv->type)) {
|
||||
for (index = 0; index < priv->bufcount; index++)
|
||||
priv->bufs[index].gpuaddr =
|
||||
priv->memdesc.physaddr + priv->bufs[index].offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
kgsl_gem_bind_gpu_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_kgsl_gem_bind_gpu *args = data;
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_kgsl_gem_object *priv;
|
||||
int ret = 0;
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
|
||||
|
||||
if (obj == NULL) {
|
||||
DRM_ERROR("Invalid GEM handle %x\n", args->handle);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
priv = obj->driver_private;
|
||||
|
||||
if (priv->bound++ == 0) {
|
||||
|
||||
if (!kgsl_gem_memory_allocated(obj)) {
|
||||
DRM_ERROR("Memory not allocated for this object\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = kgsl_gem_map(obj);
|
||||
|
||||
/* This is legacy behavior - use GET_BUFFERINFO instead */
|
||||
args->gpuptr = priv->bufs[0].gpuaddr;
|
||||
}
|
||||
out:
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate the memory and prepare it for CPU mapping */
|
||||
@ -1068,17 +903,18 @@ int kgsl_gem_kmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
struct drm_gem_object *obj = vma->vm_private_data;
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct drm_kgsl_gem_object *priv;
|
||||
unsigned long offset, pg;
|
||||
unsigned long offset;
|
||||
struct page *page;
|
||||
int i;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
priv = obj->driver_private;
|
||||
|
||||
offset = (unsigned long) vmf->virtual_address - vma->vm_start;
|
||||
pg = (unsigned long) priv->memdesc.hostptr + offset;
|
||||
i = offset >> PAGE_SHIFT;
|
||||
page = sg_page(&(priv->memdesc.sg[i]));
|
||||
|
||||
page = vmalloc_to_page((void *) pg);
|
||||
if (!page) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return VM_FAULT_SIGBUS;
|
||||
@ -1370,27 +1206,6 @@ wakeup_fence_entries(struct drm_kgsl_gem_object_fence *fence)
|
||||
fence->fence_id = ENTRY_NEEDS_CLEANUP; /* Mark it as needing cleanup */
|
||||
}
|
||||
|
||||
static int kgsl_ts_notifier_cb(struct notifier_block *blk,
|
||||
unsigned long code, void *_param)
|
||||
{
|
||||
struct drm_kgsl_gem_object_fence *fence;
|
||||
struct kgsl_device *device = kgsl_get_device(code);
|
||||
int i;
|
||||
|
||||
/* loop through the fences to see what things can be processed */
|
||||
|
||||
for (i = 0; i < DRM_KGSL_NUM_FENCE_ENTRIES; i++) {
|
||||
fence = &gem_buf_fence[i];
|
||||
if (!fence->ts_valid || fence->ts_device != code)
|
||||
continue;
|
||||
|
||||
if (kgsl_check_timestamp(device, fence->timestamp))
|
||||
wakeup_fence_entries(fence);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
kgsl_gem_lock_handle_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
@ -1583,7 +1398,7 @@ kgsl_gem_unlock_on_ts_ioctl(struct drm_device *dev, void *data,
|
||||
}
|
||||
|
||||
device = kgsl_get_device(ts_device);
|
||||
ts_done = kgsl_check_timestamp(device, args->timestamp);
|
||||
ts_done = kgsl_check_timestamp(device, NULL, args->timestamp);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
@ -1634,11 +1449,9 @@ struct drm_ioctl_desc kgsl_drm_ioctls[] = {
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features = DRIVER_USE_PLATFORM_DEVICE | DRIVER_GEM,
|
||||
.driver_features = DRIVER_GEM,
|
||||
.load = kgsl_drm_load,
|
||||
.unload = kgsl_drm_unload,
|
||||
.firstopen = kgsl_drm_firstopen,
|
||||
.lastclose = kgsl_drm_lastclose,
|
||||
.preclose = kgsl_drm_preclose,
|
||||
.suspend = kgsl_drm_suspend,
|
||||
.resume = kgsl_drm_resume,
|
||||
@ -1669,8 +1482,13 @@ int kgsl_drm_init(struct platform_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Only initialize once */
|
||||
if (kgsl_drm_inited == DRM_KGSL_INITED)
|
||||
return 0;
|
||||
|
||||
kgsl_drm_inited = DRM_KGSL_INITED;
|
||||
|
||||
driver.num_ioctls = DRM_ARRAY_SIZE(kgsl_drm_ioctls);
|
||||
driver.platform_device = dev;
|
||||
|
||||
INIT_LIST_HEAD(&kgsl_mem_list);
|
||||
|
||||
@ -1680,10 +1498,11 @@ int kgsl_drm_init(struct platform_device *dev)
|
||||
gem_buf_fence[i].fence_id = ENTRY_EMPTY;
|
||||
}
|
||||
|
||||
return drm_init(&driver);
|
||||
return drm_platform_init(&driver, dev);
|
||||
}
|
||||
|
||||
void kgsl_drm_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
kgsl_drm_inited = DRM_KGSL_NOT_INITED;
|
||||
drm_platform_exit(&driver, driver.kdriver.platform_device);
|
||||
}
|
||||
|
12
drivers/gpu/msm/kgsl_gpummu.c
Normal file → Executable file
12
drivers/gpu/msm/kgsl_gpummu.c
Normal file → Executable file
@ -356,8 +356,8 @@ err_ptpool_remove:
|
||||
int kgsl_gpummu_pt_equal(struct kgsl_pagetable *pt,
|
||||
unsigned int pt_base)
|
||||
{
|
||||
struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
|
||||
return pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
|
||||
struct kgsl_gpummu_pt *gpummu_pt = pt ? pt->priv : NULL;
|
||||
return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
|
||||
}
|
||||
|
||||
void kgsl_gpummu_destroy_pagetable(void *mmu_specific_pt)
|
||||
@ -385,14 +385,16 @@ kgsl_pt_map_set(struct kgsl_gpummu_pt *pt, uint32_t pte, uint32_t val)
|
||||
{
|
||||
uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
|
||||
|
||||
writel_relaxed(val, &baseptr[pte]);
|
||||
BUG_ON(pte*sizeof(uint32_t) >= pt->base.size);
|
||||
baseptr[pte] = val;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
kgsl_pt_map_get(struct kgsl_gpummu_pt *pt, uint32_t pte)
|
||||
{
|
||||
uint32_t *baseptr = (uint32_t *)pt->base.hostptr;
|
||||
return readl_relaxed(&baseptr[pte]) & GSL_PT_PAGE_ADDR_MASK;
|
||||
BUG_ON(pte*sizeof(uint32_t) >= pt->base.size);
|
||||
return baseptr[pte] & GSL_PT_PAGE_ADDR_MASK;
|
||||
}
|
||||
|
||||
static unsigned int kgsl_gpummu_pt_get_flags(struct kgsl_pagetable *pt,
|
||||
@ -683,7 +685,7 @@ kgsl_gpummu_map(void *mmu_specific_pt,
|
||||
flushtlb = 1;
|
||||
|
||||
for_each_sg(memdesc->sg, s, memdesc->sglen, i) {
|
||||
unsigned int paddr = sg_phys(s);
|
||||
unsigned int paddr = kgsl_get_sg_pa(s);
|
||||
unsigned int j;
|
||||
|
||||
/* Each sg entry might be multiple pages long */
|
||||
|
4
drivers/gpu/msm/kgsl_iommu.c
Normal file → Executable file
4
drivers/gpu/msm/kgsl_iommu.c
Normal file → Executable file
@ -34,8 +34,8 @@ struct kgsl_iommu {
|
||||
static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
|
||||
unsigned int pt_base)
|
||||
{
|
||||
struct iommu_domain *domain = pt->priv;
|
||||
return pt && pt_base && ((unsigned int)domain == pt_base);
|
||||
struct iommu_domain *domain = pt ? pt->priv : NULL;
|
||||
return domain && pt_base && ((unsigned int)domain == pt_base);
|
||||
}
|
||||
|
||||
static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
|
||||
|
11
drivers/gpu/msm/kgsl_mmu.c
Normal file → Executable file
11
drivers/gpu/msm/kgsl_mmu.c
Normal file → Executable file
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
|
||||
* Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
|
||||
/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -23,6 +22,7 @@
|
||||
#include "kgsl_mmu.h"
|
||||
#include "kgsl_device.h"
|
||||
#include "kgsl_sharedmem.h"
|
||||
#include "adreno_postmortem.h"
|
||||
|
||||
#define KGSL_MMU_ALIGN_SHIFT 13
|
||||
#define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
|
||||
@ -592,6 +592,12 @@ kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
|
||||
memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK,
|
||||
memdesc->size);
|
||||
|
||||
/*
|
||||
* Don't clear the gpuaddr on global mappings because they
|
||||
* may be in use by other pagetables
|
||||
*/
|
||||
if (!(memdesc->priv & KGSL_MEMFLAGS_GLOBAL))
|
||||
memdesc->gpuaddr = 0;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_mmu_unmap);
|
||||
@ -623,6 +629,7 @@ int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable,
|
||||
gpuaddr, memdesc->gpuaddr);
|
||||
goto error_unmap;
|
||||
}
|
||||
memdesc->priv |= KGSL_MEMFLAGS_GLOBAL;
|
||||
return result;
|
||||
error_unmap:
|
||||
kgsl_mmu_unmap(pagetable, memdesc);
|
||||
|
505
drivers/gpu/msm/kgsl_sharedmem.c
Normal file → Executable file
505
drivers/gpu/msm/kgsl_sharedmem.c
Normal file → Executable file
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
|
||||
* Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
|
||||
/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -11,9 +10,14 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/memory_alloc.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kmemleak.h>
|
||||
#include <linux/highmem.h>
|
||||
|
||||
#include "kgsl.h"
|
||||
#include "kgsl_sharedmem.h"
|
||||
@ -21,6 +25,59 @@
|
||||
#include "kgsl_device.h"
|
||||
#include "adreno_ringbuffer.h"
|
||||
|
||||
/* An attribute for showing per-process memory statistics */
|
||||
struct kgsl_mem_entry_attribute {
|
||||
struct attribute attr;
|
||||
int memtype;
|
||||
ssize_t (*show)(struct kgsl_process_private *priv,
|
||||
int type, char *buf);
|
||||
};
|
||||
|
||||
#define to_mem_entry_attr(a) \
|
||||
container_of(a, struct kgsl_mem_entry_attribute, attr)
|
||||
|
||||
#define __MEM_ENTRY_ATTR(_type, _name, _show) \
|
||||
{ \
|
||||
.attr = { .name = __stringify(_name), .mode = 0444 }, \
|
||||
.memtype = _type, \
|
||||
.show = _show, \
|
||||
}
|
||||
|
||||
/*
|
||||
* A structure to hold the attributes for a particular memory type.
|
||||
* For each memory type in each process we store the current and maximum
|
||||
* memory usage and display the counts in sysfs. This structure and
|
||||
* the following macro allow us to simplify the definition for those
|
||||
* adding new memory types
|
||||
*/
|
||||
|
||||
struct mem_entry_stats {
|
||||
int memtype;
|
||||
struct kgsl_mem_entry_attribute attr;
|
||||
struct kgsl_mem_entry_attribute max_attr;
|
||||
};
|
||||
|
||||
|
||||
#define MEM_ENTRY_STAT(_type, _name) \
|
||||
{ \
|
||||
.memtype = _type, \
|
||||
.attr = __MEM_ENTRY_ATTR(_type, _name, mem_entry_show), \
|
||||
.max_attr = __MEM_ENTRY_ATTR(_type, _name##_max, \
|
||||
mem_entry_max_show), \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* One page allocation for a guard region to protect against over-zealous
|
||||
* GPU pre-fetch
|
||||
*/
|
||||
|
||||
static struct page *kgsl_guard_page;
|
||||
|
||||
/**
|
||||
* Given a kobj, find the process structure attached to it
|
||||
*/
|
||||
|
||||
static struct kgsl_process_private *
|
||||
_get_priv_from_kobj(struct kobject *kobj)
|
||||
{
|
||||
@ -41,87 +98,109 @@ _get_priv_from_kobj(struct kobject *kobj)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* sharedmem / memory sysfs files */
|
||||
/**
|
||||
* Show the current amount of memory allocated for the given memtype
|
||||
*/
|
||||
|
||||
static ssize_t
|
||||
process_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
mem_entry_show(struct kgsl_process_private *priv, int type, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", priv->stats[type].cur);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the maximum memory allocated for the given memtype through the life of
|
||||
* the process
|
||||
*/
|
||||
|
||||
static ssize_t
|
||||
mem_entry_max_show(struct kgsl_process_private *priv, int type, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", priv->stats[type].max);
|
||||
}
|
||||
|
||||
|
||||
static void mem_entry_sysfs_release(struct kobject *kobj)
|
||||
{
|
||||
}
|
||||
|
||||
static ssize_t mem_entry_sysfs_show(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
struct kgsl_mem_entry_attribute *pattr = to_mem_entry_attr(attr);
|
||||
struct kgsl_process_private *priv;
|
||||
unsigned int val = 0;
|
||||
ssize_t ret;
|
||||
|
||||
mutex_lock(&kgsl_driver.process_mutex);
|
||||
priv = _get_priv_from_kobj(kobj);
|
||||
|
||||
if (priv == NULL) {
|
||||
mutex_unlock(&kgsl_driver.process_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strncmp(attr->attr.name, "user", 4))
|
||||
val = priv->stats.user;
|
||||
if (!strncmp(attr->attr.name, "user_max", 8))
|
||||
val = priv->stats.user_max;
|
||||
if (!strncmp(attr->attr.name, "mapped", 6))
|
||||
val = priv->stats.mapped;
|
||||
if (!strncmp(attr->attr.name, "mapped_max", 10))
|
||||
val = priv->stats.mapped_max;
|
||||
if (!strncmp(attr->attr.name, "flushes", 7))
|
||||
val = priv->stats.flushes;
|
||||
if (priv && pattr->show)
|
||||
ret = pattr->show(priv, pattr->memtype, buf);
|
||||
else
|
||||
ret = -EIO;
|
||||
|
||||
mutex_unlock(&kgsl_driver.process_mutex);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define KGSL_MEMSTAT_ATTR(_name, _show) \
|
||||
static struct kobj_attribute attr_##_name = \
|
||||
__ATTR(_name, 0444, _show, NULL)
|
||||
|
||||
KGSL_MEMSTAT_ATTR(user, process_show);
|
||||
KGSL_MEMSTAT_ATTR(user_max, process_show);
|
||||
KGSL_MEMSTAT_ATTR(mapped, process_show);
|
||||
KGSL_MEMSTAT_ATTR(mapped_max, process_show);
|
||||
KGSL_MEMSTAT_ATTR(flushes, process_show);
|
||||
|
||||
static struct attribute *process_attrs[] = {
|
||||
&attr_user.attr,
|
||||
&attr_user_max.attr,
|
||||
&attr_mapped.attr,
|
||||
&attr_mapped_max.attr,
|
||||
&attr_flushes.attr,
|
||||
NULL
|
||||
static const struct sysfs_ops mem_entry_sysfs_ops = {
|
||||
.show = mem_entry_sysfs_show,
|
||||
};
|
||||
|
||||
static struct attribute_group process_attr_group = {
|
||||
.attrs = process_attrs,
|
||||
static struct kobj_type ktype_mem_entry = {
|
||||
.sysfs_ops = &mem_entry_sysfs_ops,
|
||||
.default_attrs = NULL,
|
||||
.release = mem_entry_sysfs_release
|
||||
};
|
||||
|
||||
static struct mem_entry_stats mem_stats[] = {
|
||||
MEM_ENTRY_STAT(KGSL_MEM_ENTRY_KERNEL, kernel),
|
||||
#ifdef CONFIG_ANDROID_PMEM
|
||||
MEM_ENTRY_STAT(KGSL_MEM_ENTRY_PMEM, pmem),
|
||||
#endif
|
||||
#ifdef CONFIG_ASHMEM
|
||||
MEM_ENTRY_STAT(KGSL_MEM_ENTRY_ASHMEM, ashmem),
|
||||
#endif
|
||||
MEM_ENTRY_STAT(KGSL_MEM_ENTRY_USER, user),
|
||||
#ifdef CONFIG_ION
|
||||
MEM_ENTRY_STAT(KGSL_MEM_ENTRY_ION, ion),
|
||||
#endif
|
||||
};
|
||||
|
||||
void
|
||||
kgsl_process_uninit_sysfs(struct kgsl_process_private *private)
|
||||
{
|
||||
/* Remove the sysfs entry */
|
||||
if (private->kobj) {
|
||||
sysfs_remove_group(private->kobj, &process_attr_group);
|
||||
kobject_put(private->kobj);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mem_stats); i++) {
|
||||
sysfs_remove_file(&private->kobj, &mem_stats[i].attr.attr);
|
||||
sysfs_remove_file(&private->kobj,
|
||||
&mem_stats[i].max_attr.attr);
|
||||
}
|
||||
|
||||
kobject_put(&private->kobj);
|
||||
}
|
||||
|
||||
void
|
||||
kgsl_process_init_sysfs(struct kgsl_process_private *private)
|
||||
{
|
||||
unsigned char name[16];
|
||||
int i, ret;
|
||||
|
||||
/* Add a entry to the sysfs device */
|
||||
snprintf(name, sizeof(name), "%d", private->pid);
|
||||
private->kobj = kobject_create_and_add(name, kgsl_driver.prockobj);
|
||||
|
||||
/* sysfs failure isn't fatal, just annoying */
|
||||
if (private->kobj != NULL) {
|
||||
if (sysfs_create_group(private->kobj, &process_attr_group)) {
|
||||
kobject_put(private->kobj);
|
||||
private->kobj = NULL;
|
||||
}
|
||||
if (kobject_init_and_add(&private->kobj, &ktype_mem_entry,
|
||||
kgsl_driver.prockobj, name))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mem_stats); i++) {
|
||||
/* We need to check the value of sysfs_create_file, but we
|
||||
* don't really care if it passed or not */
|
||||
|
||||
ret = sysfs_create_file(&private->kobj,
|
||||
&mem_stats[i].attr.attr);
|
||||
ret = sysfs_create_file(&private->kobj,
|
||||
&mem_stats[i].max_attr.attr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,6 +214,10 @@ static int kgsl_drv_memstat_show(struct device *dev,
|
||||
val = kgsl_driver.stats.vmalloc;
|
||||
else if (!strncmp(attr->attr.name, "vmalloc_max", 11))
|
||||
val = kgsl_driver.stats.vmalloc_max;
|
||||
else if (!strncmp(attr->attr.name, "page_alloc", 10))
|
||||
val = kgsl_driver.stats.page_alloc;
|
||||
else if (!strncmp(attr->attr.name, "page_alloc_max", 14))
|
||||
val = kgsl_driver.stats.page_alloc_max;
|
||||
else if (!strncmp(attr->attr.name, "coherent", 8))
|
||||
val = kgsl_driver.stats.coherent;
|
||||
else if (!strncmp(attr->attr.name, "coherent_max", 12))
|
||||
@ -164,6 +247,8 @@ static int kgsl_drv_histogram_show(struct device *dev,
|
||||
|
||||
DEVICE_ATTR(vmalloc, 0444, kgsl_drv_memstat_show, NULL);
|
||||
DEVICE_ATTR(vmalloc_max, 0444, kgsl_drv_memstat_show, NULL);
|
||||
DEVICE_ATTR(page_alloc, 0444, kgsl_drv_memstat_show, NULL);
|
||||
DEVICE_ATTR(page_alloc_max, 0444, kgsl_drv_memstat_show, NULL);
|
||||
DEVICE_ATTR(coherent, 0444, kgsl_drv_memstat_show, NULL);
|
||||
DEVICE_ATTR(coherent_max, 0444, kgsl_drv_memstat_show, NULL);
|
||||
DEVICE_ATTR(mapped, 0444, kgsl_drv_memstat_show, NULL);
|
||||
@ -173,6 +258,8 @@ DEVICE_ATTR(histogram, 0444, kgsl_drv_histogram_show, NULL);
|
||||
static struct device_attribute *drv_attr_list[] = {
|
||||
&dev_attr_vmalloc,
|
||||
&dev_attr_vmalloc_max,
|
||||
&dev_attr_page_alloc,
|
||||
&dev_attr_page_alloc_max,
|
||||
&dev_attr_coherent,
|
||||
&dev_attr_coherent_max,
|
||||
&dev_attr_mapped,
|
||||
@ -216,7 +303,7 @@ static void outer_cache_range_op_sg(struct scatterlist *sg, int sglen, int op)
|
||||
int i;
|
||||
|
||||
for_each_sg(sg, s, sglen, i) {
|
||||
unsigned int paddr = sg_phys(s);
|
||||
unsigned int paddr = kgsl_get_sg_pa(s);
|
||||
_outer_cache_range_op(op, paddr, s->length);
|
||||
}
|
||||
}
|
||||
@ -227,17 +314,18 @@ static void outer_cache_range_op_sg(struct scatterlist *sg, int sglen, int op)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int kgsl_vmalloc_vmfault(struct kgsl_memdesc *memdesc,
|
||||
static int kgsl_page_alloc_vmfault(struct kgsl_memdesc *memdesc,
|
||||
struct vm_area_struct *vma,
|
||||
struct vm_fault *vmf)
|
||||
{
|
||||
unsigned long offset, pg;
|
||||
unsigned long offset;
|
||||
struct page *page;
|
||||
int i;
|
||||
|
||||
offset = (unsigned long) vmf->virtual_address - vma->vm_start;
|
||||
pg = (unsigned long) memdesc->hostptr + offset;
|
||||
|
||||
page = vmalloc_to_page((void *) pg);
|
||||
i = offset >> PAGE_SHIFT;
|
||||
page = sg_page(&memdesc->sg[i]);
|
||||
if (page == NULL)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
@ -247,15 +335,30 @@ static int kgsl_vmalloc_vmfault(struct kgsl_memdesc *memdesc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgsl_vmalloc_vmflags(struct kgsl_memdesc *memdesc)
|
||||
static int kgsl_page_alloc_vmflags(struct kgsl_memdesc *memdesc)
|
||||
{
|
||||
return VM_RESERVED | VM_DONTEXPAND;
|
||||
}
|
||||
|
||||
static void kgsl_vmalloc_free(struct kgsl_memdesc *memdesc)
|
||||
static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc)
|
||||
{
|
||||
int i = 0;
|
||||
struct scatterlist *sg;
|
||||
int sglen = memdesc->sglen;
|
||||
|
||||
/* Don't free the guard page if it was used */
|
||||
if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
|
||||
sglen--;
|
||||
|
||||
kgsl_driver.stats.page_alloc -= memdesc->size;
|
||||
|
||||
if (memdesc->hostptr) {
|
||||
vunmap(memdesc->hostptr);
|
||||
kgsl_driver.stats.vmalloc -= memdesc->size;
|
||||
vfree(memdesc->hostptr);
|
||||
}
|
||||
if (memdesc->sg)
|
||||
for_each_sg(memdesc->sg, sg, sglen, i)
|
||||
__free_page(sg_page(sg));
|
||||
}
|
||||
|
||||
static int kgsl_contiguous_vmflags(struct kgsl_memdesc *memdesc)
|
||||
@ -263,6 +366,48 @@ static int kgsl_contiguous_vmflags(struct kgsl_memdesc *memdesc)
|
||||
return VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
|
||||
}
|
||||
|
||||
/*
|
||||
* kgsl_page_alloc_map_kernel - Map the memory in memdesc to kernel address
|
||||
* space
|
||||
*
|
||||
* @memdesc - The memory descriptor which contains information about the memory
|
||||
*
|
||||
* Return: 0 on success else error code
|
||||
*/
|
||||
static int kgsl_page_alloc_map_kernel(struct kgsl_memdesc *memdesc)
|
||||
{
|
||||
if (!memdesc->hostptr) {
|
||||
pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
|
||||
struct page **pages = NULL;
|
||||
struct scatterlist *sg;
|
||||
int sglen = memdesc->sglen;
|
||||
int i;
|
||||
|
||||
/* Don't map the guard page if it exists */
|
||||
if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
|
||||
sglen--;
|
||||
|
||||
/* create a list of pages to call vmap */
|
||||
pages = vmalloc(sglen * sizeof(struct page *));
|
||||
if (!pages) {
|
||||
KGSL_CORE_ERR("vmalloc(%d) failed\n",
|
||||
sglen * sizeof(struct page *));
|
||||
return -ENOMEM;
|
||||
}
|
||||
for_each_sg(memdesc->sg, sg, sglen, i)
|
||||
pages[i] = sg_page(sg);
|
||||
memdesc->hostptr = vmap(pages, sglen,
|
||||
VM_IOREMAP, page_prot);
|
||||
KGSL_STATS_ADD(memdesc->size, kgsl_driver.stats.vmalloc,
|
||||
kgsl_driver.stats.vmalloc_max);
|
||||
vfree(pages);
|
||||
}
|
||||
if (!memdesc->hostptr)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc,
|
||||
struct vm_area_struct *vma,
|
||||
struct vm_fault *vmf)
|
||||
@ -302,12 +447,13 @@ static void kgsl_coherent_free(struct kgsl_memdesc *memdesc)
|
||||
}
|
||||
|
||||
/* Global - also used by kgsl_drm.c */
|
||||
struct kgsl_memdesc_ops kgsl_vmalloc_ops = {
|
||||
.free = kgsl_vmalloc_free,
|
||||
.vmflags = kgsl_vmalloc_vmflags,
|
||||
.vmfault = kgsl_vmalloc_vmfault,
|
||||
struct kgsl_memdesc_ops kgsl_page_alloc_ops = {
|
||||
.free = kgsl_page_alloc_free,
|
||||
.vmflags = kgsl_page_alloc_vmflags,
|
||||
.vmfault = kgsl_page_alloc_vmfault,
|
||||
.map_kernel_mem = kgsl_page_alloc_map_kernel,
|
||||
};
|
||||
EXPORT_SYMBOL(kgsl_vmalloc_ops);
|
||||
EXPORT_SYMBOL(kgsl_page_alloc_ops);
|
||||
|
||||
static struct kgsl_memdesc_ops kgsl_ebimem_ops = {
|
||||
.free = kgsl_ebimem_free,
|
||||
@ -341,47 +487,145 @@ void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op)
|
||||
EXPORT_SYMBOL(kgsl_cache_range_op);
|
||||
|
||||
static int
|
||||
_kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
|
||||
_kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
|
||||
struct kgsl_pagetable *pagetable,
|
||||
void *ptr, size_t size, unsigned int protflags)
|
||||
size_t size, unsigned int protflags)
|
||||
{
|
||||
int order, ret = 0;
|
||||
int i, order, ret = 0;
|
||||
int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
|
||||
int i;
|
||||
struct page **pages = NULL;
|
||||
pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
|
||||
void *ptr;
|
||||
|
||||
/*
|
||||
* Add guard page to the end of the allocation when the
|
||||
* IOMMU is in use.
|
||||
*/
|
||||
|
||||
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
|
||||
sglen++;
|
||||
|
||||
memdesc->size = size;
|
||||
memdesc->pagetable = pagetable;
|
||||
memdesc->priv = KGSL_MEMFLAGS_CACHED;
|
||||
memdesc->ops = &kgsl_vmalloc_ops;
|
||||
memdesc->hostptr = (void *) ptr;
|
||||
memdesc->ops = &kgsl_page_alloc_ops;
|
||||
|
||||
memdesc->sg = kgsl_sg_alloc(sglen);
|
||||
|
||||
memdesc->sg = kmalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL);
|
||||
if (memdesc->sg == NULL) {
|
||||
KGSL_CORE_ERR("vmalloc(%d) failed\n",
|
||||
sglen * sizeof(struct scatterlist));
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate space to store the list of pages to send to vmap.
|
||||
* This is an array of pointers so we can track 1024 pages per page of
|
||||
* allocation which means we can handle up to a 8MB buffer request with
|
||||
* two pages; well within the acceptable limits for using kmalloc.
|
||||
*/
|
||||
|
||||
pages = kmalloc(sglen * sizeof(struct page *), GFP_KERNEL);
|
||||
|
||||
if (pages == NULL) {
|
||||
KGSL_CORE_ERR("kmalloc (%d) failed\n",
|
||||
sglen * sizeof(struct page *));
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
kmemleak_not_leak(memdesc->sg);
|
||||
|
||||
memdesc->sglen = sglen;
|
||||
sg_init_table(memdesc->sg, sglen);
|
||||
|
||||
for (i = 0; i < memdesc->sglen; i++, ptr += PAGE_SIZE) {
|
||||
struct page *page = vmalloc_to_page(ptr);
|
||||
if (!page) {
|
||||
ret = -EINVAL;
|
||||
for (i = 0; i < PAGE_ALIGN(size) / PAGE_SIZE; i++) {
|
||||
|
||||
/*
|
||||
* Don't use GFP_ZERO here because it is faster to memset the
|
||||
* range ourselves (see below)
|
||||
*/
|
||||
|
||||
pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
|
||||
if (pages[i] == NULL) {
|
||||
ret = -ENOMEM;
|
||||
memdesc->sglen = i;
|
||||
goto done;
|
||||
}
|
||||
sg_set_page(&memdesc->sg[i], page, PAGE_SIZE, 0);
|
||||
|
||||
sg_set_page(&memdesc->sg[i], pages[i], PAGE_SIZE, 0);
|
||||
}
|
||||
|
||||
kgsl_cache_range_op(memdesc, KGSL_CACHE_OP_INV);
|
||||
/* ADd the guard page to the end of the sglist */
|
||||
|
||||
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) {
|
||||
/*
|
||||
* It doesn't matter if we use GFP_ZERO here, this never
|
||||
* gets mapped, and we only allocate it once in the life
|
||||
* of the system
|
||||
*/
|
||||
|
||||
if (kgsl_guard_page == NULL)
|
||||
kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
|
||||
__GFP_HIGHMEM);
|
||||
|
||||
if (kgsl_guard_page != NULL) {
|
||||
sg_set_page(&memdesc->sg[sglen - 1], kgsl_guard_page,
|
||||
PAGE_SIZE, 0);
|
||||
memdesc->flags |= KGSL_MEMDESC_GUARD_PAGE;
|
||||
} else
|
||||
memdesc->sglen--;
|
||||
}
|
||||
|
||||
/*
|
||||
* All memory that goes to the user has to be zeroed out before it gets
|
||||
* exposed to userspace. This means that the memory has to be mapped in
|
||||
* the kernel, zeroed (memset) and then unmapped. This also means that
|
||||
* the dcache has to be flushed to ensure coherency between the kernel
|
||||
* and user pages. We used to pass __GFP_ZERO to alloc_page which mapped
|
||||
* zeroed and unmaped each individual page, and then we had to turn
|
||||
* around and call flush_dcache_page() on that page to clear the caches.
|
||||
* This was killing us for performance. Instead, we found it is much
|
||||
* faster to allocate the pages without GFP_ZERO, map the entire range,
|
||||
* memset it, flush the range and then unmap - this results in a factor
|
||||
* of 4 improvement for speed for large buffers. There is a small
|
||||
* increase in speed for small buffers, but only on the order of a few
|
||||
* microseconds at best. The only downside is that there needs to be
|
||||
* enough temporary space in vmalloc to accomodate the map. This
|
||||
* shouldn't be a problem, but if it happens, fall back to a much slower
|
||||
* path
|
||||
*/
|
||||
|
||||
ptr = vmap(pages, i, VM_IOREMAP, page_prot);
|
||||
|
||||
if (ptr != NULL) {
|
||||
memset(ptr, 0, memdesc->size);
|
||||
dmac_flush_range(ptr, ptr + memdesc->size);
|
||||
vunmap(ptr);
|
||||
} else {
|
||||
int j;
|
||||
|
||||
/* Very, very, very slow path */
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
ptr = kmap_atomic(pages[j],KM_BOUNCE_READ);
|
||||
memset(ptr, 0, PAGE_SIZE);
|
||||
dmac_flush_range(ptr, ptr + PAGE_SIZE);
|
||||
kunmap_atomic(ptr,KM_BOUNCE_READ);
|
||||
}
|
||||
}
|
||||
|
||||
outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
|
||||
KGSL_CACHE_OP_FLUSH);
|
||||
|
||||
ret = kgsl_mmu_map(pagetable, memdesc, protflags);
|
||||
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
KGSL_STATS_ADD(size, kgsl_driver.stats.vmalloc,
|
||||
kgsl_driver.stats.vmalloc_max);
|
||||
KGSL_STATS_ADD(size, kgsl_driver.stats.page_alloc,
|
||||
kgsl_driver.stats.page_alloc_max);
|
||||
|
||||
order = get_order(size);
|
||||
|
||||
@ -389,6 +633,8 @@ _kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
|
||||
kgsl_driver.stats.histogram[order]++;
|
||||
|
||||
done:
|
||||
kfree(pages);
|
||||
|
||||
if (ret)
|
||||
kgsl_sharedmem_free(memdesc);
|
||||
|
||||
@ -396,51 +642,41 @@ done:
|
||||
}
|
||||
|
||||
int
|
||||
kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
|
||||
kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
|
||||
struct kgsl_pagetable *pagetable, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
int ret = 0;
|
||||
BUG_ON(size == 0);
|
||||
|
||||
size = ALIGN(size, PAGE_SIZE * 2);
|
||||
ptr = vmalloc(size);
|
||||
|
||||
if (ptr == NULL) {
|
||||
KGSL_CORE_ERR("vmalloc(%d) failed\n", size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return _kgsl_sharedmem_vmalloc(memdesc, pagetable, ptr, size,
|
||||
ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
|
||||
GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
|
||||
if (!ret)
|
||||
ret = kgsl_page_alloc_map_kernel(memdesc);
|
||||
if (ret)
|
||||
kgsl_sharedmem_free(memdesc);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_sharedmem_vmalloc);
|
||||
EXPORT_SYMBOL(kgsl_sharedmem_page_alloc);
|
||||
|
||||
int
|
||||
kgsl_sharedmem_vmalloc_user(struct kgsl_memdesc *memdesc,
|
||||
kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc,
|
||||
struct kgsl_pagetable *pagetable,
|
||||
size_t size, int flags)
|
||||
{
|
||||
void *ptr;
|
||||
unsigned int protflags;
|
||||
|
||||
BUG_ON(size == 0);
|
||||
ptr = vmalloc_user(size);
|
||||
|
||||
if (ptr == NULL) {
|
||||
KGSL_CORE_ERR("vmalloc_user(%d) failed: allocated=%d\n",
|
||||
size, kgsl_driver.stats.vmalloc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
protflags = GSL_PT_PAGE_RV;
|
||||
if (!(flags & KGSL_MEMFLAGS_GPUREADONLY))
|
||||
protflags |= GSL_PT_PAGE_WV;
|
||||
|
||||
return _kgsl_sharedmem_vmalloc(memdesc, pagetable, ptr, size,
|
||||
return _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
|
||||
protflags);
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_sharedmem_vmalloc_user);
|
||||
EXPORT_SYMBOL(kgsl_sharedmem_page_alloc_user);
|
||||
|
||||
int
|
||||
kgsl_sharedmem_alloc_coherent(struct kgsl_memdesc *memdesc, size_t size)
|
||||
@ -488,7 +724,7 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc)
|
||||
if (memdesc->ops && memdesc->ops->free)
|
||||
memdesc->ops->free(memdesc);
|
||||
|
||||
kfree(memdesc->sg);
|
||||
kgsl_sg_free(memdesc->sg, memdesc->sglen);
|
||||
|
||||
memset(memdesc, 0, sizeof(*memdesc));
|
||||
}
|
||||
@ -570,13 +806,17 @@ kgsl_sharedmem_readl(const struct kgsl_memdesc *memdesc,
|
||||
uint32_t *dst,
|
||||
unsigned int offsetbytes)
|
||||
{
|
||||
uint32_t *src;
|
||||
BUG_ON(memdesc == NULL || memdesc->hostptr == NULL || dst == NULL);
|
||||
WARN_ON(offsetbytes + sizeof(unsigned int) > memdesc->size);
|
||||
WARN_ON(offsetbytes % sizeof(uint32_t) != 0);
|
||||
if (offsetbytes % sizeof(uint32_t) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (offsetbytes + sizeof(unsigned int) > memdesc->size)
|
||||
WARN_ON(offsetbytes + sizeof(uint32_t) > memdesc->size);
|
||||
if (offsetbytes + sizeof(uint32_t) > memdesc->size)
|
||||
return -ERANGE;
|
||||
|
||||
*dst = readl_relaxed(memdesc->hostptr + offsetbytes);
|
||||
src = (uint32_t *)(memdesc->hostptr + offsetbytes);
|
||||
*dst = *src;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_sharedmem_readl);
|
||||
@ -586,12 +826,19 @@ kgsl_sharedmem_writel(const struct kgsl_memdesc *memdesc,
|
||||
unsigned int offsetbytes,
|
||||
uint32_t src)
|
||||
{
|
||||
uint32_t *dst;
|
||||
BUG_ON(memdesc == NULL || memdesc->hostptr == NULL);
|
||||
BUG_ON(offsetbytes + sizeof(unsigned int) > memdesc->size);
|
||||
WARN_ON(offsetbytes % sizeof(uint32_t) != 0);
|
||||
if (offsetbytes % sizeof(uint32_t) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
kgsl_cffdump_setmem(memdesc->physaddr + offsetbytes,
|
||||
src, sizeof(uint));
|
||||
writel_relaxed(src, memdesc->hostptr + offsetbytes);
|
||||
WARN_ON(offsetbytes + sizeof(uint32_t) > memdesc->size);
|
||||
if (offsetbytes + sizeof(uint32_t) > memdesc->size)
|
||||
return -ERANGE;
|
||||
kgsl_cffdump_setmem(memdesc->gpuaddr + offsetbytes,
|
||||
src, sizeof(uint32_t));
|
||||
dst = (uint32_t *)(memdesc->hostptr + offsetbytes);
|
||||
*dst = src;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_sharedmem_writel);
|
||||
@ -603,9 +850,39 @@ kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc, unsigned int offsetbytes,
|
||||
BUG_ON(memdesc == NULL || memdesc->hostptr == NULL);
|
||||
BUG_ON(offsetbytes + sizebytes > memdesc->size);
|
||||
|
||||
kgsl_cffdump_setmem(memdesc->physaddr + offsetbytes, value,
|
||||
kgsl_cffdump_setmem(memdesc->gpuaddr + offsetbytes, value,
|
||||
sizebytes);
|
||||
memset(memdesc->hostptr + offsetbytes, value, sizebytes);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_sharedmem_set);
|
||||
|
||||
/*
|
||||
* kgsl_sharedmem_map_vma - Map a user vma to physical memory
|
||||
*
|
||||
* @vma - The user vma to map
|
||||
* @memdesc - The memory descriptor which contains information about the
|
||||
* physical memory
|
||||
*
|
||||
* Return: 0 on success else error code
|
||||
*/
|
||||
int
|
||||
kgsl_sharedmem_map_vma(struct vm_area_struct *vma,
|
||||
const struct kgsl_memdesc *memdesc)
|
||||
{
|
||||
unsigned long addr = vma->vm_start;
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
int ret, i = 0;
|
||||
|
||||
if (!memdesc->sg || (size != memdesc->size) ||
|
||||
(memdesc->sglen != (size / PAGE_SIZE)))
|
||||
return -EINVAL;
|
||||
|
||||
for (; addr < vma->vm_end; addr += PAGE_SIZE, i++) {
|
||||
ret = vm_insert_page(vma, addr, sg_page(&memdesc->sg[i]));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_sharedmem_map_vma);
|
||||
|
82
drivers/gpu/msm/kgsl_sharedmem.h
Normal file → Executable file
82
drivers/gpu/msm/kgsl_sharedmem.h
Normal file → Executable file
@ -16,6 +16,8 @@
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/kmemleak.h>
|
||||
|
||||
/*
|
||||
* Convert a page to a physical address
|
||||
@ -31,20 +33,15 @@ struct kgsl_process_private;
|
||||
|
||||
/** Set if the memdesc describes cached memory */
|
||||
#define KGSL_MEMFLAGS_CACHED 0x00000001
|
||||
/** Set if the memdesc is mapped into all pagetables */
|
||||
#define KGSL_MEMFLAGS_GLOBAL 0x00000002
|
||||
|
||||
struct kgsl_memdesc_ops {
|
||||
int (*vmflags)(struct kgsl_memdesc *);
|
||||
int (*vmfault)(struct kgsl_memdesc *, struct vm_area_struct *,
|
||||
struct vm_fault *);
|
||||
void (*free)(struct kgsl_memdesc *memdesc);
|
||||
};
|
||||
extern struct kgsl_memdesc_ops kgsl_page_alloc_ops;
|
||||
|
||||
extern struct kgsl_memdesc_ops kgsl_vmalloc_ops;
|
||||
|
||||
int kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
|
||||
int kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
|
||||
struct kgsl_pagetable *pagetable, size_t size);
|
||||
|
||||
int kgsl_sharedmem_vmalloc_user(struct kgsl_memdesc *memdesc,
|
||||
int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc,
|
||||
struct kgsl_pagetable *pagetable,
|
||||
size_t size, int flags);
|
||||
|
||||
@ -80,19 +77,58 @@ void kgsl_process_uninit_sysfs(struct kgsl_process_private *private);
|
||||
int kgsl_sharedmem_init_sysfs(void);
|
||||
void kgsl_sharedmem_uninit_sysfs(void);
|
||||
|
||||
static inline unsigned int kgsl_get_sg_pa(struct scatterlist *sg)
|
||||
{
|
||||
/*
|
||||
* Try sg_dma_address first to support ion carveout
|
||||
* regions which do not work with sg_phys().
|
||||
*/
|
||||
unsigned int pa = sg_dma_address(sg);
|
||||
if (pa == 0)
|
||||
pa = sg_phys(sg);
|
||||
return pa;
|
||||
}
|
||||
|
||||
int
|
||||
kgsl_sharedmem_map_vma(struct vm_area_struct *vma,
|
||||
const struct kgsl_memdesc *memdesc);
|
||||
|
||||
/*
|
||||
* For relatively small sglists, it is preferable to use kzalloc
|
||||
* rather than going down the vmalloc rat hole. If the size of
|
||||
* the sglist is < PAGE_SIZE use kzalloc otherwise fallback to
|
||||
* vmalloc
|
||||
*/
|
||||
|
||||
static inline void *kgsl_sg_alloc(unsigned int sglen)
|
||||
{
|
||||
if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
|
||||
return kzalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL);
|
||||
else
|
||||
return vmalloc(sglen * sizeof(struct scatterlist));
|
||||
}
|
||||
|
||||
static inline void kgsl_sg_free(void *ptr, unsigned int sglen)
|
||||
{
|
||||
if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
|
||||
kfree(ptr);
|
||||
else
|
||||
vfree(ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
memdesc_sg_phys(struct kgsl_memdesc *memdesc,
|
||||
unsigned int physaddr, unsigned int size)
|
||||
{
|
||||
struct page *page = phys_to_page(physaddr);
|
||||
memdesc->sg = kgsl_sg_alloc(1);
|
||||
|
||||
memdesc->sg = kmalloc(sizeof(struct scatterlist) * 1, GFP_KERNEL);
|
||||
if (memdesc->sg == NULL)
|
||||
return -ENOMEM;
|
||||
kmemleak_not_leak(memdesc->sg);
|
||||
|
||||
memdesc->sglen = 1;
|
||||
sg_init_table(memdesc->sg, 1);
|
||||
sg_set_page(&memdesc->sg[0], page, size, 0);
|
||||
memdesc->sg[0].length = size;
|
||||
memdesc->sg[0].offset = 0;
|
||||
memdesc->sg[0].dma_address = physaddr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -100,11 +136,7 @@ static inline int
|
||||
kgsl_allocate(struct kgsl_memdesc *memdesc,
|
||||
struct kgsl_pagetable *pagetable, size_t size)
|
||||
{
|
||||
#ifdef CONFIG_MSM_KGSL_MMU
|
||||
return kgsl_sharedmem_vmalloc(memdesc, pagetable, size);
|
||||
#else
|
||||
return kgsl_sharedmem_ebimem(memdesc, pagetable, size);
|
||||
#endif
|
||||
return kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -112,21 +144,13 @@ kgsl_allocate_user(struct kgsl_memdesc *memdesc,
|
||||
struct kgsl_pagetable *pagetable,
|
||||
size_t size, unsigned int flags)
|
||||
{
|
||||
#ifdef CONFIG_MSM_KGSL_MMU
|
||||
return kgsl_sharedmem_vmalloc_user(memdesc, pagetable, size, flags);
|
||||
#else
|
||||
return kgsl_sharedmem_ebimem_user(memdesc, pagetable, size, flags);
|
||||
#endif
|
||||
return kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size, flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
kgsl_allocate_contiguous(struct kgsl_memdesc *memdesc, size_t size)
|
||||
{
|
||||
int ret = kgsl_sharedmem_alloc_coherent(memdesc, size);
|
||||
#ifndef CONFIG_MSM_KGSL_MMU
|
||||
if (!ret)
|
||||
memdesc->gpuaddr = memdesc->physaddr;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
548
include/linux/ion.h
Executable file
548
include/linux/ion.h
Executable file
@ -0,0 +1,548 @@
|
||||
/*
|
||||
* include/linux/ion.h
|
||||
*
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ION_H
|
||||
#define _LINUX_ION_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
|
||||
struct ion_handle;
|
||||
/**
|
||||
* enum ion_heap_types - list of all possible types of heaps
|
||||
* @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
|
||||
* @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
|
||||
* @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved
|
||||
* carveout heap, allocations are physically
|
||||
* contiguous
|
||||
* @ION_HEAP_END: helper for iterating over heaps
|
||||
*/
|
||||
enum ion_heap_type {
|
||||
ION_HEAP_TYPE_SYSTEM,
|
||||
ION_HEAP_TYPE_SYSTEM_CONTIG,
|
||||
ION_HEAP_TYPE_CARVEOUT,
|
||||
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
|
||||
are at the end of this enum */
|
||||
ION_NUM_HEAPS,
|
||||
};
|
||||
|
||||
#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM)
|
||||
#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
|
||||
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
|
||||
|
||||
|
||||
/**
|
||||
* These are the only ids that should be used for Ion heap ids.
|
||||
* The ids listed are the order in which allocation will be attempted
|
||||
* if specified. Don't swap the order of heap ids unless you know what
|
||||
* you are doing!
|
||||
*/
|
||||
|
||||
enum ion_heap_ids {
|
||||
ION_HEAP_SYSTEM_ID,
|
||||
ION_HEAP_SYSTEM_CONTIG_ID,
|
||||
ION_HEAP_EBI_ID,
|
||||
ION_HEAP_SMI_ID,
|
||||
ION_HEAP_ADSP_ID,
|
||||
ION_HEAP_AUDIO_ID,
|
||||
};
|
||||
|
||||
#define ION_KMALLOC_HEAP_NAME "kmalloc"
|
||||
#define ION_VMALLOC_HEAP_NAME "vmalloc"
|
||||
#define ION_EBI1_HEAP_NAME "EBI1"
|
||||
#define ION_ADSP_HEAP_NAME "adsp"
|
||||
#define ION_SMI_HEAP_NAME "smi"
|
||||
|
||||
#define CACHED 1
|
||||
#define UNCACHED 0
|
||||
|
||||
#define ION_CACHE_SHIFT 0
|
||||
|
||||
#define ION_SET_CACHE(__cache) ((__cache) << ION_CACHE_SHIFT)
|
||||
|
||||
#define ION_IS_CACHED(__flags) ((__flags) & (1 << ION_CACHE_SHIFT))
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/err.h>
|
||||
#include <mach/ion.h>
|
||||
struct ion_device;
|
||||
struct ion_heap;
|
||||
struct ion_mapper;
|
||||
struct ion_client;
|
||||
struct ion_buffer;
|
||||
|
||||
/* This should be removed some day when phys_addr_t's are fully
|
||||
plumbed in the kernel, and all instances of ion_phys_addr_t should
|
||||
be converted to phys_addr_t. For the time being many kernel interfaces
|
||||
do not accept phys_addr_t's that would have to */
|
||||
#define ion_phys_addr_t unsigned long
|
||||
|
||||
/**
|
||||
* struct ion_platform_heap - defines a heap in the given platform
|
||||
* @type: type of the heap from ion_heap_type enum
|
||||
* @id: unique identifier for heap. When allocating (lower numbers
|
||||
* will be allocated from first)
|
||||
* @name: used for debug purposes
|
||||
* @base: base address of heap in physical memory if applicable
|
||||
* @size: size of the heap in bytes if applicable
|
||||
*
|
||||
* Provided by the board file.
|
||||
*/
|
||||
struct ion_platform_heap {
|
||||
enum ion_heap_type type;
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
ion_phys_addr_t base;
|
||||
size_t size;
|
||||
enum ion_memory_types memory_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ion_platform_data - array of platform heaps passed from board file
|
||||
* @nr: number of structures in the array
|
||||
* @heaps: array of platform_heap structions
|
||||
*
|
||||
* Provided by the board file in the form of platform data to a platform device.
|
||||
*/
|
||||
struct ion_platform_data {
|
||||
int nr;
|
||||
struct ion_platform_heap heaps[];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ION
|
||||
|
||||
/**
|
||||
* ion_client_create() - allocate a client and returns it
|
||||
* @dev: the global ion device
|
||||
* @heap_mask: mask of heaps this client can allocate from
|
||||
* @name: used for debugging
|
||||
*/
|
||||
struct ion_client *ion_client_create(struct ion_device *dev,
|
||||
unsigned int heap_mask, const char *name);
|
||||
|
||||
/**
|
||||
* msm_ion_client_create - allocate a client using the ion_device specified in
|
||||
* drivers/gpu/ion/msm/msm_ion.c
|
||||
*
|
||||
* heap_mask and name are the same as ion_client_create, return values
|
||||
* are the same as ion_client_create.
|
||||
*/
|
||||
|
||||
struct ion_client *msm_ion_client_create(unsigned int heap_mask,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* ion_client_destroy() - free's a client and all it's handles
|
||||
* @client: the client
|
||||
*
|
||||
* Free the provided client and all it's resources including
|
||||
* any handles it is holding.
|
||||
*/
|
||||
void ion_client_destroy(struct ion_client *client);
|
||||
|
||||
/**
|
||||
* ion_alloc - allocate ion memory
|
||||
* @client: the client
|
||||
* @len: size of the allocation
|
||||
* @align: requested allocation alignment, lots of hardware blocks have
|
||||
* alignment requirements of some kind
|
||||
* @flags: mask of heaps to allocate from, if multiple bits are set
|
||||
* heaps will be tried in order from lowest to highest order bit
|
||||
*
|
||||
* Allocate memory in one of the heaps provided in heap mask and return
|
||||
* an opaque handle to it.
|
||||
*/
|
||||
struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
|
||||
size_t align, unsigned int flags);
|
||||
|
||||
/**
|
||||
* ion_free - free a handle
|
||||
* @client: the client
|
||||
* @handle: the handle to free
|
||||
*
|
||||
* Free the provided handle.
|
||||
*/
|
||||
void ion_free(struct ion_client *client, struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_phys - returns the physical address and len of a handle
|
||||
* @client: the client
|
||||
* @handle: the handle
|
||||
* @addr: a pointer to put the address in
|
||||
* @len: a pointer to put the length in
|
||||
*
|
||||
* This function queries the heap for a particular handle to get the
|
||||
* handle's physical address. It't output is only correct if
|
||||
* a heap returns physically contiguous memory -- in other cases
|
||||
* this api should not be implemented -- ion_map_dma should be used
|
||||
* instead. Returns -EINVAL if the handle is invalid. This has
|
||||
* no implications on the reference counting of the handle --
|
||||
* the returned value may not be valid if the caller is not
|
||||
* holding a reference.
|
||||
*/
|
||||
int ion_phys(struct ion_client *client, struct ion_handle *handle,
|
||||
ion_phys_addr_t *addr, size_t *len);
|
||||
|
||||
/**
|
||||
* ion_map_kernel - create mapping for the given handle
|
||||
* @client: the client
|
||||
* @handle: handle to map
|
||||
* @flags: flags for this mapping
|
||||
*
|
||||
* Map the given handle into the kernel and return a kernel address that
|
||||
* can be used to access this address. If no flags are specified, this
|
||||
* will return a non-secure uncached mapping.
|
||||
*/
|
||||
void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle,
|
||||
unsigned long flags);
|
||||
|
||||
/**
|
||||
* ion_unmap_kernel() - destroy a kernel mapping for a handle
|
||||
* @client: the client
|
||||
* @handle: handle to unmap
|
||||
*/
|
||||
void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_map_dma - create a dma mapping for a given handle
|
||||
* @client: the client
|
||||
* @handle: handle to map
|
||||
*
|
||||
* Return an sglist describing the given handle
|
||||
*/
|
||||
struct scatterlist *ion_map_dma(struct ion_client *client,
|
||||
struct ion_handle *handle,
|
||||
unsigned long flags);
|
||||
|
||||
/**
|
||||
* ion_unmap_dma() - destroy a dma mapping for a handle
|
||||
* @client: the client
|
||||
* @handle: handle to unmap
|
||||
*/
|
||||
void ion_unmap_dma(struct ion_client *client, struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_share() - given a handle, obtain a buffer to pass to other clients
|
||||
* @client: the client
|
||||
* @handle: the handle to share
|
||||
*
|
||||
* Given a handle, return a buffer, which exists in a global name
|
||||
* space, and can be passed to other clients. Should be passed into ion_import
|
||||
* to obtain a new handle for this buffer.
|
||||
*
|
||||
* NOTE: This function does do not an extra reference. The burden is on the
|
||||
* caller to make sure the buffer doesn't go away while it's being passed to
|
||||
* another client. That is, ion_free should not be called on this handle until
|
||||
* the buffer has been imported into the other client.
|
||||
*/
|
||||
struct ion_buffer *ion_share(struct ion_client *client,
|
||||
struct ion_handle *handle);
|
||||
|
||||
/**
|
||||
* ion_import() - given an buffer in another client, import it
|
||||
* @client: this blocks client
|
||||
* @buffer: the buffer to import (as obtained from ion_share)
|
||||
*
|
||||
* Given a buffer, add it to the client and return the handle to use to refer
|
||||
* to it further. This is called to share a handle from one kernel client to
|
||||
* another.
|
||||
*/
|
||||
struct ion_handle *ion_import(struct ion_client *client,
|
||||
struct ion_buffer *buffer);
|
||||
|
||||
/**
|
||||
* ion_import_fd() - given an fd obtained via ION_IOC_SHARE ioctl, import it
|
||||
* @client: this blocks client
|
||||
* @fd: the fd
|
||||
*
|
||||
* A helper function for drivers that will be recieving ion buffers shared
|
||||
* with them from userspace. These buffers are represented by a file
|
||||
* descriptor obtained as the return from the ION_IOC_SHARE ioctl.
|
||||
* This function coverts that fd into the underlying buffer, and returns
|
||||
* the handle to use to refer to it further.
|
||||
*/
|
||||
struct ion_handle *ion_import_fd(struct ion_client *client, int fd);
|
||||
|
||||
/**
|
||||
* ion_handle_get_flags - get the flags for a given handle
|
||||
*
|
||||
* @client - client who allocated the handle
|
||||
* @handle - handle to get the flags
|
||||
* @flags - pointer to store the flags
|
||||
*
|
||||
* Gets the current flags for a handle. These flags indicate various options
|
||||
* of the buffer (caching, security, etc.)
|
||||
*/
|
||||
int ion_handle_get_flags(struct ion_client *client, struct ion_handle *handle,
|
||||
unsigned long *flags);
|
||||
|
||||
#else
|
||||
static inline struct ion_client *ion_client_create(struct ion_device *dev,
|
||||
unsigned int heap_mask, const char *name)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct ion_client *msm_ion_client_create(unsigned int heap_mask,
|
||||
const char *name)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline void ion_client_destroy(struct ion_client *client) { }
|
||||
|
||||
static inline struct ion_handle *ion_alloc(struct ion_client *client,
|
||||
size_t len, size_t align, unsigned int flags)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline void ion_free(struct ion_client *client,
|
||||
struct ion_handle *handle) { }
|
||||
|
||||
|
||||
static inline int ion_phys(struct ion_client *client,
|
||||
struct ion_handle *handle, ion_phys_addr_t *addr, size_t *len)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void *ion_map_kernel(struct ion_client *client,
|
||||
struct ion_handle *handle, unsigned long flags)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline void ion_unmap_kernel(struct ion_client *client,
|
||||
struct ion_handle *handle) { }
|
||||
|
||||
static inline struct scatterlist *ion_map_dma(struct ion_client *client,
|
||||
struct ion_handle *handle, unsigned long flags)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline void ion_unmap_dma(struct ion_client *client,
|
||||
struct ion_handle *handle) { }
|
||||
|
||||
static inline struct ion_buffer *ion_share(struct ion_client *client,
|
||||
struct ion_handle *handle)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct ion_handle *ion_import(struct ion_client *client,
|
||||
struct ion_buffer *buffer)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct ion_handle *ion_import_fd(struct ion_client *client,
|
||||
int fd)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline int ion_handle_get_flags(struct ion_client *client,
|
||||
struct ion_handle *handle, unsigned long *flags)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_ION */
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/**
|
||||
* DOC: Ion Userspace API
|
||||
*
|
||||
* create a client by opening /dev/ion
|
||||
* most operations handled via following ioctls
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct ion_allocation_data - metadata passed from userspace for allocations
|
||||
* @len: size of the allocation
|
||||
* @align: required alignment of the allocation
|
||||
* @flags: flags passed to heap
|
||||
* @handle: pointer that will be populated with a cookie to use to refer
|
||||
* to this allocation
|
||||
*
|
||||
* Provided by userspace as an argument to the ioctl
|
||||
*/
|
||||
struct ion_allocation_data {
|
||||
size_t len;
|
||||
size_t align;
|
||||
unsigned int flags;
|
||||
struct ion_handle *handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair
|
||||
* @handle: a handle
|
||||
* @fd: a file descriptor representing that handle
|
||||
*
|
||||
* For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with
|
||||
* the handle returned from ion alloc, and the kernel returns the file
|
||||
* descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace
|
||||
* provides the file descriptor and the kernel returns the handle.
|
||||
*/
|
||||
struct ion_fd_data {
|
||||
struct ion_handle *handle;
|
||||
int fd;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ion_handle_data - a handle passed to/from the kernel
|
||||
* @handle: a handle
|
||||
*/
|
||||
struct ion_handle_data {
|
||||
struct ion_handle *handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ion_custom_data - metadata passed to/from userspace for a custom ioctl
|
||||
* @cmd: the custom ioctl function to call
|
||||
* @arg: additional data to pass to the custom ioctl, typically a user
|
||||
* pointer to a predefined structure
|
||||
*
|
||||
* This works just like the regular cmd and arg fields of an ioctl.
|
||||
*/
|
||||
struct ion_custom_data {
|
||||
unsigned int cmd;
|
||||
unsigned long arg;
|
||||
};
|
||||
|
||||
|
||||
/* struct ion_flush_data - data passed to ion for flushing caches
|
||||
*
|
||||
* @handle: handle with data to flush
|
||||
* @vaddr: userspace virtual address mapped with mmap
|
||||
* @offset: offset into the handle to flush
|
||||
* @length: length of handle to flush
|
||||
*
|
||||
* Performs cache operations on the handle. If p is the start address
|
||||
* of the handle, p + offset through p + offset + length will have
|
||||
* the cache operations performed
|
||||
*/
|
||||
struct ion_flush_data {
|
||||
struct ion_handle *handle;
|
||||
void *vaddr;
|
||||
unsigned int offset;
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
/* struct ion_flag_data - information about flags for this buffer
|
||||
*
|
||||
* @handle: handle to get flags from
|
||||
* @flags: flags of this handle
|
||||
*
|
||||
* Takes handle as an input and outputs the flags from the handle
|
||||
* in the flag field.
|
||||
*/
|
||||
struct ion_flag_data {
|
||||
struct ion_handle *handle;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
#define ION_IOC_MAGIC 'I'
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_ALLOC - allocate memory
|
||||
*
|
||||
* Takes an ion_allocation_data struct and returns it with the handle field
|
||||
* populated with the opaque handle for the allocation.
|
||||
*/
|
||||
#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \
|
||||
struct ion_allocation_data)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_FREE - free memory
|
||||
*
|
||||
* Takes an ion_handle_data struct and frees the handle.
|
||||
*/
|
||||
#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_MAP - get a file descriptor to mmap
|
||||
*
|
||||
* Takes an ion_fd_data struct with the handle field populated with a valid
|
||||
* opaque handle. Returns the struct with the fd field set to a file
|
||||
* descriptor open in the current address space. This file descriptor
|
||||
* can then be used as an argument to mmap.
|
||||
*/
|
||||
#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation
|
||||
*
|
||||
* Takes an ion_fd_data struct with the handle field populated with a valid
|
||||
* opaque handle. Returns the struct with the fd field set to a file
|
||||
* descriptor open in the current address space. This file descriptor
|
||||
* can then be passed to another process. The corresponding opaque handle can
|
||||
* be retrieved via ION_IOC_IMPORT.
|
||||
*/
|
||||
#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_IMPORT - imports a shared file descriptor
|
||||
*
|
||||
* Takes an ion_fd_data struct with the fd field populated with a valid file
|
||||
* descriptor obtained from ION_IOC_SHARE and returns the struct with the handle
|
||||
* filed set to the corresponding opaque handle.
|
||||
*/
|
||||
#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, int)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
|
||||
*
|
||||
* Takes the argument of the architecture specific ioctl to call and
|
||||
* passes appropriate userdata for that ioctl
|
||||
*/
|
||||
#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
|
||||
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_CLEAN_CACHES - clean the caches
|
||||
*
|
||||
* Clean the caches of the handle specified.
|
||||
*/
|
||||
#define ION_IOC_CLEAN_CACHES _IOWR(ION_IOC_MAGIC, 7, \
|
||||
struct ion_flush_data)
|
||||
/**
|
||||
* DOC: ION_MSM_IOC_INV_CACHES - invalidate the caches
|
||||
*
|
||||
* Invalidate the caches of the handle specified.
|
||||
*/
|
||||
#define ION_IOC_INV_CACHES _IOWR(ION_IOC_MAGIC, 8, \
|
||||
struct ion_flush_data)
|
||||
/**
|
||||
* DOC: ION_MSM_IOC_CLEAN_CACHES - clean and invalidate the caches
|
||||
*
|
||||
* Clean and invalidate the caches of the handle specified.
|
||||
*/
|
||||
#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MAGIC, 9, \
|
||||
struct ion_flush_data)
|
||||
|
||||
/**
|
||||
* DOC: ION_IOC_GET_FLAGS - get the flags of the handle
|
||||
*
|
||||
* Gets the flags of the current handle which indicate cachability,
|
||||
* secure state etc.
|
||||
*/
|
||||
#define ION_IOC_GET_FLAGS _IOWR(ION_IOC_MAGIC, 10, \
|
||||
struct ion_flag_data)
|
||||
#endif /* _LINUX_ION_H */
|
24
include/linux/msm_kgsl.h
Normal file → Executable file
24
include/linux/msm_kgsl.h
Normal file → Executable file
@ -42,6 +42,7 @@
|
||||
#define KGSL_CONTEXT_NO_GMEM_ALLOC 2
|
||||
#define KGSL_CONTEXT_SUBMIT_IB_LIST 4
|
||||
#define KGSL_CONTEXT_CTX_SWITCH 8
|
||||
#define KGSL_CONTEXT_PREAMBLE 16
|
||||
|
||||
/* Memory allocayion flags */
|
||||
#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000
|
||||
@ -58,6 +59,24 @@
|
||||
#define KGSL_FLAGS_RESERVED2 0x00000080
|
||||
#define KGSL_FLAGS_SOFT_RESET 0x00000100
|
||||
|
||||
/* Clock flags to show which clocks should be controled by a given platform */
|
||||
#define KGSL_CLK_SRC 0x00000001
|
||||
#define KGSL_CLK_CORE 0x00000002
|
||||
#define KGSL_CLK_IFACE 0x00000004
|
||||
#define KGSL_CLK_MEM 0x00000008
|
||||
#define KGSL_CLK_MEM_IFACE 0x00000010
|
||||
#define KGSL_CLK_AXI 0x00000020
|
||||
|
||||
/*
|
||||
* Reset status values for context
|
||||
*/
|
||||
enum kgsl_ctx_reset_stat {
|
||||
KGSL_CTX_STAT_NO_ERROR = 0x00000000,
|
||||
KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT = 0x00000001,
|
||||
KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT = 0x00000002,
|
||||
KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT = 0x00000003
|
||||
};
|
||||
|
||||
#define KGSL_MAX_PWRLEVELS 5
|
||||
|
||||
#define KGSL_CONVERT_TO_MBPS(val) \
|
||||
@ -74,7 +93,9 @@ enum kgsl_deviceid {
|
||||
enum kgsl_user_mem_type {
|
||||
KGSL_USER_MEM_TYPE_PMEM = 0x00000000,
|
||||
KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001,
|
||||
KGSL_USER_MEM_TYPE_ADDR = 0x00000002
|
||||
KGSL_USER_MEM_TYPE_ADDR = 0x00000002,
|
||||
KGSL_USER_MEM_TYPE_ION = 0x00000003,
|
||||
KGSL_USER_MEM_TYPE_MAX = 0x00000004,
|
||||
};
|
||||
|
||||
struct kgsl_devinfo {
|
||||
@ -132,6 +153,7 @@ enum kgsl_property_type {
|
||||
KGSL_PROP_MMU_ENABLE = 0x00000006,
|
||||
KGSL_PROP_INTERRUPT_WAITS = 0x00000007,
|
||||
KGSL_PROP_VERSION = 0x00000008,
|
||||
KGSL_PROP_GPU_RESET_STAT = 0x00000009
|
||||
};
|
||||
|
||||
struct kgsl_shadowprop {
|
||||
|
Loading…
x
Reference in New Issue
Block a user