diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index 03aafb89..4e47f900 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/include/mach/memory.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -12,7 +13,6 @@ * GNU General Public License for more details. * */ - #ifndef __ASM_ARCH_MEMORY_H #define __ASM_ARCH_MEMORY_H @@ -37,28 +37,41 @@ #define PHYS_OFFSET UL(0x10000000) #endif +#define MAX_PHYSMEM_BITS 32 +#define SECTION_SIZE_BITS 25 + #define HAS_ARCH_IO_REMAP_PFN_RANGE #define CONSISTENT_DMA_SIZE (4*SZ_1M) #ifndef __ASSEMBLY__ void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment); +unsigned long allocate_contiguous_ebi_nomap(unsigned long, unsigned long); void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long); void clean_caches(unsigned long, unsigned long, unsigned long); void invalidate_caches(unsigned long, unsigned long, unsigned long); +int platform_physical_remove_pages(unsigned long, unsigned long); +int platform_physical_add_pages(unsigned long, unsigned long); +int platform_physical_low_power_pages(unsigned long, unsigned long); #ifdef CONFIG_ARCH_MSM_ARM11 void write_to_strongly_ordered_memory(void); +void map_zero_page_strongly_ordered(void); + #include -#if defined(CONFIG_ARCH_MSM7227) +#ifdef CONFIG_ARCH_MSM7X27 #define arch_barrier_extra() do \ { \ write_to_strongly_ordered_memory(); \ } while (0) #else -#define arch_barrier_extra() do {} while (0) +#define arch_barrier_extra() do \ + { if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) \ + write_to_strongly_ordered_memory(); \ + } while (0) +#endif #endif #ifdef CONFIG_CACHE_L2X0 @@ -67,12 +80,17 @@ extern void l2x0_cache_flush_all(void); #define finish_arch_switch(prev) do { l2x0_cache_sync(); } while (0) #endif -#endif #endif #ifdef CONFIG_ARCH_MSM_SCORPION -#define arch_has_speculative_dfetch() 1 +#define arch_has_speculative_dfetch() 1 #endif #endif +/* these correspond to values known by the modem */ +#define MEMORY_DEEP_POWERDOWN 0 +#define MEMORY_SELF_REFRESH 1 +#define MEMORY_ACTIVE 2 + +#define NPA_MEMORY_NODE_NAME "/mem/ebi1/cs1" diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c index 111ddec5..7eabdc78 100644 --- a/arch/arm/mach-msm/memory.c +++ b/arch/arm/mach-msm/memory.c @@ -16,10 +16,19 @@ #include #include #include +#include +#include #include #include #include #include +#include +#include +#if defined(CONFIG_MSM_NPA_REMOTE) +#include "npa_remote.h" +#include +#include +#endif int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, unsigned long size, pgprot_t prot) @@ -34,7 +43,7 @@ int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, void *zero_page_strongly_ordered; -static void map_zero_page_strongly_ordered(void) +void map_zero_page_strongly_ordered(void) { if (zero_page_strongly_ordered) return; @@ -43,12 +52,15 @@ static void map_zero_page_strongly_ordered(void) ioremap_strongly_ordered(page_to_pfn(empty_zero_page) << PAGE_SHIFT, PAGE_SIZE); } +EXPORT_SYMBOL(map_zero_page_strongly_ordered); void write_to_strongly_ordered_memory(void) { map_zero_page_strongly_ordered(); *(int *)zero_page_strongly_ordered = 0; } +EXPORT_SYMBOL(write_to_strongly_ordered_memory); + void flush_axi_bus_buffer(void) { __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \ @@ -109,3 +121,57 @@ void invalidate_caches(unsigned long vstart, flush_axi_bus_buffer(); } + +void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment) +{ + void *unused_addr = NULL; + unsigned long addr, tmp_size, unused_size; + + /* Allocate maximum size needed, see where it ends up. + * Then free it -- in this path there are no other allocators + * so we can depend on getting the same address back + * when we allocate a smaller piece that is aligned + * at the end (if necessary) and the piece we really want, + * then free the unused first piece. + */ + + tmp_size = size + alignment - PAGE_SIZE; + addr = (unsigned long)alloc_bootmem(tmp_size); + free_bootmem(__pa(addr), tmp_size); + + unused_size = alignment - (addr % alignment); + if (unused_size) + unused_addr = alloc_bootmem(unused_size); + + addr = (unsigned long)alloc_bootmem(size); + if (unused_size) + free_bootmem(__pa(unused_addr), unused_size); + + return (void *)addr; +} + +int platform_physical_remove_pages(unsigned long start_pfn, + unsigned long nr_pages) +{ + return 0; +} + +int platform_physical_add_pages(unsigned long start_pfn, + unsigned long nr_pages) +{ + return 0; +} + +int platform_physical_low_power_pages(unsigned long start_pfn, + unsigned long nr_pages) +{ + return 0; +} + +unsigned long allocate_contiguous_ebi_nomap(unsigned long size, + unsigned long align) +{ + return _allocate_contiguous_memory_nomap(size, MEMTYPE_EBI0, + align, __builtin_return_address(0)); +} +EXPORT_SYMBOL(allocate_contiguous_ebi_nomap); diff --git a/arch/arm/mach-msm/nand_partitions.c b/arch/arm/mach-msm/nand_partitions.c index 89610b25..421a557c 100644 --- a/arch/arm/mach-msm/nand_partitions.c +++ b/arch/arm/mach-msm/nand_partitions.c @@ -4,6 +4,7 @@ * bootloader. * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -22,7 +23,7 @@ #include #include -#include +#include #include @@ -38,47 +39,26 @@ #define ATAG_MSM_PARTITION 0x4d534D70 /* MSMp */ -struct msm_ptbl_entry -{ +struct msm_ptbl_entry { char name[16]; __u32 offset; __u32 size; __u32 flags; }; -#define MSM_MAX_PARTITIONS 11 +#define MSM_MAX_PARTITIONS 8 static struct mtd_partition msm_nand_partitions[MSM_MAX_PARTITIONS]; static char msm_nand_names[MSM_MAX_PARTITIONS * 16]; extern struct flash_platform_data msm_nand_data; -int emmc_partition_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct mtd_partition *ptn = msm_nand_partitions; - char *p = page; - int i; - uint64_t offset; - uint64_t size; - - p += sprintf(p, "dev: size erasesize name\n"); - for (i = 0; i < MSM_MAX_PARTITIONS && ptn->name; i++, ptn++) { - offset = ptn->offset; - size = ptn->size; - p += sprintf(p, "mmcblk0p%llu: %08llx %08x \"%s\"\n", offset, size * 512, 512, ptn->name); - } - - return p - page; -} - static int __init parse_tag_msm_partition(const struct tag *tag) { struct mtd_partition *ptn = msm_nand_partitions; char *name = msm_nand_names; struct msm_ptbl_entry *entry = (void *) &tag->u; unsigned count, n; - unsigned have_kpanic = 0; count = (tag->hdr.size - 2) / (sizeof(struct msm_ptbl_entry) / sizeof(__u32)); @@ -90,9 +70,6 @@ static int __init parse_tag_msm_partition(const struct tag *tag) memcpy(name, entry->name, 15); name[15] = 0; - if (!strcmp(name, "kpanic")) - have_kpanic = 1; - ptn->name = name; ptn->offset = entry->offset; ptn->size = entry->size; @@ -102,42 +79,6 @@ static int __init parse_tag_msm_partition(const struct tag *tag) ptn++; } -#ifdef CONFIG_VIRTUAL_KPANIC_PARTITION - if (!have_kpanic) { - int i; - uint64_t kpanic_off = 0; - - if (count == MSM_MAX_PARTITIONS) { - printk("Cannot create virtual 'kpanic' partition\n"); - goto out; - } - - for (i = 0; i < count; i++) { - ptn = &msm_nand_partitions[i]; - if (!strcmp(ptn->name, CONFIG_VIRTUAL_KPANIC_SRC)) { - ptn->size -= CONFIG_VIRTUAL_KPANIC_PSIZE; - kpanic_off = ptn->offset + ptn->size; - break; - } - } - if (i == count) { - printk(KERN_ERR "Partition %s not found\n", - CONFIG_VIRTUAL_KPANIC_SRC); - goto out; - } - - ptn = &msm_nand_partitions[count]; - ptn->name ="kpanic"; - ptn->offset = kpanic_off; - ptn->size = CONFIG_VIRTUAL_KPANIC_PSIZE; - - printk("Virtual mtd partition '%s' created @%llx (%llu)\n", - ptn->name, ptn->offset, ptn->size); - - count++; - } -out: -#endif /* CONFIG_VIRTUAL_KPANIC_SRC */ msm_nand_data.nr_parts = count; msm_nand_data.parts = msm_nand_partitions; diff --git a/drivers/gpu/msm/Kconfig b/drivers/gpu/msm/Kconfig index 64cbc304..5852e269 100644 --- a/drivers/gpu/msm/Kconfig +++ b/drivers/gpu/msm/Kconfig @@ -64,22 +64,30 @@ config MSM_KGSL_DRM bool "Build a DRM interface for the MSM_KGSL driver" depends on MSM_KGSL && DRM -config MSM_KGSL_MMU +config MSM_KGSL_GPUMMU bool "Enable the GPU MMU in the MSM_KGSL driver" - depends on MSM_KGSL && MMU && !MSM_KGSL_CFF_DUMP + depends on MSM_KGSL && !MSM_KGSL_CFF_DUMP + default y + +config MSM_KGSL_IOMMU + bool "Enable the use of IOMMU in the MSM_KGSL driver" + depends on MSM_KGSL && MSM_IOMMU && !MSM_KGSL_GPUMMU && !MSM_KGSL_CFF_DUMP + +config MSM_KGSL_MMU + bool + depends on MSM_KGSL_GPUMMU || MSM_KGSL_IOMMU default y config KGSL_PER_PROCESS_PAGE_TABLE bool "Enable Per Process page tables for the KGSL driver" default n - depends on MSM_KGSL_MMU && !MSM_KGSL_DRM + depends on MSM_KGSL_GPUMMU && !MSM_KGSL_DRM ---help--- The MMU will use per process pagetables when enabled. config MSM_KGSL_PAGE_TABLE_SIZE hex "Size of pagetables" default 0xFFF0000 - depends on MSM_KGSL_MMU ---help--- Sets the pagetable size used by the MMU. The max value is 0xFFF0000 or (256M - 64K). @@ -97,7 +105,7 @@ config MSM_KGSL_PAGE_TABLE_COUNT config MSM_KGSL_MMU_PAGE_FAULT bool "Force the GPU MMU to page fault for unmapped regions" default y - depends on MSM_KGSL_MMU + depends on MSM_KGSL_GPUMMU config MSM_KGSL_DISABLE_SHADOW_WRITES bool "Disable register shadow writes for context switches" diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index c905bfec..f49e7164 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -4,17 +4,21 @@ msm_kgsl_core-y = \ kgsl.o \ kgsl_sharedmem.o \ kgsl_pwrctrl.o \ - kgsl_pwrscale.o + kgsl_pwrscale.o \ + kgsl_mmu.o \ + kgsl_gpummu.o msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o -msm_kgsl_core-$(CONFIG_MSM_KGSL_MMU) += kgsl_mmu.o msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o msm_kgsl_core-$(CONFIG_MSM_KGSL_DRM) += kgsl_drm.o +msm_kgsl_core-$(CONFIG_MSM_SCM) += kgsl_pwrscale_trustzone.o +msm_kgsl_core-$(CONFIG_MSM_SLEEP_STATS) += kgsl_pwrscale_idlestats.o msm_adreno-y += \ adreno_ringbuffer.o \ adreno_drawctxt.o \ adreno_postmortem.o \ + adreno_a2xx.o \ adreno.o msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o diff --git a/drivers/gpu/msm/a200_reg.h b/drivers/gpu/msm/a200_reg.h deleted file mode 100644 index 4df6e14c..00000000 --- a/drivers/gpu/msm/a200_reg.h +++ /dev/null @@ -1,448 +0,0 @@ -/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#ifndef __A200_REG_H -#define __A200_REG_H - -enum VGT_EVENT_TYPE { - VS_DEALLOC = 0, - PS_DEALLOC = 1, - VS_DONE_TS = 2, - PS_DONE_TS = 3, - CACHE_FLUSH_TS = 4, - CONTEXT_DONE = 5, - CACHE_FLUSH = 6, - VIZQUERY_START = 7, - VIZQUERY_END = 8, - SC_WAIT_WC = 9, - RST_PIX_CNT = 13, - RST_VTX_CNT = 14, - TILE_FLUSH = 15, - CACHE_FLUSH_AND_INV_TS_EVENT = 20, - ZPASS_DONE = 21, - CACHE_FLUSH_AND_INV_EVENT = 22, - PERFCOUNTER_START = 23, - PERFCOUNTER_STOP = 24, - VS_FETCH_DONE = 27, - FACENESS_FLUSH = 28, -}; - -enum COLORFORMATX { - COLORX_4_4_4_4 = 0, - COLORX_1_5_5_5 = 1, - COLORX_5_6_5 = 2, - COLORX_8 = 3, - COLORX_8_8 = 4, - COLORX_8_8_8_8 = 5, - COLORX_S8_8_8_8 = 6, - COLORX_16_FLOAT = 7, - COLORX_16_16_FLOAT = 8, - COLORX_16_16_16_16_FLOAT = 9, - COLORX_32_FLOAT = 10, - COLORX_32_32_FLOAT = 11, - COLORX_32_32_32_32_FLOAT = 12, - COLORX_2_3_3 = 13, - COLORX_8_8_8 = 14, -}; - -enum SURFACEFORMAT { - FMT_1_REVERSE = 0, - FMT_1 = 1, - FMT_8 = 2, - FMT_1_5_5_5 = 3, - FMT_5_6_5 = 4, - FMT_6_5_5 = 5, - FMT_8_8_8_8 = 6, - FMT_2_10_10_10 = 7, - FMT_8_A = 8, - FMT_8_B = 9, - FMT_8_8 = 10, - FMT_Cr_Y1_Cb_Y0 = 11, - FMT_Y1_Cr_Y0_Cb = 12, - FMT_5_5_5_1 = 13, - FMT_8_8_8_8_A = 14, - FMT_4_4_4_4 = 15, - FMT_10_11_11 = 16, - FMT_11_11_10 = 17, - FMT_DXT1 = 18, - FMT_DXT2_3 = 19, - FMT_DXT4_5 = 20, - FMT_24_8 = 22, - FMT_24_8_FLOAT = 23, - FMT_16 = 24, - FMT_16_16 = 25, - FMT_16_16_16_16 = 26, - FMT_16_EXPAND = 27, - FMT_16_16_EXPAND = 28, - FMT_16_16_16_16_EXPAND = 29, - FMT_16_FLOAT = 30, - FMT_16_16_FLOAT = 31, - FMT_16_16_16_16_FLOAT = 32, - FMT_32 = 33, - FMT_32_32 = 34, - FMT_32_32_32_32 = 35, - FMT_32_FLOAT = 36, - FMT_32_32_FLOAT = 37, - FMT_32_32_32_32_FLOAT = 38, - FMT_32_AS_8 = 39, - FMT_32_AS_8_8 = 40, - FMT_16_MPEG = 41, - FMT_16_16_MPEG = 42, - FMT_8_INTERLACED = 43, - FMT_32_AS_8_INTERLACED = 44, - FMT_32_AS_8_8_INTERLACED = 45, - FMT_16_INTERLACED = 46, - FMT_16_MPEG_INTERLACED = 47, - FMT_16_16_MPEG_INTERLACED = 48, - FMT_DXN = 49, - FMT_8_8_8_8_AS_16_16_16_16 = 50, - FMT_DXT1_AS_16_16_16_16 = 51, - FMT_DXT2_3_AS_16_16_16_16 = 52, - FMT_DXT4_5_AS_16_16_16_16 = 53, - FMT_2_10_10_10_AS_16_16_16_16 = 54, - FMT_10_11_11_AS_16_16_16_16 = 55, - FMT_11_11_10_AS_16_16_16_16 = 56, - FMT_32_32_32_FLOAT = 57, - FMT_DXT3A = 58, - FMT_DXT5A = 59, - FMT_CTX1 = 60, - FMT_DXT3A_AS_1_1_1_1 = 61 -}; - -#define REG_PERF_MODE_CNT 0x0 -#define REG_PERF_STATE_RESET 0x0 -#define REG_PERF_STATE_ENABLE 0x1 -#define REG_PERF_STATE_FREEZE 0x2 - -#define RB_EDRAM_INFO_EDRAM_SIZE_SIZE 4 -#define RB_EDRAM_INFO_EDRAM_MAPPING_MODE_SIZE 2 -#define RB_EDRAM_INFO_UNUSED0_SIZE 8 -#define RB_EDRAM_INFO_EDRAM_RANGE_SIZE 18 - -struct rb_edram_info_t { - unsigned int edram_size:RB_EDRAM_INFO_EDRAM_SIZE_SIZE; - unsigned int edram_mapping_mode:RB_EDRAM_INFO_EDRAM_MAPPING_MODE_SIZE; - unsigned int unused0:RB_EDRAM_INFO_UNUSED0_SIZE; - unsigned int edram_range:RB_EDRAM_INFO_EDRAM_RANGE_SIZE; -}; - -union reg_rb_edram_info { - unsigned int val; - 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 CP_RB_CNTL_RB_BUFSZ_SIZE 6 -#define CP_RB_CNTL_UNUSED0_SIZE 2 -#define CP_RB_CNTL_RB_BLKSZ_SIZE 6 -#define CP_RB_CNTL_UNUSED1_SIZE 2 -#define CP_RB_CNTL_BUF_SWAP_SIZE 2 -#define CP_RB_CNTL_UNUSED2_SIZE 2 -#define CP_RB_CNTL_RB_POLL_EN_SIZE 1 -#define CP_RB_CNTL_UNUSED3_SIZE 6 -#define CP_RB_CNTL_RB_NO_UPDATE_SIZE 1 -#define CP_RB_CNTL_UNUSED4_SIZE 3 -#define CP_RB_CNTL_RB_RPTR_WR_ENA_SIZE 1 - -struct cp_rb_cntl_t { - unsigned int rb_bufsz:CP_RB_CNTL_RB_BUFSZ_SIZE; - unsigned int unused0:CP_RB_CNTL_UNUSED0_SIZE; - unsigned int rb_blksz:CP_RB_CNTL_RB_BLKSZ_SIZE; - unsigned int unused1:CP_RB_CNTL_UNUSED1_SIZE; - unsigned int buf_swap:CP_RB_CNTL_BUF_SWAP_SIZE; - unsigned int unused2:CP_RB_CNTL_UNUSED2_SIZE; - unsigned int rb_poll_en:CP_RB_CNTL_RB_POLL_EN_SIZE; - unsigned int unused3:CP_RB_CNTL_UNUSED3_SIZE; - unsigned int rb_no_update:CP_RB_CNTL_RB_NO_UPDATE_SIZE; - unsigned int unused4:CP_RB_CNTL_UNUSED4_SIZE; - unsigned int rb_rptr_wr_ena:CP_RB_CNTL_RB_RPTR_WR_ENA_SIZE; -}; - -union reg_cp_rb_cntl { - unsigned int val:32; - struct cp_rb_cntl_t f; -}; - -#define RB_COLOR_INFO__COLOR_FORMAT_MASK 0x0000000fL -#define RB_COPY_DEST_INFO__COPY_DEST_FORMAT__SHIFT 0x00000004 - - -#define SQ_INT_CNTL__PS_WATCHDOG_MASK 0x00000001L -#define SQ_INT_CNTL__VS_WATCHDOG_MASK 0x00000002L - -#define RBBM_INT_CNTL__RDERR_INT_MASK 0x00000001L -#define RBBM_INT_CNTL__DISPLAY_UPDATE_INT_MASK 0x00000002L -#define RBBM_INT_CNTL__GUI_IDLE_INT_MASK 0x00080000L - -#define RBBM_STATUS__CMDFIFO_AVAIL_MASK 0x0000001fL -#define RBBM_STATUS__TC_BUSY_MASK 0x00000020L -#define RBBM_STATUS__HIRQ_PENDING_MASK 0x00000100L -#define RBBM_STATUS__CPRQ_PENDING_MASK 0x00000200L -#define RBBM_STATUS__CFRQ_PENDING_MASK 0x00000400L -#define RBBM_STATUS__PFRQ_PENDING_MASK 0x00000800L -#define RBBM_STATUS__VGT_BUSY_NO_DMA_MASK 0x00001000L -#define RBBM_STATUS__RBBM_WU_BUSY_MASK 0x00004000L -#define RBBM_STATUS__CP_NRT_BUSY_MASK 0x00010000L -#define RBBM_STATUS__MH_BUSY_MASK 0x00040000L -#define RBBM_STATUS__MH_COHERENCY_BUSY_MASK 0x00080000L -#define RBBM_STATUS__SX_BUSY_MASK 0x00200000L -#define RBBM_STATUS__TPC_BUSY_MASK 0x00400000L -#define RBBM_STATUS__SC_CNTX_BUSY_MASK 0x01000000L -#define RBBM_STATUS__PA_BUSY_MASK 0x02000000L -#define RBBM_STATUS__VGT_BUSY_MASK 0x04000000L -#define RBBM_STATUS__SQ_CNTX17_BUSY_MASK 0x08000000L -#define RBBM_STATUS__SQ_CNTX0_BUSY_MASK 0x10000000L -#define RBBM_STATUS__RB_CNTX_BUSY_MASK 0x40000000L -#define RBBM_STATUS__GUI_ACTIVE_MASK 0x80000000L - -#define CP_INT_CNTL__SW_INT_MASK 0x00080000L -#define CP_INT_CNTL__T0_PACKET_IN_IB_MASK 0x00800000L -#define CP_INT_CNTL__OPCODE_ERROR_MASK 0x01000000L -#define CP_INT_CNTL__PROTECTED_MODE_ERROR_MASK 0x02000000L -#define CP_INT_CNTL__RESERVED_BIT_ERROR_MASK 0x04000000L -#define CP_INT_CNTL__IB_ERROR_MASK 0x08000000L -#define CP_INT_CNTL__IB2_INT_MASK 0x20000000L -#define CP_INT_CNTL__IB1_INT_MASK 0x40000000L -#define CP_INT_CNTL__RB_INT_MASK 0x80000000L - -#define MASTER_INT_SIGNAL__MH_INT_STAT 0x00000020L -#define MASTER_INT_SIGNAL__SQ_INT_STAT 0x04000000L -#define MASTER_INT_SIGNAL__CP_INT_STAT 0x40000000L -#define MASTER_INT_SIGNAL__RBBM_INT_STAT 0x80000000L - -#define RB_EDRAM_INFO__EDRAM_SIZE_MASK 0x0000000fL -#define RB_EDRAM_INFO__EDRAM_RANGE_MASK 0xffffc000L - -#define MH_ARBITER_CONFIG__SAME_PAGE_GRANULARITY__SHIFT 0x00000006 -#define MH_ARBITER_CONFIG__L1_ARB_ENABLE__SHIFT 0x00000007 -#define MH_ARBITER_CONFIG__L1_ARB_HOLD_ENABLE__SHIFT 0x00000008 -#define MH_ARBITER_CONFIG__L2_ARB_CONTROL__SHIFT 0x00000009 -#define MH_ARBITER_CONFIG__PAGE_SIZE__SHIFT 0x0000000a -#define MH_ARBITER_CONFIG__TC_REORDER_ENABLE__SHIFT 0x0000000d -#define MH_ARBITER_CONFIG__TC_ARB_HOLD_ENABLE__SHIFT 0x0000000e -#define MH_ARBITER_CONFIG__IN_FLIGHT_LIMIT_ENABLE__SHIFT 0x0000000f -#define MH_ARBITER_CONFIG__IN_FLIGHT_LIMIT__SHIFT 0x00000010 -#define MH_ARBITER_CONFIG__CP_CLNT_ENABLE__SHIFT 0x00000016 -#define MH_ARBITER_CONFIG__VGT_CLNT_ENABLE__SHIFT 0x00000017 -#define MH_ARBITER_CONFIG__TC_CLNT_ENABLE__SHIFT 0x00000018 -#define MH_ARBITER_CONFIG__RB_CLNT_ENABLE__SHIFT 0x00000019 -#define MH_ARBITER_CONFIG__PA_CLNT_ENABLE__SHIFT 0x0000001a - -#define MH_MMU_CONFIG__RB_W_CLNT_BEHAVIOR__SHIFT 0x00000004 -#define MH_MMU_CONFIG__CP_W_CLNT_BEHAVIOR__SHIFT 0x00000006 -#define MH_MMU_CONFIG__CP_R0_CLNT_BEHAVIOR__SHIFT 0x00000008 -#define MH_MMU_CONFIG__CP_R1_CLNT_BEHAVIOR__SHIFT 0x0000000a -#define MH_MMU_CONFIG__CP_R2_CLNT_BEHAVIOR__SHIFT 0x0000000c -#define MH_MMU_CONFIG__CP_R3_CLNT_BEHAVIOR__SHIFT 0x0000000e -#define MH_MMU_CONFIG__CP_R4_CLNT_BEHAVIOR__SHIFT 0x00000010 -#define MH_MMU_CONFIG__VGT_R0_CLNT_BEHAVIOR__SHIFT 0x00000012 -#define MH_MMU_CONFIG__VGT_R1_CLNT_BEHAVIOR__SHIFT 0x00000014 -#define MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT 0x00000016 -#define MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT 0x00000018 - -#define CP_RB_CNTL__RB_BUFSZ__SHIFT 0x00000000 -#define CP_RB_CNTL__RB_BLKSZ__SHIFT 0x00000008 -#define CP_RB_CNTL__RB_POLL_EN__SHIFT 0x00000014 -#define CP_RB_CNTL__RB_NO_UPDATE__SHIFT 0x0000001b - -#define RB_COLOR_INFO__COLOR_FORMAT__SHIFT 0x00000000 -#define RB_EDRAM_INFO__EDRAM_MAPPING_MODE__SHIFT 0x00000004 -#define RB_EDRAM_INFO__EDRAM_RANGE__SHIFT 0x0000000e - -#define REG_CP_CSQ_IB1_STAT 0x01FE -#define REG_CP_CSQ_IB2_STAT 0x01FF -#define REG_CP_CSQ_RB_STAT 0x01FD -#define REG_CP_DEBUG 0x01FC -#define REG_CP_IB1_BASE 0x0458 -#define REG_CP_IB1_BUFSZ 0x0459 -#define REG_CP_IB2_BASE 0x045A -#define REG_CP_IB2_BUFSZ 0x045B -#define REG_CP_INT_ACK 0x01F4 -#define REG_CP_INT_CNTL 0x01F2 -#define REG_CP_INT_STATUS 0x01F3 -#define REG_CP_ME_CNTL 0x01F6 -#define REG_CP_ME_RAM_DATA 0x01FA -#define REG_CP_ME_RAM_WADDR 0x01F8 -#define REG_CP_ME_STATUS 0x01F7 -#define REG_CP_PFP_UCODE_ADDR 0x00C0 -#define REG_CP_PFP_UCODE_DATA 0x00C1 -#define REG_CP_QUEUE_THRESHOLDS 0x01D5 -#define REG_CP_RB_BASE 0x01C0 -#define REG_CP_RB_CNTL 0x01C1 -#define REG_CP_RB_RPTR 0x01C4 -#define REG_CP_RB_RPTR_ADDR 0x01C3 -#define REG_CP_RB_RPTR_WR 0x01C7 -#define REG_CP_RB_WPTR 0x01C5 -#define REG_CP_RB_WPTR_BASE 0x01C8 -#define REG_CP_RB_WPTR_DELAY 0x01C6 -#define REG_CP_STAT 0x047F -#define REG_CP_STATE_DEBUG_DATA 0x01ED -#define REG_CP_STATE_DEBUG_INDEX 0x01EC -#define REG_CP_ST_BASE 0x044D -#define REG_CP_ST_BUFSZ 0x044E - -#define REG_CP_PERFMON_CNTL 0x0444 -#define REG_CP_PERFCOUNTER_SELECT 0x0445 -#define REG_CP_PERFCOUNTER_LO 0x0446 -#define REG_CP_PERFCOUNTER_HI 0x0447 - -#define REG_RBBM_PERFCOUNTER1_SELECT 0x0395 -#define REG_RBBM_PERFCOUNTER1_HI 0x0398 -#define REG_RBBM_PERFCOUNTER1_LO 0x0397 - -#define REG_MASTER_INT_SIGNAL 0x03B7 - -#define REG_MH_ARBITER_CONFIG 0x0A40 -#define REG_MH_INTERRUPT_CLEAR 0x0A44 -#define REG_MH_INTERRUPT_MASK 0x0A42 -#define REG_MH_INTERRUPT_STATUS 0x0A43 -#define REG_MH_MMU_CONFIG 0x0040 -#define REG_MH_MMU_INVALIDATE 0x0045 -#define REG_MH_MMU_MPU_BASE 0x0046 -#define REG_MH_MMU_MPU_END 0x0047 -#define REG_MH_MMU_PAGE_FAULT 0x0043 -#define REG_MH_MMU_PT_BASE 0x0042 -#define REG_MH_MMU_TRAN_ERROR 0x0044 -#define REG_MH_MMU_VA_RANGE 0x0041 -#define REG_MH_CLNT_INTF_CTRL_CONFIG1 0x0A54 -#define REG_MH_CLNT_INTF_CTRL_CONFIG2 0x0A55 - -#define REG_PA_CL_VPORT_XSCALE 0x210F -#define REG_PA_CL_VPORT_ZOFFSET 0x2114 -#define REG_PA_CL_VPORT_ZSCALE 0x2113 -#define REG_PA_CL_CLIP_CNTL 0x2204 -#define REG_PA_CL_VTE_CNTL 0x2206 -#define REG_PA_SC_AA_MASK 0x2312 -#define REG_PA_SC_LINE_CNTL 0x2300 -#define REG_PA_SC_SCREEN_SCISSOR_BR 0x200F -#define REG_PA_SC_SCREEN_SCISSOR_TL 0x200E -#define REG_PA_SC_VIZ_QUERY 0x2293 -#define REG_PA_SC_VIZ_QUERY_STATUS 0x0C44 -#define REG_PA_SC_WINDOW_OFFSET 0x2080 -#define REG_PA_SC_WINDOW_SCISSOR_BR 0x2082 -#define REG_PA_SC_WINDOW_SCISSOR_TL 0x2081 -#define REG_PA_SU_FACE_DATA 0x0C86 -#define REG_PA_SU_POINT_SIZE 0x2280 -#define REG_PA_SU_LINE_CNTL 0x2282 -#define REG_PA_SU_POLY_OFFSET_BACK_OFFSET 0x2383 -#define REG_PA_SU_POLY_OFFSET_FRONT_SCALE 0x2380 -#define REG_PA_SU_SC_MODE_CNTL 0x2205 - -#define REG_PC_INDEX_OFFSET 0x2102 - -#define REG_RBBM_CNTL 0x003B -#define REG_RBBM_INT_ACK 0x03B6 -#define REG_RBBM_INT_CNTL 0x03B4 -#define REG_RBBM_INT_STATUS 0x03B5 -#define REG_RBBM_PATCH_RELEASE 0x0001 -#define REG_RBBM_PERIPHID1 0x03F9 -#define REG_RBBM_PERIPHID2 0x03FA -#define REG_RBBM_DEBUG 0x039B -#define REG_RBBM_DEBUG_OUT 0x03A0 -#define REG_RBBM_DEBUG_CNTL 0x03A1 -#define REG_RBBM_PM_OVERRIDE1 0x039C -#define REG_RBBM_PM_OVERRIDE2 0x039D -#define REG_RBBM_READ_ERROR 0x03B3 -#define REG_RBBM_SOFT_RESET 0x003C -#define REG_RBBM_STATUS 0x05D0 - -#define REG_RB_COLORCONTROL 0x2202 -#define REG_RB_COLOR_DEST_MASK 0x2326 -#define REG_RB_COLOR_MASK 0x2104 -#define REG_RB_COPY_CONTROL 0x2318 -#define REG_RB_DEPTHCONTROL 0x2200 -#define REG_RB_EDRAM_INFO 0x0F02 -#define REG_RB_MODECONTROL 0x2208 -#define REG_RB_SURFACE_INFO 0x2000 -#define REG_RB_SAMPLE_POS 0x220a - -#define REG_SCRATCH_ADDR 0x01DD -#define REG_SCRATCH_REG0 0x0578 -#define REG_SCRATCH_REG2 0x057A -#define REG_SCRATCH_UMSK 0x01DC - -#define REG_SQ_CF_BOOLEANS 0x4900 -#define REG_SQ_CF_LOOP 0x4908 -#define REG_SQ_GPR_MANAGEMENT 0x0D00 -#define REG_SQ_INST_STORE_MANAGMENT 0x0D02 -#define REG_SQ_INT_ACK 0x0D36 -#define REG_SQ_INT_CNTL 0x0D34 -#define REG_SQ_INT_STATUS 0x0D35 -#define REG_SQ_PROGRAM_CNTL 0x2180 -#define REG_SQ_PS_PROGRAM 0x21F6 -#define REG_SQ_VS_PROGRAM 0x21F7 -#define REG_SQ_WRAPPING_0 0x2183 -#define REG_SQ_WRAPPING_1 0x2184 - -#define REG_VGT_ENHANCE 0x2294 -#define REG_VGT_INDX_OFFSET 0x2102 -#define REG_VGT_MAX_VTX_INDX 0x2100 -#define REG_VGT_MIN_VTX_INDX 0x2101 - -#define REG_TP0_CHICKEN 0x0E1E -#define REG_TC_CNTL_STATUS 0x0E00 -#define REG_PA_SC_AA_CONFIG 0x2301 -#define REG_VGT_VERTEX_REUSE_BLOCK_CNTL 0x2316 -#define REG_SQ_INTERPOLATOR_CNTL 0x2182 -#define REG_RB_DEPTH_INFO 0x2002 -#define REG_COHER_DEST_BASE_0 0x2006 -#define REG_RB_FOG_COLOR 0x2109 -#define REG_RB_STENCILREFMASK_BF 0x210C -#define REG_PA_SC_LINE_STIPPLE 0x2283 -#define REG_SQ_PS_CONST 0x2308 -#define REG_RB_DEPTH_CLEAR 0x231D -#define REG_RB_SAMPLE_COUNT_CTL 0x2324 -#define REG_SQ_CONSTANT_0 0x4000 -#define REG_SQ_FETCH_0 0x4800 - -#define REG_MH_AXI_ERROR 0xA45 -#define REG_MH_DEBUG_CTRL 0xA4E -#define REG_MH_DEBUG_DATA 0xA4F -#define REG_COHER_BASE_PM4 0xA2A -#define REG_COHER_STATUS_PM4 0xA2B -#define REG_COHER_SIZE_PM4 0xA29 - -#endif /* __A200_REG_H */ diff --git a/drivers/gpu/msm/a220_reg.h b/drivers/gpu/msm/a220_reg.h deleted file mode 100644 index 9542a9ba..00000000 --- a/drivers/gpu/msm/a220_reg.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#ifndef __A205_REG_H -#define __A205_REG_H - -#define REG_LEIA_PC_INDX_OFFSET REG_VGT_INDX_OFFSET -#define REG_LEIA_PC_VERTEX_REUSE_BLOCK_CNTL REG_VGT_VERTEX_REUSE_BLOCK_CNTL -#define REG_LEIA_PC_MAX_VTX_INDX REG_VGT_MAX_VTX_INDX -#define REG_LEIA_GRAS_CONTROL 0x2210 -#define REG_LEIA_VSC_BIN_SIZE 0x0C01 -#define REG_LEIA_VSC_PIPE_DATA_LENGTH_7 0x0C1D - -#endif /*__A205_REG_H */ diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index db3d9782..61f14a4a 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -19,21 +19,26 @@ #include "kgsl.h" #include "kgsl_pwrscale.h" #include "kgsl_cffdump.h" +#include "kgsl_sharedmem.h" #include "adreno.h" #include "adreno_pm4types.h" #include "adreno_debugfs.h" #include "adreno_postmortem.h" -#include "a200_reg.h" +#include "a2xx_reg.h" +#include "kgsl_mmu.h" + +#define cpu_is_msm7x01() 0 +#define cpu_is_msm7x30() 0 +#define cpu_is_qsd8x50() 1 +#define cpu_is_msm8x60() 0 +#define cpu_is_msm8960() 0 +#define cpu_is_msm8930() 0 #define DRIVER_VERSION_MAJOR 3 #define DRIVER_VERSION_MINOR 1 -#define GSL_RBBM_INT_MASK \ - (RBBM_INT_CNTL__RDERR_INT_MASK | \ - RBBM_INT_CNTL__DISPLAY_UPDATE_INT_MASK) - /* Adreno MH arbiter config*/ #define ADRENO_CFG_MHARB \ (0x10 \ @@ -66,8 +71,7 @@ | (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT) \ | (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT)) -/* max msecs to wait for gpu to finish its operation(s) */ -#define MAX_WAITGPU_SECS (HZ + HZ/2) +static const struct kgsl_functable adreno_functable; static struct adreno_device device_3d0 = { .dev = { @@ -75,29 +79,24 @@ static struct adreno_device device_3d0 = { .id = KGSL_DEVICE_3D0, .ver_major = DRIVER_VERSION_MAJOR, .ver_minor = DRIVER_VERSION_MINOR, - .mmu = { - .config = ADRENO_MMU_CONFIG, + .mh = { + .mharb = ADRENO_CFG_MHARB, + /* Remove 1k boundary check in z470 to avoid a GPU + * hang. Notice that this solution won't work if + * both EBI and SMI are used + */ + .mh_intf_cfg1 = 0x00032f07, /* turn off memory protection unit by setting acceptable physical address range to include all pages. */ .mpu_base = 0x00000000, .mpu_range = 0xFFFFF000, - .reg = { - .config = REG_MH_MMU_CONFIG, - .mpu_base = REG_MH_MMU_MPU_BASE, - .mpu_end = REG_MH_MMU_MPU_END, - .va_range = REG_MH_MMU_VA_RANGE, - .pt_page = REG_MH_MMU_PT_BASE, - .page_fault = REG_MH_MMU_PAGE_FAULT, - .tran_error = REG_MH_MMU_TRAN_ERROR, - .invalidate = REG_MH_MMU_INVALIDATE, - .interrupt_mask = REG_MH_INTERRUPT_MASK, - .interrupt_status = REG_MH_INTERRUPT_STATUS, - .interrupt_clear = REG_MH_INTERRUPT_CLEAR, - .axi_error = REG_MH_AXI_ERROR, - }, + }, + .mmu = { + .config = ADRENO_MMU_CONFIG, }, .pwrctrl = { + .pwr_rail = PWR_RAIL_GRP_CLK, .regulator_name = "fs_gfx3d", .irq_name = KGSL_3D0_IRQ, .src_clk_name = "grp_src_clk", @@ -106,6 +105,14 @@ static struct adreno_device device_3d0 = { .state = KGSL_STATE_INIT, .active_cnt = 0, .iomemname = KGSL_3D0_REG_MEMORY, + .ftbl = &adreno_functable, +#ifdef CONFIG_HAS_EARLYSUSPEND + .display_off = { + .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING, + .suspend = kgsl_early_suspend_driver, + .resume = kgsl_late_resume_driver, + }, +#endif }, .gmemspace = { .gpu_base = 0, @@ -113,12 +120,39 @@ static struct adreno_device device_3d0 = { }, .pfp_fw = NULL, .pm4_fw = NULL, - .mharb = ADRENO_CFG_MHARB, }; -static void __devinit adreno_getfunctable(struct kgsl_functable *ftbl); +/* + * This is the master list of all GPU cores that are supported by this + * driver. + */ -static int adreno_gmeminit(struct adreno_device *adreno_dev) +#define ANY_ID (~0) + +static const struct { + enum adreno_gpurev gpurev; + unsigned int core, major, minor, patchid; + const char *pm4fw; + const char *pfpfw; + struct adreno_gpudev *gpudev; +} adreno_gpulist[] = { + { ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID, + "yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev }, + { ADRENO_REV_A205, 0, 1, 0, ANY_ID, + "yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev }, + { ADRENO_REV_A220, 2, 1, ANY_ID, ANY_ID, + "leia_pm4_470.fw", "leia_pfp_470.fw", &adreno_a2xx_gpudev }, + /* + * 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 }, + { ADRENO_REV_A225, 2, 2, ANY_ID, ANY_ID, + "a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev }, +}; + +static void adreno_gmeminit(struct adreno_device *adreno_dev) { struct kgsl_device *device = &adreno_dev->dev; union reg_rb_edram_info rb_edram_info; @@ -137,90 +171,27 @@ static int adreno_gmeminit(struct adreno_device *adreno_dev) rb_edram_info.val = 0; rb_edram_info.f.edram_size = edram_value; - if (!adreno_is_a220(adreno_dev)) - rb_edram_info.f.edram_mapping_mode = 0; /* EDRAM_MAP_UPPER */ + 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); - - return 0; } -static int adreno_gmemclose(struct kgsl_device *device) +static irqreturn_t adreno_isr(int irq, void *data) { - adreno_regwrite(device, REG_RB_EDRAM_INFO, 0x00000000); + irqreturn_t result; + struct kgsl_device *device = data; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - return 0; -} - -static void adreno_rbbm_intrcallback(struct kgsl_device *device) -{ - unsigned int status = 0; - unsigned int rderr = 0; - - adreno_regread_isr(device, REG_RBBM_INT_STATUS, &status); - - if (status & RBBM_INT_CNTL__RDERR_INT_MASK) { - union rbbm_read_error_u rerr; - adreno_regread_isr(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) - KGSL_DRV_WARN(device, - "rbbm read error interrupt: %08x\n", rderr); - else - KGSL_DRV_CRIT(device, - "rbbm read error interrupt: %08x\n", rderr); - } else if (status & RBBM_INT_CNTL__DISPLAY_UPDATE_INT_MASK) { - KGSL_DRV_INFO(device, "rbbm display update interrupt\n"); - } else if (status & RBBM_INT_CNTL__GUI_IDLE_INT_MASK) { - KGSL_DRV_INFO(device, "rbbm gui idle interrupt\n"); - } else { - KGSL_CMD_WARN(device, - "bad bits in REG_CP_INT_STATUS %08x\n", status); - } - - status &= GSL_RBBM_INT_MASK; - adreno_regwrite_isr(device, REG_RBBM_INT_ACK, status); -} - -irqreturn_t adreno_isr(int irq, void *data) -{ - irqreturn_t result = IRQ_NONE; - struct kgsl_device *device; - unsigned int status; - - device = (struct kgsl_device *) data; - - BUG_ON(device == NULL); - BUG_ON(device->regspace.sizebytes == 0); - BUG_ON(device->regspace.mmio_virt_base == 0); - - adreno_regread_isr(device, REG_MASTER_INT_SIGNAL, &status); - - if (status & MASTER_INT_SIGNAL__MH_INT_STAT) { - kgsl_mh_intrcallback(device); - result = IRQ_HANDLED; - } - - if (status & MASTER_INT_SIGNAL__CP_INT_STAT) { - kgsl_cp_intrcallback(device); - result = IRQ_HANDLED; - } - - if (status & MASTER_INT_SIGNAL__RBBM_INT_STAT) { - adreno_rbbm_intrcallback(device); - result = IRQ_HANDLED; - } + result = adreno_dev->gpudev->irq_handler(adreno_dev); if (device->requested_state == KGSL_STATE_NONE) { if (device->pwrctrl.nap_allowed == true) { device->requested_state = KGSL_STATE_NAP; queue_work(device->work_queue, &device->idle_check_ws); - } else if (device->pwrctrl.idle_pass == true) { + } else if (device->pwrscale.policy != NULL) { queue_work(device->work_queue, &device->idle_check_ws); } } @@ -231,7 +202,7 @@ irqreturn_t adreno_isr(int irq, void *data) return result; } -static int adreno_cleanup_pt(struct kgsl_device *device, +static void adreno_cleanup_pt(struct kgsl_device *device, struct kgsl_pagetable *pagetable) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); @@ -243,9 +214,7 @@ static int adreno_cleanup_pt(struct kgsl_device *device, kgsl_mmu_unmap(pagetable, &device->memstore); - kgsl_mmu_unmap(pagetable, &device->mmu.dummyspace); - - return 0; + kgsl_mmu_unmap(pagetable, &device->mmu.setstate_memory); } static int adreno_setup_pt(struct kgsl_device *device, @@ -255,12 +224,6 @@ static int adreno_setup_pt(struct kgsl_device *device, struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; - BUG_ON(rb->buffer_desc.physaddr == 0); - BUG_ON(rb->memptrs_desc.physaddr == 0); - BUG_ON(device->memstore.physaddr == 0); -#ifdef CONFIG_MSM_KGSL_MMU - BUG_ON(device->mmu.dummyspace.physaddr == 0); -#endif result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc, GSL_PT_PAGE_RV); if (result) @@ -276,7 +239,7 @@ static int adreno_setup_pt(struct kgsl_device *device, if (result) goto unmap_memptrs_desc; - result = kgsl_mmu_map_global(pagetable, &device->mmu.dummyspace, + result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory, GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); if (result) goto unmap_memstore_desc; @@ -296,7 +259,8 @@ error: return result; } -static int adreno_setstate(struct kgsl_device *device, uint32_t flags) +static void adreno_setstate(struct kgsl_device *device, + uint32_t flags) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned int link[32]; @@ -304,38 +268,36 @@ static int adreno_setstate(struct kgsl_device *device, uint32_t flags) int sizedwords = 0; unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */ -#ifndef CONFIG_MSM_KGSL_MMU - return 0; -#endif - /* if possible, set via command stream, - * otherwise set via direct register writes - */ + /* 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 (flags & KGSL_MMUFLAGS_PTUPDATE) { /* wait for graphics pipe to be idle */ - *cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); + *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1); *cmds++ = 0x00000000; /* set page table base */ - *cmds++ = pm4_type0_packet(REG_MH_MMU_PT_BASE, 1); - *cmds++ = device->mmu.hwpagetable->base.gpuaddr; + *cmds++ = cp_type0_packet(MH_MMU_PT_BASE, 1); + *cmds++ = kgsl_pt_get_base_addr( + device->mmu.hwpagetable); sizedwords += 4; } if (flags & KGSL_MMUFLAGS_TLBFLUSH) { if (!(flags & KGSL_MMUFLAGS_PTUPDATE)) { - *cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, + *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1); *cmds++ = 0x00000000; sizedwords += 2; } - *cmds++ = pm4_type0_packet(REG_MH_MMU_INVALIDATE, 1); + *cmds++ = cp_type0_packet(MH_MMU_INVALIDATE, 1); *cmds++ = mh_mmu_invalidate; sizedwords += 2; } if (flags & KGSL_MMUFLAGS_PTUPDATE && - !adreno_is_a220(adreno_dev)) { + adreno_is_a20x(adreno_dev)) { /* HW workaround: to resolve MMU page fault interrupts * caused by the VGT.It prevents the CP PFP from filling * the VGT DMA request fifo too early,thereby ensuring @@ -348,34 +310,36 @@ static int adreno_setstate(struct kgsl_device *device, uint32_t flags) * VGT DMA request fifo and prevent any further * vertex/bin updates from occurring until the wait * has finished. */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); + *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2); *cmds++ = (0x4 << 16) | (REG_PA_SU_SC_MODE_CNTL - 0x2000); *cmds++ = 0; /* disable faceness generation */ - *cmds++ = pm4_type3_packet(PM4_SET_BIN_BASE_OFFSET, 1); - *cmds++ = device->mmu.dummyspace.gpuaddr; - *cmds++ = pm4_type3_packet(PM4_DRAW_INDX_BIN, 6); + *cmds++ = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1); + *cmds++ = device->mmu.setstate_memory.gpuaddr; + *cmds++ = cp_type3_packet(CP_DRAW_INDX_BIN, 6); *cmds++ = 0; /* viz query info */ *cmds++ = 0x0003C004; /* draw indicator */ *cmds++ = 0; /* bin base */ *cmds++ = 3; /* bin size */ - *cmds++ = device->mmu.dummyspace.gpuaddr; /* dma base */ + *cmds++ = + device->mmu.setstate_memory.gpuaddr; /* dma base */ *cmds++ = 6; /* dma size */ - *cmds++ = pm4_type3_packet(PM4_DRAW_INDX_BIN, 6); + *cmds++ = cp_type3_packet(CP_DRAW_INDX_BIN, 6); *cmds++ = 0; /* viz query info */ *cmds++ = 0x0003C004; /* draw indicator */ *cmds++ = 0; /* bin base */ *cmds++ = 3; /* bin size */ /* dma base */ - *cmds++ = device->mmu.dummyspace.gpuaddr; + *cmds++ = device->mmu.setstate_memory.gpuaddr; *cmds++ = 6; /* dma size */ - *cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); + *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1); *cmds++ = 0x00000000; sizedwords += 21; } + if (flags & (KGSL_MMUFLAGS_PTUPDATE | KGSL_MMUFLAGS_TLBFLUSH)) { - *cmds++ = pm4_type3_packet(PM4_INVALIDATE_STATE, 1); + *cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1); *cmds++ = 0x7fff; /* invalidate all base pointers */ sizedwords += 2; } @@ -383,25 +347,13 @@ static int adreno_setstate(struct kgsl_device *device, uint32_t flags) adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords); } else { - if (flags & KGSL_MMUFLAGS_PTUPDATE) { - adreno_idle(device, KGSL_TIMEOUT_DEFAULT); - adreno_regwrite(device, REG_MH_MMU_PT_BASE, - device->mmu.hwpagetable->base.gpuaddr); - } - - if (flags & KGSL_MMUFLAGS_TLBFLUSH) { - adreno_regwrite(device, REG_MH_MMU_INVALIDATE, - mh_mmu_invalidate); - } + kgsl_mmu_device_setstate(device, flags); } - - return 0; } static unsigned int adreno_getchipid(struct kgsl_device *device) { - /* XXX: drewis edit: only for 8x50 */ unsigned int chipid = 0; unsigned int coreid, majorid, minorid, patchid, revid; @@ -409,57 +361,64 @@ adreno_getchipid(struct kgsl_device *device) adreno_regread(device, REG_RBBM_PERIPHID2, &majorid); adreno_regread(device, REG_RBBM_PATCH_RELEASE, &revid); - chipid = (coreid & 0xF) << 24; + /* + * adreno 22x gpus are indicated by coreid 2, + * but REG_RBBM_PERIPHID1 always contains 0 for this field + */ + if (cpu_is_msm8960() || cpu_is_msm8x60() || cpu_is_msm8930()) + chipid = 2 << 24; + else + chipid = (coreid & 0xF) << 24; chipid |= ((majorid >> 4) & 0xF) << 16; minorid = ((revid >> 0) & 0xFF); - patchid = 1; + patchid = ((revid >> 16) & 0xFF); + + /* 8x50 returns 0 for patch release, but it should be 1 */ + if (cpu_is_qsd8x50()) + patchid = 1; chipid |= (minorid << 8) | patchid; return chipid; } -/* all chipid fields are 8 bits wide so 256 won't occur in a real chipid */ -#define DONT_CARE 256 -static const struct { - unsigned int core; - unsigned int major; - unsigned int minor; - enum adreno_gpurev gpurev; -} gpurev_table[] = { - /* major and minor may be DONT_CARE, but core must not be */ - {0, 2, DONT_CARE, ADRENO_REV_A200}, - {0, 1, 0, ADRENO_REV_A205}, - {2, 1, DONT_CARE, ADRENO_REV_A220}, - {2, 2, DONT_CARE, ADRENO_REV_A225}, -}; - static inline bool _rev_match(unsigned int id, unsigned int entry) { - return (entry == DONT_CARE || entry == id); + return (entry == ANY_ID || entry == id); } -#undef DONT_CARE -enum adreno_gpurev adreno_get_rev(struct adreno_device *adreno_dev) +static void +adreno_identify_gpu(struct adreno_device *adreno_dev) { - enum adreno_gpurev gpurev = ADRENO_REV_UNKNOWN; - unsigned int i, core, major, minor; + unsigned int i, core, major, minor, patchid; + + adreno_dev->chip_id = adreno_getchipid(&adreno_dev->dev); + core = (adreno_dev->chip_id >> 24) & 0xff; major = (adreno_dev->chip_id >> 16) & 0xff; minor = (adreno_dev->chip_id >> 8) & 0xff; + patchid = (adreno_dev->chip_id & 0xff); - for (i = 0; i < ARRAY_SIZE(gpurev_table); i++) { - if (core == gpurev_table[i].core && - _rev_match(major, gpurev_table[i].major) && - _rev_match(minor, gpurev_table[i].minor)) { - gpurev = gpurev_table[i].gpurev; + for (i = 0; i < ARRAY_SIZE(adreno_gpulist); i++) { + if (core == adreno_gpulist[i].core && + _rev_match(major, adreno_gpulist[i].major) && + _rev_match(minor, adreno_gpulist[i].minor) && + _rev_match(patchid, adreno_gpulist[i].patchid)) break; - } } - return gpurev; + + if (i == ARRAY_SIZE(adreno_gpulist)) { + adreno_dev->gpurev = ADRENO_REV_UNKNOWN; + return; + } + + adreno_dev->gpurev = adreno_gpulist[i].gpurev; + adreno_dev->gpudev = adreno_gpulist[i].gpudev; + adreno_dev->pfp_fwfile = adreno_gpulist[i].pfpfw; + adreno_dev->pm4_fwfile = adreno_gpulist[i].pm4fw; } static int __devinit @@ -473,9 +432,9 @@ adreno_probe(struct platform_device *pdev) adreno_dev = ADRENO_DEVICE(device); device->parentdev = &pdev->dev; - init_completion(&device->recovery_gate); + adreno_dev->wait_timeout = 10000; /* default value in milliseconds */ - adreno_getfunctable(&device->ftbl); + init_completion(&device->recovery_gate); status = adreno_ringbuffer_init(device); if (status != 0) @@ -487,6 +446,9 @@ adreno_probe(struct platform_device *pdev) adreno_debugfs_init(device); + kgsl_pwrscale_init(device); + kgsl_pwrscale_attach_policy(device, ADRENO_DEFAULT_PWRSCALE_POLICY); + device->flags &= ~KGSL_FLAGS_SOFT_RESET; return 0; @@ -505,6 +467,9 @@ static int __devexit adreno_remove(struct platform_device *pdev) device = (struct kgsl_device *)pdev->id_entry->driver_data; adreno_dev = ADRENO_DEVICE(device); + kgsl_pwrscale_detach_policy(device); + kgsl_pwrscale_close(device); + adreno_ringbuffer_close(&adreno_dev->ringbuffer); kgsl_device_platform_remove(device); @@ -523,23 +488,38 @@ static int adreno_start(struct kgsl_device *device, unsigned int init_ram) /* Power up the device */ kgsl_pwrctrl_enable(device); + /* Identify the specific GPU */ + adreno_identify_gpu(adreno_dev); + + if (adreno_dev->gpurev == ADRENO_REV_UNKNOWN) { + KGSL_DRV_ERR(device, "Unknown chip ID %x\n", + adreno_dev->chip_id); + goto error_clk_off; + } + + if (adreno_is_a20x(adreno_dev)) { + /* + * the MH_CLNT_INTF_CTRL_CONFIG registers aren't present + * on older gpus + */ + device->mh.mh_intf_cfg1 = 0; + device->mh.mh_intf_cfg2 = 0; + } + + kgsl_mh_start(device); + if (kgsl_mmu_start(device)) goto error_clk_off; - adreno_dev->chip_id = adreno_getchipid(device); - /*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); - if (adreno_dev->chip_id == CHIP_REV_251) - adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0x000000ff); - else - adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xffffffff); + 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_a220(adreno_dev)) { + !adreno_is_a22x(adreno_dev)) { adreno_regwrite(device, REG_RBBM_SOFT_RESET, 0xFFFFFFFF); device->flags |= KGSL_FLAGS_SOFT_RESET; } else @@ -554,44 +534,39 @@ static int adreno_start(struct kgsl_device *device, unsigned int init_ram) adreno_regwrite(device, REG_RBBM_CNTL, 0x00004442); - adreno_regwrite(device, REG_MH_ARBITER_CONFIG, - adreno_dev->mharb); - - if (!adreno_is_a220(adreno_dev)) { - adreno_regwrite(device, - REG_MH_CLNT_INTF_CTRL_CONFIG1, 0x00030f27); - adreno_regwrite(device, - REG_MH_CLNT_INTF_CTRL_CONFIG2, 0x00472747); - } - - /* Remove 1k boundary check in z470 to avoid GPU hang. - Notice that, this solution won't work if both EBI and SMI are used */ - if (adreno_is_a220(adreno_dev)) { - adreno_regwrite(device, REG_MH_CLNT_INTF_CTRL_CONFIG1, - 0x00032f07); + 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); - adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0); - if (!adreno_is_a220(adreno_dev)) + 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, 0x000C0000); + adreno_regwrite(device, REG_RBBM_DEBUG, 0x00080000); - adreno_regwrite(device, REG_RBBM_INT_CNTL, GSL_RBBM_INT_MASK); + /* Make sure interrupts are disabled */ - /* make sure SQ 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_a220(adreno_dev)) + if (adreno_is_a22x(adreno_dev)) adreno_dev->gmemspace.sizebytes = SZ_512K; else adreno_dev->gmemspace.sizebytes = SZ_256K; @@ -608,9 +583,9 @@ static int adreno_start(struct kgsl_device *device, unsigned int init_ram) error_irq_off: kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); + kgsl_mmu_stop(device); error_clk_off: kgsl_pwrctrl_disable(device); - kgsl_mmu_stop(device); return status; } @@ -618,19 +593,15 @@ error_clk_off: static int adreno_stop(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - del_timer(&device->idle_timer); - adreno_regwrite(device, REG_RBBM_INT_CNTL, 0); adreno_dev->drawctxt_active = NULL; adreno_ringbuffer_stop(&adreno_dev->ringbuffer); - adreno_gmemclose(device); - kgsl_mmu_stop(device); - /* Disable the clocks before the power rail. */ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); + del_timer_sync(&device->idle_timer); /* Power down the device */ kgsl_pwrctrl_disable(device); @@ -786,7 +757,7 @@ static int adreno_getproperty(struct kgsl_device *device, devinfo.device_id = device->id+1; devinfo.chip_id = adreno_dev->chip_id; devinfo.mmu_enabled = kgsl_mmu_enabled(); - devinfo.gpu_id = adreno_get_rev(adreno_dev); + devinfo.gpu_id = adreno_dev->gpurev; devinfo.gmem_gpubaseaddr = adreno_dev->gmemspace. gpu_base; devinfo.gmem_sizebytes = adreno_dev->gmemspace. @@ -829,16 +800,13 @@ static int adreno_getproperty(struct kgsl_device *device, break; case KGSL_PROP_MMU_ENABLE: { -#ifdef CONFIG_MSM_KGSL_MMU - int mmuProp = 1; -#else - int mmuProp = 0; -#endif + int mmu_prop = kgsl_mmu_enabled(); + if (sizebytes != sizeof(int)) { status = -EINVAL; break; } - if (copy_to_user(value, &mmuProp, sizeof(mmuProp))) { + if (copy_to_user(value, &mmu_prop, sizeof(mmu_prop))) { status = -EFAULT; break; } @@ -872,7 +840,9 @@ int adreno_idle(struct kgsl_device *device, unsigned int timeout) struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; unsigned int rbbm_status; - unsigned long wait_time = jiffies + MAX_WAITGPU_SECS; + unsigned long wait_timeout = + msecs_to_jiffies(adreno_dev->wait_timeout); + unsigned long wait_time = jiffies + wait_timeout; kgsl_cffdump_regpoll(device->id, REG_RBBM_STATUS << 2, 0x00000000, 0x80000000); @@ -892,7 +862,7 @@ retry: } /* now, wait for the GPU to finish its operations */ - wait_time = jiffies + MAX_WAITGPU_SECS; + wait_time = jiffies + wait_timeout; while (time_before(jiffies, wait_time)) { adreno_regread(device, REG_RBBM_STATUS, &rbbm_status); if (rbbm_status == 0x110) @@ -902,7 +872,7 @@ retry: err: KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n"); if (!adreno_dump_and_recover(device)) { - wait_time = jiffies + MAX_WAITGPU_SECS; + wait_time = jiffies + wait_timeout; goto retry; } return -ETIMEDOUT; @@ -915,6 +885,7 @@ static unsigned int adreno_isidle(struct kgsl_device *device) struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; unsigned int rbbm_status; + WARN_ON(!(rb->flags & KGSL_FLAGS_STARTED)); if (rb->flags & KGSL_FLAGS_STARTED) { /* Is the ring buffer is empty? */ GSL_RB_GET_READPTR(rb, &rb->rptr); @@ -926,40 +897,20 @@ static unsigned int adreno_isidle(struct kgsl_device *device) status = true; } } else { - KGSL_DRV_ERR(device, "ringbuffer not started\n"); - BUG(); + /* if the ringbuffer isn't started we are VERY idle */ + status = true; } return status; } - -/******************************************************************/ -/* Caller must hold the driver mutex. */ -static int adreno_resume_context(struct kgsl_device *device) -{ - int status = 0; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - - if (device->pwrctrl.suspended_ctxt != NULL) { - adreno_drawctxt_switch(adreno_dev, - device->pwrctrl.suspended_ctxt, 0); - status = adreno_idle(device, 0); - - } - - return status; -} - -/******************************************************************/ /* Caller must hold the device mutex. */ static int adreno_suspend_context(struct kgsl_device *device) { int status = 0; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - /* save ctxt ptr and switch to NULL ctxt */ - device->pwrctrl.suspended_ctxt = adreno_dev->drawctxt_active; - if (device->pwrctrl.suspended_ctxt != NULL) { + /* switch to NULL ctxt */ + if (adreno_dev->drawctxt_active != NULL) { adreno_drawctxt_switch(adreno_dev, NULL, 0); status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT); } @@ -993,12 +944,8 @@ uint8_t *kgsl_sharedmem_convertaddr(struct kgsl_device *device, mutex_lock(&kgsl_driver.process_mutex); list_for_each_entry(priv, &kgsl_driver.process_list, list) { - if (pt_base != 0 - && priv->pagetable - && priv->pagetable->base.gpuaddr != pt_base) { + 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)); @@ -1025,42 +972,33 @@ uint8_t *kgsl_sharedmem_convertaddr(struct kgsl_device *device, return result; } -static void _adreno_regread(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value) +void adreno_regread(struct kgsl_device *device, unsigned int offsetwords, + unsigned int *value) { unsigned int *reg; BUG_ON(offsetwords*sizeof(uint32_t) >= device->regspace.sizebytes); reg = (unsigned int *)(device->regspace.mmio_virt_base + (offsetwords << 2)); + + if (!in_interrupt()) + kgsl_pre_hwaccess(device); + /*ensure this read finishes before the next one. * i.e. act like normal readl() */ *value = __raw_readl(reg); rmb(); } -void adreno_regread(struct kgsl_device *device, unsigned int offsetwords, - unsigned int *value) -{ - kgsl_pre_hwaccess(device); - _adreno_regread(device, offsetwords, value); -} - -void adreno_regread_isr(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value) -{ - _adreno_regread(device, offsetwords, value); -} - -static void _adreno_regwrite(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value) +void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords, + unsigned int value) { unsigned int *reg; BUG_ON(offsetwords*sizeof(uint32_t) >= device->regspace.sizebytes); + if (!in_interrupt()) + kgsl_pre_hwaccess(device); + kgsl_cffdump_regwrite(device->id, offsetwords << 2, value); reg = (unsigned int *)(device->regspace.mmio_virt_base + (offsetwords << 2)); @@ -1071,20 +1009,6 @@ static void _adreno_regwrite(struct kgsl_device *device, __raw_writel(value, reg); } -void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords, - unsigned int value) -{ - kgsl_pre_hwaccess(device); - _adreno_regwrite(device, offsetwords, value); -} - -void adreno_regwrite_isr(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value) -{ - _adreno_regwrite(device, offsetwords, value); -} - static int kgsl_check_interrupt_timestamp(struct kgsl_device *device, unsigned int timestamp) { @@ -1102,7 +1026,7 @@ static int kgsl_check_interrupt_timestamp(struct kgsl_device *device, kgsl_sharedmem_readl(&device->memstore, &ref_ts, KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts)); mb(); - if (timestamp_cmp(ref_ts, timestamp)) { + if (timestamp_cmp(ref_ts, timestamp) >= 0) { kgsl_sharedmem_writel(&device->memstore, KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts), timestamp); @@ -1121,7 +1045,7 @@ static int kgsl_check_interrupt_timestamp(struct kgsl_device *device, /* submit a dummy packet so that even if all * commands upto timestamp get executed we will still * get an interrupt */ - cmds[0] = pm4_type3_packet(PM4_NOP, 1); + cmds[0] = cp_type3_packet(CP_NOP, 1); cmds[1] = 0; adreno_ringbuffer_issuecmds(device, 0, &cmds[0], 2); } @@ -1132,15 +1056,18 @@ static int kgsl_check_interrupt_timestamp(struct kgsl_device *device, } /* - wait_io_event_interruptible_timeout checks for the exit condition before + wait_event_interruptible_timeout checks for the exit condition before placing a process in wait q. For conditional interrupts we expect the process to already be in its wait q when its exit condition checking function is called. */ -#define kgsl_wait_io_event_interruptible_timeout(wq, condition, timeout)\ +#define kgsl_wait_event_interruptible_timeout(wq, condition, timeout, io)\ ({ \ long __ret = timeout; \ - __wait_io_event_interruptible_timeout(wq, condition, __ret); \ + if (io) \ + __wait_io_event_interruptible_timeout(wq, condition, __ret);\ + else \ + __wait_event_interruptible_timeout(wq, condition, __ret);\ __ret; \ }) @@ -1150,11 +1077,15 @@ static int adreno_waittimestamp(struct kgsl_device *device, unsigned int msecs) { long status = 0; + uint io = 1; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; - if (timestamp != adreno_dev->ringbuffer.timestamp && - timestamp_cmp(timestamp, - adreno_dev->ringbuffer.timestamp)) { + /* Don't wait forever, set a max value for now */ + if (msecs == -1) + msecs = adreno_dev->wait_timeout; + + if (timestamp_cmp(timestamp, adreno_dev->ringbuffer.timestamp) > 0) { KGSL_DRV_ERR(device, "Cannot wait for invalid ts: %x, " "rb->timestamp: %x\n", timestamp, adreno_dev->ringbuffer.timestamp); @@ -1162,13 +1093,20 @@ static int adreno_waittimestamp(struct kgsl_device *device, 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; + } mutex_unlock(&device->mutex); /* We need to make sure that the process is placed in wait-q * before its condition is called */ - status = kgsl_wait_io_event_interruptible_timeout( + status = kgsl_wait_event_interruptible_timeout( device->wait_queue, kgsl_check_interrupt_timestamp(device, - timestamp), msecs_to_jiffies(msecs)); + timestamp), + msecs_to_jiffies(msecs), io); mutex_lock(&device->mutex); if (status > 0) @@ -1227,10 +1165,8 @@ static long adreno_ioctl(struct kgsl_device_private *dev_priv, context = kgsl_find_context(dev_priv, binbase->drawctxt_id); if (context) { - result = adreno_drawctxt_set_bin_base_offset( - dev_priv->device, - context, - binbase->offset); + adreno_drawctxt_set_bin_base_offset( + dev_priv->device, context, binbase->offset); } else { result = -EINVAL; KGSL_DRV_ERR(dev_priv->device, @@ -1299,33 +1235,36 @@ static void adreno_power_stats(struct kgsl_device *device, REG_PERF_MODE_CNT | REG_PERF_STATE_ENABLE); } -static void __devinit adreno_getfunctable(struct kgsl_functable *ftbl) +void adreno_irqctrl(struct kgsl_device *device, int state) { - if (ftbl == NULL) - return; - ftbl->device_regread = adreno_regread; - ftbl->device_regwrite = adreno_regwrite; - ftbl->device_regread_isr = adreno_regread_isr; - ftbl->device_regwrite_isr = adreno_regwrite_isr; - ftbl->device_setstate = adreno_setstate; - ftbl->device_idle = adreno_idle; - ftbl->device_isidle = adreno_isidle; - ftbl->device_suspend_context = adreno_suspend_context; - ftbl->device_resume_context = adreno_resume_context; - ftbl->device_start = adreno_start; - ftbl->device_stop = adreno_stop; - ftbl->device_getproperty = adreno_getproperty; - ftbl->device_waittimestamp = adreno_waittimestamp; - ftbl->device_readtimestamp = adreno_readtimestamp; - ftbl->device_issueibcmds = adreno_ringbuffer_issueibcmds; - ftbl->device_drawctxt_create = adreno_drawctxt_create; - ftbl->device_drawctxt_destroy = adreno_drawctxt_destroy; - ftbl->device_ioctl = adreno_ioctl; - ftbl->device_setup_pt = adreno_setup_pt; - ftbl->device_cleanup_pt = adreno_cleanup_pt; - ftbl->device_power_stats = adreno_power_stats; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + adreno_dev->gpudev->irq_control(adreno_dev, state); } +static const struct kgsl_functable adreno_functable = { + /* Mandatory functions */ + .regread = adreno_regread, + .regwrite = adreno_regwrite, + .idle = adreno_idle, + .isidle = adreno_isidle, + .suspend_context = adreno_suspend_context, + .start = adreno_start, + .stop = adreno_stop, + .getproperty = adreno_getproperty, + .waittimestamp = adreno_waittimestamp, + .readtimestamp = adreno_readtimestamp, + .issueibcmds = adreno_ringbuffer_issueibcmds, + .ioctl = adreno_ioctl, + .setup_pt = adreno_setup_pt, + .cleanup_pt = adreno_cleanup_pt, + .power_stats = adreno_power_stats, + .irqctrl = adreno_irqctrl, + /* Optional functions */ + .setstate = adreno_setstate, + .drawctxt_create = adreno_drawctxt_create, + .drawctxt_destroy = adreno_drawctxt_destroy, +}; + static struct platform_device_id adreno_id_table[] = { { DEVICE_3D0_NAME, (kernel_ulong_t)&device_3d0.dev, }, { }, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 74b3a845..51ee31a5 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1,34 +1,19 @@ /* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __ADRENO_H #define __ADRENO_H +#include "kgsl_device.h" #include "adreno_drawctxt.h" #include "adreno_ringbuffer.h" @@ -47,34 +32,11 @@ #define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0xDEADBEEF #define KGSL_CMD_IDENTIFIER 0xFEEDFACE -struct adreno_device { - struct kgsl_device dev; /* Must be first field in this struct */ - unsigned int chip_id; - struct kgsl_memregion gmemspace; - struct adreno_context *drawctxt_active; - wait_queue_head_t ib1_wq; - unsigned int *pfp_fw; - size_t pfp_fw_size; - unsigned int *pm4_fw; - size_t pm4_fw_size; - struct adreno_ringbuffer ringbuffer; - unsigned int mharb; -}; - -int adreno_idle(struct kgsl_device *device, unsigned int timeout); -void adreno_regread(struct kgsl_device *device, unsigned int offsetwords, - unsigned int *value); -void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords, - unsigned int value); -void adreno_regread_isr(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value); -void adreno_regwrite_isr(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); +#ifdef CONFIG_MSM_SCM +#define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_tz) +#else +#define ADRENO_DEFAULT_PWRSCALE_POLICY NULL +#endif enum adreno_gpurev { ADRENO_REV_UNKNOWN = 0, @@ -84,38 +46,84 @@ enum adreno_gpurev { ADRENO_REV_A225 = 225, }; -enum adreno_gpurev adreno_get_rev(struct adreno_device *adreno_dev); +struct adreno_gpudev; + +struct adreno_device { + struct kgsl_device dev; /* Must be first field in this struct */ + unsigned int chip_id; + enum adreno_gpurev gpurev; + struct kgsl_memregion gmemspace; + struct adreno_context *drawctxt_active; + const char *pfp_fwfile; + unsigned int *pfp_fw; + size_t pfp_fw_size; + const char *pm4_fwfile; + unsigned int *pm4_fw; + size_t pm4_fw_size; + struct adreno_ringbuffer ringbuffer; + unsigned int mharb; + struct adreno_gpudev *gpudev; + unsigned int wait_timeout; +}; + +struct adreno_gpudev { + int (*ctxt_gpustate_shadow)(struct adreno_device *, + struct adreno_context *); + int (*ctxt_gmem_shadow)(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); +}; + +extern struct adreno_gpudev adreno_a2xx_gpudev; + +int adreno_idle(struct kgsl_device *device, unsigned int timeout); +void adreno_regread(struct kgsl_device *device, unsigned int offsetwords, + unsigned int *value); +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); static inline int adreno_is_a200(struct adreno_device *adreno_dev) { - return (adreno_get_rev(adreno_dev) == ADRENO_REV_A200); + return (adreno_dev->gpurev == ADRENO_REV_A200); } static inline int adreno_is_a205(struct adreno_device *adreno_dev) { - return (adreno_get_rev(adreno_dev) == ADRENO_REV_A200); + return (adreno_dev->gpurev == ADRENO_REV_A200); } static inline int adreno_is_a20x(struct adreno_device *adreno_dev) { - enum adreno_gpurev rev = adreno_get_rev(adreno_dev); - return (rev == ADRENO_REV_A200 || rev == ADRENO_REV_A205); + return (adreno_dev->gpurev == ADRENO_REV_A200 || + adreno_dev->gpurev == ADRENO_REV_A205); } static inline int adreno_is_a220(struct adreno_device *adreno_dev) { - return (adreno_get_rev(adreno_dev) == ADRENO_REV_A220); + return (adreno_dev->gpurev == ADRENO_REV_A220); } static inline int adreno_is_a225(struct adreno_device *adreno_dev) { - return (adreno_get_rev(adreno_dev) == ADRENO_REV_A225); + return (adreno_dev->gpurev == ADRENO_REV_A225); } static inline int adreno_is_a22x(struct adreno_device *adreno_dev) { - enum adreno_gpurev rev = adreno_get_rev(adreno_dev); - return (rev == ADRENO_REV_A220 || rev == ADRENO_REV_A225); + return (adreno_dev->gpurev == ADRENO_REV_A220 || + adreno_dev->gpurev == ADRENO_REV_A225); } +static inline int adreno_is_a2xx(struct adreno_device *adreno_dev) +{ + return (adreno_dev->gpurev <= ADRENO_REV_A225); +} + + #endif /*__ADRENO_H */ diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 487e1f7f..c878a2c2 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -14,12 +14,13 @@ #include #include #include +#include #include "kgsl.h" #include "adreno_postmortem.h" #include "adreno.h" -#include "a200_reg.h" +#include "a2xx_reg.h" unsigned int kgsl_cff_dump_enable; int kgsl_pm_regs_enabled; @@ -130,7 +131,7 @@ static ssize_t kgsl_ib_dump_read( if (!ppos || !device || !kgsl_ib_base) return 0; - kgsl_regread(device, REG_MH_MMU_PT_BASE, &pt_base); + kgsl_regread(device, MH_MMU_PT_BASE, &pt_base); base_addr = kgsl_sharedmem_convertaddr(device, pt_base, kgsl_ib_base, &ib_memsize); @@ -395,8 +396,8 @@ static void kgsl_mh_reg_read_fill(struct kgsl_device *device, int i, int j; for (j = 0; j < linec; ++j) { - kgsl_regwrite(device, REG_MH_DEBUG_CTRL, i+j); - kgsl_regread(device, REG_MH_DEBUG_DATA, vals+j); + kgsl_regwrite(device, MH_DEBUG_CTRL, i+j); + kgsl_regread(device, MH_DEBUG_DATA, vals+j); } } @@ -420,6 +421,8 @@ static const struct file_operations kgsl_mh_debug_fops = { void adreno_debugfs_init(struct kgsl_device *device) { + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + if (!device->d_debugfs || IS_ERR(device->d_debugfs)) return; @@ -435,6 +438,8 @@ void adreno_debugfs_init(struct kgsl_device *device) &kgsl_mh_debug_fops); debugfs_create_file("cff_dump", 0644, device->d_debugfs, device, &kgsl_cff_dump_enable_fops); + debugfs_create_u32("wait_timeout", 0644, device->d_debugfs, + &adreno_dev->wait_timeout); /* Create post mortem control files */ diff --git a/drivers/gpu/msm/adreno_debugfs.h b/drivers/gpu/msm/adreno_debugfs.h index 680eb849..0356ac6e 100644 --- a/drivers/gpu/msm/adreno_debugfs.h +++ b/drivers/gpu/msm/adreno_debugfs.h @@ -1,29 +1,13 @@ /* Copyright (c) 2002,2008-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __ADRENO_DEBUGFS_H diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index ab28b0d2..b7b0ea46 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -10,157 +10,50 @@ * GNU General Public License for more details. * */ + #include #include "kgsl.h" - +#include "kgsl_sharedmem.h" #include "adreno.h" -#include "adreno_pm4types.h" -#include "adreno_drawctxt.h" -/* - * - * Memory Map for Register, Constant & Instruction Shadow, and Command Buffers - * (34.5KB) - * - * +---------------------+------------+-------------+---+---------------------+ - * | ALU Constant Shadow | Reg Shadow | C&V Buffers |Tex| Shader Instr Shadow | - * +---------------------+------------+-------------+---+---------------------+ - * ________________________________/ \____________________ - * / | - * +--------------+-----------+------+-----------+------------------------+ - * | Restore Regs | Save Regs | Quad | Gmem Save | Gmem Restore | unused | - * +--------------+-----------+------+-----------+------------------------+ - * - * 8K - ALU Constant Shadow (8K aligned) - * 4K - H/W Register Shadow (8K aligned) - * 4K - Command and Vertex Buffers - * - Indirect command buffer : Const/Reg restore - * - includes Loop & Bool const shadows - * - Indirect command buffer : Const/Reg save - * - Quad vertices & texture coordinates - * - Indirect command buffer : Gmem save - * - Indirect command buffer : Gmem restore - * - Unused (padding to 8KB boundary) - * <1K - Texture Constant Shadow (768 bytes) (8K aligned) - * 18K - Shader Instruction Shadow - * - 6K vertex (32 byte aligned) - * - 6K pixel (32 byte aligned) - * - 6K shared (32 byte aligned) - * - * Note: Reading constants into a shadow, one at a time using REG_TO_MEM, takes - * 3 DWORDS per DWORD transfered, plus 1 DWORD for the shadow, for a total of - * 16 bytes per constant. If the texture constants were transfered this way, - * the Command & Vertex Buffers section would extend past the 16K boundary. - * By moving the texture constant shadow area to start at 16KB boundary, we - * only require approximately 40 bytes more memory, but are able to use the - * LOAD_CONSTANT_CONTEXT shadowing feature for the textures, speeding up - * context switching. - * - * [Using LOAD_CONSTANT_CONTEXT shadowing feature for the Loop and/or Bool - * constants would require an additional 8KB each, for alignment.] - * - */ - -/* Constants */ - -#define ALU_CONSTANTS 2048 /* DWORDS */ -#define NUM_REGISTERS 1024 /* DWORDS */ -#ifdef CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES -#define CMD_BUFFER_LEN 9216 /* DWORDS */ -#else -#define CMD_BUFFER_LEN 3072 /* DWORDS */ -#endif -#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 */ - -#if defined(PM4_IM_STORE) -/* 96-bit instructions */ -#define SHADER_INSTRUCT (1<= 0x10000) { - exp += 16; - u >>= 16; - } - if (u >= 0x100) { - exp += 8; - u >>= 8; - } - if (u >= 0x10) { - exp += 4; - u >>= 4; - } - if (u >= 0x4) { - exp += 2; - u >>= 2; - } - if (u >= 0x2) { - exp += 1; - u >>= 1; - } + + exp = ilog2(uintval); /* Calculate fraction */ if (23 > exp) @@ -172,1018 +65,6 @@ unsigned int uint2float(unsigned int uintval) return exp | frac; } -/* context save (gmem -> sys) */ - -/* pre-compiled vertex shader program -* -* attribute vec4 P; -* void main(void) -* { -* gl_Position = P; -* } -*/ -#define GMEM2SYS_VTX_PGM_LEN 0x12 - -static unsigned int gmem2sys_vtx_pgm[GMEM2SYS_VTX_PGM_LEN] = { - 0x00011003, 0x00001000, 0xc2000000, - 0x00001004, 0x00001000, 0xc4000000, - 0x00001005, 0x00002000, 0x00000000, - 0x1cb81000, 0x00398a88, 0x00000003, - 0x140f803e, 0x00000000, 0xe2010100, - 0x14000000, 0x00000000, 0xe2000000 -}; - -/* pre-compiled fragment shader program -* -* precision highp float; -* uniform vec4 clear_color; -* void main(void) -* { -* gl_FragColor = clear_color; -* } -*/ - -#define GMEM2SYS_FRAG_PGM_LEN 0x0c - -static unsigned int gmem2sys_frag_pgm[GMEM2SYS_FRAG_PGM_LEN] = { - 0x00000000, 0x1002c400, 0x10000000, - 0x00001003, 0x00002000, 0x00000000, - 0x140f8000, 0x00000000, 0x22000000, - 0x14000000, 0x00000000, 0xe2000000 -}; - -/* context restore (sys -> gmem) */ -/* pre-compiled vertex shader program -* -* attribute vec4 position; -* attribute vec4 texcoord; -* varying vec4 texcoord0; -* void main() -* { -* gl_Position = position; -* texcoord0 = texcoord; -* } -*/ - -#define SYS2GMEM_VTX_PGM_LEN 0x18 - -static unsigned int sys2gmem_vtx_pgm[SYS2GMEM_VTX_PGM_LEN] = { - 0x00052003, 0x00001000, 0xc2000000, 0x00001005, - 0x00001000, 0xc4000000, 0x00001006, 0x10071000, - 0x20000000, 0x18981000, 0x0039ba88, 0x00000003, - 0x12982000, 0x40257b08, 0x00000002, 0x140f803e, - 0x00000000, 0xe2010100, 0x140f8000, 0x00000000, - 0xe2020200, 0x14000000, 0x00000000, 0xe2000000 -}; - -/* pre-compiled fragment shader program -* -* precision mediump float; -* uniform sampler2D tex0; -* varying vec4 texcoord0; -* void main() -* { -* gl_FragColor = texture2D(tex0, texcoord0.xy); -* } -*/ - -#define SYS2GMEM_FRAG_PGM_LEN 0x0f - -static unsigned int sys2gmem_frag_pgm[SYS2GMEM_FRAG_PGM_LEN] = { - 0x00011002, 0x00001000, 0xc4000000, 0x00001003, - 0x10041000, 0x20000000, 0x10000001, 0x1ffff688, - 0x00000002, 0x140f8000, 0x00000000, 0xe2000000, - 0x14000000, 0x00000000, 0xe2000000 -}; - -/* shader texture constants (sysmem -> gmem) */ -#define SYS2GMEM_TEX_CONST_LEN 6 - -static unsigned int sys2gmem_tex_const[SYS2GMEM_TEX_CONST_LEN] = { - /* Texture, FormatXYZW=Unsigned, ClampXYZ=Wrap/Repeat, - * RFMode=ZeroClamp-1, Dim=1:2d - */ - 0x00000002, /* Pitch = TBD */ - - /* Format=6:8888_WZYX, EndianSwap=0:None, ReqSize=0:256bit, DimHi=0, - * NearestClamp=1:OGL Mode - */ - 0x00000800, /* Address[31:12] = TBD */ - - /* Width, Height, EndianSwap=0:None */ - 0, /* Width & Height = TBD */ - - /* NumFormat=0:RF, DstSelXYZW=XYZW, ExpAdj=0, MagFilt=MinFilt=0:Point, - * Mip=2:BaseMap - */ - 0 << 1 | 1 << 4 | 2 << 7 | 3 << 10 | 2 << 23, - - /* VolMag=VolMin=0:Point, MinMipLvl=0, MaxMipLvl=1, LodBiasH=V=0, - * Dim3d=0 - */ - 0, - - /* BorderColor=0:ABGRBlack, ForceBC=0:diable, TriJuice=0, Aniso=0, - * Dim=1:2d, MipPacking=0 - */ - 1 << 9 /* Mip Address[31:12] = TBD */ -}; - -/* quad for copying GMEM to context shadow */ -#define QUAD_LEN 12 - -static unsigned int gmem_copy_quad[QUAD_LEN] = { - 0x00000000, 0x00000000, 0x3f800000, - 0x00000000, 0x00000000, 0x3f800000, - 0x00000000, 0x00000000, 0x3f800000, - 0x00000000, 0x00000000, 0x3f800000 -}; - -#define TEXCOORD_LEN 8 - -static unsigned int gmem_copy_texcoord[TEXCOORD_LEN] = { - 0x00000000, 0x3f800000, - 0x3f800000, 0x3f800000, - 0x00000000, 0x00000000, - 0x3f800000, 0x00000000 -}; - -#define NUM_COLOR_FORMATS 13 - -static enum SURFACEFORMAT surface_format_table[NUM_COLOR_FORMATS] = { - FMT_4_4_4_4, /* COLORX_4_4_4_4 */ - FMT_1_5_5_5, /* COLORX_1_5_5_5 */ - FMT_5_6_5, /* COLORX_5_6_5 */ - FMT_8, /* COLORX_8 */ - FMT_8_8, /* COLORX_8_8 */ - FMT_8_8_8_8, /* COLORX_8_8_8_8 */ - FMT_8_8_8_8, /* COLORX_S8_8_8_8 */ - FMT_16_FLOAT, /* COLORX_16_FLOAT */ - FMT_16_16_FLOAT, /* COLORX_16_16_FLOAT */ - FMT_16_16_16_16_FLOAT, /* COLORX_16_16_16_16_FLOAT */ - FMT_32_FLOAT, /* COLORX_32_FLOAT */ - FMT_32_32_FLOAT, /* COLORX_32_32_FLOAT */ - FMT_32_32_32_32_FLOAT, /* COLORX_32_32_32_32_FLOAT */ -}; - -static unsigned int format2bytesperpixel[NUM_COLOR_FORMATS] = { - 2, /* COLORX_4_4_4_4 */ - 2, /* COLORX_1_5_5_5 */ - 2, /* COLORX_5_6_5 */ - 1, /* COLORX_8 */ - 2, /* COLORX_8_8 8*/ - 4, /* COLORX_8_8_8_8 */ - 4, /* COLORX_S8_8_8_8 */ - 2, /* COLORX_16_FLOAT */ - 4, /* COLORX_16_16_FLOAT */ - 8, /* COLORX_16_16_16_16_FLOAT */ - 4, /* COLORX_32_FLOAT */ - 8, /* COLORX_32_32_FLOAT */ - 16, /* COLORX_32_32_32_32_FLOAT */ -}; - -/* shader linkage info */ -#define SHADER_CONST_ADDR (11 * 6 + 3) - -/* gmem command buffer length */ -#define PM4_REG(reg) ((0x4 << 16) | (GSL_HAL_SUBBLOCK_OFFSET(reg))) - -/* functions */ -static void config_gmemsize(struct gmem_shadow_t *shadow, int gmem_size) -{ - int w = 64, h = 64; /* 16KB surface, minimum */ - - shadow->format = COLORX_8_8_8_8; - /* convert from bytes to 32-bit words */ - gmem_size = (gmem_size + 3) / 4; - - /* find the right surface size, close to a square. */ - while (w * h < gmem_size) - if (w < h) - w *= 2; - else - h *= 2; - - shadow->width = w; - shadow->pitch = w; - shadow->height = h; - shadow->gmem_pitch = shadow->pitch; - - shadow->size = shadow->pitch * shadow->height * 4; -} - -static unsigned int gpuaddr(unsigned int *cmd, struct kgsl_memdesc *memdesc) -{ - return memdesc->gpuaddr + ((char *)cmd - (char *)memdesc->hostptr); -} - -static void -create_ib1(struct adreno_context *drawctxt, unsigned int *cmd, - unsigned int *start, unsigned int *end) -{ - cmd[0] = PM4_HDR_INDIRECT_BUFFER_PFD; - cmd[1] = gpuaddr(start, &drawctxt->gpustate); - cmd[2] = end - start; -} - -static unsigned int *program_shader(unsigned int *cmds, int vtxfrag, - unsigned int *shader_pgm, int dwords) -{ - /* load the patched vertex shader stream */ - *cmds++ = pm4_type3_packet(PM4_IM_LOAD_IMMEDIATE, 2 + dwords); - /* 0=vertex shader, 1=fragment shader */ - *cmds++ = vtxfrag; - /* instruction start & size (in 32-bit words) */ - *cmds++ = ((0 << 16) | dwords); - - memcpy(cmds, shader_pgm, dwords << 2); - cmds += dwords; - - return cmds; -} - -static unsigned int *reg_to_mem(unsigned int *cmds, uint32_t dst, - uint32_t src, int dwords) -{ - while (dwords-- > 0) { - *cmds++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmds++ = src++; - *cmds++ = dst; - dst += 4; - } - - return cmds; -} - -#ifdef CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES - -static void build_reg_to_mem_range(unsigned int start, unsigned int end, - unsigned int **cmd, - struct adreno_context *drawctxt) -{ - unsigned int i = start; - - for (i = start; i <= end; i++) { - *(*cmd)++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *(*cmd)++ = i; - *(*cmd)++ = - ((drawctxt->gpustate.gpuaddr + REG_OFFSET) & 0xFFFFE000) + - (i - 0x2000) * 4; - } -} - -#endif - -/* chicken restore */ -static unsigned int *build_chicken_restore_cmds( - struct adreno_context *drawctxt, - struct tmp_ctx *ctx) -{ - unsigned int *start = ctx->cmd; - unsigned int *cmds = start; - - *cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); - *cmds++ = 0; - - *cmds++ = pm4_type0_packet(REG_TP0_CHICKEN, 1); - ctx->chicken_restore = gpuaddr(cmds, &drawctxt->gpustate); - *cmds++ = 0x00000000; - - /* create indirect buffer command for above command sequence */ - create_ib1(drawctxt, drawctxt->chicken_restore, start, cmds); - - return cmds; -} - -/* save h/w regs, alu constants, texture contants, etc. ... -* requires: bool_shadow_gpuaddr, loop_shadow_gpuaddr -*/ -static void build_regsave_cmds(struct adreno_device *adreno_dev, - struct adreno_context *drawctxt, - struct tmp_ctx *ctx) -{ - unsigned int *start = ctx->cmd; - unsigned int *cmd = start; - - *cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); - *cmd++ = 0; - -#ifdef CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES - /* Make sure the HW context has the correct register values - * before reading them. */ - *cmd++ = pm4_type3_packet(PM4_CONTEXT_UPDATE, 1); - *cmd++ = 0; -#endif - -#ifdef CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES - /* Write HW registers into shadow */ - build_reg_to_mem_range(REG_RB_SURFACE_INFO, REG_RB_DEPTH_INFO, - &cmd, drawctxt); - build_reg_to_mem_range(REG_COHER_DEST_BASE_0, - REG_PA_SC_SCREEN_SCISSOR_BR, - &cmd, drawctxt); - build_reg_to_mem_range(REG_PA_SC_WINDOW_OFFSET, - REG_PA_SC_WINDOW_SCISSOR_BR, - &cmd, drawctxt); - if (!adreno_is_a220(adreno_dev)) { - build_reg_to_mem_range(REG_VGT_MAX_VTX_INDX, REG_RB_FOG_COLOR, - &cmd, drawctxt); - } else { - build_reg_to_mem_range(REG_LEIA_PC_MAX_VTX_INDX, - REG_LEIA_PC_INDX_OFFSET, - &cmd, drawctxt); - build_reg_to_mem_range(REG_RB_COLOR_MASK, - REG_RB_FOG_COLOR, - &cmd, drawctxt); - } - build_reg_to_mem_range(REG_RB_STENCILREFMASK_BF, - REG_PA_CL_VPORT_ZOFFSET, - &cmd, drawctxt); - build_reg_to_mem_range(REG_SQ_PROGRAM_CNTL, REG_SQ_WRAPPING_1, - &cmd, drawctxt); - if (!adreno_is_a220(adreno_dev)) { - build_reg_to_mem_range(REG_RB_DEPTHCONTROL, REG_RB_MODECONTROL, - &cmd, drawctxt); - build_reg_to_mem_range(REG_PA_SU_POINT_SIZE, - REG_PA_SC_LINE_STIPPLE, - &cmd, drawctxt); - build_reg_to_mem_range(REG_PA_SC_VIZ_QUERY, REG_PA_SC_VIZ_QUERY, - &cmd, drawctxt); - } else { - build_reg_to_mem_range(REG_RB_DEPTHCONTROL, - REG_RB_COLORCONTROL, - &cmd, drawctxt); - build_reg_to_mem_range(REG_PA_CL_CLIP_CNTL, - REG_PA_CL_VTE_CNTL, - &cmd, drawctxt); - build_reg_to_mem_range(REG_RB_MODECONTROL, - REG_LEIA_GRAS_CONTROL, - &cmd, drawctxt); - build_reg_to_mem_range(REG_PA_SU_POINT_SIZE, - REG_PA_SU_LINE_CNTL, - &cmd, drawctxt); - } - build_reg_to_mem_range(REG_PA_SC_LINE_CNTL, REG_SQ_PS_CONST, - &cmd, drawctxt); - build_reg_to_mem_range(REG_PA_SC_AA_MASK, REG_PA_SC_AA_MASK, - &cmd, drawctxt); - if (!adreno_is_a220(adreno_dev)) { - build_reg_to_mem_range(REG_VGT_VERTEX_REUSE_BLOCK_CNTL, - REG_RB_DEPTH_CLEAR, - &cmd, drawctxt); - } else { - build_reg_to_mem_range(REG_LEIA_PC_VERTEX_REUSE_BLOCK_CNTL, - REG_LEIA_PC_VERTEX_REUSE_BLOCK_CNTL, - &cmd, drawctxt); - build_reg_to_mem_range(REG_RB_COPY_CONTROL, - REG_RB_DEPTH_CLEAR, - &cmd, drawctxt); - } - build_reg_to_mem_range(REG_RB_SAMPLE_COUNT_CTL, - REG_RB_COLOR_DEST_MASK, - &cmd, drawctxt); - build_reg_to_mem_range(REG_PA_SU_POLY_OFFSET_FRONT_SCALE, - REG_PA_SU_POLY_OFFSET_BACK_OFFSET, - &cmd, drawctxt); - - /* Copy ALU constants */ - cmd = - reg_to_mem(cmd, (drawctxt->gpustate.gpuaddr) & 0xFFFFE000, - REG_SQ_CONSTANT_0, ALU_CONSTANTS); - - /* Copy Tex constants */ - cmd = - reg_to_mem(cmd, - (drawctxt->gpustate.gpuaddr + TEX_OFFSET) & 0xFFFFE000, - REG_SQ_FETCH_0, TEX_CONSTANTS); -#else - - /* Insert a wait for idle packet before reading the registers. - * This is to fix a hang/reset seen during stress testing. In this - * hang, CP encountered a timeout reading SQ's boolean constant - * register. There is logic in the HW that blocks reading of this - * register when the SQ block is not idle, which we believe is - * contributing to the hang.*/ - *cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); - *cmd++ = 0; - - /* H/w registers are already shadowed; just need to disable shadowing - * to prevent corruption. - */ - *cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3); - *cmd++ = (drawctxt->gpustate.gpuaddr + REG_OFFSET) & 0xFFFFE000; - *cmd++ = 4 << 16; /* regs, start=0 */ - *cmd++ = 0x0; /* count = 0 */ - - /* ALU constants are already shadowed; just need to disable shadowing - * to prevent corruption. - */ - *cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3); - *cmd++ = drawctxt->gpustate.gpuaddr & 0xFFFFE000; - *cmd++ = 0 << 16; /* ALU, start=0 */ - *cmd++ = 0x0; /* count = 0 */ - - /* Tex constants are already shadowed; just need to disable shadowing - * to prevent corruption. - */ - *cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3); - *cmd++ = (drawctxt->gpustate.gpuaddr + TEX_OFFSET) & 0xFFFFE000; - *cmd++ = 1 << 16; /* Tex, start=0 */ - *cmd++ = 0x0; /* count = 0 */ -#endif - - /* Need to handle some of the registers separately */ - *cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmd++ = REG_SQ_GPR_MANAGEMENT; - *cmd++ = ctx->reg_values[0]; - - *cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmd++ = REG_TP0_CHICKEN; - *cmd++ = ctx->reg_values[1]; - - *cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmd++ = REG_RBBM_PM_OVERRIDE2; - *cmd++ = ctx->reg_values[2]; - - if (adreno_is_a220(adreno_dev)) { - unsigned int i; - unsigned int j = 3; - for (i = REG_LEIA_VSC_BIN_SIZE; i <= - REG_LEIA_VSC_PIPE_DATA_LENGTH_7; i++) { - *cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmd++ = i; - *cmd++ = ctx->reg_values[j]; - j++; - } - } - - /* Copy Boolean constants */ - cmd = reg_to_mem(cmd, ctx->bool_shadow, REG_SQ_CF_BOOLEANS, - BOOL_CONSTANTS); - - /* Copy Loop constants */ - cmd = reg_to_mem(cmd, ctx->loop_shadow, REG_SQ_CF_LOOP, LOOP_CONSTANTS); - - /* create indirect buffer command for above command sequence */ - create_ib1(drawctxt, drawctxt->reg_save, start, cmd); - - ctx->cmd = cmd; -} - -/*copy colour, depth, & stencil buffers from graphics memory to system memory*/ -static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev, - struct adreno_context *drawctxt, - struct tmp_ctx *ctx, - struct gmem_shadow_t *shadow) -{ - unsigned int *cmds = shadow->gmem_save_commands; - unsigned int *start = cmds; - /* Calculate the new offset based on the adjusted base */ - unsigned int bytesperpixel = format2bytesperpixel[shadow->format]; - unsigned int addr = shadow->gmemshadow.gpuaddr; - unsigned int offset = (addr - (addr & 0xfffff000)) / bytesperpixel; - - /* Store TP0_CHICKEN register */ - *cmds++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmds++ = REG_TP0_CHICKEN; - if (ctx) - *cmds++ = ctx->chicken_restore; - else - cmds++; - - *cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); - *cmds++ = 0; - - /* Set TP0_CHICKEN to zero */ - *cmds++ = pm4_type0_packet(REG_TP0_CHICKEN, 1); - *cmds++ = 0x00000000; - - /* Set PA_SC_AA_CONFIG to 0 */ - *cmds++ = pm4_type0_packet(REG_PA_SC_AA_CONFIG, 1); - *cmds++ = 0x00000000; - - /* program shader */ - - /* load shader vtx constants ... 5 dwords */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 4); - *cmds++ = (0x1 << 16) | SHADER_CONST_ADDR; - *cmds++ = 0; - /* valid(?) vtx constant flag & addr */ - *cmds++ = shadow->quad_vertices.gpuaddr | 0x3; - /* limit = 12 dwords */ - *cmds++ = 0x00000030; - - /* Invalidate L2 cache to make sure vertices are updated */ - *cmds++ = pm4_type0_packet(REG_TC_CNTL_STATUS, 1); - *cmds++ = 0x1; - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 4); - *cmds++ = PM4_REG(REG_VGT_MAX_VTX_INDX); - *cmds++ = 0x00ffffff; /* REG_VGT_MAX_VTX_INDX */ - *cmds++ = 0x0; /* REG_VGT_MIN_VTX_INDX */ - *cmds++ = 0x00000000; /* REG_VGT_INDX_OFFSET */ - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_PA_SC_AA_MASK); - *cmds++ = 0x0000ffff; /* REG_PA_SC_AA_MASK */ - - /* load the patched vertex shader stream */ - cmds = program_shader(cmds, 0, gmem2sys_vtx_pgm, GMEM2SYS_VTX_PGM_LEN); - - /* Load the patched fragment shader stream */ - cmds = - program_shader(cmds, 1, gmem2sys_frag_pgm, GMEM2SYS_FRAG_PGM_LEN); - - /* SQ_PROGRAM_CNTL / SQ_CONTEXT_MISC */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_SQ_PROGRAM_CNTL); - if (adreno_is_a220(adreno_dev)) - *cmds++ = 0x10018001; - else - *cmds++ = 0x10010001; - *cmds++ = 0x00000008; - - /* resolve */ - - /* PA_CL_VTE_CNTL */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_PA_CL_VTE_CNTL); - /* disable X/Y/Z transforms, X/Y/Z are premultiplied by W */ - *cmds++ = 0x00000b00; - - /* program surface info */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_RB_SURFACE_INFO); - *cmds++ = shadow->gmem_pitch; /* pitch, MSAA = 1 */ - - /* RB_COLOR_INFO Endian=none, Linear, Format=RGBA8888, Swap=0, - * Base=gmem_base - */ - /* gmem base assumed 4K aligned. */ - if (ctx) { - BUG_ON(ctx->gmem_base & 0xFFF); - *cmds++ = - (shadow-> - format << RB_COLOR_INFO__COLOR_FORMAT__SHIFT) | ctx-> - gmem_base; - } else { - unsigned int temp = *cmds; - *cmds++ = (temp & ~RB_COLOR_INFO__COLOR_FORMAT_MASK) | - (shadow->format << RB_COLOR_INFO__COLOR_FORMAT__SHIFT); - } - - /* disable Z */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_RB_DEPTHCONTROL); - if (adreno_is_a220(adreno_dev)) - *cmds++ = 0x08; - else - *cmds++ = 0; - - /* set REG_PA_SU_SC_MODE_CNTL - * Front_ptype = draw triangles - * Back_ptype = draw triangles - * Provoking vertex = last - */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_PA_SU_SC_MODE_CNTL); - *cmds++ = 0x00080240; - - /* Use maximum scissor values -- quad vertices already have the - * correct bounds */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_PA_SC_SCREEN_SCISSOR_TL); - *cmds++ = (0 << 16) | 0; - *cmds++ = (0x1fff << 16) | (0x1fff); - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_PA_SC_WINDOW_SCISSOR_TL); - *cmds++ = (unsigned int)((1U << 31) | (0 << 16) | 0); - *cmds++ = (0x1fff << 16) | (0x1fff); - - /* load the viewport so that z scale = clear depth and - * z offset = 0.0f - */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_PA_CL_VPORT_ZSCALE); - *cmds++ = 0xbf800000; /* -1.0f */ - *cmds++ = 0x0; - - /* load the stencil ref value - * $AAM - do this later - */ - - /* load the COPY state */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 6); - *cmds++ = PM4_REG(REG_RB_COPY_CONTROL); - *cmds++ = 0; /* RB_COPY_CONTROL */ - *cmds++ = addr & 0xfffff000; /* RB_COPY_DEST_BASE */ - *cmds++ = shadow->pitch >> 5; /* RB_COPY_DEST_PITCH */ - - /* Endian=none, Linear, Format=RGBA8888,Swap=0,!Dither, - * MaskWrite:R=G=B=A=1 - */ - *cmds++ = 0x0003c008 | - (shadow->format << RB_COPY_DEST_INFO__COPY_DEST_FORMAT__SHIFT); - /* Make sure we stay in offsetx field. */ - BUG_ON(offset & 0xfffff000); - *cmds++ = offset; - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_RB_MODECONTROL); - *cmds++ = 0x6; /* EDRAM copy */ - - if (adreno_is_a220(adreno_dev)) { - *cmds++ = 0xc0043600; /* packet 3 3D_DRAW_INDX_2 */ - *cmds++ = 0x0; - *cmds++ = 0x00004046; /* tristrip */ - *cmds++ = 0x00000004; /* NUM_INDICES */ - *cmds++ = 0x00010000; /* index: 0x00, 0x01 */ - *cmds++ = 0x00030002; /* index: 0x02, 0x03 */ - } else { - /* queue the draw packet */ - *cmds++ = pm4_type3_packet(PM4_DRAW_INDX, 2); - *cmds++ = 0; /* viz query info. */ - /* PrimType=RectList, NumIndices=3, SrcSel=AutoIndex */ - *cmds++ = 0x00030088; - } - - /* create indirect buffer command for above command sequence */ - create_ib1(drawctxt, shadow->gmem_save, start, cmds); - - return cmds; -} - -/* context restore */ - -/*copy colour, depth, & stencil buffers from system memory to graphics memory*/ -static unsigned int *build_sys2gmem_cmds(struct adreno_device *adreno_dev, - struct adreno_context *drawctxt, - struct tmp_ctx *ctx, - struct gmem_shadow_t *shadow) -{ - unsigned int *cmds = shadow->gmem_restore_commands; - unsigned int *start = cmds; - - /* Store TP0_CHICKEN register */ - *cmds++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmds++ = REG_TP0_CHICKEN; - if (ctx) - *cmds++ = ctx->chicken_restore; - else - cmds++; - - *cmds++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); - *cmds++ = 0; - - /* Set TP0_CHICKEN to zero */ - *cmds++ = pm4_type0_packet(REG_TP0_CHICKEN, 1); - *cmds++ = 0x00000000; - - /* Set PA_SC_AA_CONFIG to 0 */ - *cmds++ = pm4_type0_packet(REG_PA_SC_AA_CONFIG, 1); - *cmds++ = 0x00000000; - /* shader constants */ - - /* vertex buffer constants */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 7); - - *cmds++ = (0x1 << 16) | (9 * 6); - /* valid(?) vtx constant flag & addr */ - *cmds++ = shadow->quad_vertices.gpuaddr | 0x3; - /* limit = 12 dwords */ - *cmds++ = 0x00000030; - /* valid(?) vtx constant flag & addr */ - *cmds++ = shadow->quad_texcoords.gpuaddr | 0x3; - /* limit = 8 dwords */ - *cmds++ = 0x00000020; - *cmds++ = 0; - *cmds++ = 0; - - /* Invalidate L2 cache to make sure vertices are updated */ - *cmds++ = pm4_type0_packet(REG_TC_CNTL_STATUS, 1); - *cmds++ = 0x1; - - cmds = program_shader(cmds, 0, sys2gmem_vtx_pgm, SYS2GMEM_VTX_PGM_LEN); - - /* Load the patched fragment shader stream */ - cmds = - program_shader(cmds, 1, sys2gmem_frag_pgm, SYS2GMEM_FRAG_PGM_LEN); - - /* SQ_PROGRAM_CNTL / SQ_CONTEXT_MISC */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_SQ_PROGRAM_CNTL); - *cmds++ = 0x10030002; - *cmds++ = 0x00000008; - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_PA_SC_AA_MASK); - *cmds++ = 0x0000ffff; /* REG_PA_SC_AA_MASK */ - - if (!adreno_is_a220(adreno_dev)) { - /* PA_SC_VIZ_QUERY */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_PA_SC_VIZ_QUERY); - *cmds++ = 0x0; /*REG_PA_SC_VIZ_QUERY */ - } - - /* RB_COLORCONTROL */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_RB_COLORCONTROL); - *cmds++ = 0x00000c20; - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 4); - *cmds++ = PM4_REG(REG_VGT_MAX_VTX_INDX); - *cmds++ = 0x00ffffff; /* mmVGT_MAX_VTX_INDX */ - *cmds++ = 0x0; /* mmVGT_MIN_VTX_INDX */ - *cmds++ = 0x00000000; /* mmVGT_INDX_OFFSET */ - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_VGT_VERTEX_REUSE_BLOCK_CNTL); - *cmds++ = 0x00000002; /* mmVGT_VERTEX_REUSE_BLOCK_CNTL */ - *cmds++ = 0x00000002; /* mmVGT_OUT_DEALLOC_CNTL */ - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_SQ_INTERPOLATOR_CNTL); - *cmds++ = 0xffffffff; /* mmSQ_INTERPOLATOR_CNTL */ - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_PA_SC_AA_CONFIG); - *cmds++ = 0x00000000; /* REG_PA_SC_AA_CONFIG */ - - /* set REG_PA_SU_SC_MODE_CNTL - * Front_ptype = draw triangles - * Back_ptype = draw triangles - * Provoking vertex = last - */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_PA_SU_SC_MODE_CNTL); - *cmds++ = 0x00080240; - - /* texture constants */ - *cmds++ = - pm4_type3_packet(PM4_SET_CONSTANT, (SYS2GMEM_TEX_CONST_LEN + 1)); - *cmds++ = (0x1 << 16) | (0 * 6); - memcpy(cmds, sys2gmem_tex_const, SYS2GMEM_TEX_CONST_LEN << 2); - cmds[0] |= (shadow->pitch >> 5) << 22; - cmds[1] |= - shadow->gmemshadow.gpuaddr | surface_format_table[shadow->format]; - cmds[2] |= (shadow->width - 1) | (shadow->height - 1) << 13; - cmds += SYS2GMEM_TEX_CONST_LEN; - - /* program surface info */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_RB_SURFACE_INFO); - *cmds++ = shadow->gmem_pitch; /* pitch, MSAA = 1 */ - - /* RB_COLOR_INFO Endian=none, Linear, Format=RGBA8888, Swap=0, - * Base=gmem_base - */ - if (ctx) - *cmds++ = - (shadow-> - format << RB_COLOR_INFO__COLOR_FORMAT__SHIFT) | ctx-> - gmem_base; - else { - unsigned int temp = *cmds; - *cmds++ = (temp & ~RB_COLOR_INFO__COLOR_FORMAT_MASK) | - (shadow->format << RB_COLOR_INFO__COLOR_FORMAT__SHIFT); - } - - /* RB_DEPTHCONTROL */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_RB_DEPTHCONTROL); - - if (adreno_is_a220(adreno_dev)) - *cmds++ = 8; /* disable Z */ - else - *cmds++ = 0; /* disable Z */ - - /* Use maximum scissor values -- quad vertices already - * have the correct bounds */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_PA_SC_SCREEN_SCISSOR_TL); - *cmds++ = (0 << 16) | 0; - *cmds++ = ((0x1fff) << 16) | 0x1fff; - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_PA_SC_WINDOW_SCISSOR_TL); - *cmds++ = (unsigned int)((1U << 31) | (0 << 16) | 0); - *cmds++ = ((0x1fff) << 16) | 0x1fff; - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_PA_CL_VTE_CNTL); - /* disable X/Y/Z transforms, X/Y/Z are premultiplied by W */ - *cmds++ = 0x00000b00; - - /*load the viewport so that z scale = clear depth and z offset = 0.0f */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_PA_CL_VPORT_ZSCALE); - *cmds++ = 0xbf800000; - *cmds++ = 0x0; - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_RB_COLOR_MASK); - *cmds++ = 0x0000000f; /* R = G = B = 1:enabled */ - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_RB_COLOR_DEST_MASK); - *cmds++ = 0xffffffff; - - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 3); - *cmds++ = PM4_REG(REG_SQ_WRAPPING_0); - *cmds++ = 0x00000000; - *cmds++ = 0x00000000; - - /* load the stencil ref value - * $AAM - do this later - */ - *cmds++ = pm4_type3_packet(PM4_SET_CONSTANT, 2); - *cmds++ = PM4_REG(REG_RB_MODECONTROL); - /* draw pixels with color and depth/stencil component */ - *cmds++ = 0x4; - - if (adreno_is_a220(adreno_dev)) { - *cmds++ = 0xc0043600; /* packet 3 3D_DRAW_INDX_2 */ - *cmds++ = 0x0; - *cmds++ = 0x00004046; /* tristrip */ - *cmds++ = 0x00000004; /* NUM_INDICES */ - *cmds++ = 0x00010000; /* index: 0x00, 0x01 */ - *cmds++ = 0x00030002; /* index: 0x02, 0x03 */ - } else { - /* queue the draw packet */ - *cmds++ = pm4_type3_packet(PM4_DRAW_INDX, 2); - *cmds++ = 0; /* viz query info. */ - /* PrimType=RectList, NumIndices=3, SrcSel=AutoIndex */ - *cmds++ = 0x00030088; - } - - /* create indirect buffer command for above command sequence */ - create_ib1(drawctxt, shadow->gmem_restore, start, cmds); - - return cmds; -} - -/* restore h/w regs, alu constants, texture constants, etc. ... */ -static unsigned *reg_range(unsigned int *cmd, unsigned int start, - unsigned int end) -{ - *cmd++ = PM4_REG(start); /* h/w regs, start addr */ - *cmd++ = end - start + 1; /* count */ - return cmd; -} - -static void build_regrestore_cmds(struct adreno_device *adreno_dev, - struct adreno_context *drawctxt, - struct tmp_ctx *ctx) -{ - unsigned int *start = ctx->cmd; - unsigned int *cmd = start; - - *cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); - *cmd++ = 0; - - /* H/W Registers */ - /* deferred pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, ???); */ - cmd++; -#ifdef CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES - /* Force mismatch */ - *cmd++ = ((drawctxt->gpustate.gpuaddr + REG_OFFSET) & 0xFFFFE000) | 1; -#else - *cmd++ = (drawctxt->gpustate.gpuaddr + REG_OFFSET) & 0xFFFFE000; -#endif - - if (!adreno_is_a220(adreno_dev)) { - cmd = reg_range(cmd, REG_RB_SURFACE_INFO, - REG_PA_SC_SCREEN_SCISSOR_BR); - } else { - cmd = reg_range(cmd, REG_RB_SURFACE_INFO, REG_RB_DEPTH_INFO); - cmd = reg_range(cmd, REG_COHER_DEST_BASE_0, - REG_PA_SC_SCREEN_SCISSOR_BR); - } - cmd = reg_range(cmd, REG_PA_SC_WINDOW_OFFSET, - REG_PA_SC_WINDOW_SCISSOR_BR); - if (!adreno_is_a220(adreno_dev)) { - cmd = reg_range(cmd, REG_VGT_MAX_VTX_INDX, - REG_PA_CL_VPORT_ZOFFSET); - } else { - cmd = reg_range(cmd, REG_LEIA_PC_MAX_VTX_INDX, - REG_LEIA_PC_INDX_OFFSET); - cmd = reg_range(cmd, REG_RB_COLOR_MASK, REG_RB_FOG_COLOR); - cmd = reg_range(cmd, REG_RB_STENCILREFMASK_BF, - REG_PA_CL_VPORT_ZOFFSET); - } - cmd = reg_range(cmd, REG_SQ_PROGRAM_CNTL, REG_SQ_WRAPPING_1); - if (!adreno_is_a220(adreno_dev)) { - cmd = reg_range(cmd, REG_RB_DEPTHCONTROL, REG_RB_MODECONTROL); - cmd = reg_range(cmd, REG_PA_SU_POINT_SIZE, - REG_PA_SC_VIZ_QUERY); /*REG_VGT_ENHANCE */ - cmd = reg_range(cmd, REG_PA_SC_LINE_CNTL, - REG_RB_COLOR_DEST_MASK); - } else { - cmd = reg_range(cmd, REG_RB_DEPTHCONTROL, REG_RB_COLORCONTROL); - cmd = reg_range(cmd, REG_PA_CL_CLIP_CNTL, REG_PA_CL_VTE_CNTL); - cmd = reg_range(cmd, REG_RB_MODECONTROL, REG_LEIA_GRAS_CONTROL); - cmd = reg_range(cmd, REG_PA_SU_POINT_SIZE, REG_PA_SU_LINE_CNTL); - cmd = reg_range(cmd, REG_PA_SC_LINE_CNTL, REG_SQ_PS_CONST); - cmd = reg_range(cmd, REG_PA_SC_AA_MASK, REG_PA_SC_AA_MASK); - cmd = reg_range(cmd, REG_LEIA_PC_VERTEX_REUSE_BLOCK_CNTL, - REG_LEIA_PC_VERTEX_REUSE_BLOCK_CNTL); - cmd = reg_range(cmd, REG_RB_COPY_CONTROL, REG_RB_DEPTH_CLEAR); - cmd = reg_range(cmd, REG_RB_SAMPLE_COUNT_CTL, - REG_RB_COLOR_DEST_MASK); - } - cmd = reg_range(cmd, REG_PA_SU_POLY_OFFSET_FRONT_SCALE, - REG_PA_SU_POLY_OFFSET_BACK_OFFSET); - - /* Now we know how many register blocks we have, we can compute command - * length - */ - start[2] = - pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, (cmd - start) - 3); - /* Enable shadowing for the entire register block. */ -#ifdef CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES - start[4] |= (0 << 24) | (4 << 16); /* Disable shadowing. */ -#else - start[4] |= (1 << 24) | (4 << 16); -#endif - - /* Need to handle some of the registers separately */ - *cmd++ = pm4_type0_packet(REG_SQ_GPR_MANAGEMENT, 1); - ctx->reg_values[0] = gpuaddr(cmd, &drawctxt->gpustate); - *cmd++ = 0x00040400; - - *cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); - *cmd++ = 0; - *cmd++ = pm4_type0_packet(REG_TP0_CHICKEN, 1); - ctx->reg_values[1] = gpuaddr(cmd, &drawctxt->gpustate); - *cmd++ = 0x00000000; - - *cmd++ = pm4_type0_packet(REG_RBBM_PM_OVERRIDE2, 1); - ctx->reg_values[2] = gpuaddr(cmd, &drawctxt->gpustate); - if (!adreno_is_a220(adreno_dev)) - *cmd++ = 0x00000000; - else - *cmd++ = 0x80; - - if (adreno_is_a220(adreno_dev)) { - unsigned int i; - unsigned int j = 3; - for (i = REG_LEIA_VSC_BIN_SIZE; i <= - REG_LEIA_VSC_PIPE_DATA_LENGTH_7; i++) { - *cmd++ = pm4_type0_packet(i, 1); - ctx->reg_values[j] = gpuaddr(cmd, &drawctxt->gpustate); - *cmd++ = 0x00000000; - j++; - } - } - - /* ALU Constants */ - *cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3); - *cmd++ = drawctxt->gpustate.gpuaddr & 0xFFFFE000; -#ifdef CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES - *cmd++ = (0 << 24) | (0 << 16) | 0; /* Disable shadowing */ -#else - *cmd++ = (1 << 24) | (0 << 16) | 0; -#endif - *cmd++ = ALU_CONSTANTS; - - /* Texture Constants */ - *cmd++ = pm4_type3_packet(PM4_LOAD_CONSTANT_CONTEXT, 3); - *cmd++ = (drawctxt->gpustate.gpuaddr + TEX_OFFSET) & 0xFFFFE000; -#ifdef CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES - /* Disable shadowing */ - *cmd++ = (0 << 24) | (1 << 16) | 0; -#else - *cmd++ = (1 << 24) | (1 << 16) | 0; -#endif - *cmd++ = TEX_CONSTANTS; - - /* Boolean Constants */ - *cmd++ = pm4_type3_packet(PM4_SET_CONSTANT, 1 + BOOL_CONSTANTS); - *cmd++ = (2 << 16) | 0; - - /* the next BOOL_CONSTANT dwords is the shadow area for - * boolean constants. - */ - ctx->bool_shadow = gpuaddr(cmd, &drawctxt->gpustate); - cmd += BOOL_CONSTANTS; - - /* Loop Constants */ - *cmd++ = pm4_type3_packet(PM4_SET_CONSTANT, 1 + LOOP_CONSTANTS); - *cmd++ = (3 << 16) | 0; - - /* the next LOOP_CONSTANTS dwords is the shadow area for - * loop constants. - */ - ctx->loop_shadow = gpuaddr(cmd, &drawctxt->gpustate); - cmd += LOOP_CONSTANTS; - - /* create indirect buffer command for above command sequence */ - create_ib1(drawctxt, drawctxt->reg_restore, start, cmd); - - ctx->cmd = cmd; -} - -/* quad for saving/restoring gmem */ static void set_gmem_copy_quad(struct gmem_shadow_t *shadow) { /* set vertex buffer values */ @@ -1192,280 +73,62 @@ 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] = uint2float(0); - gmem_copy_quad[6] = uint2float(0); - gmem_copy_quad[7] = uint2float(0); - gmem_copy_quad[10] = uint2float(0); + gmem_copy_quad[0] = 0; + gmem_copy_quad[6] = 0; + gmem_copy_quad[7] = 0; + gmem_copy_quad[10] = 0; memcpy(shadow->quad_vertices.hostptr, gmem_copy_quad, QUAD_LEN << 2); memcpy(shadow->quad_texcoords.hostptr, gmem_copy_texcoord, - TEXCOORD_LEN << 2); + TEXCOORD_LEN << 2); } +/** + * build_quad_vtxbuff - Create a quad for saving/restoring GMEM + * @ context - Pointer to the context being created + * @ shadow - Pointer to the GMEM shadow structure + * @ incmd - Pointer to pointer to the temporary command buffer + */ + /* quad for saving/restoring gmem */ -static void build_quad_vtxbuff(struct adreno_context *drawctxt, - struct tmp_ctx *ctx, struct gmem_shadow_t *shadow) +void build_quad_vtxbuff(struct adreno_context *drawctxt, + struct gmem_shadow_t *shadow, unsigned int **incmd) { - unsigned int *cmd = ctx->cmd; + unsigned int *cmd = *incmd; /* quad vertex buffer location (in GPU space) */ shadow->quad_vertices.hostptr = cmd; - shadow->quad_vertices.gpuaddr = gpuaddr(cmd, &drawctxt->gpustate); + shadow->quad_vertices.gpuaddr = virt2gpu(cmd, &drawctxt->gpustate); cmd += QUAD_LEN; /* tex coord buffer location (in GPU space) */ shadow->quad_texcoords.hostptr = cmd; - shadow->quad_texcoords.gpuaddr = gpuaddr(cmd, &drawctxt->gpustate); + shadow->quad_texcoords.gpuaddr = virt2gpu(cmd, &drawctxt->gpustate); cmd += TEXCOORD_LEN; set_gmem_copy_quad(shadow); - - ctx->cmd = cmd; + *incmd = cmd; } -static void -build_shader_save_restore_cmds(struct adreno_context *drawctxt, - struct tmp_ctx *ctx) -{ - unsigned int *cmd = ctx->cmd; - unsigned int *save, *restore, *fixup; -#if defined(PM4_IM_STORE) - unsigned int *startSizeVtx, *startSizePix, *startSizeShared; -#endif - unsigned int *partition1; - unsigned int *shaderBases, *partition2; - -#if defined(PM4_IM_STORE) - /* compute vertex, pixel and shared instruction shadow GPU addresses */ - ctx->shader_vertex = drawctxt->gpustate.gpuaddr + SHADER_OFFSET; - ctx->shader_pixel = ctx->shader_vertex + SHADER_SHADOW_SIZE; - ctx->shader_shared = ctx->shader_pixel + SHADER_SHADOW_SIZE; -#endif - - /* restore shader partitioning and instructions */ - - restore = cmd; /* start address */ - - /* Invalidate Vertex & Pixel instruction code address and sizes */ - *cmd++ = pm4_type3_packet(PM4_INVALIDATE_STATE, 1); - *cmd++ = 0x00000300; /* 0x100 = Vertex, 0x200 = Pixel */ - - /* Restore previous shader vertex & pixel instruction bases. */ - *cmd++ = pm4_type3_packet(PM4_SET_SHADER_BASES, 1); - shaderBases = cmd++; /* TBD #5: shader bases (from fixup) */ - - /* write the shader partition information to a scratch register */ - *cmd++ = pm4_type0_packet(REG_SQ_INST_STORE_MANAGMENT, 1); - partition1 = cmd++; /* TBD #4a: partition info (from save) */ - -#if defined(PM4_IM_STORE) - /* load vertex shader instructions from the shadow. */ - *cmd++ = pm4_type3_packet(PM4_IM_LOAD, 2); - *cmd++ = ctx->shader_vertex + 0x0; /* 0x0 = Vertex */ - startSizeVtx = cmd++; /* TBD #1: start/size (from save) */ - - /* load pixel shader instructions from the shadow. */ - *cmd++ = pm4_type3_packet(PM4_IM_LOAD, 2); - *cmd++ = ctx->shader_pixel + 0x1; /* 0x1 = Pixel */ - startSizePix = cmd++; /* TBD #2: start/size (from save) */ - - /* load shared shader instructions from the shadow. */ - *cmd++ = pm4_type3_packet(PM4_IM_LOAD, 2); - *cmd++ = ctx->shader_shared + 0x2; /* 0x2 = Shared */ - startSizeShared = cmd++; /* TBD #3: start/size (from save) */ -#endif - - /* create indirect buffer command for above command sequence */ - create_ib1(drawctxt, drawctxt->shader_restore, restore, cmd); - - /* - * fixup SET_SHADER_BASES data - * - * since self-modifying PM4 code is being used here, a seperate - * command buffer is used for this fixup operation, to ensure the - * commands are not read by the PM4 engine before the data fields - * have been written. - */ - - fixup = cmd; /* start address */ - - /* write the shader partition information to a scratch register */ - *cmd++ = pm4_type0_packet(REG_SCRATCH_REG2, 1); - partition2 = cmd++; /* TBD #4b: partition info (from save) */ - - /* mask off unused bits, then OR with shader instruction memory size */ - *cmd++ = pm4_type3_packet(PM4_REG_RMW, 3); - *cmd++ = REG_SCRATCH_REG2; - /* AND off invalid bits. */ - *cmd++ = 0x0FFF0FFF; - /* OR in instruction memory size */ - *cmd++ = (unsigned int)((SHADER_INSTRUCT_LOG2 - 5U) << 29); - - /* write the computed value to the SET_SHADER_BASES data field */ - *cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmd++ = REG_SCRATCH_REG2; - /* TBD #5: shader bases (to restore) */ - *cmd++ = gpuaddr(shaderBases, &drawctxt->gpustate); - - /* create indirect buffer command for above command sequence */ - create_ib1(drawctxt, drawctxt->shader_fixup, fixup, cmd); - - /* save shader partitioning and instructions */ - - save = cmd; /* start address */ - - *cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); - *cmd++ = 0; - - /* fetch the SQ_INST_STORE_MANAGMENT register value, - * store the value in the data fields of the SET_CONSTANT commands - * above. - */ - *cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmd++ = REG_SQ_INST_STORE_MANAGMENT; - /* TBD #4a: partition info (to restore) */ - *cmd++ = gpuaddr(partition1, &drawctxt->gpustate); - *cmd++ = pm4_type3_packet(PM4_REG_TO_MEM, 2); - *cmd++ = REG_SQ_INST_STORE_MANAGMENT; - /* TBD #4b: partition info (to fixup) */ - *cmd++ = gpuaddr(partition2, &drawctxt->gpustate); - -#if defined(PM4_IM_STORE) - - /* store the vertex shader instructions */ - *cmd++ = pm4_type3_packet(PM4_IM_STORE, 2); - *cmd++ = ctx->shader_vertex + 0x0; /* 0x0 = Vertex */ - /* TBD #1: start/size (to restore) */ - *cmd++ = gpuaddr(startSizeVtx, &drawctxt->gpustate); - - /* store the pixel shader instructions */ - *cmd++ = pm4_type3_packet(PM4_IM_STORE, 2); - *cmd++ = ctx->shader_pixel + 0x1; /* 0x1 = Pixel */ - /* TBD #2: start/size (to restore) */ - *cmd++ = gpuaddr(startSizePix, &drawctxt->gpustate); - - /* store the shared shader instructions if vertex base is nonzero */ - - *cmd++ = pm4_type3_packet(PM4_IM_STORE, 2); - *cmd++ = ctx->shader_shared + 0x2; /* 0x2 = Shared */ - /* TBD #3: start/size (to restore) */ - *cmd++ = gpuaddr(startSizeShared, &drawctxt->gpustate); - -#endif - - *cmd++ = pm4_type3_packet(PM4_WAIT_FOR_IDLE, 1); - *cmd++ = 0; - - /* create indirect buffer command for above command sequence */ - create_ib1(drawctxt, drawctxt->shader_save, save, cmd); - - ctx->cmd = cmd; -} - -/* create buffers for saving/restoring registers, constants, & GMEM */ -static int -create_gpustate_shadow(struct kgsl_device *device, - struct adreno_context *drawctxt, - struct tmp_ctx *ctx) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - int result; - - /* Allocate vmalloc memory to store the gpustate */ - result = kgsl_sharedmem_vmalloc(&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 */ - ctx->cmd = ctx->start - = (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET); - - /* build indirect command buffers to save & restore regs/constants */ - adreno_idle(device, KGSL_TIMEOUT_DEFAULT); - build_regrestore_cmds(adreno_dev, drawctxt, ctx); - build_regsave_cmds(adreno_dev, drawctxt, ctx); - - build_shader_save_restore_cmds(drawctxt, ctx); - - kgsl_cache_range_op(&drawctxt->gpustate, - KGSL_CACHE_OP_FLUSH); - - return 0; -} - -/* create buffers for saving/restoring registers, constants, & GMEM */ -static int -create_gmem_shadow(struct adreno_device *adreno_dev, - struct adreno_context *drawctxt, - struct tmp_ctx *ctx) -{ - struct kgsl_device *device = &adreno_dev->dev; - int result; - - config_gmemsize(&drawctxt->context_gmem_shadow, - adreno_dev->gmemspace.sizebytes); - ctx->gmem_base = adreno_dev->gmemspace.gpu_base; - - result = kgsl_sharedmem_vmalloc( - &drawctxt->context_gmem_shadow.gmemshadow, - drawctxt->pagetable, - drawctxt->context_gmem_shadow.size); - - 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; - - /* blank out gmem shadow. */ - kgsl_sharedmem_set(&drawctxt->context_gmem_shadow.gmemshadow, 0, 0, - drawctxt->context_gmem_shadow.size); - - /* build quad vertex buffer */ - build_quad_vtxbuff(drawctxt, ctx, &drawctxt->context_gmem_shadow); - - /* build TP0_CHICKEN register restore command buffer */ - ctx->cmd = build_chicken_restore_cmds(drawctxt, ctx); - - /* build indirect command buffers to save & restore gmem */ - /* Idle because we are reading PM override registers */ - adreno_idle(device, KGSL_TIMEOUT_DEFAULT); - drawctxt->context_gmem_shadow.gmem_save_commands = ctx->cmd; - ctx->cmd = - build_gmem2sys_cmds(adreno_dev, drawctxt, ctx, - &drawctxt->context_gmem_shadow); - drawctxt->context_gmem_shadow.gmem_restore_commands = ctx->cmd; - ctx->cmd = - build_sys2gmem_cmds(adreno_dev, drawctxt, ctx, - &drawctxt->context_gmem_shadow); - - kgsl_cache_range_op(&drawctxt->context_gmem_shadow.gmemshadow, - KGSL_CACHE_OP_FLUSH); - - return 0; -} - -/* create a new drawing context */ - -int -adreno_drawctxt_create(struct kgsl_device_private *dev_priv, uint32_t flags, - struct kgsl_context *context) +/** + * adreno_drawctxt_create - create a new adreno draw context + * @device - KGSL device to create the context on + * @pagetable - Pagetable for the context + * @context- Generic KGSL context structure + * @flags - flags for the context (passed from user space) + * + * Create a new draw context for the 3D core. Return 0 on success, + * or error code on failure. + */ +int adreno_drawctxt_create(struct kgsl_device *device, + struct kgsl_pagetable *pagetable, + struct kgsl_context *context, uint32_t flags) { struct adreno_context *drawctxt; - struct kgsl_device *device = dev_priv->device; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct kgsl_pagetable *pagetable = dev_priv->process_priv->pagetable; - struct tmp_ctx ctx; int ret; drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL); @@ -1476,25 +139,23 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv, uint32_t flags, drawctxt->pagetable = pagetable; drawctxt->bin_base_offset = 0; - ret = create_gpustate_shadow(device, drawctxt, &ctx); + /* FIXME: Deal with preambles */ + + ret = adreno_dev->gpudev->ctxt_gpustate_shadow(adreno_dev, drawctxt); if (ret) goto err; /* Save the shader instruction memory on context switching */ drawctxt->flags |= CTXT_FLAGS_SHADER_SAVE; - memset(&drawctxt->context_gmem_shadow.gmemshadow, - 0, sizeof(struct kgsl_memdesc)); - if (!(flags & KGSL_CONTEXT_NO_GMEM_ALLOC)) { /* create gmem shadow */ - ret = create_gmem_shadow(adreno_dev, drawctxt, &ctx); + ret = adreno_dev->gpudev->ctxt_gmem_shadow(adreno_dev, + drawctxt); if (ret != 0) goto err; } - BUG_ON(ctx.cmd - ctx.start > CMD_BUFFER_LEN); - context->devctxt = drawctxt; return 0; err: @@ -1503,16 +164,25 @@ err: return ret; } +/** + * adreno_drawctxt_destroy - destroy a draw context + * @device - KGSL device that owns the context + * @context- Generic KGSL context container for the context + * + * Destroy an existing context. Return 0 on success or error + * code on failure. + */ + /* destroy a drawing context */ -int adreno_drawctxt_destroy(struct kgsl_device *device, +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; if (drawctxt == NULL) - return -EINVAL; + return; /* deactivate context */ if (adreno_dev->drawctxt_active == drawctxt) { @@ -1534,35 +204,41 @@ int adreno_drawctxt_destroy(struct kgsl_device *device, kfree(drawctxt); context->devctxt = NULL; - - return 0; } -/* set bin base offset */ -int adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device, +/** + * adreno_drawctxt_set_bin_base_offset - set bin base offset for the context + * @device - KGSL device that owns the context + * @context- Generic KGSL context container for the context + * @offset - Offset to set + * + * Set the bin base offset for A2XX devices. Not valid for A3XX devices. + */ + +void adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device, struct kgsl_context *context, unsigned int offset) { struct adreno_context *drawctxt = context->devctxt; - if (drawctxt == NULL) - return -EINVAL; - - drawctxt->bin_base_offset = offset; - - return 0; + if (drawctxt) + drawctxt->bin_base_offset = offset; } -/* switch drawing contexts */ -void -adreno_drawctxt_switch(struct adreno_device *adreno_dev, - struct adreno_context *drawctxt, - unsigned int flags) +/** + * adreno_drawctxt_switch - switch the current draw context + * @adreno_dev - The 3D device that owns the context + * @drawctxt - the 3D context to switch to + * @flags - Flags to accompany the switch (from user space) + * + * Switch the current draw context + */ + +void adreno_drawctxt_switch(struct adreno_device *adreno_dev, + struct adreno_context *drawctxt, + unsigned int flags) { - struct adreno_context *active_ctxt = - adreno_dev->drawctxt_active; struct kgsl_device *device = &adreno_dev->dev; - unsigned int cmds[5]; if (drawctxt) { if (flags & KGSL_CONTEXT_SAVE_GMEM) @@ -1573,109 +249,18 @@ adreno_drawctxt_switch(struct adreno_device *adreno_dev, /* Remove GMEM saving flag from the context */ drawctxt->flags &= ~CTXT_FLAGS_GMEM_SAVE; } + /* already current? */ - if (active_ctxt == drawctxt) + if (adreno_dev->drawctxt_active == drawctxt) return; KGSL_CTXT_INFO(device, "from %p to %p flags %d\n", adreno_dev->drawctxt_active, drawctxt, flags); - /* save old context*/ - if (active_ctxt && active_ctxt->flags & CTXT_FLAGS_GPU_HANG) - KGSL_CTXT_WARN(device, - "Current active context has caused gpu hang\n"); - if (active_ctxt != NULL) { - KGSL_CTXT_INFO(device, - "active_ctxt flags %08x\n", active_ctxt->flags); - /* save registers and constants. */ - adreno_ringbuffer_issuecmds(device, 0, - active_ctxt->reg_save, 3); - - if (active_ctxt->flags & CTXT_FLAGS_SHADER_SAVE) { - /* save shader partitioning and instructions. */ - adreno_ringbuffer_issuecmds(device, - KGSL_CMD_FLAGS_PMODE, - active_ctxt->shader_save, 3); - - /* fixup shader partitioning parameter for - * SET_SHADER_BASES. - */ - adreno_ringbuffer_issuecmds(device, 0, - active_ctxt->shader_fixup, 3); - - active_ctxt->flags |= CTXT_FLAGS_SHADER_RESTORE; - } - - if (active_ctxt->flags & CTXT_FLAGS_GMEM_SAVE - && active_ctxt->flags & CTXT_FLAGS_GMEM_SHADOW) { - /* save gmem. - * (note: changes shader. shader must already be saved.) - */ - adreno_ringbuffer_issuecmds(device, - KGSL_CMD_FLAGS_PMODE, - active_ctxt->context_gmem_shadow.gmem_save, 3); - - /* Restore TP0_CHICKEN */ - adreno_ringbuffer_issuecmds(device, 0, - active_ctxt->chicken_restore, 3); - - active_ctxt->flags |= CTXT_FLAGS_GMEM_RESTORE; - } - } + /* Save the old context */ + adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active); + /* Set the new context */ adreno_dev->drawctxt_active = drawctxt; - - /* restore new context */ - if (drawctxt != NULL) { - - KGSL_CTXT_INFO(device, - "drawctxt flags %08x\n", drawctxt->flags); - cmds[0] = pm4_nop_packet(1); - cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER; - cmds[2] = pm4_type3_packet(PM4_MEM_WRITE, 2); - cmds[3] = device->memstore.gpuaddr + - KGSL_DEVICE_MEMSTORE_OFFSET(current_context); - cmds[4] = (unsigned int)adreno_dev->drawctxt_active; - adreno_ringbuffer_issuecmds(device, 0, cmds, 5); - kgsl_mmu_setstate(device, drawctxt->pagetable); - -#ifndef CONFIG_MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP - kgsl_cffdump_syncmem(NULL, &drawctxt->gpustate, - drawctxt->gpustate.gpuaddr, LCC_SHADOW_SIZE + - REG_SHADOW_SIZE + CMD_BUFFER_SIZE + TEX_SHADOW_SIZE, - false); -#endif - - /* restore gmem. - * (note: changes shader. shader must not already be restored.) - */ - if (drawctxt->flags & CTXT_FLAGS_GMEM_RESTORE) { - adreno_ringbuffer_issuecmds(device, - KGSL_CMD_FLAGS_PMODE, - drawctxt->context_gmem_shadow.gmem_restore, 3); - - /* Restore TP0_CHICKEN */ - adreno_ringbuffer_issuecmds(device, 0, - drawctxt->chicken_restore, 3); - - drawctxt->flags &= ~CTXT_FLAGS_GMEM_RESTORE; - } - - /* restore registers and constants. */ - adreno_ringbuffer_issuecmds(device, 0, - drawctxt->reg_restore, 3); - - /* restore shader instructions & partitioning. */ - if (drawctxt->flags & CTXT_FLAGS_SHADER_RESTORE) { - adreno_ringbuffer_issuecmds(device, 0, - drawctxt->shader_restore, 3); - } - - cmds[0] = pm4_type3_packet(PM4_SET_BIN_BASE_OFFSET, 1); - cmds[1] = drawctxt->bin_base_offset; - if (!adreno_is_a220(adreno_dev)) - adreno_ringbuffer_issuecmds(device, 0, cmds, 2); - - } else - kgsl_mmu_setstate(device, device->mmu.defaultpagetable); + adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt); } diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h index 8ea40436..3c3a8536 100644 --- a/drivers/gpu/msm/adreno_drawctxt.h +++ b/drivers/gpu/msm/adreno_drawctxt.h @@ -1,36 +1,20 @@ /* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __ADRENO_DRAWCTXT_H #define __ADRENO_DRAWCTXT_H -#include "a200_reg.h" -#include "a220_reg.h" +#include "adreno_pm4types.h" +#include "a2xx_reg.h" /* Flags */ @@ -95,19 +79,73 @@ struct adreno_context { struct gmem_shadow_t context_gmem_shadow; }; +int adreno_drawctxt_create(struct kgsl_device *device, + struct kgsl_pagetable *pagetable, + struct kgsl_context *context, + uint32_t flags); -int adreno_drawctxt_create(struct kgsl_device_private *dev_priv, - uint32_t flags, - struct kgsl_context *context); - -int adreno_drawctxt_destroy(struct kgsl_device *device, +void adreno_drawctxt_destroy(struct kgsl_device *device, struct kgsl_context *context); void adreno_drawctxt_switch(struct adreno_device *adreno_dev, struct adreno_context *drawctxt, unsigned int flags); -int adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device, +void adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device, struct kgsl_context *context, unsigned int offset); +/* GPU context switch helper functions */ + +void build_quad_vtxbuff(struct adreno_context *drawctxt, + struct gmem_shadow_t *shadow, unsigned int **incmd); + +unsigned int uint2float(unsigned int); + +static inline unsigned int virt2gpu(unsigned int *cmd, + struct kgsl_memdesc *memdesc) +{ + return memdesc->gpuaddr + ((char *) cmd - (char *) memdesc->hostptr); +} + +static inline void create_ib1(struct adreno_context *drawctxt, + unsigned int *cmd, + unsigned int *start, + unsigned int *end) +{ + cmd[0] = CP_HDR_INDIRECT_BUFFER_PFD; + cmd[1] = virt2gpu(start, &drawctxt->gpustate); + cmd[2] = end - start; +} + + +static inline unsigned int *reg_range(unsigned int *cmd, unsigned int start, + unsigned int end) +{ + *cmd++ = CP_REG(start); /* h/w regs, start addr */ + *cmd++ = end - start + 1; /* count */ + return cmd; +} + +static inline void calc_gmemsize(struct gmem_shadow_t *shadow, int gmem_size) +{ + int w = 64, h = 64; + + shadow->format = COLORX_8_8_8_8; + + /* convert from bytes to 32-bit words */ + gmem_size = (gmem_size + 3) / 4; + + while ((w * h) < gmem_size) { + if (w < h) + w *= 2; + else + h *= 2; + } + + shadow->pitch = shadow->width = w; + shadow->height = h; + shadow->gmem_pitch = shadow->pitch; + shadow->size = shadow->pitch * shadow->height * 4; +} + #endif /* __ADRENO_DRAWCTXT_H */ diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h index 246315b6..8aea58c9 100644 --- a/drivers/gpu/msm/adreno_pm4types.h +++ b/drivers/gpu/msm/adreno_pm4types.h @@ -1,193 +1,193 @@ /* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __ADRENO_PM4TYPES_H #define __ADRENO_PM4TYPES_H -#define PM4_PKT_MASK 0xc0000000 +#define CP_PKT_MASK 0xc0000000 -#define PM4_TYPE0_PKT ((unsigned int)0 << 30) -#define PM4_TYPE1_PKT ((unsigned int)1 << 30) -#define PM4_TYPE2_PKT ((unsigned int)2 << 30) -#define PM4_TYPE3_PKT ((unsigned int)3 << 30) +#define CP_TYPE0_PKT ((unsigned int)0 << 30) +#define CP_TYPE1_PKT ((unsigned int)1 << 30) +#define CP_TYPE2_PKT ((unsigned int)2 << 30) +#define CP_TYPE3_PKT ((unsigned int)3 << 30) /* type3 packets */ /* initialize CP's micro-engine */ -#define PM4_ME_INIT 0x48 +#define CP_ME_INIT 0x48 /* skip N 32-bit words to get to the next packet */ -#define PM4_NOP 0x10 +#define CP_NOP 0x10 /* indirect buffer dispatch. prefetch parser uses this packet type to determine * whether to pre-fetch the IB */ -#define PM4_INDIRECT_BUFFER 0x3f +#define CP_INDIRECT_BUFFER 0x3f /* indirect buffer dispatch. same as IB, but init is pipelined */ -#define PM4_INDIRECT_BUFFER_PFD 0x37 +#define CP_INDIRECT_BUFFER_PFD 0x37 /* wait for the IDLE state of the engine */ -#define PM4_WAIT_FOR_IDLE 0x26 +#define CP_WAIT_FOR_IDLE 0x26 /* wait until a register or memory location is a specific value */ -#define PM4_WAIT_REG_MEM 0x3c +#define CP_WAIT_REG_MEM 0x3c /* wait until a register location is equal to a specific value */ -#define PM4_WAIT_REG_EQ 0x52 +#define CP_WAIT_REG_EQ 0x52 /* wait until a register location is >= a specific value */ -#define PM4_WAT_REG_GTE 0x53 +#define CP_WAT_REG_GTE 0x53 /* wait until a read completes */ -#define PM4_WAIT_UNTIL_READ 0x5c +#define CP_WAIT_UNTIL_READ 0x5c /* wait until all base/size writes from an IB_PFD packet have completed */ -#define PM4_WAIT_IB_PFD_COMPLETE 0x5d +#define CP_WAIT_IB_PFD_COMPLETE 0x5d /* register read/modify/write */ -#define PM4_REG_RMW 0x21 +#define CP_REG_RMW 0x21 /* reads register in chip and writes to memory */ -#define PM4_REG_TO_MEM 0x3e +#define CP_REG_TO_MEM 0x3e /* write N 32-bit words to memory */ -#define PM4_MEM_WRITE 0x3d +#define CP_MEM_WRITE 0x3d /* write CP_PROG_COUNTER value to memory */ -#define PM4_MEM_WRITE_CNTR 0x4f +#define CP_MEM_WRITE_CNTR 0x4f /* conditional execution of a sequence of packets */ -#define PM4_COND_EXEC 0x44 +#define CP_COND_EXEC 0x44 /* conditional write to memory or register */ -#define PM4_COND_WRITE 0x45 +#define CP_COND_WRITE 0x45 /* generate an event that creates a write to memory when completed */ -#define PM4_EVENT_WRITE 0x46 +#define CP_EVENT_WRITE 0x46 /* generate a VS|PS_done event */ -#define PM4_EVENT_WRITE_SHD 0x58 +#define CP_EVENT_WRITE_SHD 0x58 /* generate a cache flush done event */ -#define PM4_EVENT_WRITE_CFL 0x59 +#define CP_EVENT_WRITE_CFL 0x59 /* generate a z_pass done event */ -#define PM4_EVENT_WRITE_ZPD 0x5b +#define CP_EVENT_WRITE_ZPD 0x5b /* initiate fetch of index buffer and draw */ -#define PM4_DRAW_INDX 0x22 +#define CP_DRAW_INDX 0x22 /* draw using supplied indices in packet */ -#define PM4_DRAW_INDX_2 0x36 +#define CP_DRAW_INDX_2 0x36 /* initiate fetch of index buffer and binIDs and draw */ -#define PM4_DRAW_INDX_BIN 0x34 +#define CP_DRAW_INDX_BIN 0x34 /* initiate fetch of bin IDs and draw using supplied indices */ -#define PM4_DRAW_INDX_2_BIN 0x35 +#define CP_DRAW_INDX_2_BIN 0x35 /* begin/end initiator for viz query extent processing */ -#define PM4_VIZ_QUERY 0x23 +#define CP_VIZ_QUERY 0x23 /* fetch state sub-blocks and initiate shader code DMAs */ -#define PM4_SET_STATE 0x25 +#define CP_SET_STATE 0x25 /* load constant into chip and to memory */ -#define PM4_SET_CONSTANT 0x2d +#define CP_SET_CONSTANT 0x2d /* load sequencer instruction memory (pointer-based) */ -#define PM4_IM_LOAD 0x27 +#define CP_IM_LOAD 0x27 /* load sequencer instruction memory (code embedded in packet) */ -#define PM4_IM_LOAD_IMMEDIATE 0x2b +#define CP_IM_LOAD_IMMEDIATE 0x2b /* load constants from a location in memory */ -#define PM4_LOAD_CONSTANT_CONTEXT 0x2e +#define CP_LOAD_CONSTANT_CONTEXT 0x2e /* selective invalidation of state pointers */ -#define PM4_INVALIDATE_STATE 0x3b +#define CP_INVALIDATE_STATE 0x3b /* dynamically changes shader instruction memory partition */ -#define PM4_SET_SHADER_BASES 0x4A +#define CP_SET_SHADER_BASES 0x4A /* sets the 64-bit BIN_MASK register in the PFP */ -#define PM4_SET_BIN_MASK 0x50 +#define CP_SET_BIN_MASK 0x50 /* sets the 64-bit BIN_SELECT register in the PFP */ -#define PM4_SET_BIN_SELECT 0x51 +#define CP_SET_BIN_SELECT 0x51 /* updates the current context, if needed */ -#define PM4_CONTEXT_UPDATE 0x5e +#define CP_CONTEXT_UPDATE 0x5e /* generate interrupt from the command stream */ -#define PM4_INTERRUPT 0x40 +#define CP_INTERRUPT 0x40 /* copy sequencer instruction memory to system memory */ -#define PM4_IM_STORE 0x2c +#define CP_IM_STORE 0x2c -/* program an offset that will added to the BIN_BASE value of - * the 3D_DRAW_INDX_BIN packet */ -#define PM4_SET_BIN_BASE_OFFSET 0x4B +/* + * for a20x + * program an offset that will added to the BIN_BASE value of + * the 3D_DRAW_INDX_BIN packet + */ +#define CP_SET_BIN_BASE_OFFSET 0x4B -#define PM4_SET_PROTECTED_MODE 0x5f /* sets the register protection mode */ +/* + * for a22x + * sets draw initiator flags register in PFP, gets bitwise-ORed into + * every draw initiator + */ +#define CP_SET_DRAW_INIT_FLAGS 0x4B + +#define CP_SET_PROTECTED_MODE 0x5f /* sets the register protection mode */ /* packet header building macros */ -#define pm4_type0_packet(regindx, cnt) \ - (PM4_TYPE0_PKT | (((cnt)-1) << 16) | ((regindx) & 0x7FFF)) +#define cp_type0_packet(regindx, cnt) \ + (CP_TYPE0_PKT | (((cnt)-1) << 16) | ((regindx) & 0x7FFF)) -#define pm4_type0_packet_for_sameregister(regindx, cnt) \ - ((PM4_TYPE0_PKT | (((cnt)-1) << 16) | ((1 << 15) | \ +#define cp_type0_packet_for_sameregister(regindx, cnt) \ + ((CP_TYPE0_PKT | (((cnt)-1) << 16) | ((1 << 15) | \ ((regindx) & 0x7FFF))) -#define pm4_type1_packet(reg0, reg1) \ - (PM4_TYPE1_PKT | ((reg1) << 12) | (reg0)) +#define cp_type1_packet(reg0, reg1) \ + (CP_TYPE1_PKT | ((reg1) << 12) | (reg0)) -#define pm4_type3_packet(opcode, cnt) \ - (PM4_TYPE3_PKT | (((cnt)-1) << 16) | (((opcode) & 0xFF) << 8)) +#define cp_type3_packet(opcode, cnt) \ + (CP_TYPE3_PKT | (((cnt)-1) << 16) | (((opcode) & 0xFF) << 8)) -#define pm4_predicated_type3_packet(opcode, cnt) \ - (PM4_TYPE3_PKT | (((cnt)-1) << 16) | (((opcode) & 0xFF) << 8) | 0x1) +#define cp_predicated_type3_packet(opcode, cnt) \ + (CP_TYPE3_PKT | (((cnt)-1) << 16) | (((opcode) & 0xFF) << 8) | 0x1) -#define pm4_nop_packet(cnt) \ - (PM4_TYPE3_PKT | (((cnt)-1) << 16) | (PM4_NOP << 8)) +#define cp_nop_packet(cnt) \ + (CP_TYPE3_PKT | (((cnt)-1) << 16) | (CP_NOP << 8)) /* packet headers */ -#define PM4_HDR_ME_INIT pm4_type3_packet(PM4_ME_INIT, 18) -#define PM4_HDR_INDIRECT_BUFFER_PFD pm4_type3_packet(PM4_INDIRECT_BUFFER_PFD, 2) -#define PM4_HDR_INDIRECT_BUFFER pm4_type3_packet(PM4_INDIRECT_BUFFER, 2) +#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) + +/* dword base address of the GFX decode space */ +#define SUBBLOCK_OFFSET(reg) ((unsigned int)((reg) - (0x2000))) + +/* gmem command buffer length */ +#define CP_REG(reg) ((0x4 << 16) | (SUBBLOCK_OFFSET(reg))) #endif /* __ADRENO_PM4TYPES_H */ diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c index 4911e937..3d957f69 100644 --- a/drivers/gpu/msm/adreno_postmortem.c +++ b/drivers/gpu/msm/adreno_postmortem.c @@ -22,9 +22,10 @@ #include "adreno_debugfs.h" #include "kgsl_cffdump.h" -#include "a200_reg.h" +#include "a2xx_reg.h" #define INVALID_RB_CMD 0xaaaaaaaa +#define NUM_DWORDS_OF_RINGBUFFER_HISTORY 100 struct pm_id_name { uint32_t id; @@ -43,28 +44,28 @@ static const struct pm_id_name pm0_types[] = { }; static const struct pm_id_name pm3_types[] = { - {PM4_COND_EXEC, "CND_EXEC"}, - {PM4_CONTEXT_UPDATE, "CX__UPDT"}, - {PM4_DRAW_INDX, "DRW_NDX_"}, - {PM4_DRAW_INDX_BIN, "DRW_NDXB"}, - {PM4_EVENT_WRITE, "EVENT_WT"}, - {PM4_IM_LOAD, "IN__LOAD"}, - {PM4_IM_LOAD_IMMEDIATE, "IM_LOADI"}, - {PM4_IM_STORE, "IM_STORE"}, - {PM4_INDIRECT_BUFFER, "IND_BUF_"}, - {PM4_INDIRECT_BUFFER_PFD, "IND_BUFP"}, - {PM4_INTERRUPT, "PM4_INTR"}, - {PM4_INVALIDATE_STATE, "INV_STAT"}, - {PM4_LOAD_CONSTANT_CONTEXT, "LD_CN_CX"}, - {PM4_ME_INIT, "ME__INIT"}, - {PM4_NOP, "PM4__NOP"}, - {PM4_REG_RMW, "REG__RMW"}, - {PM4_REG_TO_MEM, "REG2_MEM"}, - {PM4_SET_BIN_BASE_OFFSET, "ST_BIN_O"}, - {PM4_SET_CONSTANT, "ST_CONST"}, - {PM4_SET_PROTECTED_MODE, "ST_PRT_M"}, - {PM4_SET_SHADER_BASES, "ST_SHD_B"}, - {PM4_WAIT_FOR_IDLE, "WAIT4IDL"}, + {CP_COND_EXEC, "CND_EXEC"}, + {CP_CONTEXT_UPDATE, "CX__UPDT"}, + {CP_DRAW_INDX, "DRW_NDX_"}, + {CP_DRAW_INDX_BIN, "DRW_NDXB"}, + {CP_EVENT_WRITE, "EVENT_WT"}, + {CP_IM_LOAD, "IN__LOAD"}, + {CP_IM_LOAD_IMMEDIATE, "IM_LOADI"}, + {CP_IM_STORE, "IM_STORE"}, + {CP_INDIRECT_BUFFER, "IND_BUF_"}, + {CP_INDIRECT_BUFFER_PFD, "IND_BUFP"}, + {CP_INTERRUPT, "PM4_INTR"}, + {CP_INVALIDATE_STATE, "INV_STAT"}, + {CP_LOAD_CONSTANT_CONTEXT, "LD_CN_CX"}, + {CP_ME_INIT, "ME__INIT"}, + {CP_NOP, "PM4__NOP"}, + {CP_REG_RMW, "REG__RMW"}, + {CP_REG_TO_MEM, "REG2_MEM"}, + {CP_SET_BIN_BASE_OFFSET, "ST_BIN_O"}, + {CP_SET_CONSTANT, "ST_CONST"}, + {CP_SET_PROTECTED_MODE, "ST_PRT_M"}, + {CP_SET_SHADER_BASES, "ST_SHD_B"}, + {CP_WAIT_FOR_IDLE, "WAIT4IDL"}, }; /* Offset address pairs: start, end of range to dump (inclusive) */ @@ -174,14 +175,14 @@ static bool adreno_is_pm4_type(uint32_t word) if (adreno_is_pm4_len(word) > 16) return 0; - if ((word & (3<<30)) == PM4_TYPE0_PKT) { + if ((word & (3<<30)) == CP_TYPE0_PKT) { for (i = 0; i < ARRAY_SIZE(pm0_types); ++i) { if ((word & 0x7FFF) == pm0_types[i].id) return 1; } return 0; } - if ((word & (3<<30)) == PM4_TYPE3_PKT) { + if ((word & (3<<30)) == CP_TYPE3_PKT) { for (i = 0; i < ARRAY_SIZE(pm3_types); ++i) { if ((word & 0xFFFF) == (pm3_types[i].id << 8)) return 1; @@ -198,14 +199,14 @@ static const char *adreno_pm4_name(uint32_t word) if (word == INVALID_RB_CMD) return "--------"; - if ((word & (3<<30)) == PM4_TYPE0_PKT) { + if ((word & (3<<30)) == CP_TYPE0_PKT) { for (i = 0; i < ARRAY_SIZE(pm0_types); ++i) { if ((word & 0x7FFF) == pm0_types[i].id) return pm0_types[i].name; } return "????????"; } - if ((word & (3<<30)) == PM4_TYPE3_PKT) { + if ((word & (3<<30)) == CP_TYPE3_PKT) { for (i = 0; i < ARRAY_SIZE(pm3_types); ++i) { if ((word & 0xFFFF) == (pm3_types[i].id << 8)) return pm3_types[i].name; @@ -289,7 +290,7 @@ static void dump_ib1(struct kgsl_device *device, uint32_t pt_base, for (i = 0; i+3 < ib1_size; ) { value = ib1_addr[i++]; - if (value == pm4_type3_packet(PM4_INDIRECT_BUFFER_PFD, 2)) { + if (value == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) { uint32_t ib2_base = ib1_addr[i++]; uint32_t ib2_size = ib1_addr[i++]; @@ -456,7 +457,7 @@ static int adreno_dump(struct kgsl_device *device) unsigned int r1, r2, r3, rbbm_status; unsigned int cp_ib1_base, cp_ib1_bufsz, cp_stat; unsigned int cp_ib2_base, cp_ib2_bufsz; - unsigned int pt_base; + unsigned int pt_base, cur_pt_base; unsigned int cp_rb_base, rb_count; unsigned int cp_rb_wptr, cp_rb_rptr; unsigned int i; @@ -536,7 +537,12 @@ static int adreno_dump(struct kgsl_device *device) kgsl_regread(device, REG_CP_RB_RPTR_ADDR, &r3); KGSL_LOG_DUMP(device, "CP_RB: BASE = %08X | CNTL = %08X | RPTR_ADDR = %08X" - "\n", cp_rb_base, r2, r3); + " | rb_count = %08X\n", cp_rb_base, r2, r3, rb_count); + { + struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; + if (rb->sizedwords != rb_count) + rb_count = rb->sizedwords; + } kgsl_regread(device, REG_CP_RB_RPTR, &cp_rb_rptr); kgsl_regread(device, REG_CP_RB_WPTR, &cp_rb_wptr); @@ -628,38 +634,37 @@ static int adreno_dump(struct kgsl_device *device) "COHER: SIZE_PM4 = %08X | BASE_PM4 = %08X | STATUS_PM4" " = %08X\n", r1, r2, r3); - kgsl_regread(device, REG_MH_AXI_ERROR, &r1); + kgsl_regread(device, MH_AXI_ERROR, &r1); KGSL_LOG_DUMP(device, "MH: AXI_ERROR = %08X\n", r1); - kgsl_regread(device, REG_MH_MMU_PAGE_FAULT, &r1); - kgsl_regread(device, REG_MH_MMU_CONFIG, &r2); - kgsl_regread(device, REG_MH_MMU_MPU_BASE, &r3); + kgsl_regread(device, MH_MMU_PAGE_FAULT, &r1); + kgsl_regread(device, MH_MMU_CONFIG, &r2); + kgsl_regread(device, MH_MMU_MPU_BASE, &r3); KGSL_LOG_DUMP(device, "MH_MMU: PAGE_FAULT = %08X | CONFIG = %08X | MPU_BASE =" " %08X\n", r1, r2, r3); - kgsl_regread(device, REG_MH_MMU_MPU_END, &r1); - kgsl_regread(device, REG_MH_MMU_VA_RANGE, &r2); - kgsl_regread(device, REG_MH_MMU_PT_BASE, &pt_base); + kgsl_regread(device, MH_MMU_MPU_END, &r1); + kgsl_regread(device, MH_MMU_VA_RANGE, &r2); + pt_base = kgsl_mmu_get_current_ptbase(device); KGSL_LOG_DUMP(device, " MPU_END = %08X | VA_RANGE = %08X | PT_BASE =" " %08X\n", r1, r2, pt_base); + cur_pt_base = pt_base; KGSL_LOG_DUMP(device, "PAGETABLE SIZE: %08X ", KGSL_PAGETABLE_SIZE); - kgsl_regread(device, REG_MH_MMU_TRAN_ERROR, &r1); + kgsl_regread(device, MH_MMU_TRAN_ERROR, &r1); KGSL_LOG_DUMP(device, " TRAN_ERROR = %08X\n", r1); - kgsl_regread(device, REG_MH_INTERRUPT_MASK, &r1); - kgsl_regread(device, REG_MH_INTERRUPT_STATUS, &r2); + kgsl_regread(device, MH_INTERRUPT_MASK, &r1); + kgsl_regread(device, MH_INTERRUPT_STATUS, &r2); KGSL_LOG_DUMP(device, "MH_INTERRUPT: MASK = %08X | STATUS = %08X\n", r1, r2); - if (device->ftbl.device_readtimestamp != NULL) { - ts_processed = device->ftbl.device_readtimestamp( - device, KGSL_TIMESTAMP_RETIRED); - KGSL_LOG_DUMP(device, "TIMESTM RTRD: %08X\n", ts_processed); - } + ts_processed = device->ftbl->readtimestamp(device, + KGSL_TIMESTAMP_RETIRED); + KGSL_LOG_DUMP(device, "TIMESTM RTRD: %08X\n", ts_processed); num_item = adreno_ringbuffer_count(&adreno_dev->ringbuffer, cp_rb_rptr); @@ -676,21 +681,21 @@ 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, pt_base, - cp_rb_base, &rb_memsize); + rb_vaddr = (const uint32_t *)kgsl_sharedmem_convertaddr(device, + cur_pt_base, cp_rb_base, &rb_memsize); if (!rb_vaddr) { KGSL_LOG_POSTMORTEM_WRITE(device, "Can't fetch vaddr for CP_RB_BASE\n"); goto error_vfree; } - read_idx = (int)cp_rb_rptr - 64; + read_idx = (int)cp_rb_rptr - NUM_DWORDS_OF_RINGBUFFER_HISTORY; if (read_idx < 0) read_idx += rb_count; write_idx = (int)cp_rb_wptr + 16; if (write_idx > rb_count) write_idx -= rb_count; - num_item += 64+16; + num_item += NUM_DWORDS_OF_RINGBUFFER_HISTORY+16; if (num_item > rb_count) num_item = rb_count; if (write_idx >= read_idx) @@ -706,20 +711,27 @@ 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 == pm4_type3_packet(PM4_INDIRECT_BUFFER_PFD, 2)) { + if (this_cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) { uint32_t ib_addr = rb_copy[read_idx++]; uint32_t ib_size = rb_copy[read_idx++]; - dump_ib1(device, pt_base, (read_idx-3)<<2, ib_addr, + dump_ib1(device, cur_pt_base, (read_idx-3)<<2, ib_addr, ib_size, &ib_list, 0); for (; i < ib_list.count; ++i) - dump_ib(device, "IB2:", pt_base, + dump_ib(device, "IB2:", cur_pt_base, ib_list.offsets[i], ib_list.bases[i], ib_list.sizes[i], 0); + } else if (this_cmd == cp_type0_packet(MH_MMU_PT_BASE, 1)) { + /* Set cur_pt_base to the new pagetable base */ + cur_pt_base = rb_copy[read_idx++]; } } - read_idx = (int)cp_rb_rptr - 64; + /* Restore cur_pt_base back to the pt_base of + the process in whose context the GPU hung */ + cur_pt_base = pt_base; + + read_idx = (int)cp_rb_rptr - NUM_DWORDS_OF_RINGBUFFER_HISTORY; if (read_idx < 0) read_idx += rb_count; KGSL_LOG_DUMP(device, @@ -728,30 +740,31 @@ static int adreno_dump(struct kgsl_device *device) adreno_dump_rb(device, rb_copy, num_item<<2, read_idx, rb_count); if (adreno_ib_dump_enabled()) { - for (read_idx = 64; read_idx >= 0; --read_idx) { + for (read_idx = NUM_DWORDS_OF_RINGBUFFER_HISTORY; + read_idx >= 0; --read_idx) { uint32_t this_cmd = rb_copy[read_idx]; - if (this_cmd == pm4_type3_packet( - PM4_INDIRECT_BUFFER_PFD, 2)) { + if (this_cmd == cp_type3_packet( + CP_INDIRECT_BUFFER_PFD, 2)) { uint32_t ib_addr = rb_copy[read_idx+1]; uint32_t ib_size = rb_copy[read_idx+2]; - if (cp_ib1_bufsz && cp_ib1_base == ib_addr) { + if (ib_size && cp_ib1_base == ib_addr) { KGSL_LOG_DUMP(device, "IB1: base:%8.8X " "count:%d\n", ib_addr, ib_size); - dump_ib(device, "IB1: ", pt_base, + dump_ib(device, "IB1: ", cur_pt_base, read_idx<<2, ib_addr, ib_size, 1); } } } for (i = 0; i < ib_list.count; ++i) { - if (cp_ib2_bufsz && cp_ib2_base == ib_list.bases[i]) { - uint32_t ib_size = ib_list.sizes[i]; - uint32_t ib_offset = ib_list.offsets[i]; + uint32_t ib_size = ib_list.sizes[i]; + uint32_t ib_offset = ib_list.offsets[i]; + if (ib_size && cp_ib2_base == ib_list.bases[i]) { KGSL_LOG_DUMP(device, "IB2: base:%8.8X count:%d\n", cp_ib2_base, ib_size); - dump_ib(device, "IB2: ", pt_base, ib_offset, + dump_ib(device, "IB2: ", cur_pt_base, ib_offset, ib_list.bases[i], ib_size, 1); } } @@ -802,7 +815,7 @@ int adreno_postmortem_dump(struct kgsl_device *device, int manual) } /* Disable the idle timer so we don't get interrupted */ - del_timer(&device->idle_timer); + del_timer_sync(&device->idle_timer); /* Turn off napping to make sure we have the clocks full attention through the following process */ diff --git a/drivers/gpu/msm/adreno_postmortem.h b/drivers/gpu/msm/adreno_postmortem.h index 1a432489..b6778006 100644 --- a/drivers/gpu/msm/adreno_postmortem.h +++ b/drivers/gpu/msm/adreno_postmortem.h @@ -1,29 +1,13 @@ /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 4aaa2c6c..d59057c8 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -16,14 +16,15 @@ #include #include "kgsl.h" +#include "kgsl_sharedmem.h" +#include "kgsl_cffdump.h" #include "adreno.h" #include "adreno_pm4types.h" #include "adreno_ringbuffer.h" -#include "a200_reg.h" +#include "a2xx_reg.h" -#define VALID_STATUS_COUNT_MAX 10 #define GSL_RB_NOP_SIZEDWORDS 2 /* protected mode error checking below register address 0x800 * note: if CP_INTERRUPT packet is used then checking needs @@ -31,17 +32,6 @@ */ #define GSL_RB_PROTECTED_MODE_CONTROL 0x200001F2 -#define GSL_CP_INT_MASK \ - (CP_INT_CNTL__SW_INT_MASK | \ - CP_INT_CNTL__T0_PACKET_IN_IB_MASK | \ - CP_INT_CNTL__OPCODE_ERROR_MASK | \ - CP_INT_CNTL__PROTECTED_MODE_ERROR_MASK | \ - CP_INT_CNTL__RESERVED_BIT_ERROR_MASK | \ - CP_INT_CNTL__IB_ERROR_MASK | \ - CP_INT_CNTL__IB2_INT_MASK | \ - CP_INT_CNTL__IB1_INT_MASK | \ - CP_INT_CNTL__RB_INT_MASK) - /* Firmware file names * Legacy names must remain but replacing macro names to * match current kgsl model. @@ -52,102 +42,17 @@ #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" - -/* functions */ -void kgsl_cp_intrcallback(struct kgsl_device *device) -{ - unsigned int status = 0, num_reads = 0, master_status = 0; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; - - adreno_regread_isr(device, REG_MASTER_INT_SIGNAL, &master_status); - while (!status && (num_reads < VALID_STATUS_COUNT_MAX) && - (master_status & MASTER_INT_SIGNAL__CP_INT_STAT)) { - adreno_regread_isr(device, REG_CP_INT_STATUS, &status); - adreno_regread_isr(device, REG_MASTER_INT_SIGNAL, - &master_status); - num_reads++; - } - if (num_reads > 1) - KGSL_DRV_WARN(device, - "Looped %d times to read REG_CP_INT_STATUS\n", - num_reads); - if (!status) { - if (master_status & MASTER_INT_SIGNAL__CP_INT_STAT) { - /* This indicates that we could not read CP_INT_STAT. - * As a precaution just wake up processes so - * they can check their timestamps. Since, we - * did not ack any interrupts this interrupt will - * be generated again */ - KGSL_DRV_WARN(device, "Unable to read CP_INT_STATUS\n"); - wake_up_interruptible_all(&device->wait_queue); - } else - KGSL_DRV_WARN(device, "Spurious interrput detected\n"); - return; - } - - if (status & CP_INT_CNTL__RB_INT_MASK) { - /* signal intr completion event */ - unsigned int enableflag = 0; - kgsl_sharedmem_writel(&rb->device->memstore, - KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable), - enableflag); - wmb(); - KGSL_CMD_WARN(rb->device, "ringbuffer rb interrupt\n"); - } - - if (status & CP_INT_CNTL__T0_PACKET_IN_IB_MASK) { - KGSL_CMD_CRIT(rb->device, - "ringbuffer TO packet in IB interrupt\n"); - adreno_regwrite_isr(rb->device, REG_CP_INT_CNTL, 0); - } - if (status & CP_INT_CNTL__OPCODE_ERROR_MASK) { - KGSL_CMD_CRIT(rb->device, - "ringbuffer opcode error interrupt\n"); - adreno_regwrite_isr(rb->device, REG_CP_INT_CNTL, 0); - } - if (status & CP_INT_CNTL__PROTECTED_MODE_ERROR_MASK) { - KGSL_CMD_CRIT(rb->device, - "ringbuffer protected mode error interrupt\n"); - adreno_regwrite_isr(rb->device, REG_CP_INT_CNTL, 0); - } - if (status & CP_INT_CNTL__RESERVED_BIT_ERROR_MASK) { - KGSL_CMD_CRIT(rb->device, - "ringbuffer reserved bit error interrupt\n"); - adreno_regwrite_isr(rb->device, REG_CP_INT_CNTL, 0); - } - if (status & CP_INT_CNTL__IB_ERROR_MASK) { - KGSL_CMD_CRIT(rb->device, - "ringbuffer IB error interrupt\n"); - adreno_regwrite_isr(rb->device, REG_CP_INT_CNTL, 0); - } - if (status & CP_INT_CNTL__SW_INT_MASK) - KGSL_CMD_INFO(rb->device, "ringbuffer software interrupt\n"); - - if (status & CP_INT_CNTL__IB2_INT_MASK) - KGSL_CMD_INFO(rb->device, "ringbuffer ib2 interrupt\n"); - - if (status & (~GSL_CP_INT_MASK)) - KGSL_CMD_WARN(rb->device, - "bad bits in REG_CP_INT_STATUS %08x\n", status); - - /* only ack bits we understand */ - status &= GSL_CP_INT_MASK; - adreno_regwrite_isr(device, REG_CP_INT_ACK, status); - - if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) { - KGSL_CMD_WARN(rb->device, "ringbuffer ib1/rb interrupt\n"); - wake_up_interruptible_all(&device->wait_queue); - atomic_notifier_call_chain(&(device->ts_notifier_list), - device->id, - NULL); - } -} +#define A225_PFP_FW "a225_pfp.fw" +#define A225_PM4_FW "a225_pm4.fw" static void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb) { BUG_ON(rb->wptr == 0); + /* Let the pwrscale policy know that new commands have + been submitted. */ + kgsl_pwrscale_busy(rb->device); + /*synchronize memory before informing the hardware of the *new commands. */ @@ -156,7 +61,7 @@ static void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb) adreno_regwrite(rb->device, REG_CP_RB_WPTR, rb->wptr); } -static int +static void adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, unsigned int numcmds, int wptr_ahead) { @@ -173,7 +78,7 @@ adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, unsigned int numcmds, cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr; cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*rb->wptr; - GSL_RB_WRITE(cmds, cmds_gpu, pm4_nop_packet(nopcount)); + GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount)); /* Make sure that rptr is not 0 before submitting * commands at the end of ringbuffer. We do not @@ -197,8 +102,6 @@ adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, unsigned int numcmds, freecmds = rb->rptr - rb->wptr; } while ((freecmds != 0) && (freecmds <= numcmds)); - - return 0; } @@ -206,7 +109,6 @@ static unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb, unsigned int numcmds) { unsigned int *ptr = NULL; - int status = 0; BUG_ON(numcmds >= rb->sizedwords); @@ -217,22 +119,20 @@ static unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb, /* reserve dwords for nop packet */ if ((rb->wptr + numcmds) > (rb->sizedwords - GSL_RB_NOP_SIZEDWORDS)) - status = adreno_ringbuffer_waitspace(rb, numcmds, 1); + adreno_ringbuffer_waitspace(rb, numcmds, 1); } else { /* wptr behind rptr */ if ((rb->wptr + numcmds) >= rb->rptr) - status = adreno_ringbuffer_waitspace(rb, numcmds, 0); + adreno_ringbuffer_waitspace(rb, numcmds, 0); /* check for remaining space */ /* reserve dwords for nop packet */ if ((rb->wptr + numcmds) > (rb->sizedwords - GSL_RB_NOP_SIZEDWORDS)) - status = adreno_ringbuffer_waitspace(rb, numcmds, 1); + adreno_ringbuffer_waitspace(rb, numcmds, 1); } - if (status == 0) { - ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr; - rb->wptr += numcmds; - } + ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr; + rb->wptr += numcmds; return ptr; } @@ -266,19 +166,15 @@ static int _load_firmware(struct kgsl_device *device, const char *fwfile, static int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - const char *fwfile; int i, ret = 0; - if (adreno_is_a220(adreno_dev)) - fwfile = A220_PM4_470_FW; - else - fwfile = A200_PM4_FW; - if (adreno_dev->pm4_fw == NULL) { int len; - unsigned int *ptr; + void *ptr; + + ret = _load_firmware(device, adreno_dev->pm4_fwfile, + &ptr, &len); - ret = _load_firmware(device, fwfile, (void *) &ptr, &len); if (ret) goto err; @@ -309,19 +205,14 @@ err: static int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - const char *fwfile; int i, ret = 0; - if (adreno_is_a220(adreno_dev)) - fwfile = A220_PFP_470_FW; - else - fwfile = A200_PFP_FW; - if (adreno_dev->pfp_fw == NULL) { int len; - unsigned int *ptr; + void *ptr; - ret = _load_firmware(device, fwfile, (void *) &ptr, &len); + ret = _load_firmware(device, adreno_dev->pfp_fwfile, + &ptr, &len); if (ret) goto err; @@ -441,7 +332,7 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram) cmds = adreno_ringbuffer_allocspace(rb, 19); cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-19); - GSL_RB_WRITE(cmds, cmds_gpu, PM4_HDR_ME_INIT); + 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) */ @@ -450,21 +341,21 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram) GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000); GSL_RB_WRITE(cmds, cmds_gpu, - GSL_HAL_SUBBLOCK_OFFSET(REG_RB_SURFACE_INFO)); + SUBBLOCK_OFFSET(REG_RB_SURFACE_INFO)); GSL_RB_WRITE(cmds, cmds_gpu, - GSL_HAL_SUBBLOCK_OFFSET(REG_PA_SC_WINDOW_OFFSET)); + SUBBLOCK_OFFSET(REG_PA_SC_WINDOW_OFFSET)); GSL_RB_WRITE(cmds, cmds_gpu, - GSL_HAL_SUBBLOCK_OFFSET(REG_VGT_MAX_VTX_INDX)); + SUBBLOCK_OFFSET(REG_VGT_MAX_VTX_INDX)); GSL_RB_WRITE(cmds, cmds_gpu, - GSL_HAL_SUBBLOCK_OFFSET(REG_SQ_PROGRAM_CNTL)); + SUBBLOCK_OFFSET(REG_SQ_PROGRAM_CNTL)); GSL_RB_WRITE(cmds, cmds_gpu, - GSL_HAL_SUBBLOCK_OFFSET(REG_RB_DEPTHCONTROL)); + SUBBLOCK_OFFSET(REG_RB_DEPTHCONTROL)); GSL_RB_WRITE(cmds, cmds_gpu, - GSL_HAL_SUBBLOCK_OFFSET(REG_PA_SU_POINT_SIZE)); + SUBBLOCK_OFFSET(REG_PA_SU_POINT_SIZE)); GSL_RB_WRITE(cmds, cmds_gpu, - GSL_HAL_SUBBLOCK_OFFSET(REG_PA_SC_LINE_CNTL)); + SUBBLOCK_OFFSET(REG_PA_SC_LINE_CNTL)); GSL_RB_WRITE(cmds, cmds_gpu, - GSL_HAL_SUBBLOCK_OFFSET(REG_PA_SU_POLY_OFFSET_FRONT_SCALE)); + SUBBLOCK_OFFSET(REG_PA_SU_POLY_OFFSET_FRONT_SCALE)); /* Vertex and Pixel Shader Start Addresses in instructions * (3 DWORDS per instruction) */ @@ -489,25 +380,20 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram) /* idle device to validate ME INIT */ status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT); - adreno_regwrite(rb->device, REG_CP_INT_CNTL, GSL_CP_INT_MASK); if (status == 0) rb->flags |= KGSL_FLAGS_STARTED; return status; } -int adreno_ringbuffer_stop(struct adreno_ringbuffer *rb) +void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb) { if (rb->flags & KGSL_FLAGS_STARTED) { - adreno_regwrite(rb->device, REG_CP_INT_CNTL, 0); - /* ME_HALT */ adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000); rb->flags &= ~KGSL_FLAGS_STARTED; } - - return 0; } int adreno_ringbuffer_init(struct kgsl_device *device) @@ -525,7 +411,8 @@ int adreno_ringbuffer_init(struct kgsl_device *device) rb->sizedwords = KGSL_RB_SIZE >> 2; /* allocate memory for ringbuffer */ - status = kgsl_allocate_contig(&rb->buffer_desc, (rb->sizedwords << 2)); + status = kgsl_allocate_contiguous(&rb->buffer_desc, + (rb->sizedwords << 2)); if (status != 0) { adreno_ringbuffer_close(rb); @@ -535,7 +422,7 @@ int adreno_ringbuffer_init(struct kgsl_device *device) /* allocate memory for polling and timestamps */ /* This really can be at 4 byte alignment boundry but for using MMU * we need to make it at page boundary */ - status = kgsl_allocate_contig(&rb->memptrs_desc, + status = kgsl_allocate_contiguous(&rb->memptrs_desc, sizeof(struct kgsl_rbmemptrs)); if (status != 0) { @@ -549,7 +436,7 @@ int adreno_ringbuffer_init(struct kgsl_device *device) return 0; } -int adreno_ringbuffer_close(struct adreno_ringbuffer *rb) +void adreno_ringbuffer_close(struct adreno_ringbuffer *rb) { struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device); @@ -563,8 +450,6 @@ int adreno_ringbuffer_close(struct adreno_ringbuffer *rb) adreno_dev->pm4_fw = NULL; memset(rb, 0, sizeof(struct adreno_ringbuffer)); - - return 0; } static uint32_t @@ -590,13 +475,13 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, + sizeof(uint)*(rb->wptr-total_sizedwords); if (!(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD)) { - GSL_RB_WRITE(ringcmds, rcmd_gpu, pm4_nop_packet(1)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1)); GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER); } if (flags & KGSL_CMD_FLAGS_PMODE) { /* disable protected mode error checking */ GSL_RB_WRITE(ringcmds, rcmd_gpu, - pm4_type3_packet(PM4_SET_PROTECTED_MODE, 1)); + cp_type3_packet(CP_SET_PROTECTED_MODE, 1)); GSL_RB_WRITE(ringcmds, rcmd_gpu, 0); } @@ -608,7 +493,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, if (flags & KGSL_CMD_FLAGS_PMODE) { /* re-enable protected mode error checking */ GSL_RB_WRITE(ringcmds, rcmd_gpu, - pm4_type3_packet(PM4_SET_PROTECTED_MODE, 1)); + cp_type3_packet(CP_SET_PROTECTED_MODE, 1)); GSL_RB_WRITE(ringcmds, rcmd_gpu, 1); } @@ -616,9 +501,9 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, timestamp = rb->timestamp; /* start-of-pipeline and end-of-pipeline timestamps */ - GSL_RB_WRITE(ringcmds, rcmd_gpu, pm4_type0_packet(REG_CP_TIMESTAMP, 1)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1)); GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp); - GSL_RB_WRITE(ringcmds, rcmd_gpu, pm4_type3_packet(PM4_EVENT_WRITE, 3)); + 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, (rb->device->memstore.gpuaddr + @@ -628,7 +513,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) { /* Conditional execution based on memory values */ GSL_RB_WRITE(ringcmds, rcmd_gpu, - pm4_type3_packet(PM4_COND_EXEC, 4)); + cp_type3_packet(CP_COND_EXEC, 4)); GSL_RB_WRITE(ringcmds, rcmd_gpu, (rb->device->memstore.gpuaddr + KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable)) >> 2); GSL_RB_WRITE(ringcmds, rcmd_gpu, (rb->device->memstore.gpuaddr + @@ -637,7 +522,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, /* # of conditional command DWORDs */ GSL_RB_WRITE(ringcmds, rcmd_gpu, 2); GSL_RB_WRITE(ringcmds, rcmd_gpu, - pm4_type3_packet(PM4_INTERRUPT, 1)); + cp_type3_packet(CP_INTERRUPT, 1)); GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK); } @@ -701,13 +586,13 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, (void)kgsl_cffdump_parse_ibs(dev_priv, NULL, ibdesc[i].gpuaddr, ibdesc[i].sizedwords, false); - *cmds++ = PM4_HDR_INDIRECT_BUFFER_PFD; + *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD; *cmds++ = ibdesc[i].gpuaddr; *cmds++ = ibdesc[i].sizedwords; } kgsl_setstate(device, - kgsl_pt_get_flags(device->mmu.hwpagetable, + kgsl_mmu_pt_get_flags(device->mmu.hwpagetable, device->id)); adreno_drawctxt_switch(adreno_dev, drawctxt, flags); @@ -751,13 +636,8 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb, GSL_RB_GET_READPTR(rb, &rb->rptr); -/* drewis: still not sure where this struct was changed */ -#if 0 retired_timestamp = device->ftbl->readtimestamp(device, KGSL_TIMESTAMP_RETIRED); -#endif - retired_timestamp = device->ftbl.device_readtimestamp( - device, KGSL_TIMESTAMP_RETIRED); KGSL_DRV_ERR(device, "GPU successfully executed till ts: %x\n", retired_timestamp); /* @@ -786,9 +666,9 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb, kgsl_sharedmem_readl(&rb->buffer_desc, &val3, rb_rptr); /* match the pattern found at the end of a command */ if ((val1 == 2 && - val2 == pm4_type3_packet(PM4_INTERRUPT, 1) + val2 == cp_type3_packet(CP_INTERRUPT, 1) && val3 == CP_INT_CNTL__RB_INT_MASK) || - (val1 == pm4_type3_packet(PM4_EVENT_WRITE, 3) + (val1 == cp_type3_packet(CP_EVENT_WRITE, 3) && val2 == CACHE_FLUSH_TS && val3 == (rb->device->memstore.gpuaddr + KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp)))) { @@ -830,7 +710,7 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb, kgsl_sharedmem_readl(&rb->buffer_desc, &val2, adreno_ringbuffer_inc_wrapped(rb_rptr, rb->buffer_desc.size)); - if (val1 == pm4_nop_packet(1) && val2 == KGSL_CMD_IDENTIFIER) { + if (val1 == cp_nop_packet(1) && val2 == KGSL_CMD_IDENTIFIER) { KGSL_DRV_ERR(device, "GPU recovery from hang not possible because " "of hang in kgsl command\n"); @@ -850,7 +730,7 @@ 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(value != pm4_type3_packet(PM4_MEM_WRITE, 2)); + BUG_ON(value != cp_type3_packet(CP_MEM_WRITE, 2)); kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr); rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, rb->buffer_desc.size); @@ -873,14 +753,14 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb, * commands can be executed */ if (value != cur_context) { copy_rb_contents = 1; - temp_rb_buffer[temp_idx++] = pm4_nop_packet(1); + temp_rb_buffer[temp_idx++] = cp_nop_packet(1); temp_rb_buffer[temp_idx++] = KGSL_CMD_IDENTIFIER; - temp_rb_buffer[temp_idx++] = pm4_nop_packet(1); + temp_rb_buffer[temp_idx++] = cp_nop_packet(1); temp_rb_buffer[temp_idx++] = KGSL_CONTEXT_TO_MEM_IDENTIFIER; temp_rb_buffer[temp_idx++] = - pm4_type3_packet(PM4_MEM_WRITE, 2); + cp_type3_packet(CP_MEM_WRITE, 2); temp_rb_buffer[temp_idx++] = val1; temp_rb_buffer[temp_idx++] = value; } else { diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index 9162dea2..3e7a6880 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -1,29 +1,14 @@ /* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. + * Copyright (C) 2011 Sony Ericsson Mobile Communications AB. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __ADRENO_RINGBUFFER_H @@ -77,9 +62,6 @@ struct adreno_ringbuffer { uint32_t timestamp; }; -/* dword base address of the GFX decode space */ -#define GSL_HAL_SUBBLOCK_OFFSET(reg) ((unsigned int)((reg) - (0x2000))) - #define GSL_RB_WRITE(ring, gpuaddr, data) \ do { \ writel_relaxed(data, ring); \ @@ -135,9 +117,9 @@ int adreno_ringbuffer_init(struct kgsl_device *device); int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram); -int adreno_ringbuffer_stop(struct adreno_ringbuffer *rb); +void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb); -int adreno_ringbuffer_close(struct adreno_ringbuffer *rb); +void adreno_ringbuffer_close(struct adreno_ringbuffer *rb); void adreno_ringbuffer_issuecmds(struct kgsl_device *device, unsigned int flags, diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 2732ffeb..e21ca09c 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1,4 +1,5 @@ /* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved. + * Copyright (C) 2011 Sony Ericsson Mobile Communications AB. * * 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 @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -27,14 +29,78 @@ #include "kgsl.h" #include "kgsl_debugfs.h" #include "kgsl_cffdump.h" +#include "kgsl_log.h" +#include "kgsl_sharedmem.h" +#include "kgsl_device.h" #undef MODULE_PARAM_PREFIX #define MODULE_PARAM_PREFIX "kgsl." static int kgsl_pagetable_count = KGSL_PAGETABLE_COUNT; +static char *ksgl_mmu_type; module_param_named(ptcount, kgsl_pagetable_count, int, 0); MODULE_PARM_DESC(kgsl_pagetable_count, "Minimum number of pagetables for KGSL to allocate at initialization time"); +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 + +/** + * kgsl_add_event - Add a new timstamp event for the KGSL device + * @device - KGSL device for the new event + * @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 + * + * @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) +{ + struct kgsl_event *event; + struct list_head *n; + unsigned int cur = device->ftbl->readtimestamp(device, + KGSL_TIMESTAMP_RETIRED); + + if (cb == NULL) + return -EINVAL; + + /* Check to see if the requested timestamp has already fired */ + + if (timestamp_cmp(cur, ts) >= 0) { + cb(device, priv, cur); + return 0; + } + + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (event == NULL) + return -ENOMEM; + + event->timestamp = ts; + event->priv = priv; + event->func = cb; + + /* Add the event in order to the list */ + + for (n = device->events.next ; n != &device->events; n = n->next) { + struct kgsl_event *e = + list_entry(n, struct kgsl_event, list); + + if (timestamp_cmp(e->timestamp, ts) > 0) { + list_add(&event->list, n->prev); + break; + } + } + + if (n == &device->events) + list_add_tail(&event->list, &device->events); + + return 0; +} +#endif static inline struct kgsl_mem_entry * kgsl_mem_entry_create(void) @@ -173,36 +239,41 @@ static void kgsl_memqueue_freememontimestamp(struct kgsl_device *device, list_add_tail(&entry->list, &device->memqueue); } -static void kgsl_memqueue_drain(struct kgsl_device *device) +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; - BUG_ON(!mutex_is_locked(&device->mutex)); + mutex_lock(&device->mutex); /* get current EOP timestamp */ - ts_processed = device->ftbl.device_readtimestamp( - device, - KGSL_TIMESTAMP_RETIRED); + ts_processed = device->ftbl->readtimestamp(device, + KGSL_TIMESTAMP_RETIRED); + /* Flush the freememontimestamp queue */ list_for_each_entry_safe(entry, entry_tmp, &device->memqueue, list) { - KGSL_MEM_INFO(device, - "ts_processed %d ts_free %d gpuaddr %x)\n", - ts_processed, entry->free_timestamp, - entry->memdesc.gpuaddr); - if (!timestamp_cmp(ts_processed, entry->free_timestamp)) + if (timestamp_cmp(ts_processed, entry->free_timestamp) < 0) break; list_del(&entry->list); kgsl_mem_entry_put(entry); } -} -static void kgsl_memqueue_drain_unlocked(struct kgsl_device *device) -{ - mutex_lock(&device->mutex); - kgsl_check_suspended(device); - kgsl_memqueue_drain(device); + /* Process expired events */ + list_for_each_entry_safe(event, event_tmp, &device->events, list) { + if (timestamp_cmp(ts_processed, event->timestamp) < 0) + break; + + if (event->func) + event->func(device, event->priv, ts_processed); + + list_del(&event->list); + kfree(event); + } + mutex_unlock(&device->mutex); } @@ -280,43 +351,19 @@ EXPORT_SYMBOL(kgsl_unregister_ts_notifier); int kgsl_check_timestamp(struct kgsl_device *device, unsigned int timestamp) { unsigned int ts_processed; - BUG_ON(device->ftbl.device_readtimestamp == NULL); - ts_processed = device->ftbl.device_readtimestamp( - device, KGSL_TIMESTAMP_RETIRED); + ts_processed = device->ftbl->readtimestamp(device, + KGSL_TIMESTAMP_RETIRED); - return timestamp_cmp(ts_processed, timestamp); + return (timestamp_cmp(ts_processed, timestamp) >= 0); } EXPORT_SYMBOL(kgsl_check_timestamp); -int kgsl_setstate(struct kgsl_device *device, uint32_t flags) -{ - int status = -ENXIO; - - if (flags && device->ftbl.device_setstate) { - status = device->ftbl.device_setstate(device, flags); - } else - status = 0; - - return status; -} -EXPORT_SYMBOL(kgsl_setstate); - -int kgsl_idle(struct kgsl_device *device, unsigned int timeout) -{ - int status = -ENXIO; - - if (device->ftbl.device_idle) - status = device->ftbl.device_idle(device, timeout); - - return status; -} -EXPORT_SYMBOL(kgsl_idle); - static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) { int status = -EINVAL; unsigned int nap_allowed_saved; + struct kgsl_pwrscale_policy *policy_saved; if (!device) return -EINVAL; @@ -326,6 +373,8 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) mutex_lock(&device->mutex); nap_allowed_saved = device->pwrctrl.nap_allowed; device->pwrctrl.nap_allowed = false; + policy_saved = device->pwrscale.policy; + device->pwrscale.policy = NULL; device->requested_state = KGSL_STATE_SUSPEND; /* Make sure no user process is waiting for a timestamp * * before supending */ @@ -335,19 +384,19 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) mutex_lock(&device->mutex); } /* Don't let the timer wake us during suspended sleep. */ - del_timer(&device->idle_timer); + del_timer_sync(&device->idle_timer); switch (device->state) { case KGSL_STATE_INIT: break; case KGSL_STATE_ACTIVE: /* Wait for the device to become idle */ - device->ftbl.device_idle(device, KGSL_TIMEOUT_DEFAULT); + device->ftbl->idle(device, KGSL_TIMEOUT_DEFAULT); case KGSL_STATE_NAP: case KGSL_STATE_SLEEP: /* Get the completion ready to be waited upon. */ INIT_COMPLETION(device->hwaccess_gate); - device->ftbl.device_suspend_context(device); - device->ftbl.device_stop(device); + device->ftbl->suspend_context(device); + device->ftbl->stop(device); device->state = KGSL_STATE_SUSPEND; KGSL_PWR_WARN(device, "state -> SUSPEND, device %d\n", device->id); @@ -359,6 +408,7 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) } device->requested_state = KGSL_STATE_NONE; device->pwrctrl.nap_allowed = nap_allowed_saved; + device->pwrscale.policy = policy_saved; status = 0; end: @@ -378,7 +428,8 @@ static int kgsl_resume_device(struct kgsl_device *device) mutex_lock(&device->mutex); if (device->state == KGSL_STATE_SUSPEND) { device->requested_state = KGSL_STATE_ACTIVE; - status = device->ftbl.device_start(device, 0); + kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL); + status = device->ftbl->start(device, 0); if (status == 0) { device->state = KGSL_STATE_ACTIVE; KGSL_PWR_WARN(device, @@ -391,13 +442,13 @@ static int kgsl_resume_device(struct kgsl_device *device) device->state = KGSL_STATE_INIT; goto end; } - status = device->ftbl.device_resume_context(device); complete_all(&device->hwaccess_gate); } device->requested_state = KGSL_STATE_NONE; end: mutex_unlock(&device->mutex); + kgsl_check_idle(device); KGSL_PWR_WARN(device, "resume end\n"); return status; } @@ -434,6 +485,16 @@ const struct dev_pm_ops kgsl_pm_ops = { }; EXPORT_SYMBOL(kgsl_pm_ops); +void kgsl_early_suspend_driver(struct early_suspend *h) +{ + struct kgsl_device *device = container_of(h, + struct kgsl_device, display_off); + mutex_lock(&device->mutex); + kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL); + mutex_unlock(&device->mutex); +} +EXPORT_SYMBOL(kgsl_early_suspend_driver); + int kgsl_suspend_driver(struct platform_device *pdev, pm_message_t state) { @@ -449,6 +510,16 @@ int kgsl_resume_driver(struct platform_device *pdev) } EXPORT_SYMBOL(kgsl_resume_driver); +void kgsl_late_resume_driver(struct early_suspend *h) +{ + struct kgsl_device *device = container_of(h, + struct kgsl_device, display_off); + mutex_lock(&device->mutex); + kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO); + mutex_unlock(&device->mutex); +} +EXPORT_SYMBOL(kgsl_late_resume_driver); + /* file operations */ static struct kgsl_process_private * kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv) @@ -477,15 +548,11 @@ kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv) INIT_LIST_HEAD(&private->mem_list); -#ifdef CONFIG_MSM_KGSL_MMU + if (kgsl_mmu_enabled()) { unsigned long pt_name; -#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE pt_name = task_tgid_nr(current); -#else - pt_name = KGSL_MMU_GLOBAL_PT; -#endif private->pagetable = kgsl_mmu_getpagetable(pt_name); if (private->pagetable == NULL) { kfree(private); @@ -493,7 +560,6 @@ kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv) goto out; } } -#endif list_add(&private->list, &kgsl_driver.process_list); @@ -559,7 +625,7 @@ static int kgsl_release(struct inode *inodep, struct file *filep) break; if (context->dev_priv == dev_priv) { - device->ftbl.device_drawctxt_destroy(device, context); + device->ftbl->drawctxt_destroy(device, context); kgsl_destroy_context(dev_priv, context); } @@ -568,7 +634,7 @@ static int kgsl_release(struct inode *inodep, struct file *filep) device->open_count--; if (device->open_count == 0) { - result = device->ftbl.device_stop(device); + result = device->ftbl->stop(device); device->state = KGSL_STATE_INIT; KGSL_PWR_WARN(device, "state -> INIT, device %d\n", device->id); } @@ -602,7 +668,6 @@ static int kgsl_open(struct inode *inodep, struct file *filep) } result = pm_runtime_get_sync(device->parentdev); - result = 0; if (result < 0) { KGSL_DRV_ERR(device, "Runtime PM: Unable to wake up the device, rc = %d\n", @@ -633,7 +698,7 @@ static int kgsl_open(struct inode *inodep, struct file *filep) kgsl_check_suspended(device); if (device->open_count == 0) { - result = device->ftbl.device_start(device, true); + result = device->ftbl->start(device, true); if (result) { mutex_unlock(&device->mutex); @@ -648,7 +713,7 @@ static int kgsl_open(struct inode *inodep, struct file *filep) KGSL_DRV_INFO(device, "Initialized %s: mmu=%s pagetable_count=%d\n", device->name, kgsl_mmu_enabled() ? "on" : "off", - KGSL_PAGETABLE_COUNT); + kgsl_pagetable_count); return result; @@ -746,7 +811,7 @@ static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv, break; } default: - result = dev_priv->device->ftbl.device_getproperty( + result = dev_priv->device->ftbl->getproperty( dev_priv->device, param->type, param->value, param->sizebytes); } @@ -767,16 +832,10 @@ static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private dev_priv->device->active_cnt++; - /* Don't wait forever, set a max value for now */ - if (param->timeout == -1) - param->timeout = 10 * MSEC_PER_SEC; - - result = dev_priv->device->ftbl.device_waittimestamp(dev_priv->device, + result = dev_priv->device->ftbl->waittimestamp(dev_priv->device, param->timestamp, param->timeout); - kgsl_memqueue_drain(dev_priv->device); - /* Fire off any pending suspend operations that are in flight */ INIT_COMPLETION(dev_priv->device->suspend_gate); @@ -894,15 +953,7 @@ static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv, goto free_ibdesc; } - /* Let the pwrscale policy know that a new command buffer - is being issued */ - - kgsl_pwrscale_busy(dev_priv->device); - -/* drewis: don't know what changed this...diff from cherry-pick - f3c1074d1539be20cecbb82f37705bd16058418e */ -/* result = dev_priv->device->ftbl->issueibcmds(dev_priv,*/ - result = dev_priv->device->ftbl.device_issueibcmds(dev_priv, + result = dev_priv->device->ftbl->issueibcmds(dev_priv, context, ibdesc, param->numibs, @@ -939,8 +990,8 @@ static long kgsl_ioctl_cmdstream_readtimestamp(struct kgsl_device_private struct kgsl_cmdstream_readtimestamp *param = data; param->timestamp = - dev_priv->device->ftbl.device_readtimestamp( - dev_priv->device, param->type); + dev_priv->device->ftbl->readtimestamp(dev_priv->device, + param->type); return 0; } @@ -962,7 +1013,6 @@ static long kgsl_ioctl_cmdstream_freememontimestamp(struct kgsl_device_private if (entry) { kgsl_memqueue_freememontimestamp(dev_priv->device, entry, param->timestamp, param->type); - kgsl_memqueue_drain(dev_priv->device); } else { KGSL_DRV_ERR(dev_priv->device, "invalid gpuaddr %08x\n", param->gpuaddr); @@ -986,10 +1036,10 @@ static long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv, goto done; } - if (dev_priv->device->ftbl.device_drawctxt_create != NULL) - result = dev_priv->device->ftbl.device_drawctxt_create(dev_priv, - param->flags, - context); + if (dev_priv->device->ftbl->drawctxt_create) + result = dev_priv->device->ftbl->drawctxt_create( + dev_priv->device, dev_priv->process_priv->pagetable, + context, param->flags); param->drawctxt_id = context->id; @@ -1014,9 +1064,9 @@ static long kgsl_ioctl_drawctxt_destroy(struct kgsl_device_private *dev_priv, goto done; } - result = dev_priv->device->ftbl.device_drawctxt_destroy( - dev_priv->device, - context); + if (dev_priv->device->ftbl->drawctxt_destroy) + dev_priv->device->ftbl->drawctxt_destroy(dev_priv->device, + context); kgsl_destroy_context(dev_priv, context); @@ -1074,9 +1124,6 @@ kgsl_ioctl_sharedmem_from_vmalloc(struct kgsl_device_private *dev_priv, if (!kgsl_mmu_enabled()) return -ENODEV; - /* Make sure all pending freed memory is collected */ - kgsl_memqueue_drain_unlocked(dev_priv->device); - if (!param->hostptr) { KGSL_CORE_ERR("invalid hostptr %x\n", param->hostptr); result = -EINVAL; @@ -1251,7 +1298,11 @@ static int kgsl_setup_phys_file(struct kgsl_mem_entry *entry, entry->memdesc.size = size; entry->memdesc.physaddr = phys + (offset & PAGE_MASK); entry->memdesc.hostptr = (void *) (virt + (offset & PAGE_MASK)); - entry->memdesc.ops = &kgsl_contig_ops; + + ret = memdesc_sg_phys(&entry->memdesc, + phys + (offset & PAGE_MASK), size); + if (ret) + goto err; return 0; err: @@ -1261,6 +1312,60 @@ err: return ret; } +static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, + void *addr, int size) +{ + int i; + int sglen = PAGE_ALIGN(size) / PAGE_SIZE; + unsigned long paddr = (unsigned long) addr; + + memdesc->sg = kmalloc(sglen * sizeof(struct scatterlist), + GFP_KERNEL); + if (memdesc->sg == NULL) + return -ENOMEM; + + memdesc->sglen = sglen; + sg_init_table(memdesc->sg, sglen); + + spin_lock(¤t->mm->page_table_lock); + + for (i = 0; i < sglen; i++, paddr += PAGE_SIZE) { + struct page *page; + pmd_t *ppmd; + pte_t *ppte; + pgd_t *ppgd = pgd_offset(current->mm, paddr); + + if (pgd_none(*ppgd) || pgd_bad(*ppgd)) + goto err; + + ppmd = pmd_offset(ppgd, paddr); + if (pmd_none(*ppmd) || pmd_bad(*ppmd)) + goto err; + + ppte = pte_offset_map(ppmd, paddr); + if (ppte == NULL) + goto err; + + page = pfn_to_page(pte_pfn(*ppte)); + if (!page) + goto err; + + sg_set_page(&memdesc->sg[i], page, PAGE_SIZE, 0); + pte_unmap(ppte); + } + + spin_unlock(¤t->mm->page_table_lock); + + return 0; + +err: + spin_unlock(¤t->mm->page_table_lock); + kfree(memdesc->sg); + memdesc->sg = NULL; + + return -EINVAL; +} + static int kgsl_setup_hostptr(struct kgsl_mem_entry *entry, struct kgsl_pagetable *pagetable, void *hostptr, unsigned int offset, @@ -1310,9 +1415,9 @@ static int kgsl_setup_hostptr(struct kgsl_mem_entry *entry, entry->memdesc.pagetable = pagetable; entry->memdesc.size = size; entry->memdesc.hostptr = hostptr + (offset & PAGE_MASK); - entry->memdesc.ops = &kgsl_userptr_ops; - return 0; + return memdesc_sg_virt(&entry->memdesc, + hostptr + (offset & PAGE_MASK), size); } #ifdef CONFIG_ASHMEM @@ -1360,11 +1465,13 @@ static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry, } entry->file_ptr = filep; - entry->memdesc.pagetable = pagetable; entry->memdesc.size = ALIGN(size, PAGE_SIZE); entry->memdesc.hostptr = hostptr; - entry->memdesc.ops = &kgsl_userptr_ops; + + ret = memdesc_sg_virt(&entry->memdesc, hostptr, size); + if (ret) + goto err; return 0; @@ -1395,8 +1502,6 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, if (entry == NULL) return -ENOMEM; - kgsl_memqueue_drain_unlocked(dev_priv->device); - if (_IOC_SIZE(cmd) == sizeof(struct kgsl_sharedmem_from_pmem)) memtype = KGSL_USER_MEM_TYPE_PMEM; else @@ -1536,9 +1641,6 @@ kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv, if (entry == NULL) return -ENOMEM; - /* Make sure all pending freed memory is collected */ - kgsl_memqueue_drain_unlocked(dev_priv->device); - result = kgsl_allocate_user(&entry->memdesc, private->pagetable, param->size, param->flags); @@ -1586,6 +1688,114 @@ static long kgsl_ioctl_cff_user_event(struct kgsl_device_private *dev_priv, return result; } +#ifdef CONFIG_GENLOCK +struct kgsl_genlock_event_priv { + struct genlock_handle *handle; + struct genlock *lock; +}; + +/** + * kgsl_genlock_event_cb - Event callback for a genlock timestamp event + * @device - The KGSL device that expired the timestamp + * @priv - private data for the event + * @timestamp - the timestamp that triggered the event + * + * Release a genlock lock following the expiration of a timestamp + */ + +static void kgsl_genlock_event_cb(struct kgsl_device *device, + void *priv, u32 timestamp) +{ + struct kgsl_genlock_event_priv *ev = priv; + int ret; + + ret = genlock_lock(ev->handle, GENLOCK_UNLOCK, 0, 0); + if (ret) + KGSL_CORE_ERR("Error while unlocking genlock: %d\n", ret); + + genlock_put_handle(ev->handle); + + kfree(ev); +} + +/** + * kgsl_add_genlock-event - Create a new genlock event + * @device - KGSL device to create the event on + * @timestamp - Timestamp to trigger the event + * @data - User space buffer containing struct kgsl_genlock_event_priv + * @len - length of the userspace buffer + * @returns 0 on success or error code on error + * + * Attack to a genlock handle and register an event to release the + * genlock lock when the timestamp expires + */ + +static int kgsl_add_genlock_event(struct kgsl_device *device, + u32 timestamp, void __user *data, int len) +{ + struct kgsl_genlock_event_priv *event; + struct kgsl_timestamp_event_genlock priv; + int ret; + + if (len != sizeof(priv)) + return -EINVAL; + + if (copy_from_user(&priv, data, sizeof(priv))) + return -EFAULT; + + event = kzalloc(sizeof(*event), GFP_KERNEL); + + if (event == NULL) + return -ENOMEM; + + event->handle = genlock_get_handle_fd(priv.handle); + + if (IS_ERR(event->handle)) { + int ret = PTR_ERR(event->handle); + kfree(event); + return ret; + } + + ret = kgsl_add_event(device, timestamp, kgsl_genlock_event_cb, event); + if (ret) + kfree(event); + + return ret; +} +#else +static long kgsl_add_genlock_event(struct kgsl_device *device, + u32 timestamp, void __user *data, int len) +{ + return -EINVAL; +} +#endif + +/** + * kgsl_ioctl_timestamp_event - Register a new timestamp event from userspace + * @dev_priv - pointer to the private device structure + * @cmd - the ioctl cmd passed from kgsl_ioctl + * @data - the user data buffer from kgsl_ioctl + * @returns 0 on success or error code on failure + */ + +static long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_timestamp_event *param = data; + int ret; + + switch (param->type) { + case KGSL_TIMESTAMP_EVENT_GENLOCK: + ret = kgsl_add_genlock_event(dev_priv->device, + param->timestamp, param->priv, param->len); + break; + default: + ret = -EINVAL; + } + + return ret; +} + typedef long (*kgsl_ioctl_func_t)(struct kgsl_device_private *, unsigned int, void *); @@ -1627,6 +1837,8 @@ static const struct { kgsl_ioctl_cff_syncmem, 0), KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_USER_EVENT, kgsl_ioctl_cff_user_event, 0), + KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT, + kgsl_ioctl_timestamp_event, 1), }; static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) @@ -1676,7 +1888,13 @@ static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) func = kgsl_ioctl_funcs[nr].func; lock = kgsl_ioctl_funcs[nr].lock; } else { - func = dev_priv->device->ftbl.device_ioctl; + func = dev_priv->device->ftbl->ioctl; + if (!func) { + KGSL_DRV_INFO(dev_priv->device, + "invalid ioctl code %08x\n", cmd); + ret = -EINVAL; + goto done; + } lock = 1; } @@ -1749,7 +1967,7 @@ kgsl_gpumem_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct kgsl_mem_entry *entry = vma->vm_private_data; - if (!entry->memdesc.ops->vmfault) + if (!entry->memdesc.ops || !entry->memdesc.ops->vmfault) return VM_FAULT_SIGBUS; return entry->memdesc.ops->vmfault(&entry->memdesc, vma, vmf); @@ -1773,7 +1991,7 @@ static int kgsl_mmap(struct file *file, struct vm_area_struct *vma) unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT; struct kgsl_device_private *dev_priv = file->private_data; struct kgsl_process_private *private = dev_priv->process_priv; - struct kgsl_mem_entry *entry; + struct kgsl_mem_entry *tmp, *entry = NULL; struct kgsl_device *device = dev_priv->device; /* Handle leagacy behavior for memstore */ @@ -1784,9 +2002,10 @@ static int kgsl_mmap(struct file *file, struct vm_area_struct *vma) /* Find a chunk of GPU memory */ spin_lock(&private->mem_lock); - list_for_each_entry(entry, &private->mem_list, list) { - if (vma_offset == entry->memdesc.gpuaddr) { - kgsl_mem_entry_get(entry); + list_for_each_entry(tmp, &private->mem_list, list) { + if (vma_offset == tmp->memdesc.gpuaddr) { + kgsl_mem_entry_get(tmp); + entry = tmp; break; } } @@ -1795,7 +2014,9 @@ static int kgsl_mmap(struct file *file, struct vm_area_struct *vma) if (entry == NULL) return -EINVAL; - if (!entry->memdesc.ops->vmflags || !entry->memdesc.ops->vmfault) + if (!entry->memdesc.ops || + !entry->memdesc.ops->vmflags || + !entry->memdesc.ops->vmfault) return -EINVAL; vma->vm_flags |= entry->memdesc.ops->vmflags(&entry->memdesc); @@ -1818,7 +2039,7 @@ static const struct file_operations kgsl_fops = { struct kgsl_driver kgsl_driver = { .process_mutex = __MUTEX_INITIALIZER(kgsl_driver.process_mutex), - .pt_mutex = __MUTEX_INITIALIZER(kgsl_driver.pt_mutex), + .ptlock = __SPIN_LOCK_UNLOCKED(kgsl_driver.ptlock), .devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock), }; EXPORT_SYMBOL(kgsl_driver); @@ -1842,6 +2063,8 @@ void kgsl_unregister_device(struct kgsl_device *device) kgsl_pwrctrl_uninit_sysfs(device); wake_lock_destroy(&device->idle_wakelock); + pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "kgsl"); + idr_destroy(&device->context_idr); if (device->memstore.hostptr) @@ -1860,8 +2083,6 @@ void kgsl_unregister_device(struct kgsl_device *device) mutex_lock(&kgsl_driver.devlock); kgsl_driver.devp[minor] = NULL; mutex_unlock(&kgsl_driver.devlock); - - atomic_dec(&kgsl_driver.device_count); } EXPORT_SYMBOL(kgsl_unregister_device); @@ -1904,8 +2125,6 @@ kgsl_register_device(struct kgsl_device *device) dev_set_drvdata(device->parentdev, device); /* Generic device initialization */ - atomic_inc(&kgsl_driver.device_count); - init_waitqueue_head(&device->wait_queue); kgsl_cffdump_open(device->id); @@ -1921,22 +2140,25 @@ kgsl_register_device(struct kgsl_device *device) goto err_devlist; 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); if (ret != 0) goto err_dest_work_q; - ret = kgsl_allocate_contig(&device->memstore, + ret = kgsl_allocate_contiguous(&device->memstore, sizeof(struct kgsl_devmemstore)); if (ret != 0) goto err_close_mmu; - kgsl_sharedmem_set(&device->memstore, 0, 0, device->memstore.size); - wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name); + pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "kgsl", + PM_QOS_DEFAULT_VALUE); + idr_init(&device->context_idr); /* sysfs and debugfs initalization - failure here is non fatal */ @@ -2066,17 +2288,19 @@ EXPORT_SYMBOL(kgsl_device_platform_remove); static int __devinit kgsl_ptdata_init(void) { - INIT_LIST_HEAD(&kgsl_driver.pagetable_list); - - return kgsl_ptpool_init(&kgsl_driver.ptpool, KGSL_PAGETABLE_SIZE, - kgsl_pagetable_count); + kgsl_driver.ptpool = kgsl_mmu_ptpool_init(KGSL_PAGETABLE_SIZE, + kgsl_pagetable_count); + if (!kgsl_driver.ptpool) + return -ENOMEM; + return 0; } static void kgsl_core_exit(void) { unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX); - kgsl_ptpool_destroy(&kgsl_driver.ptpool); + kgsl_mmu_ptpool_destroy(&kgsl_driver.ptpool); + kgsl_driver.ptpool = NULL; device_unregister(&kgsl_driver.virtdev); @@ -2094,7 +2318,6 @@ static void kgsl_core_exit(void) static int __init kgsl_core_init(void) { int result = 0; - /* alloc major and minor device numbers */ result = alloc_chrdev_region(&kgsl_driver.major, 0, KGSL_DEVICE_MAX, KGSL_NAME); @@ -2148,14 +2371,17 @@ static int __init kgsl_core_init(void) kgsl_sharedmem_init_sysfs(); kgsl_cffdump_init(); - /* Generic device initialization */ - atomic_set(&kgsl_driver.device_count, -1); - INIT_LIST_HEAD(&kgsl_driver.process_list); - result = kgsl_ptdata_init(); - if (result) - goto err; + INIT_LIST_HEAD(&kgsl_driver.pagetable_list); + + kgsl_mmu_set_mmutype(ksgl_mmu_type); + + if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype()) { + result = kgsl_ptdata_init(); + if (result) + goto err; + } result = kgsl_drm_init(NULL); diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index d107a0b0..e26cdc9e 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,29 +1,13 @@ /* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __KGSL_H @@ -38,26 +22,8 @@ #include #include -#include - -#include "kgsl_device.h" -#include "kgsl_pwrctrl.h" -#include "kgsl_sharedmem.h" -#include "kgsl_log.h" -#include "kgsl_cffdump.h" - #define KGSL_NAME "kgsl" -#define CHIP_REV_251 0x020501 - -/* Flags to control whether to flush or invalidate a cached memory range */ -#define KGSL_CACHE_INV 0x00000000 -#define KGSL_CACHE_CLEAN 0x00000001 -#define KGSL_CACHE_FLUSH 0x00000002 - -#define KGSL_CACHE_USER_ADDR 0x00000010 -#define KGSL_CACHE_VMALLOC_ADDR 0x00000020 - /*cache coherency ops */ #define DRM_KGSL_GEM_CACHE_OP_TO_DEV 0x0001 #define DRM_KGSL_GEM_CACHE_OP_FROM_DEV 0x0002 @@ -74,13 +40,9 @@ #define KGSL_PAGETABLE_ENTRIES(_sz) (((_sz) >> PAGE_SHIFT) + \ KGSL_PT_EXTRA_ENTRIES) -#ifdef CONFIG_MSM_KGSL_MMU #define KGSL_PAGETABLE_SIZE \ ALIGN(KGSL_PAGETABLE_ENTRIES(CONFIG_MSM_KGSL_PAGE_TABLE_SIZE) * \ KGSL_PAGETABLE_ENTRY_SIZE, PAGE_SIZE) -#else -#define KGSL_PAGETABLE_SIZE 0 -#endif #ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE #define KGSL_PAGETABLE_COUNT (CONFIG_MSM_KGSL_PAGE_TABLE_COUNT) @@ -99,6 +61,8 @@ KGSL_PAGETABLE_ENTRY_SIZE, PAGE_SIZE) #define KGSL_STATS_ADD(_size, _stat, _max) \ do { _stat += (_size); if (_stat > _max) _max = _stat; } while (0) +struct kgsl_device; + struct kgsl_driver { struct cdev cdev; dev_t major; @@ -108,24 +72,21 @@ struct kgsl_driver { /* Kobjects for storing pagetable and process statistics */ struct kobject *ptkobj; struct kobject *prockobj; - atomic_t device_count; struct kgsl_device *devp[KGSL_DEVICE_MAX]; - uint32_t flags_debug; - /* Global lilst of open processes */ struct list_head process_list; /* Global list of pagetables */ struct list_head pagetable_list; - /* Mutex for accessing the pagetable list */ - struct mutex pt_mutex; + /* Spinlock for accessing the pagetable list */ + spinlock_t ptlock; /* Mutex for accessing the process list */ struct mutex process_mutex; /* Mutex for protecting the device list */ struct mutex devlock; - struct kgsl_ptpool ptpool; + void *ptpool; struct { unsigned int vmalloc; @@ -143,6 +104,22 @@ extern struct kgsl_driver kgsl_driver; #define KGSL_USER_MEMORY 1 #define KGSL_MAPPED_MEMORY 2 +struct kgsl_pagetable; +struct kgsl_memdesc_ops; + +/* shared memory allocation */ +struct kgsl_memdesc { + struct kgsl_pagetable *pagetable; + void *hostptr; + unsigned int gpuaddr; + unsigned int physaddr; + unsigned int size; + unsigned int priv; + struct scatterlist *sg; + unsigned int sglen; + struct kgsl_memdesc_ops *ops; +}; + struct kgsl_mem_entry { struct kref refcount; struct kgsl_memdesc memdesc; @@ -167,53 +144,14 @@ uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc, struct kgsl_mem_entry *kgsl_sharedmem_find_region( struct kgsl_process_private *private, unsigned int gpuaddr, size_t size); -int kgsl_idle(struct kgsl_device *device, unsigned int timeout); -int kgsl_setstate(struct kgsl_device *device, uint32_t flags); - -static inline void kgsl_regread(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value) -{ - device->ftbl.device_regread(device, offsetwords, value); -} - -static inline void kgsl_regwrite(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value) -{ - device->ftbl.device_regwrite(device, offsetwords, value); -} - -static inline void kgsl_regread_isr(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value) -{ - device->ftbl.device_regread_isr(device, offsetwords, value); -} - -static inline void kgsl_regwrite_isr(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value) -{ - device->ftbl.device_regwrite_isr(device, offsetwords, value); -} - -int kgsl_check_timestamp(struct kgsl_device *device, unsigned int timestamp); - -int kgsl_register_ts_notifier(struct kgsl_device *device, - struct notifier_block *nb); - -int kgsl_unregister_ts_notifier(struct kgsl_device *device, - struct notifier_block *nb); - -int kgsl_device_platform_probe(struct kgsl_device *device, - irqreturn_t (*dev_isr) (int, void*)); -void kgsl_device_platform_remove(struct kgsl_device *device); extern const struct dev_pm_ops kgsl_pm_ops; +struct early_suspend; int kgsl_suspend_driver(struct platform_device *pdev, pm_message_t state); int kgsl_resume_driver(struct platform_device *pdev); +void kgsl_early_suspend_driver(struct early_suspend *h); +void kgsl_late_resume_driver(struct early_suspend *h); #ifdef CONFIG_MSM_KGSL_DRM extern int kgsl_drm_init(struct platform_device *dev); @@ -240,22 +178,14 @@ static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc, return 0; } -static inline struct kgsl_device *kgsl_device_from_dev(struct device *dev) -{ - int i; - - for (i = 0; i < KGSL_DEVICE_MAX; i++) { - if (kgsl_driver.devp[i] && kgsl_driver.devp[i]->dev == dev) - return kgsl_driver.devp[i]; - } - - return NULL; -} - -static inline bool timestamp_cmp(unsigned int new, unsigned int old) +static inline int timestamp_cmp(unsigned int new, unsigned int old) { int ts_diff = new - old; - return (ts_diff >= 0) || (ts_diff < -20000); + + if (ts_diff == 0) + return 0; + + return ((ts_diff > 0) || (ts_diff < -20000)) ? 1 : -1; } static inline void @@ -270,21 +200,4 @@ kgsl_mem_entry_put(struct kgsl_mem_entry *entry) kref_put(&entry->refcount, kgsl_mem_entry_destroy); } -static inline int kgsl_create_device_sysfs_files(struct device *root, - struct device_attribute **list) -{ - int ret = 0, i; - for (i = 0; list[i] != NULL; i++) - ret |= device_create_file(root, list[i]); - return ret; -} - -static inline void kgsl_remove_device_sysfs_files(struct device *root, - struct device_attribute **list) -{ - int i; - for (i = 0; list[i] != NULL; i++) - device_remove_file(root, list[i]); -} - #endif /* __KGSL_H */ diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c index 702e1ac7..aa33152c 100644 --- a/drivers/gpu/msm/kgsl_cffdump.c +++ b/drivers/gpu/msm/kgsl_cffdump.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "kgsl.h" #include "kgsl_cffdump.h" @@ -362,8 +363,10 @@ void kgsl_cffdump_open(enum kgsl_deviceid device_id) /*TODO: move this to where we can report correct gmemsize*/ unsigned int va_base; - /* XXX: drewis edit: only for 8x50 */ - va_base = 0x20000000; + 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, CONFIG_MSM_KGSL_PAGE_TABLE_SIZE, SZ_256K); @@ -523,8 +526,8 @@ static bool kgsl_cffdump_handle_type3(struct kgsl_device_private *dev_priv, static uint size_stack[ADDRESS_STACK_SIZE]; switch (GET_PM4_TYPE3_OPCODE(hostaddr)) { - case PM4_INDIRECT_BUFFER_PFD: - case PM4_INDIRECT_BUFFER: + case CP_INDIRECT_BUFFER_PFD: + case CP_INDIRECT_BUFFER: { /* traverse indirect buffers */ int i; @@ -607,7 +610,6 @@ bool kgsl_cffdump_parse_ibs(struct kgsl_device_private *dev_priv, if (!memdesc->physaddr) { KGSL_CORE_ERR("no physaddr"); - return true; } else { mb(); kgsl_cache_range_op((struct kgsl_memdesc *)memdesc, diff --git a/drivers/gpu/msm/kgsl_cffdump.h b/drivers/gpu/msm/kgsl_cffdump.h index d2f9d172..140e4868 100644 --- a/drivers/gpu/msm/kgsl_cffdump.h +++ b/drivers/gpu/msm/kgsl_cffdump.h @@ -1,29 +1,13 @@ /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index d98586a9..f5eeb3fb 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -14,6 +14,7 @@ #include #include "kgsl.h" +#include "kgsl_device.h" /*default log levels is error for everything*/ #define KGSL_LOG_LEVEL_DEFAULT 3 diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index bb0f2b35..64d369eb 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -1,29 +1,14 @@ /* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. + * Copyright (C) 2011 Sony Ericsson Mobile Communications AB. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __KGSL_DEVICE_H @@ -31,7 +16,10 @@ #include #include +#include +#include +#include "kgsl.h" #include "kgsl_mmu.h" #include "kgsl_pwrctrl.h" #include "kgsl_log.h" @@ -71,55 +59,48 @@ struct kgsl_context; struct kgsl_power_stats; struct kgsl_functable { - void (*device_regread) (struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value); - void (*device_regwrite) (struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value); - void (*device_regread_isr) (struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value); - void (*device_regwrite_isr) (struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value); - int (*device_setstate) (struct kgsl_device *device, uint32_t flags); - int (*device_idle) (struct kgsl_device *device, unsigned int timeout); - unsigned int (*device_isidle) (struct kgsl_device *device); - int (*device_suspend_context) (struct kgsl_device *device); - int (*device_resume_context) (struct kgsl_device *device); - int (*device_start) (struct kgsl_device *device, unsigned int init_ram); - int (*device_stop) (struct kgsl_device *device); - int (*device_getproperty) (struct kgsl_device *device, - enum kgsl_property_type type, - void *value, - unsigned int sizebytes); - int (*device_waittimestamp) (struct kgsl_device *device, - unsigned int timestamp, - unsigned int msecs); - unsigned int (*device_readtimestamp) ( - struct kgsl_device *device, - enum kgsl_timestamp_type type); - int (*device_issueibcmds) (struct kgsl_device_private *dev_priv, - struct kgsl_context *context, - struct kgsl_ibdesc *ibdesc, - unsigned int sizedwords, - uint32_t *timestamp, - unsigned int flags); - int (*device_drawctxt_create) (struct kgsl_device_private *dev_priv, - uint32_t flags, - struct kgsl_context *context); - int (*device_drawctxt_destroy) (struct kgsl_device *device, - struct kgsl_context *context); - long (*device_ioctl) (struct kgsl_device_private *dev_priv, - unsigned int cmd, void *data); - int (*device_setup_pt)(struct kgsl_device *device, - struct kgsl_pagetable *pagetable); - - int (*device_cleanup_pt)(struct kgsl_device *device, - struct kgsl_pagetable *pagetable); - void (*device_power_stats)(struct kgsl_device *device, + /* Mandatory functions - these functions must be implemented + by the client device. The driver will not check for a NULL + pointer before calling the hook. + */ + void (*regread) (struct kgsl_device *device, + unsigned int offsetwords, unsigned int *value); + void (*regwrite) (struct kgsl_device *device, + unsigned int offsetwords, unsigned int value); + int (*idle) (struct kgsl_device *device, unsigned int timeout); + unsigned int (*isidle) (struct kgsl_device *device); + int (*suspend_context) (struct kgsl_device *device); + int (*start) (struct kgsl_device *device, unsigned int init_ram); + int (*stop) (struct kgsl_device *device); + int (*getproperty) (struct kgsl_device *device, + enum kgsl_property_type type, void *value, + unsigned int sizebytes); + int (*waittimestamp) (struct kgsl_device *device, + unsigned int timestamp, unsigned int msecs); + unsigned int (*readtimestamp) (struct kgsl_device *device, + enum kgsl_timestamp_type type); + int (*issueibcmds) (struct kgsl_device_private *dev_priv, + struct kgsl_context *context, struct kgsl_ibdesc *ibdesc, + unsigned int sizedwords, uint32_t *timestamp, + unsigned int flags); + int (*setup_pt)(struct kgsl_device *device, + struct kgsl_pagetable *pagetable); + void (*cleanup_pt)(struct kgsl_device *device, + struct kgsl_pagetable *pagetable); + void (*power_stats)(struct kgsl_device *device, struct kgsl_power_stats *stats); + void (*irqctrl)(struct kgsl_device *device, int state); + /* Optional functions - these functions are not mandatory. The + driver will check that the function pointer is not NULL before + calling the hook */ + void (*setstate) (struct kgsl_device *device, uint32_t flags); + int (*drawctxt_create) (struct kgsl_device *device, + struct kgsl_pagetable *pagetable, struct kgsl_context *context, + uint32_t flags); + void (*drawctxt_destroy) (struct kgsl_device *device, + struct kgsl_context *context); + long (*ioctl) (struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data); }; struct kgsl_memregion { @@ -129,6 +110,23 @@ struct kgsl_memregion { unsigned int sizebytes; }; +/* MH register values */ +struct kgsl_mh { + unsigned int mharb; + unsigned int mh_intf_cfg1; + unsigned int mh_intf_cfg2; + uint32_t mpu_base; + int mpu_range; +}; + +struct kgsl_event { + uint32_t timestamp; + void (*func)(struct kgsl_device *, void *, u32); + void *priv; + struct list_head list; +}; + + struct kgsl_device { struct device *dev; const char *name; @@ -140,9 +138,10 @@ struct kgsl_device { struct kgsl_memdesc memstore; const char *iomemname; + struct kgsl_mh mh; struct kgsl_mmu mmu; struct completion hwaccess_gate; - struct kgsl_functable ftbl; + const struct kgsl_functable *ftbl; struct work_struct idle_check_ws; struct timer_list idle_timer; struct kgsl_pwrctrl pwrctrl; @@ -163,6 +162,7 @@ struct kgsl_device { struct completion recovery_gate; struct dentry *d_debugfs; struct idr context_idr; + struct early_suspend display_off; /* Logging levels */ int cmd_log; @@ -173,6 +173,8 @@ struct kgsl_device { struct wake_lock idle_wakelock; struct kgsl_pwrscale pwrscale; struct kobject pwrscale_kobj; + struct work_struct ts_expired_ws; + struct list_head events; }; struct kgsl_context { @@ -215,12 +217,60 @@ struct kgsl_power_stats { struct kgsl_device *kgsl_get_device(int dev_idx); +static inline void kgsl_regread(struct kgsl_device *device, + unsigned int offsetwords, + unsigned int *value) +{ + device->ftbl->regread(device, offsetwords, value); +} + +static inline void kgsl_regwrite(struct kgsl_device *device, + unsigned int offsetwords, + unsigned int value) +{ + device->ftbl->regwrite(device, offsetwords, value); +} + +static inline int kgsl_idle(struct kgsl_device *device, unsigned int timeout) +{ + return device->ftbl->idle(device, timeout); +} + +static inline int kgsl_create_device_sysfs_files(struct device *root, + struct device_attribute **list) +{ + int ret = 0, i; + for (i = 0; list[i] != NULL; i++) + ret |= device_create_file(root, list[i]); + return ret; +} + +static inline void kgsl_remove_device_sysfs_files(struct device *root, + struct device_attribute **list) +{ + int i; + for (i = 0; list[i] != NULL; i++) + device_remove_file(root, list[i]); +} + static inline struct kgsl_mmu * kgsl_get_mmu(struct kgsl_device *device) { return (struct kgsl_mmu *) (device ? &device->mmu : NULL); } +static inline struct kgsl_device *kgsl_device_from_dev(struct device *dev) +{ + int i; + + for (i = 0; i < KGSL_DEVICE_MAX; i++) { + if (kgsl_driver.devp[i] && kgsl_driver.devp[i]->dev == dev) + return kgsl_driver.devp[i]; + } + + return NULL; +} + static inline int kgsl_create_device_workqueue(struct kgsl_device *device) { device->work_queue = create_workqueue(device->name); @@ -244,4 +294,16 @@ kgsl_find_context(struct kgsl_device_private *dev_priv, uint32_t id) return (ctxt && ctxt->dev_priv == dev_priv) ? ctxt : NULL; } +int kgsl_check_timestamp(struct kgsl_device *device, unsigned int timestamp); + +int kgsl_register_ts_notifier(struct kgsl_device *device, + struct notifier_block *nb); + +int kgsl_unregister_ts_notifier(struct kgsl_device *device, + struct notifier_block *nb); + +int kgsl_device_platform_probe(struct kgsl_device *device, + irqreturn_t (*dev_isr) (int, void*)); +void kgsl_device_platform_remove(struct kgsl_device *device); + #endif /* __KGSL_DEVICE_H */ diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c index 1e878e15..cdf9dc4e 100644 --- a/drivers/gpu/msm/kgsl_drm.c +++ b/drivers/gpu/msm/kgsl_drm.c @@ -293,7 +293,6 @@ kgsl_gem_alloc_memory(struct drm_gem_object *obj) } priv->memdesc.size = obj->size * priv->bufcount; - priv->memdesc.ops = &kgsl_contig_ops; } else if (TYPE_IS_MEM(priv->type)) { priv->memdesc.hostptr = diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h index e816e568..9fafcf4d 100644 --- a/drivers/gpu/msm/kgsl_log.h +++ b/drivers/gpu/msm/kgsl_log.h @@ -1,29 +1,13 @@ /* Copyright (c) 2002,2008-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __KGSL_LOG_H diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index bc35c411..7916ecb0 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. + * Copyright (C) 2011 Sony Ericsson Mobile Communications AB. * * 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 @@ -16,335 +17,76 @@ #include #include #include +#include #include "kgsl.h" #include "kgsl_mmu.h" +#include "kgsl_device.h" +#include "kgsl_sharedmem.h" #define KGSL_MMU_ALIGN_SHIFT 13 #define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1)) -#define GSL_PT_PAGE_BITS_MASK 0x00000007 -#define GSL_PT_PAGE_ADDR_MASK PAGE_MASK +static enum kgsl_mmutype kgsl_mmu_type; -#define GSL_MMU_INT_MASK \ - (MH_INTERRUPT_MASK__AXI_READ_ERROR | \ - MH_INTERRUPT_MASK__AXI_WRITE_ERROR) +static void pagetable_remove_sysfs_objects(struct kgsl_pagetable *pagetable); -static ssize_t -sysfs_show_ptpool_entries(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) +static int kgsl_cleanup_pt(struct kgsl_pagetable *pt) { - return snprintf(buf, PAGE_SIZE, "%d\n", kgsl_driver.ptpool.entries); -} - -static ssize_t -sysfs_show_ptpool_min(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - kgsl_driver.ptpool.static_entries); -} - -static ssize_t -sysfs_show_ptpool_chunks(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", kgsl_driver.ptpool.chunks); -} - -static ssize_t -sysfs_show_ptpool_ptsize(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", kgsl_driver.ptpool.ptsize); -} - -static struct kobj_attribute attr_ptpool_entries = { - .attr = { .name = "ptpool_entries", .mode = 0444 }, - .show = sysfs_show_ptpool_entries, - .store = NULL, -}; - -static struct kobj_attribute attr_ptpool_min = { - .attr = { .name = "ptpool_min", .mode = 0444 }, - .show = sysfs_show_ptpool_min, - .store = NULL, -}; - -static struct kobj_attribute attr_ptpool_chunks = { - .attr = { .name = "ptpool_chunks", .mode = 0444 }, - .show = sysfs_show_ptpool_chunks, - .store = NULL, -}; - -static struct kobj_attribute attr_ptpool_ptsize = { - .attr = { .name = "ptpool_ptsize", .mode = 0444 }, - .show = sysfs_show_ptpool_ptsize, - .store = NULL, -}; - -static struct attribute *ptpool_attrs[] = { - &attr_ptpool_entries.attr, - &attr_ptpool_min.attr, - &attr_ptpool_chunks.attr, - &attr_ptpool_ptsize.attr, - NULL, -}; - -static struct attribute_group ptpool_attr_group = { - .attrs = ptpool_attrs, -}; - -static int -_kgsl_ptpool_add_entries(struct kgsl_ptpool *pool, int count, int dynamic) -{ - struct kgsl_ptpool_chunk *chunk; - size_t size = ALIGN(count * pool->ptsize, PAGE_SIZE); - - BUG_ON(count == 0); - - if (get_order(size) >= MAX_ORDER) { - KGSL_CORE_ERR("ptpool allocation is too big: %d\n", size); - return -EINVAL; + int i; + for (i = 0; i < KGSL_DEVICE_MAX; i++) { + struct kgsl_device *device = kgsl_driver.devp[i]; + if (device) + device->ftbl->cleanup_pt(device, pt); } - - chunk = kzalloc(sizeof(*chunk), GFP_KERNEL); - if (chunk == NULL) { - KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*chunk)); - return -ENOMEM; - } - - chunk->size = size; - chunk->count = count; - chunk->dynamic = dynamic; - - chunk->data = dma_alloc_coherent(NULL, size, - &chunk->phys, GFP_KERNEL); - - if (chunk->data == NULL) { - KGSL_CORE_ERR("dma_alloc_coherent(%d) failed\n", size); - goto err; - } - - chunk->bitmap = kzalloc(BITS_TO_LONGS(count) * 4, GFP_KERNEL); - - if (chunk->bitmap == NULL) { - KGSL_CORE_ERR("kzalloc(%d) failed\n", - BITS_TO_LONGS(count) * 4); - goto err_dma; - } - - list_add_tail(&chunk->list, &pool->list); - - pool->chunks++; - pool->entries += count; - - if (!dynamic) - pool->static_entries += count; - return 0; - -err_dma: - dma_free_coherent(NULL, chunk->size, chunk->data, chunk->phys); -err: - kfree(chunk); - return -ENOMEM; } -static void * -_kgsl_ptpool_get_entry(struct kgsl_ptpool *pool, unsigned int *physaddr) +static void kgsl_destroy_pagetable(struct kref *kref) { - struct kgsl_ptpool_chunk *chunk; + struct kgsl_pagetable *pagetable = container_of(kref, + struct kgsl_pagetable, refcount); + unsigned long flags; - list_for_each_entry(chunk, &pool->list, list) { - int bit = find_first_zero_bit(chunk->bitmap, chunk->count); + spin_lock_irqsave(&kgsl_driver.ptlock, flags); + list_del(&pagetable->list); + spin_unlock_irqrestore(&kgsl_driver.ptlock, flags); - if (bit >= chunk->count) - continue; + pagetable_remove_sysfs_objects(pagetable); - set_bit(bit, chunk->bitmap); - *physaddr = chunk->phys + (bit * pool->ptsize); + kgsl_cleanup_pt(pagetable); - return chunk->data + (bit * pool->ptsize); - } + if (pagetable->pool) + gen_pool_destroy(pagetable->pool); - return NULL; + pagetable->pt_ops->mmu_destroy_pagetable(pagetable->priv); + + kfree(pagetable); } -/** - * kgsl_ptpool_add - * @pool: A pointer to a ptpool structure - * @entries: Number of entries to add - * - * Add static entries to the pagetable pool. - */ - -int -kgsl_ptpool_add(struct kgsl_ptpool *pool, int count) +static inline void kgsl_put_pagetable(struct kgsl_pagetable *pagetable) { - int ret = 0; - BUG_ON(count == 0); - - mutex_lock(&pool->lock); - - /* Only 4MB can be allocated in one chunk, so larger allocations - need to be split into multiple sections */ - - while (count) { - int entries = ((count * pool->ptsize) > SZ_4M) ? - SZ_4M / pool->ptsize : count; - - /* Add the entries as static, i.e. they don't ever stand - a chance of being removed */ - - ret = _kgsl_ptpool_add_entries(pool, entries, 0); - if (ret) - break; - - count -= entries; - } - - mutex_unlock(&pool->lock); - return ret; + if (pagetable) + kref_put(&pagetable->refcount, kgsl_destroy_pagetable); } -/** - * kgsl_ptpool_alloc - * @pool: A pointer to a ptpool structure - * @addr: A pointer to store the physical address of the chunk - * - * Allocate a pagetable from the pool. Returns the virtual address - * of the pagetable, the physical address is returned in physaddr - */ - -void *kgsl_ptpool_alloc(struct kgsl_ptpool *pool, unsigned int *physaddr) -{ - void *addr = NULL; - int ret; - - mutex_lock(&pool->lock); - addr = _kgsl_ptpool_get_entry(pool, physaddr); - if (addr) - goto done; - - /* Add a chunk for 1 more pagetable and mark it as dynamic */ - ret = _kgsl_ptpool_add_entries(pool, 1, 1); - - if (ret) - goto done; - - addr = _kgsl_ptpool_get_entry(pool, physaddr); -done: - mutex_unlock(&pool->lock); - return addr; -} - -static inline void _kgsl_ptpool_rm_chunk(struct kgsl_ptpool_chunk *chunk) -{ - list_del(&chunk->list); - - if (chunk->data) - dma_free_coherent(NULL, chunk->size, chunk->data, - chunk->phys); - kfree(chunk->bitmap); - kfree(chunk); -} - -/** - * kgsl_ptpool_free - * @pool: A pointer to a ptpool structure - * @addr: A pointer to the virtual address to free - * - * Free a pagetable allocated from the pool - */ - -void kgsl_ptpool_free(struct kgsl_ptpool *pool, void *addr) -{ - struct kgsl_ptpool_chunk *chunk, *tmp; - - if (pool == NULL || addr == NULL) - return; - - mutex_lock(&pool->lock); - list_for_each_entry_safe(chunk, tmp, &pool->list, list) { - if (addr >= chunk->data && - addr < chunk->data + chunk->size) { - int bit = ((unsigned long) (addr - chunk->data)) / - pool->ptsize; - - clear_bit(bit, chunk->bitmap); - memset(addr, 0, pool->ptsize); - - if (chunk->dynamic && - bitmap_empty(chunk->bitmap, chunk->count)) - _kgsl_ptpool_rm_chunk(chunk); - - break; - } - } - - mutex_unlock(&pool->lock); -} - -void kgsl_ptpool_destroy(struct kgsl_ptpool *pool) -{ - struct kgsl_ptpool_chunk *chunk, *tmp; - - if (pool == NULL) - return; - - mutex_lock(&pool->lock); - list_for_each_entry_safe(chunk, tmp, &pool->list, list) - _kgsl_ptpool_rm_chunk(chunk); - mutex_unlock(&pool->lock); - - memset(pool, 0, sizeof(*pool)); -} - -/** - * kgsl_ptpool_init - * @pool: A pointer to a ptpool structure to initialize - * @ptsize: The size of each pagetable entry - * @entries: The number of inital entries to add to the pool - * - * Initalize a pool and allocate an initial chunk of entries. - */ - -int kgsl_ptpool_init(struct kgsl_ptpool *pool, int ptsize, int entries) -{ - int ret = 0; - BUG_ON(ptsize == 0); - - pool->ptsize = ptsize; - mutex_init(&pool->lock); - INIT_LIST_HEAD(&pool->list); - - if (entries) { - ret = kgsl_ptpool_add(pool, entries); - if (ret) - return ret; - } - - return sysfs_create_group(kgsl_driver.ptkobj, &ptpool_attr_group); -} - -/* pt_mutex needs to be held in this function */ - static struct kgsl_pagetable * kgsl_get_pagetable(unsigned long name) { - struct kgsl_pagetable *pt; + struct kgsl_pagetable *pt, *ret = NULL; + unsigned long flags; - list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) { - if (pt->name == name) - return pt; + spin_lock_irqsave(&kgsl_driver.ptlock, flags); + list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) { + if (pt->name == name) { + ret = pt; + kref_get(&ret->refcount); + break; + } } - return NULL; + spin_unlock_irqrestore(&kgsl_driver.ptlock, flags); + return ret; } static struct kgsl_pagetable * @@ -369,13 +111,12 @@ sysfs_show_entries(struct kobject *kobj, struct kgsl_pagetable *pt; int ret = 0; - mutex_lock(&kgsl_driver.pt_mutex); pt = _get_pt_from_kobj(kobj); if (pt) ret += snprintf(buf, PAGE_SIZE, "%d\n", pt->stats.entries); - mutex_unlock(&kgsl_driver.pt_mutex); + kgsl_put_pagetable(pt); return ret; } @@ -387,13 +128,12 @@ sysfs_show_mapped(struct kobject *kobj, struct kgsl_pagetable *pt; int ret = 0; - mutex_lock(&kgsl_driver.pt_mutex); pt = _get_pt_from_kobj(kobj); if (pt) ret += snprintf(buf, PAGE_SIZE, "%d\n", pt->stats.mapped); - mutex_unlock(&kgsl_driver.pt_mutex); + kgsl_put_pagetable(pt); return ret; } @@ -405,13 +145,13 @@ sysfs_show_va_range(struct kobject *kobj, struct kgsl_pagetable *pt; int ret = 0; - mutex_lock(&kgsl_driver.pt_mutex); pt = _get_pt_from_kobj(kobj); if (pt) - ret += snprintf(buf, PAGE_SIZE, "0x%x\n", pt->va_range); + ret += snprintf(buf, PAGE_SIZE, "0x%x\n", + CONFIG_MSM_KGSL_PAGE_TABLE_SIZE); - mutex_unlock(&kgsl_driver.pt_mutex); + kgsl_put_pagetable(pt); return ret; } @@ -423,13 +163,12 @@ sysfs_show_max_mapped(struct kobject *kobj, struct kgsl_pagetable *pt; int ret = 0; - mutex_lock(&kgsl_driver.pt_mutex); pt = _get_pt_from_kobj(kobj); if (pt) ret += snprintf(buf, PAGE_SIZE, "%d\n", pt->stats.max_mapped); - mutex_unlock(&kgsl_driver.pt_mutex); + kgsl_put_pagetable(pt); return ret; } @@ -441,13 +180,12 @@ sysfs_show_max_entries(struct kobject *kobj, struct kgsl_pagetable *pt; int ret = 0; - mutex_lock(&kgsl_driver.pt_mutex); pt = _get_pt_from_kobj(kobj); if (pt) ret += snprintf(buf, PAGE_SIZE, "%d\n", pt->stats.max_entries); - mutex_unlock(&kgsl_driver.pt_mutex); + kgsl_put_pagetable(pt); return ret; } @@ -529,55 +267,96 @@ err: return ret; } -static inline uint32_t -kgsl_pt_entry_get(struct kgsl_pagetable *pt, uint32_t va) +unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_device *device) { - return (va - pt->va_base) >> PAGE_SHIFT; + struct kgsl_mmu *mmu = &device->mmu; + if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) + return 0; + else + return mmu->mmu_ops->mmu_get_current_ptbase(device); } +EXPORT_SYMBOL(kgsl_mmu_get_current_ptbase); -static inline void -kgsl_pt_map_set(struct kgsl_pagetable *pt, uint32_t pte, uint32_t val) +int +kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base) { - uint32_t *baseptr = (uint32_t *)pt->base.hostptr; + struct kgsl_pagetable *pt; + int ptid = -1; - writel_relaxed(val, &baseptr[pte]); + spin_lock(&kgsl_driver.ptlock); + list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) { + if (pt->pt_ops->mmu_pt_equal(pt, pt_base)) { + ptid = (int) pt->name; + break; + } + } + spin_unlock(&kgsl_driver.ptlock); + + return ptid; } +EXPORT_SYMBOL(kgsl_mmu_get_ptname_from_ptbase); -static inline uint32_t -kgsl_pt_map_getaddr(struct kgsl_pagetable *pt, uint32_t pte) +void kgsl_mmu_setstate(struct kgsl_device *device, + struct kgsl_pagetable *pagetable) { - uint32_t *baseptr = (uint32_t *)pt->base.hostptr; - uint32_t ret = readl_relaxed(&baseptr[pte]) & GSL_PT_PAGE_ADDR_MASK; - return ret; + struct kgsl_mmu *mmu = &device->mmu; + + if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) + return; + else + mmu->mmu_ops->mmu_setstate(device, + pagetable); } +EXPORT_SYMBOL(kgsl_mmu_setstate); + +int kgsl_mmu_init(struct kgsl_device *device) +{ + struct kgsl_mmu *mmu = &device->mmu; + + mmu->device = device; + + if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type || + KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) { + dev_info(device->dev, "|%s| MMU type set for device is " + "NOMMU\n", __func__); + return 0; + } else if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type) + mmu->mmu_ops = &gpummu_ops; + + return mmu->mmu_ops->mmu_init(device); +} +EXPORT_SYMBOL(kgsl_mmu_init); + +int kgsl_mmu_start(struct kgsl_device *device) +{ + struct kgsl_mmu *mmu = &device->mmu; + + if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) { + kgsl_regwrite(device, MH_MMU_CONFIG, 0); + return 0; + } else { + return mmu->mmu_ops->mmu_start(device); + } +} +EXPORT_SYMBOL(kgsl_mmu_start); void kgsl_mh_intrcallback(struct kgsl_device *device) { unsigned int status = 0; unsigned int reg; - kgsl_regread_isr(device, device->mmu.reg.interrupt_status, &status); + kgsl_regread(device, MH_INTERRUPT_STATUS, &status); + kgsl_regread(device, MH_AXI_ERROR, ®); - if (status & MH_INTERRUPT_MASK__AXI_READ_ERROR) { - kgsl_regread_isr(device, device->mmu.reg.axi_error, ®); + if (status & MH_INTERRUPT_MASK__AXI_READ_ERROR) KGSL_MEM_CRIT(device, "axi read error interrupt: %08x\n", reg); - } else if (status & MH_INTERRUPT_MASK__AXI_WRITE_ERROR) { - kgsl_regread_isr(device, device->mmu.reg.axi_error, ®); + if (status & MH_INTERRUPT_MASK__AXI_WRITE_ERROR) KGSL_MEM_CRIT(device, "axi write error interrupt: %08x\n", reg); - } else if (status & MH_INTERRUPT_MASK__MMU_PAGE_FAULT) { - kgsl_regread_isr(device, device->mmu.reg.page_fault, ®); - KGSL_MEM_CRIT(device, "mmu page fault interrupt: %08x\n", reg); - } else { - KGSL_MEM_WARN(device, - "bad bits in REG_MH_INTERRUPT_STATUS %08x\n", status); - } + if (status & MH_INTERRUPT_MASK__MMU_PAGE_FAULT) + device->mmu.mmu_ops->mmu_pagefault(device); - kgsl_regwrite_isr(device, device->mmu.reg.interrupt_clear, status); - - /*TODO: figure out how to handle errror interupts. - * specifically, page faults should probably nuke the client that - * caused them, but we don't have enough info to figure that out yet. - */ + status &= KGSL_MMU_INT_MASK; + kgsl_regwrite(device, MH_INTERRUPT_CLEAR, status); } EXPORT_SYMBOL(kgsl_mh_intrcallback); @@ -589,7 +368,7 @@ static int kgsl_setup_pt(struct kgsl_pagetable *pt) for (i = 0; i < KGSL_DEVICE_MAX; i++) { struct kgsl_device *device = kgsl_driver.devp[i]; if (device) { - status = device->ftbl.device_setup_pt(device, pt); + status = device->ftbl->setup_pt(device, pt); if (status) goto error_pt; } @@ -599,28 +378,18 @@ error_pt: while (i >= 0) { struct kgsl_device *device = kgsl_driver.devp[i]; if (device) - device->ftbl.device_cleanup_pt(device, pt); + device->ftbl->cleanup_pt(device, pt); i--; } return status; } -static int kgsl_cleanup_pt(struct kgsl_pagetable *pt) -{ - int i; - for (i = 0; i < KGSL_DEVICE_MAX; i++) { - struct kgsl_device *device = kgsl_driver.devp[i]; - if (device) - device->ftbl.device_cleanup_pt(device, pt); - } - return 0; -} - static struct kgsl_pagetable *kgsl_mmu_createpagetableobject( unsigned int name) { int status = 0; struct kgsl_pagetable *pagetable = NULL; + unsigned long flags; pagetable = kzalloc(sizeof(struct kgsl_pagetable), GFP_KERNEL); if (pagetable == NULL) { @@ -629,311 +398,127 @@ static struct kgsl_pagetable *kgsl_mmu_createpagetableobject( return NULL; } - pagetable->refcnt = 1; + kref_init(&pagetable->refcount); spin_lock_init(&pagetable->lock); - pagetable->tlb_flags = 0; pagetable->name = name; - pagetable->va_base = KGSL_PAGETABLE_BASE; - pagetable->va_range = CONFIG_MSM_KGSL_PAGE_TABLE_SIZE; - pagetable->last_superpte = 0; - pagetable->max_entries = KGSL_PAGETABLE_ENTRIES(pagetable->va_range); - - pagetable->tlbflushfilter.size = (pagetable->va_range / - (PAGE_SIZE * GSL_PT_SUPER_PTE * 8)) + 1; - pagetable->tlbflushfilter.base = (unsigned int *) - kzalloc(pagetable->tlbflushfilter.size, GFP_KERNEL); - if (!pagetable->tlbflushfilter.base) { - KGSL_CORE_ERR("kzalloc(%d) failed\n", - pagetable->tlbflushfilter.size); - goto err_alloc; - } - GSL_TLBFLUSH_FILTER_RESET(); + pagetable->max_entries = KGSL_PAGETABLE_ENTRIES( + CONFIG_MSM_KGSL_PAGE_TABLE_SIZE); pagetable->pool = gen_pool_create(PAGE_SHIFT, -1); if (pagetable->pool == NULL) { KGSL_CORE_ERR("gen_pool_create(%d) failed\n", PAGE_SHIFT); - goto err_flushfilter; + goto err_alloc; } - if (gen_pool_add(pagetable->pool, pagetable->va_base, - pagetable->va_range, -1)) { + if (gen_pool_add(pagetable->pool, KGSL_PAGETABLE_BASE, + CONFIG_MSM_KGSL_PAGE_TABLE_SIZE, -1)) { KGSL_CORE_ERR("gen_pool_add failed\n"); goto err_pool; } - pagetable->base.hostptr = kgsl_ptpool_alloc(&kgsl_driver.ptpool, - &pagetable->base.physaddr); + if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type) + pagetable->pt_ops = &gpummu_pt_ops; - if (pagetable->base.hostptr == NULL) + pagetable->priv = pagetable->pt_ops->mmu_create_pagetable(); + if (!pagetable->priv) goto err_pool; - /* ptpool allocations are from coherent memory, so update the - device statistics acordingly */ - - KGSL_STATS_ADD(KGSL_PAGETABLE_SIZE, kgsl_driver.stats.coherent, - kgsl_driver.stats.coherent_max); - - pagetable->base.gpuaddr = pagetable->base.physaddr; - pagetable->base.size = KGSL_PAGETABLE_SIZE; - status = kgsl_setup_pt(pagetable); if (status) - goto err_free_sharedmem; + goto err_mmu_create; + spin_lock_irqsave(&kgsl_driver.ptlock, flags); list_add(&pagetable->list, &kgsl_driver.pagetable_list); + spin_unlock_irqrestore(&kgsl_driver.ptlock, flags); /* Create the sysfs entries */ pagetable_add_sysfs_objects(pagetable); return pagetable; -err_free_sharedmem: - kgsl_ptpool_free(&kgsl_driver.ptpool, &pagetable->base.hostptr); +err_mmu_create: + pagetable->pt_ops->mmu_destroy_pagetable(pagetable->priv); err_pool: gen_pool_destroy(pagetable->pool); -err_flushfilter: - kfree(pagetable->tlbflushfilter.base); err_alloc: kfree(pagetable); return NULL; } -static void kgsl_mmu_destroypagetable(struct kgsl_pagetable *pagetable) -{ - list_del(&pagetable->list); - - pagetable_remove_sysfs_objects(pagetable); - - kgsl_cleanup_pt(pagetable); - - kgsl_ptpool_free(&kgsl_driver.ptpool, pagetable->base.hostptr); - - kgsl_driver.stats.coherent -= KGSL_PAGETABLE_SIZE; - - if (pagetable->pool) { - gen_pool_destroy(pagetable->pool); - pagetable->pool = NULL; - } - - if (pagetable->tlbflushfilter.base) { - pagetable->tlbflushfilter.size = 0; - kfree(pagetable->tlbflushfilter.base); - pagetable->tlbflushfilter.base = NULL; - } - - kfree(pagetable); -} - struct kgsl_pagetable *kgsl_mmu_getpagetable(unsigned long name) { struct kgsl_pagetable *pt; - mutex_lock(&kgsl_driver.pt_mutex); + if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) + return (void *)(-1); +#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE +#else + name = KGSL_MMU_GLOBAL_PT; +#endif pt = kgsl_get_pagetable(name); - if (pt) { - spin_lock(&pt->lock); - pt->refcnt++; - spin_unlock(&pt->lock); - goto done; - } + if (pt == NULL) + pt = kgsl_mmu_createpagetableobject(name); - pt = kgsl_mmu_createpagetableobject(name); - -done: - mutex_unlock(&kgsl_driver.pt_mutex); return pt; } void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable) { - bool dead; - if (pagetable == NULL) + kgsl_put_pagetable(pagetable); +} +EXPORT_SYMBOL(kgsl_mmu_putpagetable); + +void kgsl_setstate(struct kgsl_device *device, uint32_t flags) +{ + struct kgsl_mmu *mmu = &device->mmu; + if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) return; - - mutex_lock(&kgsl_driver.pt_mutex); - - spin_lock(&pagetable->lock); - dead = (--pagetable->refcnt) == 0; - spin_unlock(&pagetable->lock); - - if (dead) - kgsl_mmu_destroypagetable(pagetable); - - mutex_unlock(&kgsl_driver.pt_mutex); + else if (device->ftbl->setstate) + device->ftbl->setstate(device, flags); + else if (mmu->mmu_ops->mmu_device_setstate) + mmu->mmu_ops->mmu_device_setstate(device, flags); } +EXPORT_SYMBOL(kgsl_setstate); -int kgsl_mmu_setstate(struct kgsl_device *device, - struct kgsl_pagetable *pagetable) +void kgsl_mmu_device_setstate(struct kgsl_device *device, uint32_t flags) { - int status = 0; struct kgsl_mmu *mmu = &device->mmu; - - if (mmu->flags & KGSL_FLAGS_STARTED) { - /* page table not current, then setup mmu to use new - * specified page table - */ - if (mmu->hwpagetable != pagetable) { - mmu->hwpagetable = pagetable; - spin_lock(&mmu->hwpagetable->lock); - mmu->hwpagetable->tlb_flags &= ~(1<id); - spin_unlock(&mmu->hwpagetable->lock); - - /* call device specific set page table */ - status = kgsl_setstate(mmu->device, - KGSL_MMUFLAGS_TLBFLUSH | - KGSL_MMUFLAGS_PTUPDATE); - - } - } - - return status; + if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) + return; + else if (mmu->mmu_ops->mmu_device_setstate) + mmu->mmu_ops->mmu_device_setstate(device, flags); } -EXPORT_SYMBOL(kgsl_mmu_setstate); +EXPORT_SYMBOL(kgsl_mmu_device_setstate); -int kgsl_mmu_init(struct kgsl_device *device) +void kgsl_mh_start(struct kgsl_device *device) { - /* - * intialize device mmu - * - * call this with the global lock held - */ - int status = 0; - struct kgsl_mmu *mmu = &device->mmu; - - mmu->device = device; - - /* make sure aligned to pagesize */ - BUG_ON(mmu->mpu_base & (PAGE_SIZE - 1)); - BUG_ON((mmu->mpu_base + mmu->mpu_range) & (PAGE_SIZE - 1)); - - /* sub-client MMU lookups require address translation */ - if ((mmu->config & ~0x1) > 0) { - /*make sure virtual address range is a multiple of 64Kb */ - BUG_ON(CONFIG_MSM_KGSL_PAGE_TABLE_SIZE & ((1 << 16) - 1)); - - /* allocate memory used for completing r/w operations that - * cannot be mapped by the MMU - */ - status = kgsl_allocate_contig(&mmu->dummyspace, 64); - if (!status) - kgsl_sharedmem_set(&mmu->dummyspace, 0, 0, - mmu->dummyspace.size); - } - - return status; -} - -int kgsl_mmu_start(struct kgsl_device *device) -{ - /* - * intialize device mmu - * - * call this with the global lock held - */ - int status; - struct kgsl_mmu *mmu = &device->mmu; - - if (mmu->flags & KGSL_FLAGS_STARTED) - return 0; - - /* MMU not enabled */ - if ((mmu->config & 0x1) == 0) - return 0; - - mmu->flags |= KGSL_FLAGS_STARTED; - - /* setup MMU and sub-client behavior */ - kgsl_regwrite(device, device->mmu.reg.config, mmu->config); - - /* enable axi interrupts */ - kgsl_regwrite(device, device->mmu.reg.interrupt_mask, - GSL_MMU_INT_MASK); - - /* idle device */ + struct kgsl_mh *mh = &device->mh; + /* force mmu off to for now*/ + kgsl_regwrite(device, MH_MMU_CONFIG, 0); kgsl_idle(device, KGSL_TIMEOUT_DEFAULT); /* define physical memory range accessible by the core */ - kgsl_regwrite(device, device->mmu.reg.mpu_base, mmu->mpu_base); - kgsl_regwrite(device, device->mmu.reg.mpu_end, - mmu->mpu_base + mmu->mpu_range); + kgsl_regwrite(device, MH_MMU_MPU_BASE, mh->mpu_base); + kgsl_regwrite(device, MH_MMU_MPU_END, + mh->mpu_base + mh->mpu_range); + kgsl_regwrite(device, MH_ARBITER_CONFIG, mh->mharb); - /* enable axi interrupts */ - kgsl_regwrite(device, device->mmu.reg.interrupt_mask, - GSL_MMU_INT_MASK | MH_INTERRUPT_MASK__MMU_PAGE_FAULT); + if (mh->mh_intf_cfg1 != 0) + kgsl_regwrite(device, MH_CLNT_INTF_CTRL_CONFIG1, + mh->mh_intf_cfg1); - /* sub-client MMU lookups require address translation */ - if ((mmu->config & ~0x1) > 0) { + if (mh->mh_intf_cfg2 != 0) + kgsl_regwrite(device, MH_CLNT_INTF_CTRL_CONFIG2, + mh->mh_intf_cfg2); - kgsl_sharedmem_set(&mmu->dummyspace, 0, 0, - mmu->dummyspace.size); - - /* TRAN_ERROR needs a 32 byte (32 byte aligned) chunk of memory - * to complete transactions in case of an MMU fault. Note that - * we'll leave the bottom 32 bytes of the dummyspace for other - * purposes (e.g. use it when dummy read cycles are needed - * for other blocks */ - kgsl_regwrite(device, device->mmu.reg.tran_error, - mmu->dummyspace.physaddr + 32); - - if (mmu->defaultpagetable == NULL) - mmu->defaultpagetable = - kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT); - mmu->hwpagetable = mmu->defaultpagetable; - - kgsl_regwrite(device, device->mmu.reg.pt_page, - mmu->hwpagetable->base.gpuaddr); - kgsl_regwrite(device, device->mmu.reg.va_range, - (mmu->hwpagetable->va_base | - (mmu->hwpagetable->va_range >> 16))); - status = kgsl_setstate(device, KGSL_MMUFLAGS_TLBFLUSH); - if (status) { - KGSL_MEM_ERR(device, "Failed to setstate TLBFLUSH\n"); - goto error; - } - } - - return 0; -error: - /* disable MMU */ - kgsl_regwrite(device, device->mmu.reg.interrupt_mask, 0); - kgsl_regwrite(device, device->mmu.reg.config, 0x00000000); - return status; -} -EXPORT_SYMBOL(kgsl_mmu_start); - -unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr) -{ - unsigned int physaddr = 0; - pgd_t *pgd_ptr = NULL; - pmd_t *pmd_ptr = NULL; - pte_t *pte_ptr = NULL, pte; - - pgd_ptr = pgd_offset(current->mm, (unsigned long) virtaddr); - if (pgd_none(*pgd) || pgd_bad(*pgd)) { - KGSL_CORE_ERR("Invalid pgd entry\n"); - return 0; - } - - pmd_ptr = pmd_offset(pgd_ptr, (unsigned long) virtaddr); - if (pmd_none(*pmd_ptr) || pmd_bad(*pmd_ptr)) { - KGSL_CORE_ERR("Invalid pmd entry\n"); - return 0; - } - - pte_ptr = pte_offset_map(pmd_ptr, (unsigned long) virtaddr); - if (!pte_ptr) { - KGSL_CORE_ERR("pt_offset_map failed\n"); - return 0; - } - pte = *pte_ptr; - physaddr = pte_pfn(pte); - pte_unmap(pte_ptr); - physaddr <<= PAGE_SHIFT; - return physaddr; + /* + * Interrupts are enabled on a per-device level when + * kgsl_pwrctrl_irq() is called + */ } int @@ -941,14 +526,12 @@ kgsl_mmu_map(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc, unsigned int protflags) { - int numpages; - unsigned int pte, ptefirst, ptelast, physaddr; - int flushtlb; - unsigned int offset = 0; - - BUG_ON(protflags & ~(GSL_PT_PAGE_RV | GSL_PT_PAGE_WV)); - BUG_ON(protflags == 0); + int ret; + if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) { + memdesc->gpuaddr = memdesc->physaddr; + return 0; + } memdesc->gpuaddr = gen_pool_alloc_aligned(pagetable->pool, memdesc->size, KGSL_MMU_ALIGN_SHIFT); @@ -960,36 +543,11 @@ kgsl_mmu_map(struct kgsl_pagetable *pagetable, return -ENOMEM; } - numpages = (memdesc->size >> PAGE_SHIFT); - - ptefirst = kgsl_pt_entry_get(pagetable, memdesc->gpuaddr); - ptelast = ptefirst + numpages; - - pte = ptefirst; - flushtlb = 0; - - /* tlb needs to be flushed when the first and last pte are not at - * superpte boundaries */ - if ((ptefirst & (GSL_PT_SUPER_PTE - 1)) != 0 || - ((ptelast + 1) & (GSL_PT_SUPER_PTE-1)) != 0) - flushtlb = 1; - spin_lock(&pagetable->lock); - for (pte = ptefirst; pte < ptelast; pte++, offset += PAGE_SIZE) { -#ifdef VERBOSE_DEBUG - /* check if PTE exists */ - uint32_t val = kgsl_pt_map_getaddr(pagetable, pte); - BUG_ON(val != 0 && val != GSL_PT_PAGE_DIRTY); -#endif - if ((pte & (GSL_PT_SUPER_PTE-1)) == 0) - if (GSL_TLBFLUSH_FILTER_ISDIRTY(pte / GSL_PT_SUPER_PTE)) - flushtlb = 1; - /* mark pte as in use */ + ret = pagetable->pt_ops->mmu_map(pagetable->priv, memdesc, protflags); - physaddr = memdesc->ops->physaddr(memdesc, offset); - BUG_ON(physaddr == 0); - kgsl_pt_map_set(pagetable, pte, physaddr | protflags); - } + if (ret) + goto err_free_gpuaddr; /* Keep track of the statistics for the sysfs files */ @@ -999,70 +557,40 @@ kgsl_mmu_map(struct kgsl_pagetable *pagetable, KGSL_STATS_ADD(memdesc->size, pagetable->stats.mapped, pagetable->stats.max_mapped); - /* Post all writes to the pagetable */ - wmb(); - - /* Invalidate tlb only if current page table used by GPU is the - * pagetable that we used to allocate */ - if (flushtlb) { - /*set all devices as needing flushing*/ - pagetable->tlb_flags = UINT_MAX; - GSL_TLBFLUSH_FILTER_RESET(); - } spin_unlock(&pagetable->lock); return 0; + +err_free_gpuaddr: + spin_unlock(&pagetable->lock); + gen_pool_free(pagetable->pool, memdesc->gpuaddr, memdesc->size); + memdesc->gpuaddr = 0; + return ret; } +EXPORT_SYMBOL(kgsl_mmu_map); int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc) { - unsigned int numpages; - unsigned int pte, ptefirst, ptelast, superpte; - unsigned int range = memdesc->size; - - /* All GPU addresses as assigned are page aligned, but some - functions purturb the gpuaddr with an offset, so apply the - mask here to make sure we have the right address */ - - unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK; - - if (range == 0 || gpuaddr == 0) + if (memdesc->size == 0 || memdesc->gpuaddr == 0) return 0; - numpages = (range >> PAGE_SHIFT); - if (range & (PAGE_SIZE - 1)) - numpages++; - - ptefirst = kgsl_pt_entry_get(pagetable, gpuaddr); - ptelast = ptefirst + numpages; - - spin_lock(&pagetable->lock); - superpte = ptefirst - (ptefirst & (GSL_PT_SUPER_PTE-1)); - GSL_TLBFLUSH_FILTER_SETDIRTY(superpte / GSL_PT_SUPER_PTE); - for (pte = ptefirst; pte < ptelast; pte++) { -#ifdef VERBOSE_DEBUG - /* check if PTE exists */ - BUG_ON(!kgsl_pt_map_getaddr(pagetable, pte)); -#endif - kgsl_pt_map_set(pagetable, pte, GSL_PT_PAGE_DIRTY); - superpte = pte - (pte & (GSL_PT_SUPER_PTE - 1)); - if (pte == superpte) - GSL_TLBFLUSH_FILTER_SETDIRTY(superpte / - GSL_PT_SUPER_PTE); + if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) { + memdesc->gpuaddr = 0; + return 0; } - + spin_lock(&pagetable->lock); + pagetable->pt_ops->mmu_unmap(pagetable->priv, memdesc); /* Remove the statistics */ pagetable->stats.entries--; - pagetable->stats.mapped -= range; - - /* Post all writes to the pagetable */ - wmb(); + pagetable->stats.mapped -= memdesc->size; spin_unlock(&pagetable->lock); - gen_pool_free(pagetable->pool, gpuaddr, range); + gen_pool_free(pagetable->pool, + memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK, + memdesc->size); return 0; } @@ -1078,6 +606,9 @@ int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable, KGSL_CORE_ERR("invalid memdesc\n"); goto error; } + /* Not all global mappings are needed for all MMU types */ + if (!memdesc->size) + return 0; gpuaddr = memdesc->gpuaddr; @@ -1102,40 +633,88 @@ EXPORT_SYMBOL(kgsl_mmu_map_global); int kgsl_mmu_stop(struct kgsl_device *device) { - /* - * stop device mmu - * - * call this with the global lock held - */ struct kgsl_mmu *mmu = &device->mmu; - if (mmu->flags & KGSL_FLAGS_STARTED) { - /* disable mh interrupts */ - /* disable MMU */ - kgsl_regwrite(device, device->mmu.reg.interrupt_mask, 0); - kgsl_regwrite(device, device->mmu.reg.config, 0x00000000); - - mmu->flags &= ~KGSL_FLAGS_STARTED; - } - - return 0; + if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) + return 0; + else + return mmu->mmu_ops->mmu_stop(device); } EXPORT_SYMBOL(kgsl_mmu_stop); int kgsl_mmu_close(struct kgsl_device *device) { - /* - * close device mmu - * - * call this with the global lock held - */ struct kgsl_mmu *mmu = &device->mmu; - if (mmu->dummyspace.gpuaddr) - kgsl_sharedmem_free(&mmu->dummyspace); - - if (mmu->defaultpagetable) - kgsl_mmu_putpagetable(mmu->defaultpagetable); - - return 0; + if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) + return 0; + else + return mmu->mmu_ops->mmu_close(device); } +EXPORT_SYMBOL(kgsl_mmu_close); + +int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt, + enum kgsl_deviceid id) +{ + if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type) + return pt->pt_ops->mmu_pt_get_flags(pt, id); + else + return 0; +} +EXPORT_SYMBOL(kgsl_mmu_pt_get_flags); + +void kgsl_mmu_ptpool_destroy(void *ptpool) +{ + if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type) + kgsl_gpummu_ptpool_destroy(ptpool); + ptpool = 0; +} +EXPORT_SYMBOL(kgsl_mmu_ptpool_destroy); + +void *kgsl_mmu_ptpool_init(int ptsize, int entries) +{ + if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type) + return kgsl_gpummu_ptpool_init(ptsize, entries); + else + return (void *)(-1); +} +EXPORT_SYMBOL(kgsl_mmu_ptpool_init); + +int kgsl_mmu_enabled(void) +{ + if (KGSL_MMU_TYPE_NONE != kgsl_mmu_type) + return 1; + else + return 0; +} +EXPORT_SYMBOL(kgsl_mmu_enabled); + +int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt, + unsigned int pt_base) +{ + if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) + return true; + else + return pt->pt_ops->mmu_pt_equal(pt, pt_base); +} +EXPORT_SYMBOL(kgsl_mmu_pt_equal); + +enum kgsl_mmutype kgsl_mmu_get_mmutype(void) +{ + return kgsl_mmu_type; +} +EXPORT_SYMBOL(kgsl_mmu_get_mmutype); + +void kgsl_mmu_set_mmutype(char *mmutype) +{ + kgsl_mmu_type = KGSL_MMU_TYPE_NONE; +#ifdef CONFIG_MSM_KGSL_GPUMMU + kgsl_mmu_type = KGSL_MMU_TYPE_GPU; +#elif defined(CONFIG_MSM_KGSL_IOMMU) +#endif + if (mmutype && !strncmp(mmutype, "gpummu", 6)) + kgsl_mmu_type = KGSL_MMU_TYPE_GPU; + if (mmutype && !strncmp(mmutype, "nommu", 5)) + kgsl_mmu_type = KGSL_MMU_TYPE_NONE; +} +EXPORT_SYMBOL(kgsl_mmu_set_mmutype); diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 4a67ea67..4af073a7 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -1,34 +1,20 @@ /* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __KGSL_MMU_H #define __KGSL_MMU_H -#include "kgsl_sharedmem.h" + +#define KGSL_MMU_ALIGN_SHIFT 13 +#define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1)) /* Identifier for the global page table */ /* Per process page tables will probably pass in the thread group @@ -36,10 +22,52 @@ #define KGSL_MMU_GLOBAL_PT 0 +struct kgsl_device; + #define GSL_PT_SUPER_PTE 8 #define GSL_PT_PAGE_WV 0x00000001 #define GSL_PT_PAGE_RV 0x00000002 #define GSL_PT_PAGE_DIRTY 0x00000004 + +/* MMU registers - the register locations for all cores are the + same. The method for getting to those locations differs between + 2D and 3D, but the 2D and 3D register functions do that magic + for us */ + +#define MH_MMU_CONFIG 0x0040 +#define MH_MMU_VA_RANGE 0x0041 +#define MH_MMU_PT_BASE 0x0042 +#define MH_MMU_PAGE_FAULT 0x0043 +#define MH_MMU_TRAN_ERROR 0x0044 +#define MH_MMU_INVALIDATE 0x0045 +#define MH_MMU_MPU_BASE 0x0046 +#define MH_MMU_MPU_END 0x0047 + +#define MH_INTERRUPT_MASK 0x0A42 +#define MH_INTERRUPT_STATUS 0x0A43 +#define MH_INTERRUPT_CLEAR 0x0A44 +#define MH_AXI_ERROR 0x0A45 +#define MH_ARBITER_CONFIG 0x0A40 +#define MH_DEBUG_CTRL 0x0A4E +#define MH_DEBUG_DATA 0x0A4F +#define MH_AXI_HALT_CONTROL 0x0A50 +#define MH_CLNT_INTF_CTRL_CONFIG1 0x0A54 +#define MH_CLNT_INTF_CTRL_CONFIG2 0x0A55 + +/* MH_MMU_CONFIG bit definitions */ + +#define MH_MMU_CONFIG__RB_W_CLNT_BEHAVIOR__SHIFT 0x00000004 +#define MH_MMU_CONFIG__CP_W_CLNT_BEHAVIOR__SHIFT 0x00000006 +#define MH_MMU_CONFIG__CP_R0_CLNT_BEHAVIOR__SHIFT 0x00000008 +#define MH_MMU_CONFIG__CP_R1_CLNT_BEHAVIOR__SHIFT 0x0000000a +#define MH_MMU_CONFIG__CP_R2_CLNT_BEHAVIOR__SHIFT 0x0000000c +#define MH_MMU_CONFIG__CP_R3_CLNT_BEHAVIOR__SHIFT 0x0000000e +#define MH_MMU_CONFIG__CP_R4_CLNT_BEHAVIOR__SHIFT 0x00000010 +#define MH_MMU_CONFIG__VGT_R0_CLNT_BEHAVIOR__SHIFT 0x00000012 +#define MH_MMU_CONFIG__VGT_R1_CLNT_BEHAVIOR__SHIFT 0x00000014 +#define MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT 0x00000016 +#define MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT 0x00000018 + /* MMU Flags */ #define KGSL_MMUFLAGS_TLBFLUSH 0x10000000 #define KGSL_MMUFLAGS_PTUPDATE 0x20000000 @@ -48,43 +76,30 @@ #define MH_INTERRUPT_MASK__AXI_WRITE_ERROR 0x00000002L #define MH_INTERRUPT_MASK__MMU_PAGE_FAULT 0x00000004L -/* Macros to manage TLB flushing */ -#define GSL_TLBFLUSH_FILTER_ENTRY_NUMBITS (sizeof(unsigned char) * 8) -#define GSL_TLBFLUSH_FILTER_GET(superpte) \ - (*((unsigned char *) \ - (((unsigned int)pagetable->tlbflushfilter.base) \ - + (superpte / GSL_TLBFLUSH_FILTER_ENTRY_NUMBITS)))) -#define GSL_TLBFLUSH_FILTER_SETDIRTY(superpte) \ - (GSL_TLBFLUSH_FILTER_GET((superpte)) |= 1 << \ - (superpte % GSL_TLBFLUSH_FILTER_ENTRY_NUMBITS)) -#define GSL_TLBFLUSH_FILTER_ISDIRTY(superpte) \ - (GSL_TLBFLUSH_FILTER_GET((superpte)) & \ - (1 << (superpte % GSL_TLBFLUSH_FILTER_ENTRY_NUMBITS))) -#define GSL_TLBFLUSH_FILTER_RESET() memset(pagetable->tlbflushfilter.base,\ - 0, pagetable->tlbflushfilter.size) +#ifdef CONFIG_MSM_KGSL_MMU +#define KGSL_MMU_INT_MASK \ + (MH_INTERRUPT_MASK__AXI_READ_ERROR | \ + MH_INTERRUPT_MASK__AXI_WRITE_ERROR | \ + MH_INTERRUPT_MASK__MMU_PAGE_FAULT) +#else +#define KGSL_MMU_INT_MASK \ + (MH_INTERRUPT_MASK__AXI_READ_ERROR | \ + MH_INTERRUPT_MASK__AXI_WRITE_ERROR) +#endif - -struct kgsl_device; - -struct kgsl_tlbflushfilter { - unsigned int *base; - unsigned int size; +enum kgsl_mmutype { + KGSL_MMU_TYPE_GPU = 0, + KGSL_MMU_TYPE_IOMMU, + KGSL_MMU_TYPE_NONE }; struct kgsl_pagetable { spinlock_t lock; - unsigned int refcnt; - struct kgsl_memdesc base; - uint32_t va_base; - unsigned int va_range; - unsigned int last_superpte; + struct kref refcount; unsigned int max_entries; struct gen_pool *pool; struct list_head list; unsigned int name; - /* Maintain filter to manage tlb flushing */ - struct kgsl_tlbflushfilter tlbflushfilter; - unsigned int tlb_flags; struct kobject *kobj; struct { @@ -93,22 +108,36 @@ struct kgsl_pagetable { unsigned int max_mapped; unsigned int max_entries; } stats; + const struct kgsl_mmu_pt_ops *pt_ops; + void *priv; }; -struct kgsl_mmu_reg { +struct kgsl_mmu_ops { + int (*mmu_init) (struct kgsl_device *device); + int (*mmu_close) (struct kgsl_device *device); + int (*mmu_start) (struct kgsl_device *device); + int (*mmu_stop) (struct kgsl_device *device); + void (*mmu_setstate) (struct kgsl_device *device, + struct kgsl_pagetable *pagetable); + void (*mmu_device_setstate) (struct kgsl_device *device, + uint32_t flags); + void (*mmu_pagefault) (struct kgsl_device *device); + unsigned int (*mmu_get_current_ptbase) + (struct kgsl_device *device); +}; - uint32_t config; - uint32_t mpu_base; - uint32_t mpu_end; - uint32_t va_range; - uint32_t pt_page; - uint32_t page_fault; - uint32_t tran_error; - uint32_t invalidate; - uint32_t interrupt_mask; - uint32_t interrupt_status; - uint32_t interrupt_clear; - uint32_t axi_error; +struct kgsl_mmu_pt_ops { + int (*mmu_map) (void *mmu_pt, + struct kgsl_memdesc *memdesc, + unsigned int protflags); + int (*mmu_unmap) (void *mmu_pt, + struct kgsl_memdesc *memdesc); + void *(*mmu_create_pagetable) (void); + void (*mmu_destroy_pagetable) (void *pt); + int (*mmu_pt_equal) (struct kgsl_pagetable *pt, + unsigned int pt_base); + unsigned int (*mmu_pt_get_flags) (struct kgsl_pagetable *pt, + enum kgsl_deviceid id); }; struct kgsl_mmu { @@ -116,46 +145,27 @@ struct kgsl_mmu { uint32_t flags; struct kgsl_device *device; unsigned int config; - uint32_t mpu_base; - int mpu_range; - struct kgsl_memdesc dummyspace; - struct kgsl_mmu_reg reg; + struct kgsl_memdesc setstate_memory; /* current page table object being used by device mmu */ struct kgsl_pagetable *defaultpagetable; struct kgsl_pagetable *hwpagetable; + const struct kgsl_mmu_ops *mmu_ops; + void *priv; }; -struct kgsl_ptpool_chunk { - size_t size; - unsigned int count; - int dynamic; +#include "kgsl_gpummu.h" - void *data; - unsigned int phys; - - unsigned long *bitmap; - struct list_head list; -}; - -struct kgsl_ptpool { - size_t ptsize; - struct mutex lock; - struct list_head list; - int entries; - int static_entries; - int chunks; -}; +extern struct kgsl_mmu_ops iommu_ops; +extern struct kgsl_mmu_pt_ops iommu_pt_ops; struct kgsl_pagetable *kgsl_mmu_getpagetable(unsigned long name); - -#ifdef CONFIG_MSM_KGSL_MMU - +void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable); +void kgsl_mh_start(struct kgsl_device *device); +void kgsl_mh_intrcallback(struct kgsl_device *device); int kgsl_mmu_init(struct kgsl_device *device); int kgsl_mmu_start(struct kgsl_device *device); int kgsl_mmu_stop(struct kgsl_device *device); int kgsl_mmu_close(struct kgsl_device *device); -int kgsl_mmu_setstate(struct kgsl_device *device, - struct kgsl_pagetable *pagetable); int kgsl_mmu_map(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc, unsigned int protflags); @@ -163,105 +173,21 @@ int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc, unsigned int protflags); int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc); -void kgsl_ptpool_destroy(struct kgsl_ptpool *pool); -int kgsl_ptpool_init(struct kgsl_ptpool *pool, int ptsize, int entries); -void kgsl_mh_intrcallback(struct kgsl_device *device); -void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable); unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr); +void kgsl_setstate(struct kgsl_device *device, uint32_t flags); +void kgsl_mmu_device_setstate(struct kgsl_device *device, uint32_t flags); +void kgsl_mmu_setstate(struct kgsl_device *device, + struct kgsl_pagetable *pt); +int kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base); +int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt, + enum kgsl_deviceid id); -static inline int kgsl_mmu_enabled(void) -{ - return 1; -} - -#else - -static inline int kgsl_mmu_enabled(void) -{ - return 0; -} - -static inline int kgsl_mmu_init(struct kgsl_device *device) -{ - return 0; -} - -static inline int kgsl_mmu_start(struct kgsl_device *device) -{ - return 0; -} - -static inline int kgsl_mmu_stop(struct kgsl_device *device) -{ - return 0; -} - -static inline int kgsl_mmu_close(struct kgsl_device *device) -{ - return 0; -} - -static inline int kgsl_mmu_setstate(struct kgsl_device *device, - struct kgsl_pagetable *pagetable) -{ - return 0; -} - -static inline int kgsl_mmu_map(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc, - unsigned int protflags) -{ - memdesc->gpuaddr = memdesc->physaddr; - return 0; -} - -static inline int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc) -{ - return 0; -} - -static inline int kgsl_ptpool_init(struct kgsl_ptpool *pool, int ptsize, - int entries) -{ - return 0; -} - -static inline int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc, unsigned int protflags) -{ - /* gpuaddr is the same that gets passed in */ - return 0; -} - -static inline void kgsl_ptpool_destroy(struct kgsl_ptpool *pool) { } - -static inline void kgsl_mh_intrcallback(struct kgsl_device *device) { } - -static inline void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable) { } - -static inline unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr) -{ - return 0; -} - -#endif - -static inline unsigned int kgsl_pt_get_flags(struct kgsl_pagetable *pt, - enum kgsl_deviceid id) -{ - unsigned int result = 0; - - if (pt == NULL) - return 0; - - spin_lock(&pt->lock); - if (pt->tlb_flags && (1<tlb_flags &= ~(1<lock); - return result; -} - +void kgsl_mmu_ptpool_destroy(void *ptpool); +void *kgsl_mmu_ptpool_init(int ptsize, int entries); +int kgsl_mmu_enabled(void); +int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt, + unsigned int pt_base); +void kgsl_mmu_set_mmutype(char *mmutype); +unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_device *device); +enum kgsl_mmutype kgsl_mmu_get_mmutype(void); #endif /* __KGSL_MMU_H */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index dcac6aba..730a1e17 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,5 @@ /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (C) 2011 Sony Ericsson Mobile Communications AB. * * 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,53 +12,22 @@ * */ #include +#include #include -#include #include "kgsl.h" +#include "kgsl_pwrscale.h" +#include "kgsl_device.h" + +#define KGSL_PWRFLAGS_POWER_ON 0 +#define KGSL_PWRFLAGS_CLK_ON 1 +#define KGSL_PWRFLAGS_AXI_ON 2 +#define KGSL_PWRFLAGS_IRQ_ON 3 #define SWITCH_OFF 200 -#define TZ_UPDATE_ID 0x01404000 -#define TZ_RESET_ID 0x01403000 - -#ifdef CONFIG_MSM_SECURE_IO -/* Trap into the TrustZone, and call funcs there. */ -static int __secure_tz_entry(u32 cmd, u32 val) -{ - register u32 r0 asm("r0") = cmd; - register u32 r1 asm("r1") = 0x0; - register u32 r2 asm("r2") = val; - - __iowmb(); - asm( - __asmeq("%0", "r0") - __asmeq("%1", "r0") - __asmeq("%2", "r1") - __asmeq("%3", "r2") - "smc #0 @ switch to secure world\n" - : "=r" (r0) - : "r" (r0), "r" (r1), "r" (r2) - ); - return r0; -} -#else -static int __secure_tz_entry(u32 cmd, u32 val) -{ - return 0; -} -#endif /* CONFIG_MSM_SECURE_IO */ - -/* Returns the requested update to our power level. * - * Either up/down (-1/1) a level, or stay the same (0). */ -static inline int kgsl_pwrctrl_tz_update(u32 idle) -{ - return __secure_tz_entry(TZ_UPDATE_ID, idle); -} - -static inline void kgsl_pwrctrl_tz_reset(void) -{ - __secure_tz_entry(TZ_RESET_ID, 0); -} +#define GPU_SWFI_LATENCY 3 +#define UPDATE_BUSY_VAL 1000000 +#define UPDATE_BUSY 50 void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, unsigned int new_level) @@ -67,16 +37,18 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, new_level >= pwr->thermal_pwrlevel && new_level != pwr->active_pwrlevel) { pwr->active_pwrlevel = new_level; - if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) + if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) || + (device->state == KGSL_STATE_NAP)) clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->active_pwrlevel]. gpu_freq); - if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) - if (pwr->pcl) - msm_bus_scale_client_update_request(pwr->pcl, + if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) { + if (pwr->ebi1_clk) + clk_set_rate(pwr->ebi1_clk, pwr->pwrlevels[pwr->active_pwrlevel]. bus_freq); - KGSL_PWR_WARN(device, "pwr level changed to %d\n", + } + KGSL_PWR_WARN(device, "kgsl pwr level changed to %d\n", pwr->active_pwrlevel); } } @@ -257,41 +229,20 @@ static int kgsl_pwrctrl_idle_timer_show(struct device *dev, device->pwrctrl.interval_timeout); } -static int kgsl_pwrctrl_scaling_governor_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - char temp[20]; - struct kgsl_device *device = kgsl_device_from_dev(dev); - struct kgsl_pwrctrl *pwr = &device->pwrctrl; - unsigned int reset = pwr->idle_pass; - - snprintf(temp, sizeof(temp), "%.*s", - (int)min(count, sizeof(temp) - 1), buf); - if (strncmp(temp, "ondemand", 8) == 0) - reset = 1; - else if (strncmp(temp, "performance", 11) == 0) - reset = 0; - - mutex_lock(&device->mutex); - pwr->idle_pass = reset; - if (pwr->idle_pass == 0) - kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel); - mutex_unlock(&device->mutex); - - return count; -} - -static int kgsl_pwrctrl_scaling_governor_show(struct device *dev, +static int kgsl_pwrctrl_gpubusy_show(struct device *dev, struct device_attribute *attr, char *buf) { + int ret; struct kgsl_device *device = kgsl_device_from_dev(dev); - struct kgsl_pwrctrl *pwr = &device->pwrctrl; - if (pwr->idle_pass) - return snprintf(buf, 10, "ondemand\n"); - else - return snprintf(buf, 13, "performance\n"); + struct kgsl_busy *b = &device->pwrctrl.busy; + ret = snprintf(buf, 17, "%7d %7d\n", + b->on_time_old, b->time_old); + if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { + b->on_time_old = 0; + b->time_old = 0; + } + return ret; } DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store); @@ -300,15 +251,15 @@ DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show, DEVICE_ATTR(pwrnap, 0644, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store); DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show, kgsl_pwrctrl_idle_timer_store); -DEVICE_ATTR(scaling_governor, 0644, kgsl_pwrctrl_scaling_governor_show, - kgsl_pwrctrl_scaling_governor_store); +DEVICE_ATTR(gpubusy, 0644, kgsl_pwrctrl_gpubusy_show, + NULL); -static const struct device_attribute *pwrctrl_attr_list[] = { +static struct device_attribute *pwrctrl_attr_list[] = { &dev_attr_gpuclk, &dev_attr_max_gpuclk, &dev_attr_pwrnap, &dev_attr_idle_timer, - &dev_attr_scaling_governor, + &dev_attr_gpubusy, NULL }; @@ -322,28 +273,29 @@ void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device) kgsl_remove_device_sysfs_files(device->dev, pwrctrl_attr_list); } -static void kgsl_pwrctrl_idle_calc(struct kgsl_device *device) +/* Track the amount of time the gpu is on vs the total system time. * + * Regularly update the percentage of busy time displayed by sysfs. */ +static void kgsl_pwrctrl_busy_time(struct kgsl_device *device, bool on_time) { - int val; - struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct kgsl_power_stats stats; - - device->ftbl.device_power_stats(device, &stats); - - if (stats.total_time == 0) - return; - - /* If the GPU has stayed in turbo mode for a while, * - * stop writing out values. */ - if (pwr->active_pwrlevel) - pwr->no_switch_cnt = 0; - else if (pwr->no_switch_cnt > SWITCH_OFF) - return; - pwr->no_switch_cnt++; - val = kgsl_pwrctrl_tz_update(stats.total_time - stats.busy_time); - if (val) - kgsl_pwrctrl_pwrlevel_change(device, - pwr->active_pwrlevel + val); + struct kgsl_busy *b = &device->pwrctrl.busy; + int elapsed; + if (b->start.tv_sec == 0) + do_gettimeofday(&(b->start)); + do_gettimeofday(&(b->stop)); + elapsed = (b->stop.tv_sec - b->start.tv_sec) * 1000000; + elapsed += b->stop.tv_usec - b->start.tv_usec; + b->time += elapsed; + if (on_time) + b->on_time += elapsed; + /* Update the output regularly and reset the counters. */ + if ((b->time > UPDATE_BUSY_VAL) || + !test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { + b->on_time_old = b->on_time; + b->time_old = b->time; + b->on_time = 0; + b->time = 0; + } + do_gettimeofday(&(b->start)); } void kgsl_pwrctrl_clk(struct kgsl_device *device, int state) @@ -363,6 +315,7 @@ void kgsl_pwrctrl_clk(struct kgsl_device *device, int state) clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); + kgsl_pwrctrl_busy_time(device, true); } } else if (state == KGSL_PWRFLAGS_ON) { if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON, @@ -381,6 +334,7 @@ void kgsl_pwrctrl_clk(struct kgsl_device *device, int state) for (i = KGSL_MAX_CLKS - 1; i > 0; i--) if (pwr->grp_clks[i]) clk_enable(pwr->grp_clks[i]); + kgsl_pwrctrl_busy_time(device, false); } } } @@ -399,9 +353,6 @@ void kgsl_pwrctrl_axi(struct kgsl_device *device, int state) clk_set_rate(pwr->ebi1_clk, 0); clk_disable(pwr->ebi1_clk); } - if (pwr->pcl) - msm_bus_scale_client_update_request(pwr->pcl, - 0); } } else if (state == KGSL_PWRFLAGS_ON) { if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON, @@ -414,10 +365,6 @@ void kgsl_pwrctrl_axi(struct kgsl_device *device, int state) pwr->pwrlevels[pwr->active_pwrlevel]. bus_freq); } - if (pwr->pcl) - msm_bus_scale_client_update_request(pwr->pcl, - pwr->pwrlevels[pwr->active_pwrlevel]. - bus_freq); } } } @@ -458,13 +405,18 @@ void kgsl_pwrctrl_irq(struct kgsl_device *device, int state) KGSL_PWR_INFO(device, "irq on, device %d\n", device->id); enable_irq(pwr->interrupt_num); + device->ftbl->irqctrl(device, 1); } } else if (state == KGSL_PWRFLAGS_OFF) { if (test_and_clear_bit(KGSL_PWRFLAGS_IRQ_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "irq off, device %d\n", device->id); - disable_irq(pwr->interrupt_num); + device->ftbl->irqctrl(device, 0); + if (in_interrupt()) + disable_irq_nosync(pwr->interrupt_num); + else + disable_irq(pwr->interrupt_num); } } } @@ -533,9 +485,6 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->power_flags = 0; pwr->nap_allowed = pdata_pwr->nap_allowed; -/* drewis: below was removed at some point before i cherry-picked the below commit */ - pwr->idle_pass = pdata_pwr->idle_pass; -/*dc14311... msm: kgsl: Replace internal_power_rail API calls with regulator APIs*/ pwr->interval_timeout = pdata_pwr->idle_timeout; pwr->ebi1_clk = clk_get(NULL, "ebi1_kgsl_clk"); if (IS_ERR(pwr->ebi1_clk)) @@ -544,19 +493,6 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) clk_set_rate(pwr->ebi1_clk, pwr->pwrlevels[pwr->active_pwrlevel]. bus_freq); - if (pdata_dev->clk.bus_scale_table != NULL) { - pwr->pcl = - msm_bus_scale_register_client(pdata_dev->clk. - bus_scale_table); - if (!pwr->pcl) { - KGSL_PWR_ERR(device, - "msm_bus_scale_register_client failed: " - "id %d table %p", device->id, - pdata_dev->clk.bus_scale_table); - result = -EINVAL; - goto done; - } - } /*acquire interrupt */ pwr->interrupt_num = @@ -568,6 +504,8 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) result = -EINVAL; goto done; } + + register_early_suspend(&device->display_off); return result; clk_err: @@ -586,6 +524,8 @@ void kgsl_pwrctrl_close(struct kgsl_device *device) KGSL_PWR_INFO(device, "close device %d\n", device->id); + unregister_early_suspend(&device->display_off); + if (pwr->interrupt_num > 0) { if (pwr->have_irq) { free_irq(pwr->interrupt_num, NULL); @@ -596,8 +536,6 @@ void kgsl_pwrctrl_close(struct kgsl_device *device) clk_put(pwr->ebi1_clk); - if (pwr->pcl) - msm_bus_scale_unregister_client(pwr->pcl); pwr->pcl = 0; @@ -622,15 +560,22 @@ void kgsl_idle_check(struct work_struct *work) idle_check_ws); mutex_lock(&device->mutex); - if ((device->pwrctrl.idle_pass) && - (device->requested_state != KGSL_STATE_SLEEP)) - kgsl_pwrctrl_idle_calc(device); - if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) { - if (kgsl_pwrctrl_sleep(device) != 0) + if (device->requested_state != KGSL_STATE_SLEEP) + kgsl_pwrscale_idle(device); + + if (kgsl_pwrctrl_sleep(device) != 0) { mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); + /* If the GPU has been too busy to sleep, make sure * + * that is acurately reflected in the % busy numbers. */ + device->pwrctrl.busy.no_nap_cnt++; + if (device->pwrctrl.busy.no_nap_cnt > UPDATE_BUSY) { + kgsl_pwrctrl_busy_time(device, true); + device->pwrctrl.busy.no_nap_cnt = 0; + } + } } else if (device->state & (KGSL_STATE_HUNG | KGSL_STATE_DUMP_AND_RECOVER)) { device->requested_state = KGSL_STATE_NONE; @@ -684,11 +629,11 @@ int kgsl_pwrctrl_sleep(struct kgsl_device *device) /* Work through the legal state transitions */ if (device->requested_state == KGSL_STATE_NAP) { - if (device->ftbl.device_isidle(device)) + if (device->ftbl->isidle(device)) goto nap; } else if (device->requested_state == KGSL_STATE_SLEEP) { if (device->state == KGSL_STATE_NAP || - device->ftbl.device_isidle(device)) + device->ftbl->isidle(device)) goto sleep; } @@ -702,9 +647,10 @@ sleep: clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); - device->pwrctrl.no_switch_cnt = 0; + kgsl_pwrctrl_busy_time(device, false); + pwr->busy.start.tv_sec = 0; device->pwrctrl.time = 0; - kgsl_pwrctrl_tz_reset(); + goto clk_off; nap: @@ -730,11 +676,9 @@ void kgsl_pwrctrl_wake(struct kgsl_device *device) return; if (device->state != KGSL_STATE_NAP) { - if (device->pwrctrl.idle_pass) - kgsl_pwrctrl_pwrlevel_change(device, - device->pwrctrl.thermal_pwrlevel); kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); } + /* Turn on the core clocks */ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 108cc309..97a428df 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -1,53 +1,48 @@ /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __KGSL_PWRCTRL_H #define __KGSL_PWRCTRL_H +#include + /***************************************************************************** ** power flags *****************************************************************************/ -#define KGSL_PWRFLAGS_POWER_ON 0 -#define KGSL_PWRFLAGS_CLK_ON 1 -#define KGSL_PWRFLAGS_AXI_ON 2 -#define KGSL_PWRFLAGS_IRQ_ON 3 - #define KGSL_PWRFLAGS_ON 1 #define KGSL_PWRFLAGS_OFF 0 -#define KGSL_DEFAULT_PWRLEVEL 1 +#define KGSL_PWRLEVEL_TURBO 0 +#define KGSL_PWRLEVEL_NOMINAL 1 +#define KGSL_PWRLEVEL_LOW_OFFSET 2 + #define KGSL_MAX_CLKS 5 struct platform_device; +struct kgsl_busy { + struct timeval start; + struct timeval stop; + int on_time; + int time; + int on_time_old; + int time_old; + unsigned int no_nap_cnt; +}; + struct kgsl_pwrctrl { int interrupt_num; int have_irq; + unsigned int pwr_rail; struct clk *ebi1_clk; struct clk *grp_clks[KGSL_MAX_CLKS]; unsigned long power_flags; @@ -59,13 +54,11 @@ struct kgsl_pwrctrl { struct regulator *gpu_reg; uint32_t pcl; unsigned int nap_allowed; - struct adreno_context *suspended_ctxt; const char *regulator_name; const char *irq_name; const char *src_clk_name; s64 time; - unsigned int no_switch_cnt; - unsigned int idle_pass; + struct kgsl_busy busy; }; void kgsl_pwrctrl_clk(struct kgsl_device *device, int state); diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index f2250283..629a83f0 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -1,4 +1,5 @@ /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (C) 2011 Sony Ericsson Mobile Communications AB. * * 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 @@ -15,6 +16,7 @@ #include "kgsl.h" #include "kgsl_pwrscale.h" +#include "kgsl_device.h" struct kgsl_pwrscale_attribute { struct attribute attr; @@ -38,6 +40,12 @@ __ATTR(_name, _mode, _show, _store) /* Master list of available policies */ static struct kgsl_pwrscale_policy *kgsl_pwrscale_policies[] = { +#ifdef CONFIG_MSM_SCM + &kgsl_pwrscale_policy_tz, +#endif +#ifdef CONFIG_MSM_SLEEP_STATS + &kgsl_pwrscale_policy_idlestats, +#endif NULL }; @@ -141,9 +149,6 @@ static ssize_t policy_sysfs_store(struct kobject *kobj, static void policy_sysfs_release(struct kobject *kobj) { - struct kgsl_pwrscale *pwrscale = to_pwrscale(kobj); - - complete(&pwrscale->kobj_unregister); } static ssize_t pwrscale_sysfs_show(struct kobject *kobj, @@ -181,12 +186,12 @@ static void pwrscale_sysfs_release(struct kobject *kobj) { } -static const struct sysfs_ops policy_sysfs_ops = { +static struct sysfs_ops policy_sysfs_ops = { .show = policy_sysfs_show, .store = policy_sysfs_store }; -static const struct sysfs_ops pwrscale_sysfs_ops = { +static struct sysfs_ops pwrscale_sysfs_ops = { .show = pwrscale_sysfs_show, .store = pwrscale_sysfs_store }; @@ -220,13 +225,17 @@ EXPORT_SYMBOL(kgsl_pwrscale_wake); void kgsl_pwrscale_busy(struct kgsl_device *device) { if (device->pwrscale.policy && device->pwrscale.policy->busy) - device->pwrscale.policy->busy(device, &device->pwrscale); + if (!device->pwrscale.gpu_busy) + device->pwrscale.policy->busy(device, + &device->pwrscale); + device->pwrscale.gpu_busy = 1; } void kgsl_pwrscale_idle(struct kgsl_device *device) { if (device->pwrscale.policy && device->pwrscale.policy->idle) device->pwrscale.policy->idle(device, &device->pwrscale); + device->pwrscale.gpu_busy = 0; } EXPORT_SYMBOL(kgsl_pwrscale_idle); @@ -236,12 +245,8 @@ int kgsl_pwrscale_policy_add_files(struct kgsl_device *device, { int ret; - init_completion(&pwrscale->kobj_unregister); - - ret = kobject_init_and_add(&pwrscale->kobj, - &ktype_pwrscale_policy, - &device->pwrscale_kobj, - "%s", pwrscale->policy->name); + ret = kobject_add(&pwrscale->kobj, &device->pwrscale_kobj, + "%s", pwrscale->policy->name); if (ret) return ret; @@ -249,8 +254,8 @@ int kgsl_pwrscale_policy_add_files(struct kgsl_device *device, ret = sysfs_create_group(&pwrscale->kobj, attr_group); if (ret) { + kobject_del(&pwrscale->kobj); kobject_put(&pwrscale->kobj); - wait_for_completion(&pwrscale->kobj_unregister); } return ret; @@ -261,16 +266,24 @@ void kgsl_pwrscale_policy_remove_files(struct kgsl_device *device, struct attribute_group *attr_group) { sysfs_remove_group(&pwrscale->kobj, attr_group); + kobject_del(&pwrscale->kobj); kobject_put(&pwrscale->kobj); - wait_for_completion(&pwrscale->kobj_unregister); +} + +static void _kgsl_pwrscale_detach_policy(struct kgsl_device *device) +{ + if (device->pwrscale.policy != NULL) { + device->pwrscale.policy->close(device, &device->pwrscale); + kgsl_pwrctrl_pwrlevel_change(device, + device->pwrctrl.thermal_pwrlevel); + } + device->pwrscale.policy = NULL; } void kgsl_pwrscale_detach_policy(struct kgsl_device *device) { mutex_lock(&device->mutex); - if (device->pwrscale.policy != NULL) - device->pwrscale.policy->close(device, &device->pwrscale); - device->pwrscale.policy = NULL; + _kgsl_pwrscale_detach_policy(device); mutex_unlock(&device->mutex); } EXPORT_SYMBOL(kgsl_pwrscale_detach_policy); @@ -278,16 +291,25 @@ EXPORT_SYMBOL(kgsl_pwrscale_detach_policy); int kgsl_pwrscale_attach_policy(struct kgsl_device *device, struct kgsl_pwrscale_policy *policy) { - int ret; - - if (device->pwrscale.policy != NULL) - kgsl_pwrscale_detach_policy(device); + int ret = 0; mutex_lock(&device->mutex); + + if (device->pwrscale.policy == policy) + goto done; + + if (device->pwrscale.policy != NULL) + _kgsl_pwrscale_detach_policy(device); + device->pwrscale.policy = policy; - ret = device->pwrscale.policy->init(device, &device->pwrscale); - if (ret) - device->pwrscale.policy = NULL; + + if (policy) { + ret = device->pwrscale.policy->init(device, &device->pwrscale); + if (ret) + device->pwrscale.policy = NULL; + } + +done: mutex_unlock(&device->mutex); return ret; @@ -296,8 +318,16 @@ EXPORT_SYMBOL(kgsl_pwrscale_attach_policy); int kgsl_pwrscale_init(struct kgsl_device *device) { - return kobject_init_and_add(&device->pwrscale_kobj, &ktype_pwrscale, - &device->dev->kobj, "pwrscale"); + int ret; + + ret = kobject_init_and_add(&device->pwrscale_kobj, &ktype_pwrscale, + &device->dev->kobj, "pwrscale"); + + if (ret) + return ret; + + kobject_init(&device->pwrscale.kobj, &ktype_pwrscale_policy); + return ret; } EXPORT_SYMBOL(kgsl_pwrscale_init); diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h index f05adbd5..b4f831ee 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.h +++ b/drivers/gpu/msm/kgsl_pwrscale.h @@ -1,29 +1,13 @@ /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -51,8 +35,8 @@ struct kgsl_pwrscale_policy { struct kgsl_pwrscale { struct kgsl_pwrscale_policy *policy; struct kobject kobj; - struct completion kobj_unregister; void *priv; + int gpu_busy; }; struct kgsl_pwrscale_policy_attribute { @@ -68,8 +52,12 @@ struct kgsl_pwrscale_policy_attribute { struct kgsl_pwrscale_policy_attribute policy_attr_##_name = \ __ATTR(_name, _mode, _show, _store) +extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_tz; +extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_idlestats; + int kgsl_pwrscale_init(struct kgsl_device *device); void kgsl_pwrscale_close(struct kgsl_device *device); + int kgsl_pwrscale_attach_policy(struct kgsl_device *device, struct kgsl_pwrscale_policy *policy); void kgsl_pwrscale_detach_policy(struct kgsl_device *device); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 36ff19c7..a587c44a 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. + * Copyright (C) 2011 Sony Ericsson Mobile Communications AB. * * 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,11 +12,14 @@ * */ #include +#include #include #include "kgsl.h" #include "kgsl_sharedmem.h" #include "kgsl_cffdump.h" +#include "kgsl_device.h" +#include "adreno_ringbuffer.h" static struct kgsl_process_private * _get_priv_from_kobj(struct kobject *kobj) @@ -166,7 +170,7 @@ DEVICE_ATTR(mapped, 0444, kgsl_drv_memstat_show, NULL); DEVICE_ATTR(mapped_max, 0444, kgsl_drv_memstat_show, NULL); DEVICE_ATTR(histogram, 0444, kgsl_drv_histogram_show, NULL); -static const struct device_attribute *drv_attr_list[] = { +static struct device_attribute *drv_attr_list[] = { &dev_attr_vmalloc, &dev_attr_vmalloc_max, &dev_attr_coherent, @@ -205,28 +209,21 @@ static void _outer_cache_range_op(int op, unsigned long addr, size_t size) break; } } -#endif -static unsigned long kgsl_vmalloc_physaddr(struct kgsl_memdesc *memdesc, - unsigned int offset) +static void outer_cache_range_op_sg(struct scatterlist *sg, int sglen, int op) { - unsigned int addr; + struct scatterlist *s; + int i; - if (offset > memdesc->size) - return 0; - - addr = vmalloc_to_pfn(memdesc->hostptr + offset); - return addr << PAGE_SHIFT; + for_each_sg(sg, s, sglen, i) { + unsigned int paddr = sg_phys(s); + _outer_cache_range_op(op, paddr, s->length); + } } -#ifdef CONFIG_OUTER_CACHE -static void kgsl_vmalloc_outer_cache(struct kgsl_memdesc *memdesc, int op) +#else +static void outer_cache_range_op_sg(struct scatterlist *sg, int sglen, int op) { - void *vaddr = memdesc->hostptr; - for (; vaddr < (memdesc->hostptr + memdesc->size); vaddr += PAGE_SIZE) { - unsigned long paddr = page_to_phys(vmalloc_to_page(vaddr)); - _outer_cache_range_op(op, paddr, PAGE_SIZE); - } } #endif @@ -261,6 +258,42 @@ static void kgsl_vmalloc_free(struct kgsl_memdesc *memdesc) vfree(memdesc->hostptr); } +static int kgsl_contiguous_vmflags(struct kgsl_memdesc *memdesc) +{ + return VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND; +} + +static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc, + struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + unsigned long offset, pfn; + int ret; + + offset = ((unsigned long) vmf->virtual_address - vma->vm_start) >> + PAGE_SHIFT; + + pfn = (memdesc->physaddr >> PAGE_SHIFT) + offset; + ret = vm_insert_pfn(vma, (unsigned long) vmf->virtual_address, pfn); + + if (ret == -ENOMEM || ret == -EAGAIN) + return VM_FAULT_OOM; + else if (ret == -EFAULT) + return VM_FAULT_SIGBUS; + + return VM_FAULT_NOPAGE; +} + +static void kgsl_ebimem_free(struct kgsl_memdesc *memdesc) + +{ + kgsl_driver.stats.coherent -= memdesc->size; + if (memdesc->hostptr) + iounmap(memdesc->hostptr); + + free_contiguous_memory_by_paddr(memdesc->physaddr); +} + static void kgsl_coherent_free(struct kgsl_memdesc *memdesc) { kgsl_driver.stats.coherent -= memdesc->size; @@ -268,78 +301,24 @@ static void kgsl_coherent_free(struct kgsl_memdesc *memdesc) memdesc->hostptr, memdesc->physaddr); } -static unsigned long kgsl_contig_physaddr(struct kgsl_memdesc *memdesc, - unsigned int offset) -{ - if (offset > memdesc->size) - return 0; - - return memdesc->physaddr + offset; -} - -#ifdef CONFIG_OUTER_CACHE -static void kgsl_contig_outer_cache(struct kgsl_memdesc *memdesc, int op) -{ - _outer_cache_range_op(op, memdesc->physaddr, memdesc->size); -} -#endif - -#ifdef CONFIG_OUTER_CACHE -static void kgsl_userptr_outer_cache(struct kgsl_memdesc *memdesc, int op) -{ - void *vaddr = memdesc->hostptr; - for (; vaddr < (memdesc->hostptr + memdesc->size); vaddr += PAGE_SIZE) { - unsigned long paddr = kgsl_virtaddr_to_physaddr(vaddr); - if (paddr) - _outer_cache_range_op(op, paddr, PAGE_SIZE); - } -} -#endif - -static unsigned long kgsl_userptr_physaddr(struct kgsl_memdesc *memdesc, - unsigned int offset) -{ - return kgsl_virtaddr_to_physaddr(memdesc->hostptr + offset); -} - /* Global - also used by kgsl_drm.c */ struct kgsl_memdesc_ops kgsl_vmalloc_ops = { - .physaddr = kgsl_vmalloc_physaddr, .free = kgsl_vmalloc_free, .vmflags = kgsl_vmalloc_vmflags, .vmfault = kgsl_vmalloc_vmfault, -#ifdef CONFIG_OUTER_CACHE - .outer_cache = kgsl_vmalloc_outer_cache, -#endif }; EXPORT_SYMBOL(kgsl_vmalloc_ops); +static struct kgsl_memdesc_ops kgsl_ebimem_ops = { + .free = kgsl_ebimem_free, + .vmflags = kgsl_contiguous_vmflags, + .vmfault = kgsl_contiguous_vmfault, +}; + static struct kgsl_memdesc_ops kgsl_coherent_ops = { - .physaddr = kgsl_contig_physaddr, .free = kgsl_coherent_free, -#ifdef CONFIG_OUTER_CACHE - .outer_cache = kgsl_contig_outer_cache, -#endif }; -/* Global - also used by kgsl.c and kgsl_drm.c */ -struct kgsl_memdesc_ops kgsl_contig_ops = { - .physaddr = kgsl_contig_physaddr, -#ifdef CONFIG_OUTER_CACHE - .outer_cache = kgsl_contig_outer_cache -#endif -}; -EXPORT_SYMBOL(kgsl_contig_ops); - -/* Global - also used by kgsl.c */ -struct kgsl_memdesc_ops kgsl_userptr_ops = { - .physaddr = kgsl_userptr_physaddr, -#ifdef CONFIG_OUTER_CACHE - .outer_cache = kgsl_userptr_outer_cache, -#endif -}; -EXPORT_SYMBOL(kgsl_userptr_ops); - void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op) { void *addr = memdesc->hostptr; @@ -357,8 +336,7 @@ void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op) break; } - if (memdesc->ops->outer_cache) - memdesc->ops->outer_cache(memdesc, op); + outer_cache_range_op_sg(memdesc->sg, memdesc->sglen, op); } EXPORT_SYMBOL(kgsl_cache_range_op); @@ -367,7 +345,9 @@ _kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, void *ptr, size_t size, unsigned int protflags) { - int result; + int order, ret = 0; + int sglen = PAGE_ALIGN(size) / PAGE_SIZE; + int i; memdesc->size = size; memdesc->pagetable = pagetable; @@ -375,25 +355,44 @@ _kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc, memdesc->ops = &kgsl_vmalloc_ops; memdesc->hostptr = (void *) ptr; - kgsl_cache_range_op(memdesc, KGSL_CACHE_OP_INV); - - result = kgsl_mmu_map(pagetable, memdesc, protflags); - - if (result) { - kgsl_sharedmem_free(memdesc); - } else { - int order; - - KGSL_STATS_ADD(size, kgsl_driver.stats.vmalloc, - kgsl_driver.stats.vmalloc_max); - - order = get_order(size); - - if (order < 16) - kgsl_driver.stats.histogram[order]++; + memdesc->sg = kmalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL); + if (memdesc->sg == NULL) { + ret = -ENOMEM; + goto done; } - return result; + 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; + goto done; + } + sg_set_page(&memdesc->sg[i], page, PAGE_SIZE, 0); + } + + kgsl_cache_range_op(memdesc, KGSL_CACHE_OP_INV); + + ret = kgsl_mmu_map(pagetable, memdesc, protflags); + + if (ret) + goto done; + + KGSL_STATS_ADD(size, kgsl_driver.stats.vmalloc, + kgsl_driver.stats.vmalloc_max); + + order = get_order(size); + + if (order < 16) + kgsl_driver.stats.histogram[order]++; + +done: + if (ret) + kgsl_sharedmem_free(memdesc); + + return ret; } int @@ -446,24 +445,35 @@ EXPORT_SYMBOL(kgsl_sharedmem_vmalloc_user); int kgsl_sharedmem_alloc_coherent(struct kgsl_memdesc *memdesc, size_t size) { + int result = 0; + size = ALIGN(size, PAGE_SIZE); + memdesc->size = size; + memdesc->ops = &kgsl_coherent_ops; + memdesc->hostptr = dma_alloc_coherent(NULL, size, &memdesc->physaddr, GFP_KERNEL); if (memdesc->hostptr == NULL) { KGSL_CORE_ERR("dma_alloc_coherent(%d) failed\n", size); - return -ENOMEM; + result = -ENOMEM; + goto err; } - memdesc->size = size; - memdesc->ops = &kgsl_coherent_ops; + result = memdesc_sg_phys(memdesc, memdesc->physaddr, size); + if (result) + goto err; /* Record statistics */ KGSL_STATS_ADD(size, kgsl_driver.stats.coherent, kgsl_driver.stats.coherent_max); - return 0; +err: + if (result) + kgsl_sharedmem_free(memdesc); + + return result; } EXPORT_SYMBOL(kgsl_sharedmem_alloc_coherent); @@ -475,13 +485,86 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) if (memdesc->gpuaddr) kgsl_mmu_unmap(memdesc->pagetable, memdesc); - if (memdesc->ops->free) + if (memdesc->ops && memdesc->ops->free) memdesc->ops->free(memdesc); + kfree(memdesc->sg); + memset(memdesc, 0, sizeof(*memdesc)); } EXPORT_SYMBOL(kgsl_sharedmem_free); +static int +_kgsl_sharedmem_ebimem(struct kgsl_memdesc *memdesc, + struct kgsl_pagetable *pagetable, size_t size) +{ + int result = 0; + + memdesc->size = size; + memdesc->pagetable = pagetable; + memdesc->ops = &kgsl_ebimem_ops; + memdesc->physaddr = allocate_contiguous_ebi_nomap(size, SZ_8K); + + if (memdesc->physaddr == 0) { + KGSL_CORE_ERR("allocate_contiguous_ebi_nomap(%d) failed\n", + size); + return -ENOMEM; + } + + result = memdesc_sg_phys(memdesc, memdesc->physaddr, size); + + if (result) + goto err; + + result = kgsl_mmu_map(pagetable, memdesc, + GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); + + if (result) + goto err; + + KGSL_STATS_ADD(size, kgsl_driver.stats.coherent, + kgsl_driver.stats.coherent_max); + +err: + if (result) + kgsl_sharedmem_free(memdesc); + + return result; +} + +int +kgsl_sharedmem_ebimem_user(struct kgsl_memdesc *memdesc, + struct kgsl_pagetable *pagetable, + size_t size, int flags) +{ + size = ALIGN(size, PAGE_SIZE); + return _kgsl_sharedmem_ebimem(memdesc, pagetable, size); +} +EXPORT_SYMBOL(kgsl_sharedmem_ebimem_user); + +int +kgsl_sharedmem_ebimem(struct kgsl_memdesc *memdesc, + struct kgsl_pagetable *pagetable, size_t size) +{ + int result; + size = ALIGN(size, 8192); + result = _kgsl_sharedmem_ebimem(memdesc, pagetable, size); + + if (result) + return result; + + memdesc->hostptr = ioremap(memdesc->physaddr, size); + + if (memdesc->hostptr == NULL) { + KGSL_CORE_ERR("ioremap failed\n"); + kgsl_sharedmem_free(memdesc); + return -ENOMEM; + } + + return 0; +} +EXPORT_SYMBOL(kgsl_sharedmem_ebimem); + int kgsl_sharedmem_readl(const struct kgsl_memdesc *memdesc, uint32_t *dst, diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index d0070584..61bcf05b 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -1,37 +1,27 @@ /* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. + * Copyright (C) 2011 Sony Ericsson Mobile Communications AB. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __KGSL_SHAREDMEM_H #define __KGSL_SHAREDMEM_H +#include #include -struct kgsl_pagetable; +/* + * Convert a page to a physical address + */ +#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) + struct kgsl_device; struct kgsl_process_private; @@ -42,31 +32,14 @@ struct kgsl_process_private; /** Set if the memdesc describes cached memory */ #define KGSL_MEMFLAGS_CACHED 0x00000001 -struct kgsl_memdesc; - struct kgsl_memdesc_ops { - unsigned long (*physaddr)(struct kgsl_memdesc *, unsigned int); - void (*outer_cache)(struct kgsl_memdesc *, int); int (*vmflags)(struct kgsl_memdesc *); int (*vmfault)(struct kgsl_memdesc *, struct vm_area_struct *, struct vm_fault *); void (*free)(struct kgsl_memdesc *memdesc); }; -/* shared memory allocation */ -struct kgsl_memdesc { - struct kgsl_pagetable *pagetable; - void *hostptr; - unsigned int gpuaddr; - unsigned int physaddr; - unsigned int size; - unsigned int priv; - struct kgsl_memdesc_ops *ops; -}; - extern struct kgsl_memdesc_ops kgsl_vmalloc_ops; -extern struct kgsl_memdesc_ops kgsl_contig_ops; -extern struct kgsl_memdesc_ops kgsl_userptr_ops; int kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, size_t size); @@ -77,6 +50,14 @@ int kgsl_sharedmem_vmalloc_user(struct kgsl_memdesc *memdesc, int kgsl_sharedmem_alloc_coherent(struct kgsl_memdesc *memdesc, size_t size); +int kgsl_sharedmem_ebimem_user(struct kgsl_memdesc *memdesc, + struct kgsl_pagetable *pagetable, + size_t size, int flags); + +int kgsl_sharedmem_ebimem(struct kgsl_memdesc *memdesc, + struct kgsl_pagetable *pagetable, + size_t size); + void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc); int kgsl_sharedmem_readl(const struct kgsl_memdesc *memdesc, @@ -99,18 +80,54 @@ void kgsl_process_uninit_sysfs(struct kgsl_process_private *private); int kgsl_sharedmem_init_sysfs(void); void kgsl_sharedmem_uninit_sysfs(void); +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 = kmalloc(sizeof(struct scatterlist) * 1, GFP_KERNEL); + if (memdesc->sg == NULL) + return -ENOMEM; + + memdesc->sglen = 1; + sg_init_table(memdesc->sg, 1); + sg_set_page(&memdesc->sg[0], page, size, 0); + return 0; +} + +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 +} + static inline int 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 } static inline int -kgsl_allocate_contig(struct kgsl_memdesc *memdesc, size_t size) +kgsl_allocate_contiguous(struct kgsl_memdesc *memdesc, size_t size) { - return kgsl_sharedmem_alloc_coherent(memdesc, size); + int ret = kgsl_sharedmem_alloc_coherent(memdesc, size); +#ifndef CONFIG_MSM_KGSL_MMU + if (!ret) + memdesc->gpuaddr = memdesc->physaddr; +#endif + return ret; } #endif /* __KGSL_SHAREDMEM_H */ diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c index 27da432e..e7a1d521 100644 --- a/drivers/gpu/msm/z180.c +++ b/drivers/gpu/msm/z180.c @@ -14,6 +14,7 @@ #include "kgsl.h" #include "kgsl_cffdump.h" +#include "kgsl_sharedmem.h" #include "z180.h" #include "z180_reg.h" @@ -86,6 +87,11 @@ #define Z180_TIMESTAMP_EPSILON 20000 #define Z180_IDLE_COUNT_MAX 1000000 +enum z180_cmdwindow_type { + Z180_CMDWINDOW_2D = 0x00000000, + Z180_CMDWINDOW_MMU = 0x00000002, +}; + #define Z180_CMDWINDOW_TARGET_MASK 0x000000FF #define Z180_CMDWINDOW_ADDR_MASK 0x00FFFF00 #define Z180_CMDWINDOW_TARGET_SHIFT 0 @@ -102,17 +108,9 @@ static void z180_regread(struct kgsl_device *device, static void z180_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value); -static int z180_cmdwindow_write(struct kgsl_device *device, - enum kgsl_cmdwindow_type target, +static void z180_cmdwindow_write(struct kgsl_device *device, unsigned int addr, unsigned int data); -static void z180_regread_isr(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value); -static void z180_regwrite_isr(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value); -static void __devinit z180_getfunctable(struct kgsl_functable *ftbl); #define Z180_MMU_CONFIG \ (0x01 \ @@ -128,35 +126,29 @@ static void __devinit z180_getfunctable(struct kgsl_functable *ftbl); | (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT) \ | (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT)) +static const struct kgsl_functable z180_functable; + static struct z180_device device_2d0 = { .dev = { .name = DEVICE_2D0_NAME, .id = KGSL_DEVICE_2D0, .ver_major = DRIVER_VERSION_MAJOR, .ver_minor = DRIVER_VERSION_MINOR, - .mmu = { - .config = Z180_MMU_CONFIG, + .mh = { + .mharb = Z180_CFG_MHARB, + .mh_intf_cfg1 = 0x00032f07, + .mh_intf_cfg2 = 0x004b274f, /* turn off memory protection unit by setting acceptable physical address range to include all pages. */ .mpu_base = 0x00000000, .mpu_range = 0xFFFFF000, - .reg = { - .config = ADDR_MH_MMU_CONFIG, - .mpu_base = ADDR_MH_MMU_MPU_BASE, - .mpu_end = ADDR_MH_MMU_MPU_END, - .va_range = ADDR_MH_MMU_VA_RANGE, - .pt_page = ADDR_MH_MMU_PT_BASE, - .page_fault = ADDR_MH_MMU_PAGE_FAULT, - .tran_error = ADDR_MH_MMU_TRAN_ERROR, - .invalidate = ADDR_MH_MMU_INVALIDATE, - .interrupt_mask = ADDR_MH_INTERRUPT_MASK, - .interrupt_status = ADDR_MH_INTERRUPT_STATUS, - .interrupt_clear = ADDR_MH_INTERRUPT_CLEAR, - .axi_error = ADDR_MH_AXI_ERROR, - }, + }, + .mmu = { + .config = Z180_MMU_CONFIG, }, .pwrctrl = { + .pwr_rail = PWR_RAIL_GRP_2D_CLK, .regulator_name = "fs_gfx2d0", .irq_name = KGSL_2D0_IRQ, }, @@ -164,6 +156,14 @@ static struct z180_device device_2d0 = { .state = KGSL_STATE_INIT, .active_cnt = 0, .iomemname = KGSL_2D0_REG_MEMORY, + .ftbl = &z180_functable, +#ifdef CONFIG_HAS_EARLYSUSPEND + .display_off = { + .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING, + .suspend = kgsl_early_suspend_driver, + .resume = kgsl_late_resume_driver, + }, +#endif }, }; @@ -173,29 +173,21 @@ static struct z180_device device_2d1 = { .id = KGSL_DEVICE_2D1, .ver_major = DRIVER_VERSION_MAJOR, .ver_minor = DRIVER_VERSION_MINOR, - .mmu = { - .config = Z180_MMU_CONFIG, + .mh = { + .mharb = Z180_CFG_MHARB, + .mh_intf_cfg1 = 0x00032f07, + .mh_intf_cfg2 = 0x004b274f, /* turn off memory protection unit by setting acceptable physical address range to include all pages. */ .mpu_base = 0x00000000, .mpu_range = 0xFFFFF000, - .reg = { - .config = ADDR_MH_MMU_CONFIG, - .mpu_base = ADDR_MH_MMU_MPU_BASE, - .mpu_end = ADDR_MH_MMU_MPU_END, - .va_range = ADDR_MH_MMU_VA_RANGE, - .pt_page = ADDR_MH_MMU_PT_BASE, - .page_fault = ADDR_MH_MMU_PAGE_FAULT, - .tran_error = ADDR_MH_MMU_TRAN_ERROR, - .invalidate = ADDR_MH_MMU_INVALIDATE, - .interrupt_mask = ADDR_MH_INTERRUPT_MASK, - .interrupt_status = ADDR_MH_INTERRUPT_STATUS, - .interrupt_clear = ADDR_MH_INTERRUPT_CLEAR, - .axi_error = ADDR_MH_AXI_ERROR, - }, + }, + .mmu = { + .config = Z180_MMU_CONFIG, }, .pwrctrl = { + .pwr_rail = PWR_RAIL_GRP_2D_CLK, .regulator_name = "fs_gfx2d1", .irq_name = KGSL_2D1_IRQ, }, @@ -203,6 +195,14 @@ static struct z180_device device_2d1 = { .state = KGSL_STATE_INIT, .active_cnt = 0, .iomemname = KGSL_2D1_REG_MEMORY, + .ftbl = &z180_functable, + .display_off = { +#ifdef CONFIG_HAS_EARLYSUSPEND + .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING, + .suspend = kgsl_early_suspend_driver, + .resume = kgsl_late_resume_driver, +#endif + }, }, }; @@ -213,10 +213,10 @@ static irqreturn_t z180_isr(int irq, void *data) struct kgsl_device *device = (struct kgsl_device *) data; struct z180_device *z180_dev = Z180_DEVICE(device); - z180_regread_isr(device, ADDR_VGC_IRQSTATUS >> 2, &status); + z180_regread(device, ADDR_VGC_IRQSTATUS >> 2, &status); if (status & GSL_VGC_INT_MASK) { - z180_regwrite_isr(device, + z180_regwrite(device, ADDR_VGC_IRQSTATUS >> 2, status & GSL_VGC_INT_MASK); result = IRQ_HANDLED; @@ -228,7 +228,7 @@ static irqreturn_t z180_isr(int irq, void *data) if (status & REG_VGC_IRQSTATUS__G2D_MASK) { int count; - z180_regread_isr(device, + z180_regread(device, ADDR_VGC_IRQ_ACTIVE_CNT >> 2, &count); @@ -236,6 +236,7 @@ static irqreturn_t z180_isr(int irq, void *data) count &= 255; z180_dev->timestamp += count; + queue_work(device->work_queue, &device->ts_expired_ws); wake_up_interruptible(&device->wait_queue); atomic_notifier_call_chain( @@ -255,18 +256,16 @@ static irqreturn_t z180_isr(int irq, void *data) return result; } -static int z180_cleanup_pt(struct kgsl_device *device, +static void z180_cleanup_pt(struct kgsl_device *device, struct kgsl_pagetable *pagetable) { struct z180_device *z180_dev = Z180_DEVICE(device); - kgsl_mmu_unmap(pagetable, &device->mmu.dummyspace); + kgsl_mmu_unmap(pagetable, &device->mmu.setstate_memory); kgsl_mmu_unmap(pagetable, &device->memstore); kgsl_mmu_unmap(pagetable, &z180_dev->ringbuffer.cmdbufdesc); - - return 0; } static int z180_setup_pt(struct kgsl_device *device, @@ -275,7 +274,7 @@ static int z180_setup_pt(struct kgsl_device *device, int result = 0; struct z180_device *z180_dev = Z180_DEVICE(device); - result = kgsl_mmu_map_global(pagetable, &device->mmu.dummyspace, + result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory, GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); if (result) @@ -294,7 +293,7 @@ static int z180_setup_pt(struct kgsl_device *device, return result; error_unmap_dummy: - kgsl_mmu_unmap(pagetable, &device->mmu.dummyspace); + kgsl_mmu_unmap(pagetable, &device->mmu.setstate_memory); error_unmap_memstore: kgsl_mmu_unmap(pagetable, &device->memstore); @@ -339,10 +338,9 @@ static void addcmd(struct z180_ringbuffer *rb, unsigned int index, *p++ = ADDR_VGV3_LAST << 24; } -static int z180_cmdstream_start(struct kgsl_device *device) +static void z180_cmdstream_start(struct kgsl_device *device) { struct z180_device *z180_dev = Z180_DEVICE(device); - int result; unsigned int cmd = VGV3_NEXTCMD_JUMP << VGV3_NEXTCMD_NEXTCMD_FSHIFT; z180_dev->timestamp = 0; @@ -350,43 +348,22 @@ static int z180_cmdstream_start(struct kgsl_device *device) addmarker(&z180_dev->ringbuffer, 0); - result = z180_cmdwindow_write(device, KGSL_CMDWINDOW_2D, - ADDR_VGV3_MODE, 4); - if (result != 0) - return result; + z180_cmdwindow_write(device, ADDR_VGV3_MODE, 4); - result = z180_cmdwindow_write(device, KGSL_CMDWINDOW_2D, - ADDR_VGV3_NEXTADDR, + z180_cmdwindow_write(device, ADDR_VGV3_NEXTADDR, z180_dev->ringbuffer.cmdbufdesc.gpuaddr); - if (result != 0) - return result; - result = z180_cmdwindow_write(device, KGSL_CMDWINDOW_2D, - ADDR_VGV3_NEXTCMD, cmd | 5); - if (result != 0) - return result; + z180_cmdwindow_write(device, ADDR_VGV3_NEXTCMD, cmd | 5); - result = z180_cmdwindow_write(device, KGSL_CMDWINDOW_2D, - ADDR_VGV3_WRITEADDR, device->memstore.gpuaddr); - - if (result != 0) - return result; + z180_cmdwindow_write(device, ADDR_VGV3_WRITEADDR, + device->memstore.gpuaddr); cmd = (int)(((1) & VGV3_CONTROL_MARKADD_FMASK) << VGV3_CONTROL_MARKADD_FSHIFT); - result = z180_cmdwindow_write(device, KGSL_CMDWINDOW_2D, - ADDR_VGV3_CONTROL, cmd); + z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, cmd); - if (result != 0) - return result; - - result = z180_cmdwindow_write(device, KGSL_CMDWINDOW_2D, - ADDR_VGV3_CONTROL, 0); - if (result != 0) - return result; - - return result; + z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, 0); } static int room_in_rb(struct z180_device *device) @@ -403,7 +380,8 @@ static int z180_idle(struct kgsl_device *device, unsigned int timeout) int status = 0; struct z180_device *z180_dev = Z180_DEVICE(device); - if (z180_dev->current_timestamp > z180_dev->timestamp) + if (timestamp_cmp(z180_dev->current_timestamp, + z180_dev->timestamp) > 0) status = z180_wait(device, z180_dev->current_timestamp, timeout); @@ -413,30 +391,6 @@ static int z180_idle(struct kgsl_device *device, unsigned int timeout) return status; } -static int z180_setstate(struct kgsl_device *device, uint32_t flags) -{ -#ifdef CONFIG_MSM_KGSL_MMU - unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */ - - if (flags & KGSL_MMUFLAGS_PTUPDATE) { - z180_idle(device, KGSL_TIMEOUT_DEFAULT); - z180_regwrite(device, ADDR_MH_MMU_PT_BASE, - device->mmu.hwpagetable->base.gpuaddr); - z180_regwrite(device, ADDR_MH_MMU_VA_RANGE, - (device->mmu.hwpagetable-> - va_base | (device->mmu.hwpagetable-> - va_range >> 16))); - z180_regwrite(device, ADDR_MH_MMU_INVALIDATE, - mh_mmu_invalidate); - } - - if (flags & KGSL_MMUFLAGS_TLBFLUSH) - z180_regwrite(device, ADDR_MH_MMU_INVALIDATE, - mh_mmu_invalidate); -#endif - return 0; -} - int z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, struct kgsl_context *context, @@ -445,7 +399,7 @@ z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, uint32_t *timestamp, unsigned int ctrl) { - unsigned int result = 0; + long result = 0; unsigned int ofs = PACKETSIZE_STATESTREAM * sizeof(unsigned int); unsigned int cnt = 5; unsigned int nextaddr = 0; @@ -460,7 +414,7 @@ z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, unsigned int sizedwords; if (device->state & KGSL_STATE_HUNG) { - return -EINVAL; + result = -EINVAL; goto error; } if (numibs != 1) { @@ -484,7 +438,7 @@ z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, cnt = PACKETSIZE_STATESTREAM; ofs = 0; } - z180_setstate(device, kgsl_pt_get_flags(device->mmu.hwpagetable, + kgsl_setstate(device, kgsl_mmu_pt_get_flags(device->mmu.hwpagetable, device->id)); result = wait_event_interruptible_timeout(device->wait_queue, @@ -492,7 +446,7 @@ z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, msecs_to_jiffies(KGSL_TIMEOUT_DEFAULT)); if (result < 0) { KGSL_CMD_ERR(device, "wait_event_interruptible_timeout " - "failed: %d\n", result); + "failed: %ld\n", result); goto error; } result = 0; @@ -525,12 +479,10 @@ z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, cmd = (int)(((2) & VGV3_CONTROL_MARKADD_FMASK) << VGV3_CONTROL_MARKADD_FSHIFT); - z180_cmdwindow_write(device, - KGSL_CMDWINDOW_2D, ADDR_VGV3_CONTROL, cmd); - z180_cmdwindow_write(device, - KGSL_CMDWINDOW_2D, ADDR_VGV3_CONTROL, 0); + z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, cmd); + z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, 0); error: - return result; + return (int)result; } static int z180_ringbuffer_init(struct kgsl_device *device) @@ -538,9 +490,8 @@ static int z180_ringbuffer_init(struct kgsl_device *device) struct z180_device *z180_dev = Z180_DEVICE(device); memset(&z180_dev->ringbuffer, 0, sizeof(struct z180_ringbuffer)); z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT; - return kgsl_sharedmem_alloc_coherent( - &z180_dev->ringbuffer.cmdbufdesc, - Z180_RB_SIZE); + return kgsl_allocate_contiguous(&z180_dev->ringbuffer.cmdbufdesc, + Z180_RB_SIZE); } static void z180_ringbuffer_close(struct kgsl_device *device) @@ -559,8 +510,6 @@ static int __devinit z180_probe(struct platform_device *pdev) device = (struct kgsl_device *)pdev->id_entry->driver_data; device->parentdev = &pdev->dev; - z180_getfunctable(&device->ftbl); - z180_dev = Z180_DEVICE(device); spin_lock_init(&z180_dev->cmdwin_lock); @@ -572,6 +521,8 @@ static int __devinit z180_probe(struct platform_device *pdev) if (status) goto error_close_ringbuffer; + kgsl_pwrscale_init(device); + return status; error_close_ringbuffer: @@ -587,6 +538,7 @@ static int __devexit z180_remove(struct platform_device *pdev) device = (struct kgsl_device *)pdev->id_entry->driver_data; + kgsl_pwrscale_close(device); kgsl_device_platform_remove(device); z180_ringbuffer_close(device); @@ -604,31 +556,24 @@ static int z180_start(struct kgsl_device *device, unsigned int init_ram) kgsl_pwrctrl_enable(device); - /* Set up MH arbiter. MH offsets are considered to be dword - * based, therefore no down shift. */ - z180_regwrite(device, ADDR_MH_ARBITER_CONFIG, Z180_CFG_MHARB); + /* Set interrupts to 0 to ensure a good state */ + z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0x0); - z180_regwrite(device, ADDR_MH_CLNT_INTF_CTRL_CONFIG1, 0x00030F27); - z180_regwrite(device, ADDR_MH_CLNT_INTF_CTRL_CONFIG2, 0x004B274F); - - z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0x3); + kgsl_mh_start(device); status = kgsl_mmu_start(device); if (status) goto error_clk_off; - status = z180_cmdstream_start(device); - if (status) - goto error_mmu_stop; + z180_cmdstream_start(device); mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT); - kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_IRQ_ON); + kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); return 0; + error_clk_off: z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0); kgsl_pwrctrl_disable(device); -error_mmu_stop: - kgsl_mmu_stop(device); return status; } @@ -636,7 +581,7 @@ static int z180_stop(struct kgsl_device *device) { z180_idle(device, KGSL_TIMEOUT_DEFAULT); - del_timer(&device->idle_timer); + del_timer_sync(&device->idle_timer); kgsl_mmu_stop(device); @@ -680,16 +625,12 @@ static int z180_getproperty(struct kgsl_device *device, break; case KGSL_PROP_MMU_ENABLE: { -#ifdef CONFIG_MSM_KGSL_MMU - int mmuProp = 1; -#else - int mmuProp = 0; -#endif + int mmu_prop = kgsl_mmu_enabled(); if (sizebytes != sizeof(int)) { status = -EINVAL; break; } - if (copy_to_user(value, &mmuProp, sizeof(mmuProp))) { + if (copy_to_user(value, &mmu_prop, sizeof(mmu_prop))) { status = -EFAULT; break; } @@ -706,22 +647,10 @@ static int z180_getproperty(struct kgsl_device *device, static unsigned int z180_isidle(struct kgsl_device *device) { - int status = false; struct z180_device *z180_dev = Z180_DEVICE(device); - int timestamp = z180_dev->timestamp; - - if (timestamp == z180_dev->current_timestamp) - status = true; - - return status; -} - -static int z180_resume_context(struct kgsl_device *device) -{ - /* Context is in the pre-amble, automatically restored. */ - - return 0; + return (timestamp_cmp(z180_dev->timestamp, + z180_dev->current_timestamp) == 0) ? true : false; } static int z180_suspend_context(struct kgsl_device *device) @@ -800,7 +729,7 @@ static void _z180_regwrite_mmu(struct kgsl_device *device, unsigned int cmdwinaddr; unsigned long flags; - cmdwinaddr = ((KGSL_CMDWINDOW_MMU << Z180_CMDWINDOW_TARGET_SHIFT) & + cmdwinaddr = ((Z180_CMDWINDOW_MMU << Z180_CMDWINDOW_TARGET_SHIFT) & Z180_CMDWINDOW_TARGET_MASK); cmdwinaddr |= ((offsetwords << Z180_CMDWINDOW_ADDR_SHIFT) & Z180_CMDWINDOW_ADDR_MASK); @@ -815,91 +744,52 @@ static void _z180_regwrite_mmu(struct kgsl_device *device, /* the rest of the code doesn't want to think about if it is writing mmu * registers or normal registers so handle it here */ -static void _z180_regread(struct kgsl_device *device, unsigned int offsetwords, - unsigned int *value) +static void z180_regread(struct kgsl_device *device, + unsigned int offsetwords, + unsigned int *value) { - if ((offsetwords >= ADDR_MH_ARBITER_CONFIG && - offsetwords <= ADDR_MH_AXI_HALT_CONTROL) || - (offsetwords >= ADDR_MH_MMU_CONFIG && - offsetwords <= ADDR_MH_MMU_MPU_END)) { + if (!in_interrupt()) + kgsl_pre_hwaccess(device); + + if ((offsetwords >= MH_ARBITER_CONFIG && + offsetwords <= MH_AXI_HALT_CONTROL) || + (offsetwords >= MH_MMU_CONFIG && + offsetwords <= MH_MMU_MPU_END)) { _z180_regread_mmu(device, offsetwords, value); } else { _z180_regread_simple(device, offsetwords, value); } } -static void _z180_regwrite(struct kgsl_device *device, unsigned int offsetwords, +static void z180_regwrite(struct kgsl_device *device, + unsigned int offsetwords, unsigned int value) { - if ((offsetwords >= ADDR_MH_ARBITER_CONFIG && - offsetwords <= ADDR_MH_CLNT_INTF_CTRL_CONFIG2) || - (offsetwords >= ADDR_MH_MMU_CONFIG && - offsetwords <= ADDR_MH_MMU_MPU_END)) { - _z180_regwrite_mmu(device, offsetwords, value); + if (!in_interrupt()) + kgsl_pre_hwaccess(device); + if ((offsetwords >= MH_ARBITER_CONFIG && + offsetwords <= MH_CLNT_INTF_CTRL_CONFIG2) || + (offsetwords >= MH_MMU_CONFIG && + offsetwords <= MH_MMU_MPU_END)) { + _z180_regwrite_mmu(device, offsetwords, value); } else { _z180_regwrite_simple(device, offsetwords, value); } } - -static void z180_regread(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value) -{ - kgsl_pre_hwaccess(device); - _z180_regread(device, offsetwords, value); -} - -static void z180_regread_isr(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value) -{ - _z180_regread(device, offsetwords, value); -} - -static void z180_regwrite(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value) -{ - kgsl_pre_hwaccess(device); - _z180_regwrite(device, offsetwords, value); -} - -static void z180_regwrite_isr(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value) -{ - _z180_regwrite(device, offsetwords, value); -} - -static int z180_cmdwindow_write(struct kgsl_device *device, - enum kgsl_cmdwindow_type target, unsigned int addr, - unsigned int data) +static void z180_cmdwindow_write(struct kgsl_device *device, + unsigned int addr, unsigned int data) { unsigned int cmdwinaddr; - unsigned int cmdstream; - if (target < KGSL_CMDWINDOW_MIN || - target > KGSL_CMDWINDOW_MAX) { - KGSL_DRV_ERR(device, "invalid target\n"); - return -EINVAL; - } - - if (target == KGSL_CMDWINDOW_MMU) - cmdstream = ADDR_VGC_MMUCOMMANDSTREAM; - else - cmdstream = ADDR_VGC_COMMANDSTREAM; - - cmdwinaddr = ((target << Z180_CMDWINDOW_TARGET_SHIFT) & + cmdwinaddr = ((Z180_CMDWINDOW_2D << Z180_CMDWINDOW_TARGET_SHIFT) & Z180_CMDWINDOW_TARGET_MASK); cmdwinaddr |= ((addr << Z180_CMDWINDOW_ADDR_SHIFT) & Z180_CMDWINDOW_ADDR_MASK); - z180_regwrite(device, cmdstream >> 2, cmdwinaddr); - z180_regwrite(device, cmdstream >> 2, data); - - return 0; + z180_regwrite(device, ADDR_VGC_COMMANDSTREAM >> 2, cmdwinaddr); + z180_regwrite(device, ADDR_VGC_COMMANDSTREAM >> 2, data); } static unsigned int z180_readtimestamp(struct kgsl_device *device, @@ -915,6 +805,11 @@ static int z180_waittimestamp(struct kgsl_device *device, unsigned int msecs) { int status = -EINVAL; + + /* Don't wait forever, set a max (10 sec) value for now */ + if (msecs == -1) + msecs = 10 * MSEC_PER_SEC; + mutex_unlock(&device->mutex); status = z180_wait(device, timestamp, msecs); mutex_lock(&device->mutex); @@ -946,19 +841,7 @@ static int z180_wait(struct kgsl_device *device, return status; } -static long -z180_ioctl_cmdwindow_write(struct kgsl_device_private *dev_priv, - void *data) -{ - struct kgsl_cmdwindow_write *param = data; - - return z180_cmdwindow_write(dev_priv->device, - param->target, - param->addr, - param->data); -} - -static int +static void z180_drawctxt_destroy(struct kgsl_device *device, struct kgsl_context *context) { @@ -971,63 +854,62 @@ z180_drawctxt_destroy(struct kgsl_device *device, device->mmu.hwpagetable = device->mmu.defaultpagetable; kgsl_setstate(device, KGSL_MMUFLAGS_PTUPDATE); } - - return 0; -} - -static long z180_ioctl(struct kgsl_device_private *dev_priv, - unsigned int cmd, void *data) -{ - int result = 0; - - switch (cmd) { - case IOCTL_KGSL_CMDWINDOW_WRITE: - result = z180_ioctl_cmdwindow_write(dev_priv, data); - break; - default: - KGSL_DRV_INFO(dev_priv->device, - "invalid ioctl code %08x\n", cmd); - result = -EINVAL; - break; - } - return result; - } static void z180_power_stats(struct kgsl_device *device, struct kgsl_power_stats *stats) { - stats->total_time = 0; - stats->busy_time = 0; + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + + if (pwr->time == 0) { + pwr->time = ktime_to_us(ktime_get()); + stats->total_time = 0; + stats->busy_time = 0; + } else { + s64 tmp; + tmp = ktime_to_us(ktime_get()); + stats->total_time = tmp - pwr->time; + stats->busy_time = tmp - pwr->time; + pwr->time = tmp; + } } -static void __devinit z180_getfunctable(struct kgsl_functable *ftbl) +static void z180_irqctrl(struct kgsl_device *device, int state) { - if (ftbl == NULL) - return; - ftbl->device_regread = z180_regread; - ftbl->device_regwrite = z180_regwrite; - ftbl->device_regread_isr = z180_regread_isr; - ftbl->device_regwrite_isr = z180_regwrite_isr; - ftbl->device_setstate = z180_setstate; - ftbl->device_idle = z180_idle; - ftbl->device_isidle = z180_isidle; - ftbl->device_suspend_context = z180_suspend_context; - ftbl->device_resume_context = z180_resume_context; - ftbl->device_start = z180_start; - ftbl->device_stop = z180_stop; - ftbl->device_getproperty = z180_getproperty; - ftbl->device_waittimestamp = z180_waittimestamp; - ftbl->device_readtimestamp = z180_readtimestamp; - ftbl->device_issueibcmds = z180_cmdstream_issueibcmds; - ftbl->device_drawctxt_create = NULL; - ftbl->device_drawctxt_destroy = z180_drawctxt_destroy; - ftbl->device_ioctl = z180_ioctl; - ftbl->device_setup_pt = z180_setup_pt; - ftbl->device_cleanup_pt = z180_cleanup_pt; - ftbl->device_power_stats = z180_power_stats, + /* Control interrupts for Z180 and the Z180 MMU */ + + if (state) { + z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 3); + z180_regwrite(device, MH_INTERRUPT_MASK, KGSL_MMU_INT_MASK); + } else { + z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0); + z180_regwrite(device, MH_INTERRUPT_MASK, 0); + } } +static const struct kgsl_functable z180_functable = { + /* Mandatory functions */ + .regread = z180_regread, + .regwrite = z180_regwrite, + .idle = z180_idle, + .isidle = z180_isidle, + .suspend_context = z180_suspend_context, + .start = z180_start, + .stop = z180_stop, + .getproperty = z180_getproperty, + .waittimestamp = z180_waittimestamp, + .readtimestamp = z180_readtimestamp, + .issueibcmds = z180_cmdstream_issueibcmds, + .setup_pt = z180_setup_pt, + .cleanup_pt = z180_cleanup_pt, + .power_stats = z180_power_stats, + .irqctrl = z180_irqctrl, + /* Optional functions */ + .drawctxt_create = NULL, + .drawctxt_destroy = z180_drawctxt_destroy, + .ioctl = NULL, +}; + static struct platform_device_id z180_id_table[] = { { DEVICE_2D0_NAME, (kernel_ulong_t)&device_2d0.dev, }, { DEVICE_2D1_NAME, (kernel_ulong_t)&device_2d1.dev, }, diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h index c62398a5..28b1cc6b 100644 --- a/drivers/gpu/msm/z180.h +++ b/drivers/gpu/msm/z180.h @@ -1,34 +1,20 @@ /* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __Z180_H #define __Z180_H +#include "kgsl_device.h" + #define DEVICE_2D_NAME "kgsl-2d" #define DEVICE_2D0_NAME "kgsl-2d0" #define DEVICE_2D1_NAME "kgsl-2d1" diff --git a/drivers/gpu/msm/z180_reg.h b/drivers/gpu/msm/z180_reg.h index f5625535..5b6c0017 100644 --- a/drivers/gpu/msm/z180_reg.h +++ b/drivers/gpu/msm/z180_reg.h @@ -1,29 +1,13 @@ /* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Code Aurora Forum, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 __Z80_REG_H @@ -48,36 +32,8 @@ #define MH_ARBITER_CONFIG__RB_CLNT_ENABLE__SHIFT 0x00000019 #define MH_ARBITER_CONFIG__PA_CLNT_ENABLE__SHIFT 0x0000001a -#define MH_MMU_CONFIG__RB_W_CLNT_BEHAVIOR__SHIFT 0x00000004 -#define MH_MMU_CONFIG__CP_W_CLNT_BEHAVIOR__SHIFT 0x00000006 -#define MH_MMU_CONFIG__CP_R0_CLNT_BEHAVIOR__SHIFT 0x00000008 -#define MH_MMU_CONFIG__CP_R1_CLNT_BEHAVIOR__SHIFT 0x0000000a -#define MH_MMU_CONFIG__CP_R2_CLNT_BEHAVIOR__SHIFT 0x0000000c -#define MH_MMU_CONFIG__CP_R3_CLNT_BEHAVIOR__SHIFT 0x0000000e -#define MH_MMU_CONFIG__CP_R4_CLNT_BEHAVIOR__SHIFT 0x00000010 -#define MH_MMU_CONFIG__VGT_R0_CLNT_BEHAVIOR__SHIFT 0x00000012 -#define MH_MMU_CONFIG__VGT_R1_CLNT_BEHAVIOR__SHIFT 0x00000014 -#define MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT 0x00000016 -#define MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT 0x00000018 - -#define ADDR_MH_ARBITER_CONFIG 0x0A40 -#define ADDR_MH_INTERRUPT_CLEAR 0x0A44 -#define ADDR_MH_INTERRUPT_MASK 0x0A42 -#define ADDR_MH_INTERRUPT_STATUS 0x0A43 -#define ADDR_MH_AXI_ERROR 0x0A45 -#define ADDR_MH_AXI_HALT_CONTROL 0x0A50 -#define ADDR_MH_CLNT_INTF_CTRL_CONFIG1 0x0A54 -#define ADDR_MH_CLNT_INTF_CTRL_CONFIG2 0x0A55 -#define ADDR_MH_MMU_CONFIG 0x0040 -#define ADDR_MH_MMU_INVALIDATE 0x0045 -#define ADDR_MH_MMU_MPU_BASE 0x0046 -#define ADDR_MH_MMU_MPU_END 0x0047 -#define ADDR_MH_MMU_PT_BASE 0x0042 -#define ADDR_MH_MMU_TRAN_ERROR 0x0044 -#define ADDR_MH_MMU_VA_RANGE 0x0041 #define ADDR_VGC_MH_READ_ADDR 0x0510 #define ADDR_VGC_MH_DATA_ADDR 0x0518 -#define ADDR_MH_MMU_PAGE_FAULT 0x0043 #define ADDR_VGC_COMMANDSTREAM 0x0000 #define ADDR_VGC_IRQENABLE 0x0438 #define ADDR_VGC_IRQSTATUS 0x0418 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 3481842f..ce7e1547 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -12,15 +12,7 @@ obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o -ifeq ($(CONFIG_ARCH_MSM7227),y) - obj-$(CONFIG_ANDROID_PMEM) += pmem_7x27.o -else - ifeq ($(CONFIG_ARCH_MSM7X30),y) - obj-$(CONFIG_ANDROID_PMEM) += pmem_7x30.o - else - obj-$(CONFIG_ANDROID_PMEM) += pmem.o - endif -endif +obj-$(CONFIG_ANDROID_PMEM) += pmem.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KERNEL_DEBUGGER_CORE) += kernel_debugger.o diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 079918eb..a0763da9 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -3,6 +3,7 @@ * Android IPC Subsystem * * Copyright (C) 2007-2008 Google, Inc. + * Copyright (c) 2012, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -26,9 +27,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include @@ -42,15 +44,29 @@ static HLIST_HEAD(binder_procs); static HLIST_HEAD(binder_deferred_list); static HLIST_HEAD(binder_dead_nodes); -static struct proc_dir_entry *binder_proc_dir_entry_root; -static struct proc_dir_entry *binder_proc_dir_entry_proc; +static struct dentry *binder_debugfs_dir_entry_root; +static struct dentry *binder_debugfs_dir_entry_proc; static struct binder_node *binder_context_mgr_node; static uid_t binder_context_mgr_uid = -1; static int binder_last_id; static struct workqueue_struct *binder_deferred_workqueue; -static int binder_read_proc_proc(char *page, char **start, off_t off, - int count, int *eof, void *data); +#define BINDER_DEBUG_ENTRY(name) \ +static int binder_##name##_open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, binder_##name##_show, inode->i_private); \ +} \ +\ +static const struct file_operations binder_##name##_fops = { \ + .owner = THIS_MODULE, \ + .open = binder_##name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + +static int binder_proc_show(struct seq_file *m, void *unused); +BINDER_DEBUG_ENTRY(proc); /* This is only defined in include/asm-arm/sizes.h */ #ifndef SZ_1K @@ -82,9 +98,9 @@ enum { BINDER_DEBUG_BUFFER_ALLOC = 1U << 13, BINDER_DEBUG_PRIORITY_CAP = 1U << 14, BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15, + BINDER_DEBUG_TOP_ERRORS = 1U << 16, }; -static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | - BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; +static uint32_t binder_debug_mask; module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); static int binder_debug_no_lock; @@ -296,6 +312,7 @@ struct binder_proc { int requested_threads_started; int ready_threads; long default_priority; + struct dentry *debugfs_entry; }; enum { @@ -622,7 +639,8 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, goto free_range; if (vma == NULL) { - printk(KERN_ERR "binder: %d: binder_alloc_buf failed to " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: %d: binder_alloc_buf failed to " "map pages in userspace, no vma\n", proc->pid); goto err_no_vma; } @@ -635,7 +653,8 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, BUG_ON(*page); *page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (*page == NULL) { - printk(KERN_ERR "binder: %d: binder_alloc_buf failed " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: %d: binder_alloc_buf failed " "for page at %p\n", proc->pid, page_addr); goto err_alloc_page_failed; } @@ -644,7 +663,8 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, page_array_ptr = page; ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr); if (ret) { - printk(KERN_ERR "binder: %d: binder_alloc_buf failed " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: %d: binder_alloc_buf failed " "to map page at %p in kernel\n", proc->pid, page_addr); goto err_map_kernel_failed; @@ -653,7 +673,8 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, (uintptr_t)page_addr + proc->user_buffer_offset; ret = vm_insert_page(vma, user_page_addr, page[0]); if (ret) { - printk(KERN_ERR "binder: %d: binder_alloc_buf failed " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: %d: binder_alloc_buf failed " "to map page at %lx in userspace\n", proc->pid, user_page_addr); goto err_vm_insert_page_failed; @@ -702,7 +723,8 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, size_t size; if (proc->vma == NULL) { - printk(KERN_ERR "binder: %d: binder_alloc_buf, no vma\n", + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: %d: binder_alloc_buf, no vma\n", proc->pid); return NULL; } @@ -740,7 +762,8 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, } } if (best_fit == NULL) { - printk(KERN_ERR "binder: %d: binder_alloc_buf size %zd failed, " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: %d: binder_alloc_buf size %zd failed, " "no address space\n", proc->pid, size); return NULL; } @@ -975,7 +998,8 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, node->internal_strong_refs == 0 && !(node == binder_context_mgr_node && node->has_strong_ref)) { - printk(KERN_ERR "binder: invalid inc strong " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: invalid inc strong " "node for %d\n", node->debug_id); return -EINVAL; } @@ -991,7 +1015,8 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, node->local_weak_refs++; if (!node->has_weak_ref && list_empty(&node->work.entry)) { if (target_list == NULL) { - printk(KERN_ERR "binder: invalid inc weak node " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: invalid inc weak node " "for %d\n", node->debug_id); return -EINVAL; } @@ -1028,7 +1053,7 @@ static int binder_dec_node(struct binder_node *node, int strong, int internal) if (node->proc) { rb_erase(&node->rb_node, &node->proc->nodes); binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "binder: refless node %d deleted\n", + "binder: refless node %d deleted\n", node->debug_id); } else { hlist_del(&node->dead_node); @@ -1247,14 +1272,16 @@ static void binder_send_failed_reply(struct binder_transaction *t, binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, "binder: send failed reply for " "transaction %d to %d:%d\n", - t->debug_id, target_thread->proc->pid, + t->debug_id, + target_thread->proc->pid, target_thread->pid); binder_pop_transaction(target_thread, t); target_thread->return_error = error_code; wake_up_interruptible(&target_thread->wait); } else { - printk(KERN_ERR "binder: reply failed, target " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: reply failed, target " "thread, %d:%d, has error code %d " "already\n", target_thread->proc->pid, target_thread->pid, @@ -1292,14 +1319,15 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, int debug_id = buffer->debug_id; binder_debug(BINDER_DEBUG_TRANSACTION, - "binder: %d buffer release %d, size %zd-%zd, failed at %p\n", - proc->pid, buffer->debug_id, + "binder: %d buffer release %d, size %zd-%zd, failed at" + " %p\n", proc->pid, buffer->debug_id, buffer->data_size, buffer->offsets_size, failed_at); if (buffer->target_node) binder_dec_node(buffer->target_node, 1, 0); - offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, sizeof(void *))); + offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, + sizeof(void *))); if (failed_at) off_end = failed_at; else @@ -1309,7 +1337,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, if (*offp > buffer->data_size - sizeof(*fp) || buffer->data_size < sizeof(*fp) || !IS_ALIGNED(*offp, sizeof(void *))) { - printk(KERN_ERR "binder: transaction release %d bad" + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: transaction release %d bad" "offset %zd, size %zd\n", debug_id, *offp, buffer->data_size); continue; @@ -1318,29 +1347,35 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, switch (fp->type) { case BINDER_TYPE_BINDER: case BINDER_TYPE_WEAK_BINDER: { - struct binder_node *node = binder_get_node(proc, fp->binder); + struct binder_node *node = binder_get_node(proc, + fp->binder); if (node == NULL) { - printk(KERN_ERR "binder: transaction release %d" + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: transaction release %d" " bad node %p\n", debug_id, fp->binder); break; } binder_debug(BINDER_DEBUG_TRANSACTION, " node %d u%p\n", node->debug_id, node->ptr); - binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0); + binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, + 0); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { - struct binder_ref *ref = binder_get_ref(proc, fp->handle); + struct binder_ref *ref = binder_get_ref(proc, + fp->handle); if (ref == NULL) { - printk(KERN_ERR "binder: transaction release %d" + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: transaction release %d" " bad handle %ld\n", debug_id, fp->handle); break; } binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, ref->node->debug_id); + ref->debug_id, ref->desc, + ref->node->debug_id); binder_dec_ref(ref, fp->type == BINDER_TYPE_HANDLE); } break; @@ -1352,7 +1387,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, break; default: - printk(KERN_ERR "binder: transaction release %d bad " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: transaction release %d bad " "object type %lx\n", debug_id, fp->type); break; } @@ -1503,21 +1539,19 @@ static void binder_transaction(struct binder_proc *proc, if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, "binder: %d:%d BC_REPLY %d -> %d:%d, " - "data %p-%p size %zd-%zd async: %d\n", + "data %p-%p size %zd-%zd\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_thread->pid, tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size, - (tr->flags & TF_ONE_WAY) ? 1 : 0); + tr->data_size, tr->offsets_size); else binder_debug(BINDER_DEBUG_TRANSACTION, "binder: %d:%d BC_TRANSACTION %d -> " - "%d - node %d, data %p-%p size %zd-%zd async: %d\n", + "%d - node %d, data %p-%p size %zd-%zd\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_node->debug_id, tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size, - (tr->flags & TF_ONE_WAY) ? 1 : 0); + tr->data_size, tr->offsets_size); if (!reply && !(tr->flags & TF_ONE_WAY)) t->from = thread; @@ -1580,15 +1614,19 @@ static void binder_transaction(struct binder_proc *proc, case BINDER_TYPE_BINDER: case BINDER_TYPE_WEAK_BINDER: { struct binder_ref *ref; - struct binder_node *node = binder_get_node(proc, fp->binder); + struct binder_node *node = binder_get_node(proc, + fp->binder); if (node == NULL) { - node = binder_new_node(proc, fp->binder, fp->cookie); + node = binder_new_node(proc, fp->binder, + fp->cookie); if (node == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_new_node_failed; } - node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK; - node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); + node->min_priority = fp->flags & + FLAT_BINDER_FLAG_PRIORITY_MASK; + node->accept_fds = !!(fp->flags & + FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { binder_user_error("binder: %d:%d sending u%p " @@ -1618,7 +1656,8 @@ static void binder_transaction(struct binder_proc *proc, } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { - struct binder_ref *ref = binder_get_ref(proc, fp->handle); + struct binder_ref *ref = binder_get_ref(proc, + fp->handle); if (ref == NULL) { binder_user_error("binder: %d:%d got " "transaction with invalid " @@ -1634,24 +1673,31 @@ static void binder_transaction(struct binder_proc *proc, fp->type = BINDER_TYPE_WEAK_BINDER; fp->binder = ref->node->ptr; fp->cookie = ref->node->cookie; - binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); + binder_inc_node(ref->node, fp->type == + BINDER_TYPE_BINDER, 0, NULL); binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d -> node %d u%p\n", - ref->debug_id, ref->desc, ref->node->debug_id, - ref->node->ptr); + " ref %d desc %d -> node %d u%p\n", + ref->debug_id, ref->desc, + ref->node->debug_id, + ref->node->ptr); } else { struct binder_ref *new_ref; - new_ref = binder_get_ref_for_node(target_proc, ref->node); + new_ref = binder_get_ref_for_node(target_proc, + ref->node); if (new_ref == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_get_ref_for_node_failed; } fp->handle = new_ref->desc; - binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); + binder_inc_ref(new_ref, fp->type == + BINDER_TYPE_HANDLE, NULL); binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d -> ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, new_ref->debug_id, - new_ref->desc, ref->node->debug_id); + " ref %d desc %d -> ref %d" + " desc %d (node %d)\n", + ref->debug_id, ref->desc, + new_ref->debug_id, + new_ref->desc, + ref->node->debug_id); } } break; @@ -1661,13 +1707,19 @@ static void binder_transaction(struct binder_proc *proc, if (reply) { if (!(in_reply_to->flags & TF_ACCEPT_FDS)) { - binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n", - proc->pid, thread->pid, fp->handle); + binder_user_error("binder: %d:%d got" + " reply with fd, %ld, but" + " target does not allow fds\n", + proc->pid, thread->pid, + fp->handle); return_error = BR_FAILED_REPLY; goto err_fd_not_allowed; } } else if (!target_node->accept_fds) { - binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n", + binder_user_error( + "binder: %d:%d got transaction" + " with fd, %ld, but target does" + " not allow fds\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fd_not_allowed; @@ -1675,12 +1727,15 @@ static void binder_transaction(struct binder_proc *proc, file = fget(fp->handle); if (file == NULL) { - binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n", + binder_user_error( + "binder: %d:%d got transaction" + " with invalid fd, %ld\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fget_failed; } - target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); + target_fd = task_get_unused_fd_flags(target_proc, + O_CLOEXEC); if (target_fd < 0) { fput(file); return_error = BR_FAILED_REPLY; @@ -1688,7 +1743,8 @@ static void binder_transaction(struct binder_proc *proc, } task_fd_install(target_proc, target_fd, file); binder_debug(BINDER_DEBUG_TRANSACTION, - " fd %ld -> %d\n", fp->handle, target_fd); + " fd %ld -> %d\n", fp->handle, + target_fd); /* TODO: fput? */ fp->handle = target_fd; } break; @@ -1837,9 +1893,11 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, break; } binder_debug(BINDER_DEBUG_USER_REFS, - "binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n", - proc->pid, thread->pid, debug_string, ref->debug_id, - ref->desc, ref->strong, ref->weak, ref->node->debug_id); + "binder: %d:%d %s ref %d desc %d s %d w %d" + " for node %d\n", proc->pid, thread->pid, + debug_string, ref->debug_id, ref->desc, + ref->strong, ref->weak, + ref->node->debug_id); break; } case BC_INCREFS_DONE: @@ -1900,15 +1958,19 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_debug(BINDER_DEBUG_USER_REFS, "binder: %d:%d %s node %d ls %d lw %d\n", proc->pid, thread->pid, - cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node->debug_id, node->local_strong_refs, node->local_weak_refs); + cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" + : "BC_ACQUIRE_DONE", + node->debug_id, node->local_strong_refs, + node->local_weak_refs); break; } case BC_ATTEMPT_ACQUIRE: - printk(KERN_ERR "binder: BC_ATTEMPT_ACQUIRE not supported\n"); + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: BC_ATTEMPT_ACQUIRE not supported\n"); return -EINVAL; case BC_ACQUIRE_RESULT: - printk(KERN_ERR "binder: BC_ACQUIRE_RESULT not supported\n"); + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: BC_ACQUIRE_RESULT not supported\n"); return -EINVAL; case BC_FREE_BUFFER: { @@ -1934,9 +1996,11 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, break; } binder_debug(BINDER_DEBUG_FREE_BUFFER, - "binder: %d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n", - proc->pid, thread->pid, data_ptr, buffer->debug_id, - buffer->transaction ? "active" : "finished"); + "binder: %d:%d BC_FREE_BUFFER u%p found" + " buffer %d for %s transaction\n", + proc->pid, thread->pid, data_ptr, + buffer->debug_id, buffer->transaction ? + "active" : "finished"); if (buffer->transaction) { buffer->transaction->buffer = NULL; @@ -2033,13 +2097,15 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "binder: %d:%d %s %p ref %d desc %d s %d w %d for node %d\n", + "binder: %d:%d %s %p ref %d desc %d s %d" + " w %d for node %d\n", proc->pid, thread->pid, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", cookie, ref->debug_id, ref->desc, - ref->strong, ref->weak, ref->node->debug_id); + ref->strong, ref->weak, + ref->node->debug_id); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { if (ref->death) { @@ -2053,10 +2119,12 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, death = kzalloc(sizeof(*death), GFP_KERNEL); if (death == NULL) { thread->return_error = BR_ERROR; - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "binder: %d:%d " - "BC_REQUEST_DEATH_NOTIFICATION failed\n", - proc->pid, thread->pid); + binder_debug( + BINDER_DEBUG_FAILED_TRANSACTION, + "binder: %d:%d " + "BC_REQUEST_DEATH_NOTIFICATION" + " failed\n", + proc->pid, thread->pid); break; } binder_stats_created(BINDER_STAT_DEATH); @@ -2145,7 +2213,8 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } break; default: - printk(KERN_ERR "binder: %d:%d unknown command %d\n", + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: %d:%d unknown command %d\n", proc->pid, thread->pid, cmd); return -EINVAL; } @@ -2615,9 +2684,11 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg; - /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/ + /*binder_debug(BINDER_DEBUG_TOP_ERRORS, "binder_ioctl: %d:%d %x %lx\n", + proc->pid, current->pid, cmd, arg);*/ - ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); + ret = wait_event_interruptible(binder_user_error_wait, + binder_stop_on_user_error < 2); if (ret) return ret; @@ -2674,20 +2745,23 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } case BINDER_SET_MAX_THREADS: - if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) { + if (copy_from_user(&proc->max_threads, ubuf, + sizeof(proc->max_threads))) { ret = -EINVAL; goto err; } break; case BINDER_SET_CONTEXT_MGR: if (binder_context_mgr_node != NULL) { - printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n"); + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: BINDER_SET_CONTEXT_MGR already set\n"); ret = -EBUSY; goto err; } if (binder_context_mgr_uid != -1) { if (binder_context_mgr_uid != current->cred->euid) { - printk(KERN_ERR "binder: BINDER_SET_" + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: BINDER_SET_" "CONTEXT_MGR bad uid %d != %d\n", current->cred->euid, binder_context_mgr_uid); @@ -2733,7 +2807,9 @@ err: mutex_unlock(&binder_lock); wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret && ret != -ERESTARTSYS) - printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: %d:%d ioctl %x %lx returned %d\n", + proc->pid, current->pid, cmd, arg, ret); return ret; } @@ -2807,7 +2883,9 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) #ifdef CONFIG_CPU_CACHE_VIPT if (cache_is_vipt_aliasing()) { while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { - printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder_mmap: %d %lx-%lx maps %p bad alignment\n", + proc->pid, vma->vm_start, vma->vm_end, proc->buffer); vma->vm_start += PAGE_SIZE; } } @@ -2838,7 +2916,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) proc->files = get_files_struct(current); proc->vma = vma; - /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", + /*binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ return 0; @@ -2851,7 +2930,8 @@ err_alloc_pages_failed: err_get_vm_area_failed: err_already_mapped: err_bad_arg: - printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n", + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; } @@ -2879,13 +2959,11 @@ static int binder_open(struct inode *nodp, struct file *filp) filp->private_data = proc; mutex_unlock(&binder_lock); - if (binder_proc_dir_entry_proc) { + if (binder_debugfs_dir_entry_proc) { char strbuf[11]; snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); - remove_proc_entry(strbuf, binder_proc_dir_entry_proc); - create_proc_read_entry(strbuf, S_IRUGO, - binder_proc_dir_entry_proc, - binder_read_proc_proc, proc); + proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, + binder_debugfs_dir_entry_proc, proc, &binder_proc_fops); } return 0; @@ -2922,12 +3000,7 @@ static void binder_deferred_flush(struct binder_proc *proc) static int binder_release(struct inode *nodp, struct file *filp) { struct binder_proc *proc = filp->private_data; - if (binder_proc_dir_entry_proc) { - char strbuf[11]; - snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); - remove_proc_entry(strbuf, binder_proc_dir_entry_proc); - } - + debugfs_remove(proc->debugfs_entry); binder_defer_work(proc, BINDER_DEFERRED_RELEASE); return 0; @@ -3013,7 +3086,8 @@ static void binder_deferred_release(struct binder_proc *proc) if (t) { t->buffer = NULL; buffer->transaction = NULL; - printk(KERN_ERR "binder: release proc %d, " + binder_debug(BINDER_DEBUG_TOP_ERRORS, + "binder: release proc %d, " "transaction %d, not freed\n", proc->pid, t->debug_id); /*BUG();*/ @@ -3111,49 +3185,41 @@ binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) mutex_unlock(&binder_deferred_lock); } -static char *print_binder_transaction(char *buf, char *end, const char *prefix, - struct binder_transaction *t) +static void print_binder_transaction(struct seq_file *m, const char *prefix, + struct binder_transaction *t) { - buf += snprintf(buf, end - buf, - "%s %d: %p from %d:%d to %d:%d code %x " - "flags %x pri %ld r%d", - prefix, t->debug_id, t, - t->from ? t->from->proc->pid : 0, - t->from ? t->from->pid : 0, - t->to_proc ? t->to_proc->pid : 0, - t->to_thread ? t->to_thread->pid : 0, - t->code, t->flags, t->priority, t->need_reply); - if (buf >= end) - return buf; + seq_printf(m, + "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", + prefix, t->debug_id, t, + t->from ? t->from->proc->pid : 0, + t->from ? t->from->pid : 0, + t->to_proc ? t->to_proc->pid : 0, + t->to_thread ? t->to_thread->pid : 0, + t->code, t->flags, t->priority, t->need_reply); if (t->buffer == NULL) { - buf += snprintf(buf, end - buf, " buffer free\n"); - return buf; + seq_puts(m, " buffer free\n"); + return; } - if (t->buffer->target_node) { - buf += snprintf(buf, end - buf, " node %d", - t->buffer->target_node->debug_id); - if (buf >= end) - return buf; - } - buf += snprintf(buf, end - buf, " size %zd:%zd data %p\n", - t->buffer->data_size, t->buffer->offsets_size, - t->buffer->data); - return buf; + if (t->buffer->target_node) + seq_printf(m, " node %d", + t->buffer->target_node->debug_id); + seq_printf(m, " size %zd:%zd data %p\n", + t->buffer->data_size, t->buffer->offsets_size, + t->buffer->data); } -static char *print_binder_buffer(char *buf, char *end, const char *prefix, - struct binder_buffer *buffer) +static void print_binder_buffer(struct seq_file *m, const char *prefix, + struct binder_buffer *buffer) { - buf += snprintf(buf, end - buf, "%s %d: %p size %zd:%zd %s\n", - prefix, buffer->debug_id, buffer->data, - buffer->data_size, buffer->offsets_size, - buffer->transaction ? "active" : "delivered"); - return buf; + seq_printf(m, "%s %d: %p size %zd:%zd %s\n", + prefix, buffer->debug_id, buffer->data, + buffer->data_size, buffer->offsets_size, + buffer->transaction ? "active" : "delivered"); } -static char *print_binder_work(char *buf, char *end, const char *prefix, - const char *transaction_prefix, - struct binder_work *w) +static void print_binder_work(struct seq_file *m, const char *prefix, + const char *transaction_prefix, + struct binder_work *w) { struct binder_node *node; struct binder_transaction *t; @@ -3161,79 +3227,65 @@ static char *print_binder_work(char *buf, char *end, const char *prefix, switch (w->type) { case BINDER_WORK_TRANSACTION: t = container_of(w, struct binder_transaction, work); - buf = print_binder_transaction(buf, end, transaction_prefix, t); + print_binder_transaction(m, transaction_prefix, t); break; case BINDER_WORK_TRANSACTION_COMPLETE: - buf += snprintf(buf, end - buf, - "%stransaction complete\n", prefix); + seq_printf(m, "%stransaction complete\n", prefix); break; case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); - buf += snprintf(buf, end - buf, "%snode work %d: u%p c%p\n", - prefix, node->debug_id, node->ptr, - node->cookie); + seq_printf(m, "%snode work %d: u%p c%p\n", + prefix, node->debug_id, node->ptr, node->cookie); break; case BINDER_WORK_DEAD_BINDER: - buf += snprintf(buf, end - buf, "%shas dead binder\n", prefix); + seq_printf(m, "%shas dead binder\n", prefix); break; case BINDER_WORK_DEAD_BINDER_AND_CLEAR: - buf += snprintf(buf, end - buf, - "%shas cleared dead binder\n", prefix); + seq_printf(m, "%shas cleared dead binder\n", prefix); break; case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: - buf += snprintf(buf, end - buf, - "%shas cleared death notification\n", prefix); + seq_printf(m, "%shas cleared death notification\n", prefix); break; default: - buf += snprintf(buf, end - buf, "%sunknown work: type %d\n", - prefix, w->type); + seq_printf(m, "%sunknown work: type %d\n", prefix, w->type); break; } - return buf; } -static char *print_binder_thread(char *buf, char *end, - struct binder_thread *thread, - int print_always) +static void print_binder_thread(struct seq_file *m, + struct binder_thread *thread, + int print_always) { struct binder_transaction *t; struct binder_work *w; - char *start_buf = buf; - char *header_buf; + size_t start_pos = m->count; + size_t header_pos; - buf += snprintf(buf, end - buf, " thread %d: l %02x\n", - thread->pid, thread->looper); - header_buf = buf; + seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper); + header_pos = m->count; t = thread->transaction_stack; while (t) { - if (buf >= end) - break; if (t->from == thread) { - buf = print_binder_transaction(buf, end, - " outgoing transaction", t); + print_binder_transaction(m, + " outgoing transaction", t); t = t->from_parent; } else if (t->to_thread == thread) { - buf = print_binder_transaction(buf, end, - " incoming transaction", t); + print_binder_transaction(m, + " incoming transaction", t); t = t->to_parent; } else { - buf = print_binder_transaction(buf, end, - " bad transaction", t); + print_binder_transaction(m, " bad transaction", t); t = NULL; } } list_for_each_entry(w, &thread->todo, entry) { - if (buf >= end) - break; - buf = print_binder_work(buf, end, " ", - " pending transaction", w); + print_binder_work(m, " ", " pending transaction", w); } - if (!print_always && buf == header_buf) - buf = start_buf; - return buf; + if (!print_always && m->count == header_pos) + m->count = start_pos; } -static char *print_binder_node(char *buf, char *end, struct binder_node *node) +static void print_binder_node(struct seq_file *m, struct binder_node *node) { struct binder_ref *ref; struct hlist_node *pos; @@ -3244,100 +3296,67 @@ static char *print_binder_node(char *buf, char *end, struct binder_node *node) hlist_for_each_entry(ref, pos, &node->refs, node_entry) count++; - buf += snprintf(buf, end - buf, - " node %d: u%p c%p hs %d hw %d ls %d lw %d " - "is %d iw %d", - node->debug_id, node->ptr, node->cookie, - node->has_strong_ref, node->has_weak_ref, - node->local_strong_refs, node->local_weak_refs, - node->internal_strong_refs, count); - if (buf >= end) - return buf; + seq_printf(m, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d", + node->debug_id, node->ptr, node->cookie, + node->has_strong_ref, node->has_weak_ref, + node->local_strong_refs, node->local_weak_refs, + node->internal_strong_refs, count); if (count) { - buf += snprintf(buf, end - buf, " proc"); - if (buf >= end) - return buf; - hlist_for_each_entry(ref, pos, &node->refs, node_entry) { - buf += snprintf(buf, end - buf, " %d", ref->proc->pid); - if (buf >= end) - return buf; - } + seq_puts(m, " proc"); + hlist_for_each_entry(ref, pos, &node->refs, node_entry) + seq_printf(m, " %d", ref->proc->pid); } - buf += snprintf(buf, end - buf, "\n"); - list_for_each_entry(w, &node->async_todo, entry) { - if (buf >= end) - break; - buf = print_binder_work(buf, end, " ", - " pending async transaction", w); - } - return buf; + seq_puts(m, "\n"); + list_for_each_entry(w, &node->async_todo, entry) + print_binder_work(m, " ", + " pending async transaction", w); } -static char *print_binder_ref(char *buf, char *end, struct binder_ref *ref) +static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) { - buf += snprintf(buf, end - buf, - " ref %d: desc %d %snode %d s %d w %d d %p\n", - ref->debug_id, ref->desc, - ref->node->proc ? "" : "dead ", ref->node->debug_id, - ref->strong, ref->weak, ref->death); - return buf; + seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n", + ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", + ref->node->debug_id, ref->strong, ref->weak, ref->death); } -static char *print_binder_proc(char *buf, char *end, - struct binder_proc *proc, int print_all) +static void print_binder_proc(struct seq_file *m, + struct binder_proc *proc, int print_all) { struct binder_work *w; struct rb_node *n; - char *start_buf = buf; - char *header_buf; + size_t start_pos = m->count; + size_t header_pos; - buf += snprintf(buf, end - buf, "proc %d\n", proc->pid); - header_buf = buf; + seq_printf(m, "proc %d\n", proc->pid); + header_pos = m->count; - for (n = rb_first(&proc->threads); - n != NULL && buf < end; - n = rb_next(n)) - buf = print_binder_thread(buf, end, - rb_entry(n, struct binder_thread, - rb_node), print_all); - for (n = rb_first(&proc->nodes); - n != NULL && buf < end; - n = rb_next(n)) { + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) + print_binder_thread(m, rb_entry(n, struct binder_thread, + rb_node), print_all); + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { struct binder_node *node = rb_entry(n, struct binder_node, rb_node); if (print_all || node->has_async_transaction) - buf = print_binder_node(buf, end, node); + print_binder_node(m, node); } if (print_all) { for (n = rb_first(&proc->refs_by_desc); - n != NULL && buf < end; + n != NULL; n = rb_next(n)) - buf = print_binder_ref(buf, end, - rb_entry(n, struct binder_ref, - rb_node_desc)); - } - for (n = rb_first(&proc->allocated_buffers); - n != NULL && buf < end; - n = rb_next(n)) - buf = print_binder_buffer(buf, end, " buffer", - rb_entry(n, struct binder_buffer, - rb_node)); - list_for_each_entry(w, &proc->todo, entry) { - if (buf >= end) - break; - buf = print_binder_work(buf, end, " ", - " pending transaction", w); + print_binder_ref(m, rb_entry(n, struct binder_ref, + rb_node_desc)); } + for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) + print_binder_buffer(m, " buffer", + rb_entry(n, struct binder_buffer, rb_node)); + list_for_each_entry(w, &proc->todo, entry) + print_binder_work(m, " ", " pending transaction", w); list_for_each_entry(w, &proc->delivered_death, entry) { - if (buf >= end) - break; - buf += snprintf(buf, end - buf, - " has delivered dead binder\n"); + seq_puts(m, " has delivered dead binder\n"); break; } - if (!print_all && buf == header_buf) - buf = start_buf; - return buf; + if (!print_all && m->count == header_pos) + m->count = start_pos; } static const char *binder_return_strings[] = { @@ -3391,79 +3410,61 @@ static const char *binder_objstat_strings[] = { "transaction_complete" }; -static char *print_binder_stats(char *buf, char *end, const char *prefix, - struct binder_stats *stats) +static void print_binder_stats(struct seq_file *m, const char *prefix, + struct binder_stats *stats) { int i; BUILD_BUG_ON(ARRAY_SIZE(stats->bc) != - ARRAY_SIZE(binder_command_strings)); + ARRAY_SIZE(binder_command_strings)); for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { if (stats->bc[i]) - buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, - binder_command_strings[i], - stats->bc[i]); - if (buf >= end) - return buf; + seq_printf(m, "%s%s: %d\n", prefix, + binder_command_strings[i], stats->bc[i]); } BUILD_BUG_ON(ARRAY_SIZE(stats->br) != - ARRAY_SIZE(binder_return_strings)); + ARRAY_SIZE(binder_return_strings)); for (i = 0; i < ARRAY_SIZE(stats->br); i++) { if (stats->br[i]) - buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, - binder_return_strings[i], stats->br[i]); - if (buf >= end) - return buf; + seq_printf(m, "%s%s: %d\n", prefix, + binder_return_strings[i], stats->br[i]); } BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != - ARRAY_SIZE(binder_objstat_strings)); + ARRAY_SIZE(binder_objstat_strings)); BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != - ARRAY_SIZE(stats->obj_deleted)); + ARRAY_SIZE(stats->obj_deleted)); for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { if (stats->obj_created[i] || stats->obj_deleted[i]) - buf += snprintf(buf, end - buf, - "%s%s: active %d total %d\n", prefix, - binder_objstat_strings[i], - stats->obj_created[i] - - stats->obj_deleted[i], - stats->obj_created[i]); - if (buf >= end) - return buf; + seq_printf(m, "%s%s: active %d total %d\n", prefix, + binder_objstat_strings[i], + stats->obj_created[i] - stats->obj_deleted[i], + stats->obj_created[i]); } - return buf; } -static char *print_binder_proc_stats(char *buf, char *end, - struct binder_proc *proc) +static void print_binder_proc_stats(struct seq_file *m, + struct binder_proc *proc) { struct binder_work *w; struct rb_node *n; int count, strong, weak; - buf += snprintf(buf, end - buf, "proc %d\n", proc->pid); - if (buf >= end) - return buf; + seq_printf(m, "proc %d\n", proc->pid); count = 0; for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) count++; - buf += snprintf(buf, end - buf, " threads: %d\n", count); - if (buf >= end) - return buf; - buf += snprintf(buf, end - buf, " requested threads: %d+%d/%d\n" + seq_printf(m, " threads: %d\n", count); + seq_printf(m, " requested threads: %d+%d/%d\n" " ready threads %d\n" " free async space %zd\n", proc->requested_threads, proc->requested_threads_started, proc->max_threads, proc->ready_threads, proc->free_async_space); - if (buf >= end) - return buf; count = 0; for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) count++; - buf += snprintf(buf, end - buf, " nodes: %d\n", count); - if (buf >= end) - return buf; + seq_printf(m, " nodes: %d\n", count); count = 0; strong = 0; weak = 0; @@ -3474,17 +3475,12 @@ static char *print_binder_proc_stats(char *buf, char *end, strong += ref->strong; weak += ref->weak; } - buf += snprintf(buf, end - buf, " refs: %d s %d w %d\n", - count, strong, weak); - if (buf >= end) - return buf; + seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak); count = 0; for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) count++; - buf += snprintf(buf, end - buf, " buffers: %d\n", count); - if (buf >= end) - return buf; + seq_printf(m, " buffers: %d\n", count); count = 0; list_for_each_entry(w, &proc->todo, entry) { @@ -3496,222 +3492,110 @@ static char *print_binder_proc_stats(char *buf, char *end, break; } } - buf += snprintf(buf, end - buf, " pending transactions: %d\n", count); - if (buf >= end) - return buf; + seq_printf(m, " pending transactions: %d\n", count); - buf = print_binder_stats(buf, end, " ", &proc->stats); - - return buf; + print_binder_stats(m, " ", &proc->stats); } -static int binder_read_proc_state(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int binder_state_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct hlist_node *pos; struct binder_node *node; - int len = 0; - char *buf = page; - char *end = page + PAGE_SIZE; int do_lock = !binder_debug_no_lock; - if (off) - return 0; - if (do_lock) mutex_lock(&binder_lock); - buf += snprintf(buf, end - buf, "binder state:\n"); + seq_puts(m, "binder state:\n"); if (!hlist_empty(&binder_dead_nodes)) - buf += snprintf(buf, end - buf, "dead nodes:\n"); - hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node) { - if (buf >= end) - break; - buf = print_binder_node(buf, end, node); - } + seq_puts(m, "dead nodes:\n"); + hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node) + print_binder_node(m, node); - hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { - if (buf >= end) - break; - buf = print_binder_proc(buf, end, proc, 1); - } + hlist_for_each_entry(proc, pos, &binder_procs, proc_node) + print_binder_proc(m, proc, 1); if (do_lock) mutex_unlock(&binder_lock); - if (buf > page + PAGE_SIZE) - buf = page + PAGE_SIZE; - - *start = page + off; - - len = buf - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + return 0; } -static int binder_read_proc_stats(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int binder_stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct hlist_node *pos; - int len = 0; - char *p = page; int do_lock = !binder_debug_no_lock; - if (off) - return 0; - if (do_lock) mutex_lock(&binder_lock); - p += snprintf(p, PAGE_SIZE, "binder stats:\n"); + seq_puts(m, "binder stats:\n"); - p = print_binder_stats(p, page + PAGE_SIZE, "", &binder_stats); + print_binder_stats(m, "", &binder_stats); - hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { - if (p >= page + PAGE_SIZE) - break; - p = print_binder_proc_stats(p, page + PAGE_SIZE, proc); - } + hlist_for_each_entry(proc, pos, &binder_procs, proc_node) + print_binder_proc_stats(m, proc); if (do_lock) mutex_unlock(&binder_lock); - if (p > page + PAGE_SIZE) - p = page + PAGE_SIZE; - - *start = page + off; - - len = p - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + return 0; } -static int binder_read_proc_transactions(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int binder_transactions_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct hlist_node *pos; - int len = 0; - char *buf = page; - char *end = page + PAGE_SIZE; int do_lock = !binder_debug_no_lock; - if (off) - return 0; - if (do_lock) mutex_lock(&binder_lock); - buf += snprintf(buf, end - buf, "binder transactions:\n"); - hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { - if (buf >= end) - break; - buf = print_binder_proc(buf, end, proc, 0); - } + seq_puts(m, "binder transactions:\n"); + hlist_for_each_entry(proc, pos, &binder_procs, proc_node) + print_binder_proc(m, proc, 0); if (do_lock) mutex_unlock(&binder_lock); - if (buf > page + PAGE_SIZE) - buf = page + PAGE_SIZE; - - *start = page + off; - - len = buf - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + return 0; } -static int binder_read_proc_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int binder_proc_show(struct seq_file *m, void *unused) { - struct binder_proc *proc = data; - int len = 0; - char *p = page; + struct binder_proc *proc = m->private; int do_lock = !binder_debug_no_lock; - if (off) - return 0; - if (do_lock) mutex_lock(&binder_lock); - p += snprintf(p, PAGE_SIZE, "binder proc state:\n"); - p = print_binder_proc(p, page + PAGE_SIZE, proc, 1); + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, proc, 1); if (do_lock) mutex_unlock(&binder_lock); - - if (p > page + PAGE_SIZE) - p = page + PAGE_SIZE; - *start = page + off; - - len = p - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + return 0; } -static char *print_binder_transaction_log_entry(char *buf, char *end, +static void print_binder_transaction_log_entry(struct seq_file *m, struct binder_transaction_log_entry *e) { - buf += snprintf(buf, end - buf, - "%d: %s from %d:%d to %d:%d node %d handle %d " - "size %d:%d\n", - e->debug_id, (e->call_type == 2) ? "reply" : - ((e->call_type == 1) ? "async" : "call "), e->from_proc, - e->from_thread, e->to_proc, e->to_thread, e->to_node, - e->target_handle, e->data_size, e->offsets_size); - return buf; + seq_printf(m, + "%d: %s from %d:%d to %d:%d node %d handle %d size %d:%d\n", + e->debug_id, (e->call_type == 2) ? "reply" : + ((e->call_type == 1) ? "async" : "call "), e->from_proc, + e->from_thread, e->to_proc, e->to_thread, e->to_node, + e->target_handle, e->data_size, e->offsets_size); } -static int binder_read_proc_transaction_log( - char *page, char **start, off_t off, int count, int *eof, void *data) +static int binder_transaction_log_show(struct seq_file *m, void *unused) { - struct binder_transaction_log *log = data; - int len = 0; + struct binder_transaction_log *log = m->private; int i; - char *buf = page; - char *end = page + PAGE_SIZE; - - if (off) - return 0; if (log->full) { - for (i = log->next; i < ARRAY_SIZE(log->entry); i++) { - if (buf >= end) - break; - buf = print_binder_transaction_log_entry(buf, end, - &log->entry[i]); - } + for (i = log->next; i < ARRAY_SIZE(log->entry); i++) + print_binder_transaction_log_entry(m, &log->entry[i]); } - for (i = 0; i < log->next; i++) { - if (buf >= end) - break; - buf = print_binder_transaction_log_entry(buf, end, - &log->entry[i]); - } - - *start = page + off; - - len = buf - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + for (i = 0; i < log->next; i++) + print_binder_transaction_log_entry(m, &log->entry[i]); + return 0; } static const struct file_operations binder_fops = { @@ -3730,6 +3614,11 @@ static struct miscdevice binder_miscdev = { .fops = &binder_fops }; +BINDER_DEBUG_ENTRY(state); +BINDER_DEBUG_ENTRY(stats); +BINDER_DEBUG_ENTRY(transactions); +BINDER_DEBUG_ENTRY(transaction_log); + static int __init binder_init(void) { int ret; @@ -3738,37 +3627,37 @@ static int __init binder_init(void) if (!binder_deferred_workqueue) return -ENOMEM; - binder_proc_dir_entry_root = proc_mkdir("binder", NULL); - if (binder_proc_dir_entry_root) - binder_proc_dir_entry_proc = proc_mkdir("proc", - binder_proc_dir_entry_root); + binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); + if (binder_debugfs_dir_entry_root) + binder_debugfs_dir_entry_proc = debugfs_create_dir("proc", + binder_debugfs_dir_entry_root); ret = misc_register(&binder_miscdev); - if (binder_proc_dir_entry_root) { - create_proc_read_entry("state", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_state, - NULL); - create_proc_read_entry("stats", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_stats, - NULL); - create_proc_read_entry("transactions", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_transactions, - NULL); - create_proc_read_entry("transaction_log", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_transaction_log, - &binder_transaction_log); - create_proc_read_entry("failed_transaction_log", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_transaction_log, - &binder_transaction_log_failed); + if (binder_debugfs_dir_entry_root) { + debugfs_create_file("state", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_state_fops); + debugfs_create_file("stats", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_stats_fops); + debugfs_create_file("transactions", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_transactions_fops); + debugfs_create_file("transaction_log", + S_IRUGO, + binder_debugfs_dir_entry_root, + &binder_transaction_log, + &binder_transaction_log_fops); + debugfs_create_file("failed_transaction_log", + S_IRUGO, + binder_debugfs_dir_entry_root, + &binder_transaction_log_failed, + &binder_transaction_log_fops); } return ret; } diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c index 7adbdc68..55bf2dda 100644 --- a/drivers/staging/android/ram_console.c +++ b/drivers/staging/android/ram_console.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #if defined(CONFIG_VERY_EARLY_CONSOLE) #include @@ -395,7 +395,7 @@ static ssize_t ram_console_read_old(struct file *file, char __user *buf, return count; } -static const struct file_operations ram_console_file_ops = { +static struct file_operations ram_console_file_ops = { .owner = THIS_MODULE, .read = ram_console_read_old, }; diff --git a/include/linux/memory_alloc.h b/include/linux/memory_alloc.h index ec005a1c..a49bc37f 100644 --- a/include/linux/memory_alloc.h +++ b/include/linux/memory_alloc.h @@ -16,6 +16,7 @@ #include #include #include +#include struct mem_pool { struct mutex pool_mutex; @@ -56,4 +57,3 @@ unsigned long memory_pool_node_len(void *vaddr); int memory_pool_init(void); #endif /* _LINUX_MEMALLOC_H */ - diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h index ceada785..56e6cc6b 100644 --- a/include/linux/msm_kgsl.h +++ b/include/linux/msm_kgsl.h @@ -35,7 +35,7 @@ #define _MSM_KGSL_H #define KGSL_VERSION_MAJOR 3 -#define KGSL_VERSION_MINOR 7 +#define KGSL_VERSION_MINOR 8 /*context flags */ #define KGSL_CONTEXT_SAVE_GMEM 1 @@ -60,6 +60,9 @@ #define KGSL_MAX_PWRLEVELS 5 +#define KGSL_CONVERT_TO_MBPS(val) \ + (val*1000*1000U) + /* device id */ enum kgsl_deviceid { KGSL_DEVICE_3D0 = 0x00000000, @@ -170,7 +173,6 @@ struct kgsl_device_pwr_data { int (*set_grp_async)(void); unsigned int idle_timeout; unsigned int nap_allowed; - unsigned int idle_pass; }; struct kgsl_clk_data { @@ -183,6 +185,8 @@ struct kgsl_device_platform_data { struct kgsl_clk_data clk; /* imem_clk_name is for 3d only, not used in 2d devices */ struct kgsl_grp_clk_name imem_clk_name; + const char *iommu_user_ctx_name; + const char *iommu_priv_ctx_name; }; #endif @@ -454,6 +458,30 @@ struct kgsl_cff_syncmem { #define IOCTL_KGSL_CFF_SYNCMEM \ _IOW(KGSL_IOC_TYPE, 0x30, struct kgsl_cff_syncmem) +/* +* A timestamp event allows the user space to register an action following an +* expired timestamp. +*/ + +struct kgsl_timestamp_event { + int type; /* Type of event (see list below) */ + unsigned int timestamp; /* Timestamp to trigger event on */ + unsigned int context_id; /* Context for the timestamp */ + void *priv; /* Pointer to the event specific blob */ + size_t len; /* Size of the event specific blob */ +}; + +#define IOCTL_KGSL_TIMESTAMP_EVENT \ + _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_timestamp_event) + +/* A genlock timestamp event releases an existing lock on timestamp expire */ + +#define KGSL_TIMESTAMP_EVENT_GENLOCK 1 + +struct kgsl_timestamp_event_genlock { + int handle; /* Handle of the genlock lock to release */ +}; + #ifdef __KERNEL__ #ifdef CONFIG_MSM_KGSL_DRM int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start, diff --git a/include/linux/msm_q6vdec.h b/include/linux/msm_q6vdec.h index ed7cf782..3b1d0930 100644 --- a/include/linux/msm_q6vdec.h +++ b/include/linux/msm_q6vdec.h @@ -46,6 +46,8 @@ #define VDEC_IOCTL_GETDECATTRIBUTES _IOR(VDEC_IOCTL_MAGIC, 10, \ struct vdec_dec_attributes) #define VDEC_IOCTL_GETVERSION _IOR(VDEC_IOCTL_MAGIC, 11, struct vdec_version) +#define VDEC_IOCTL_PERFORMANCE_CHANGE_REQ _IOW(VDEC_IOCTL_MAGIC, 14, \ + unsigned int) enum { VDEC_FRAME_DECODE_OK, @@ -83,6 +85,13 @@ enum { VDEC_COLOR_FORMAT_NV21_YAMOTO = 0x02 }; +enum { + PERF_REQUEST_SET_MIN = 0, + PERF_REQUEST_LOWER, + PERF_REQUEST_RAISE, + PERF_REQUEST_SET_MAX +}; + struct vdec_input_buf_info { u32 offset; u32 data; diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h index 265729ec..1cc93892 100644 --- a/include/linux/pm_qos_params.h +++ b/include/linux/pm_qos_params.h @@ -1,6 +1,8 @@ /* interface for the pm_qos_power infrastructure of the linux kernel. * * Mark Gross + * + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. */ #ifndef __PM_QOS_PARAMS_H__ #define __PM_QOS_PARAMS_H__ @@ -57,3 +59,4 @@ int pm_qos_add_notifier(int qos, struct notifier_block *notifier); int pm_qos_remove_notifier(int qos, struct notifier_block *notifier); #endif /* __PM_QOS_PARAMS_H__ */ + diff --git a/lib/Makefile b/lib/Makefile index 019e8ef7..11003485 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -12,7 +12,8 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ idr.o int_sqrt.o extable.o prio_tree.o \ sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \ proportions.o prio_heap.o ratelimit.o show_mem.o \ - is_single_threaded.o plist.o decompress.o flex_array.o memcopy.o + is_single_threaded.o plist.o decompress.o flex_array.o memcopy.o \ + memory_alloc.o lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o @@ -38,9 +39,10 @@ lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o -obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o +lib-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o +obj-$(CONFIG_PLIST) += plist.o obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o obj-$(CONFIG_DEBUG_LIST) += list_debug.o obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o diff --git a/mm/ashmem.c b/mm/ashmem.c index a16f3f7c..5e059283 100644 --- a/mm/ashmem.c +++ b/mm/ashmem.c @@ -29,10 +29,9 @@ #include #include #include -#include -#define ASHMEM_NAME_PREFIX "dev/ashmem/" -#define ASHMEM_NAME_PREFIX_LEN (sizeof(ASHMEM_NAME_PREFIX) - 1) +#define ASHMEM_NAME_PREFIX "" +#define ASHMEM_NAME_PREFIX_LEN 0 #define ASHMEM_FULL_NAME_LEN (ASHMEM_NAME_LEN + ASHMEM_NAME_PREFIX_LEN) /* @@ -46,8 +45,6 @@ struct ashmem_area { struct list_head unpinned_list; /* list of all ashmem areas */ struct file *file; /* the shmem-based backing file */ size_t size; /* size of the mapping, in bytes */ - unsigned long vm_start; /* Start address of vm_area - * which maps this ashmem */ unsigned long prot_mask; /* allowed prot bits, as vm_flags */ }; @@ -181,7 +178,7 @@ static int ashmem_open(struct inode *inode, struct file *file) struct ashmem_area *asma; int ret; - ret = generic_file_open(inode, file); + ret = nonseekable_open(inode, file); if (unlikely(ret)) return ret; @@ -190,7 +187,6 @@ static int ashmem_open(struct inode *inode, struct file *file) return -ENOMEM; INIT_LIST_HEAD(&asma->unpinned_list); - memcpy(asma->name, ASHMEM_NAME_PREFIX, ASHMEM_NAME_PREFIX_LEN); asma->prot_mask = PROT_MASK; file->private_data = asma; @@ -214,67 +210,6 @@ static int ashmem_release(struct inode *ignored, struct file *file) return 0; } -static ssize_t ashmem_read(struct file *file, char __user *buf, - size_t len, loff_t *pos) -{ - struct ashmem_area *asma = file->private_data; - int ret = 0; - - mutex_lock(&ashmem_mutex); - - /* If size is not set, or set to 0, always return EOF. */ - if (asma->size == 0) { - goto out; - } - - if (!asma->file) { - ret = -EBADF; - goto out; - } - - ret = asma->file->f_op->read(asma->file, buf, len, pos); - if (ret < 0) { - goto out; - } - - /** Update backing file pos, since f_ops->read() doesn't */ - asma->file->f_pos = *pos; - -out: - mutex_unlock(&ashmem_mutex); - return ret; -} - -static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin) -{ - struct ashmem_area *asma = file->private_data; - int ret; - - mutex_lock(&ashmem_mutex); - - if (asma->size == 0) { - ret = -EINVAL; - goto out; - } - - if (!asma->file) { - ret = -EBADF; - goto out; - } - - ret = asma->file->f_op->llseek(asma->file, offset, origin); - if (ret < 0) { - goto out; - } - - /** Copy f_pos from backing file, since f_ops->llseek() sets it */ - file->f_pos = asma->file->f_pos; - -out: - mutex_unlock(&ashmem_mutex); - return ret; -} - static inline unsigned long calc_vm_may_flags(unsigned long prot) { @@ -329,7 +264,6 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_file = asma->file; } vma->vm_flags |= VM_CAN_NONLINEAR; - asma->vm_start = vma->vm_start; out: mutex_unlock(&ashmem_mutex); @@ -351,7 +285,7 @@ out: * chunks of ashmem regions LRU-wise one-at-a-time until we hit 'nr_to_scan' * pages freed. */ -static int ashmem_shrink(struct shrinker *s, int nr_to_scan, gfp_t gfp_mask) +static int ashmem_shrink(int nr_to_scan, gfp_t gfp_mask) { struct ashmem_range *range, *next; @@ -630,69 +564,6 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, return ret; } -#ifdef CONFIG_OUTER_CACHE -static unsigned int virtaddr_to_physaddr(unsigned int virtaddr) -{ - unsigned int physaddr = 0; - pgd_t *pgd_ptr = NULL; - pmd_t *pmd_ptr = NULL; - pte_t *pte_ptr = NULL, pte; - - spin_lock(¤t->mm->page_table_lock); - pgd_ptr = pgd_offset(current->mm, virtaddr); - if (pgd_none(*pgd) || pgd_bad(*pgd)) { - pr_err("Failed to convert virtaddr %x to pgd_ptr\n", - virtaddr); - goto done; - } - - pmd_ptr = pmd_offset(pgd_ptr, virtaddr); - if (pmd_none(*pmd_ptr) || pmd_bad(*pmd_ptr)) { - pr_err("Failed to convert pgd_ptr %p to pmd_ptr\n", - (void *)pgd_ptr); - goto done; - } - - pte_ptr = pte_offset_map(pmd_ptr, virtaddr); - if (!pte_ptr) { - pr_err("Failed to convert pmd_ptr %p to pte_ptr\n", - (void *)pmd_ptr); - goto done; - } - pte = *pte_ptr; - physaddr = pte_pfn(pte); - pte_unmap(pte_ptr); -done: - spin_unlock(¤t->mm->page_table_lock); - physaddr <<= PAGE_SHIFT; - return physaddr; -} -#endif - -static int ashmem_cache_op(struct ashmem_area *asma, - void (*cache_func)(unsigned long vstart, unsigned long length, - unsigned long pstart)) -{ -#ifdef CONFIG_OUTER_CACHE - unsigned long vaddr; -#endif - mutex_lock(&ashmem_mutex); -#ifndef CONFIG_OUTER_CACHE - cache_func(asma->vm_start, asma->size, 0); -#else - for (vaddr = asma->vm_start; vaddr < asma->vm_start + asma->size; - vaddr += PAGE_SIZE) { - unsigned long physaddr; - physaddr = virtaddr_to_physaddr(vaddr); - if (!physaddr) - return -EINVAL; - cache_func(vaddr, PAGE_SIZE, physaddr); - } -#endif - mutex_unlock(&ashmem_mutex); - return 0; -} - static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ashmem_area *asma = file->private_data; @@ -729,19 +600,10 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case ASHMEM_PURGE_ALL_CACHES: ret = -EPERM; if (capable(CAP_SYS_ADMIN)) { - ret = ashmem_shrink(&ashmem_shrinker, 0, GFP_KERNEL); - ashmem_shrink(&ashmem_shrinker, ret, GFP_KERNEL); + ret = ashmem_shrink(0, GFP_KERNEL); + ashmem_shrink(ret, GFP_KERNEL); } break; - case ASHMEM_CACHE_FLUSH_RANGE: - ret = ashmem_cache_op(asma, &clean_and_invalidate_caches); - break; - case ASHMEM_CACHE_CLEAN_RANGE: - ret = ashmem_cache_op(asma, &clean_caches); - break; - case ASHMEM_CACHE_INV_RANGE: - ret = ashmem_cache_op(asma, &invalidate_caches); - break; } return ret; @@ -804,8 +666,6 @@ static struct file_operations ashmem_fops = { .owner = THIS_MODULE, .open = ashmem_open, .release = ashmem_release, - .read = ashmem_read, - .llseek = ashmem_llseek, .mmap = ashmem_mmap, .unlocked_ioctl = ashmem_ioctl, .compat_ioctl = ashmem_ioctl,