diff options
author | Mathieu J. Poirier <mathieu.poirier@linaro.org> | 2011-09-18 11:37:01 -0600 |
---|---|---|
committer | Mathieu J. Poirier <mathieu.poirier@linaro.org> | 2011-09-18 11:37:01 -0600 |
commit | aa8366e08836ece21fe8dcee87f6065ca7cb9d1c (patch) | |
tree | a85e8ed1547f0b4f3609a3b4a5c4829fef055067 | |
parent | 6242e334ff8a9f1651c2515535d98485e343dcb1 (diff) | |
parent | ae2294a089c4c2289b8ad4c18447d45c439e8db1 (diff) |
Merge branch 'meego-device-adaptation.n9xx-v3.0-wip' into new-oneiric-meego-merge.sept18
138 files changed, 48242 insertions, 134 deletions
diff --git a/arch/arm/configs/meego_n9xx_defconfig b/arch/arm/configs/meego_n9xx_defconfig new file mode 100644 index 00000000000..8f07a3f4e81 --- /dev/null +++ b/arch/arm/configs/meego_n9xx_defconfig @@ -0,0 +1,2456 @@ +# +# Automatically generated make config: don't edit +# Linux/arm 3.0.0 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_SCHED_CLOCK=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_HAVE_SPARSE_IRQ=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_CHIP=y +# CONFIG_SPARSE_IRQ is not set + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_PREEMPT_RCU is not set +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_CGROUPS is not set +# CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_PERF_COUNTERS is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +CONFIG_OPROFILE=y +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_NUC93X is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS4 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_TCC_926 is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +CONFIG_ARCH_OMAP=y +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# TI OMAP Common Features +# +CONFIG_ARCH_OMAP_OTG=y +# CONFIG_ARCH_OMAP1 is not set +CONFIG_ARCH_OMAP2PLUS=y + +# +# OMAP Feature Selections +# +CONFIG_OMAP_DEBUG_DEVICES=y +# CONFIG_OMAP_SMARTREFLEX is not set +CONFIG_OMAP_RESET_CLOCKS=y +CONFIG_OMAP_MUX=y +CONFIG_OMAP_MUX_DEBUG=y +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_MCBSP=y +# CONFIG_OMAP_MBOX_FWK is not set +CONFIG_OMAP_32K_TIMER=y +# CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set +CONFIG_OMAP_32K_TIMER_HZ=128 +CONFIG_OMAP_DM_TIMER=y +# CONFIG_OMAP_PM_NONE is not set +CONFIG_OMAP_PM_NOOP=y +CONFIG_MACH_OMAP_GENERIC=y + +# +# TI OMAP2/3/4 Specific Features +# +CONFIG_ARCH_OMAP2PLUS_TYPICAL=y +CONFIG_ARCH_OMAP2=y +CONFIG_ARCH_OMAP3=y +CONFIG_ARCH_OMAP4=y + +# +# OMAP Core Type +# +CONFIG_SOC_OMAP2420=y +CONFIG_SOC_OMAP2430=y +CONFIG_SOC_OMAP3430=y +CONFIG_SOC_OMAPTI816X=y +CONFIG_OMAP_PACKAGE_ZAF=y +CONFIG_OMAP_PACKAGE_ZAC=y +CONFIG_OMAP_PACKAGE_CBB=y +CONFIG_OMAP_PACKAGE_CUS=y +CONFIG_OMAP_PACKAGE_CBP=y +CONFIG_OMAP_PACKAGE_CBL=y +CONFIG_OMAP_PACKAGE_CBS=y + +# +# OMAP Board Type +# +CONFIG_MACH_OMAP2_TUSB6010=y +CONFIG_MACH_OMAP_H4=y +CONFIG_MACH_OMAP_APOLLON=y +CONFIG_MACH_OMAP_2430SDP=y +CONFIG_MACH_OMAP3_BEAGLE=y +CONFIG_MACH_DEVKIT8000=y +CONFIG_MACH_OMAP_LDP=y +CONFIG_MACH_OMAP3530_LV_SOM=y +CONFIG_MACH_OMAP3_TORPEDO=y +CONFIG_MACH_OVERO=y +CONFIG_MACH_OMAP3EVM=y +CONFIG_MACH_OMAP3517EVM=y +# CONFIG_MACH_CRANEBOARD is not set +CONFIG_MACH_OMAP3_PANDORA=y +CONFIG_MACH_OMAP3_TOUCHBOOK=y +CONFIG_MACH_OMAP_3430SDP=y +CONFIG_MACH_NOKIA_N800=y +CONFIG_MACH_NOKIA_N810=y +CONFIG_MACH_NOKIA_N810_WIMAX=y +CONFIG_MACH_NOKIA_N8X0=y +CONFIG_MACH_NOKIA_RM680=y +CONFIG_MACH_NOKIA_RX51=y +CONFIG_MACH_OMAP_ZOOM2=y +CONFIG_MACH_OMAP_ZOOM3=y +CONFIG_MACH_CM_T35=y +CONFIG_MACH_CM_T3517=y +CONFIG_MACH_IGEP0020=y +CONFIG_MACH_IGEP0030=y +CONFIG_MACH_SBC3530=y +CONFIG_MACH_OMAP_3630SDP=y +CONFIG_MACH_TI8168EVM=y +CONFIG_MACH_OMAP_4430SDP=y +CONFIG_MACH_OMAP4_PANDA=y +# CONFIG_OMAP3_EMU is not set +# CONFIG_OMAP3_SDRC_AC_TIMING is not set + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V6=y +CONFIG_CPU_V7=y +CONFIG_CPU_32v6=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV6=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V6=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V6=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_USE_DOMAINS=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_CACHE_L2X0=y +CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_ERRATA_411920=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +CONFIG_PL310_ERRATA_588369=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_PL310_ERRATA_727915=y +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +CONFIG_ARM_GIC=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_HAVE_ARM_SCU=y +CONFIG_HAVE_ARM_TWD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_HZ=128 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +# CONFIG_HIGHMEM is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=999999 +# CONFIG_COMPACTION is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_CLEANCACHE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_LEDS=y +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/mmcblk0p1 rootwait rw console=ttyO2,115200n8 console=tty0 omapfb.vram=0:2M,1:2M,2:2M mtdoops.mtddev=2" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_CAN_PM_TRACE=y +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_PM_RUNTIME_CLK=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_MIGRATE=y +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETLABEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=m +# CONFIG_BT_L2CAP is not set +# CONFIG_BT_SCO is not set + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_CFG80211=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +CONFIG_LIB80211=m +# CONFIG_LIB80211_DEBUG is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +CONFIG_MAC80211_RC_PID=y +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL_HT=y +CONFIG_MAC80211_RC_DEFAULT_PID=y +# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set +CONFIG_MAC80211_RC_DEFAULT="pid" +# CONFIG_MAC80211_MESH is not set +# CONFIG_MAC80211_DEBUGFS is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +CONFIG_MTD_OOPS=y +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_OMAP2=y +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set +CONFIG_MTD_ONENAND=y +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_GENERIC is not set +CONFIG_MTD_ONENAND_OMAP2=y +# CONFIG_MTD_ONENAND_OTP is not set +# CONFIG_MTD_ONENAND_2X_PROGRAM is not set +# CONFIG_MTD_ONENAND_SIM is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set +# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_MISC_DEVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_DM is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +CONFIG_MII=y +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +CONFIG_SMSC_PHY=y +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +# CONFIG_AX88796 is not set +CONFIG_SMC91X=y +# CONFIG_TI_DAVINCI_EMAC is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +# CONFIG_DNET is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +CONFIG_KS8851=y +CONFIG_KS8851_MLL=y +# CONFIG_FTMAC100 is not set +CONFIG_NETDEV_1000=y +# CONFIG_STMMAC_ETH is not set +CONFIG_NETDEV_10000=y +CONFIG_WLAN=y +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_RTL8187 is not set +# CONFIG_MAC80211_HWSIM is not set +# CONFIG_ATH_COMMON is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_SPI is not set +CONFIG_LIBERTAS_DEBUG=y +# CONFIG_LIBERTAS_MESH is not set +# CONFIG_P54_COMMON is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTL8192SE is not set +# CONFIG_RTL8192CU is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX_MENU is not set +# CONFIG_ZD1211RW is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_WAN is not set + +# +# CAIF transport drivers +# +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_OMAP is not set +# CONFIG_KEYBOARD_OMAP4 is not set +CONFIG_KEYBOARD_TWL4030=y +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=y +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +CONFIG_TOUCHSCREEN_TSC2005=y +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_TWL4030_PWRBUTTON=y +# CONFIG_INPUT_TWL4030_VIBRA is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_OMAP=y +CONFIG_SERIAL_OMAP_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_OMAP=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_OMAP=y +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +CONFIG_SPI_OMAP24XX=y +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_BASIC_MMIO is not set +# CONFIG_GPIO_IT8761E is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +CONFIG_GPIO_TWL4030=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_W1=y +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_HDQ_MASTER_OMAP is not set + +# +# 1-wire Slaves +# +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_BQ27000 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_BQ20Z75 is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHARGER_GPIO is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_MPCORE_WATCHDOG is not set +CONFIG_OMAP_WATCHDOG=y +CONFIG_TWL4030_WATCHDOG=y +# CONFIG_MAX63XX_WATCHDOG is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set +CONFIG_MFD_SUPPORT=y +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS6586X is not set +CONFIG_MENELAUS=y +CONFIG_TWL4030_CORE=y +# CONFIG_TWL4030_MADC is not set +CONFIG_TWL4030_POWER=y +CONFIG_TWL4030_CODEC=y +# CONFIG_TWL6030_PWM is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_TPS65910 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_BQ24022 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +CONFIG_REGULATOR_TWL4030=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +CONFIG_REGULATOR_TPS65023=y +CONFIG_REGULATOR_TPS6507X=y +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_PVR=m +CONFIG_PVR_RELEASE=y +# CONFIG_PVR_DEBUG is not set +# CONFIG_PVR_TIMING is not set +# CONFIG_PVR_DEBUG_PDUMP is not set +# CONFIG_PVR_EDM_DEBUG is not set +# CONFIG_PVR_NO_HARDWARE is not set +# CONFIG_PVR_FORCE_CLOCKS_ON is not set +# CONFIG_PVR_EXAMPLES is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_FB_OMAP_LCD_VGA=y +# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set +CONFIG_OMAP2_VRAM=y +CONFIG_OMAP2_VRFB=y +CONFIG_OMAP2_DSS=y +CONFIG_OMAP2_VRAM_SIZE=6 +# CONFIG_OMAP2_DSS_DEBUG_SUPPORT is not set +# CONFIG_OMAP2_DSS_DPI is not set +# CONFIG_OMAP2_DSS_RFBI is not set +CONFIG_OMAP2_DSS_VENC=y +CONFIG_OMAP4_DSS_HDMI=y +CONFIG_OMAP2_DSS_SDI=y +# CONFIG_OMAP2_DSS_DSI is not set +# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set +CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 +CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET=y +CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET=y +CONFIG_FB_OMAP2=y +CONFIG_FB_OMAP2_DEBUG_SUPPORT=y +CONFIG_FB_OMAP2_NUM_FBS=3 + +# +# OMAP2/3 Display Device Drivers +# +CONFIG_PANEL_ACX565AKM=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +CONFIG_LCD_PLATFORM=y +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set + +# +# Display device support +# +CONFIG_DISPLAY_SUPPORT=y + +# +# Display hardware drivers +# + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +CONFIG_SND_VERBOSE_PRINTK=y +CONFIG_SND_DEBUG=y +# CONFIG_SND_DEBUG_VERBOSE is not set +# CONFIG_SND_PCM_XRUN_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=m +# CONFIG_SND_SOC_CACHE_LZO is not set +CONFIG_SND_OMAP_SOC=m +CONFIG_SND_OMAP_SOC_MCBSP=m +# CONFIG_SND_OMAP_SOC_N810 is not set +# CONFIG_SND_OMAP_SOC_RX51 is not set +# CONFIG_SND_OMAP_SOC_OVERO is not set +# CONFIG_SND_OMAP_SOC_OMAP3EVM is not set +# CONFIG_SND_OMAP_SOC_AM3517EVM is not set +# CONFIG_SND_OMAP_SOC_SDP3430 is not set +# CONFIG_SND_OMAP_SOC_SDP4430 is not set +CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m +# CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE is not set +# CONFIG_SND_OMAP_SOC_ZOOM2 is not set +# CONFIG_SND_OMAP_SOC_IGEP0020 is not set +CONFIG_SND_SOC_I2C_AND_SPI=m +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_TWL4030=m +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_QUANTA is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_ROCCAT_ARVO is not set +# CONFIG_HID_ROCCAT_KONE is not set +# CONFIG_HID_ROCCAT_KONEPLUS is not set +# CONFIG_HID_ROCCAT_KOVAPLUS is not set +# CONFIG_HID_ROCCAT_PYRA is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +CONFIG_USB_DEBUG=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +CONFIG_USB_MUSB_HDRC=y +# CONFIG_USB_MUSB_TUSB6010 is not set +# CONFIG_USB_MUSB_OMAP2PLUS is not set +# CONFIG_USB_MUSB_AM35X is not set +# CONFIG_USB_MUSB_HOST is not set +# CONFIG_USB_MUSB_PERIPHERAL is not set +CONFIG_USB_MUSB_OTG=y +CONFIG_USB_GADGET_MUSB_HDRC=y +CONFIG_USB_MUSB_HDRC_HCD=y +CONFIG_MUSB_PIO_ONLY=y + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_WDM=y +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +CONFIG_USB_TEST=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_GADGET=m +CONFIG_USB_GADGET_DEBUG=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_FUSB300 is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_R8A66597 is not set +# CONFIG_USB_GADGET_PXA_U2O is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +# CONFIG_USB_ZERO_HNPTEST is not set +# CONFIG_USB_AUDIO is not set +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +# CONFIG_USB_ETH_EEM is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_ISP1301_OMAP is not set +# CONFIG_USB_ULPI is not set +CONFIG_TWL4030_USB=y +CONFIG_TWL6030_USB=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_UNSAFE_RESUME=y +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=y +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +CONFIG_MMC_OMAP=y +CONFIG_MMC_OMAP_HS=y +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_NFC_DEVICES is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_TWL92330=y +CONFIG_RTC_DRV_TWL4030=y +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set +CONFIG_CLKDEV_LOOKUP=y +# CONFIG_HWSPINLOCK is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_FS_POSIX_ACL=y +CONFIG_JFFS2_FS_SECURITY=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +CONFIG_JFFS2_RUBIN=y +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_XATTR is not set +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFS_USE_NEW_IDMAPPER is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_SCHED_DEBUG=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_PROVE_LOCKING=y +# CONFIG_PROVE_RCU is not set +# CONFIG_SPARSE_RCU_POINTER is not set +CONFIG_LOCKDEP=y +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_LOCKDEP is not set +CONFIG_TRACE_IRQFLAGS=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_RING_BUFFER_ALLOW_SWAP=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_KPROBE_EVENT=y +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_LL=y +CONFIG_EARLY_PRINTK=y +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_OC_ETM is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_NETWORK is not set +# CONFIG_SECURITY_PATH is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_IMA is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=m +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_OMAP_SHAM is not set +# CONFIG_CRYPTO_DEV_OMAP_AES is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +CONFIG_CRC7=y +CONFIG_LIBCRC32C=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y +CONFIG_AVERAGE=y diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 88bd6f7705f..11e99c3834e 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -15,6 +15,7 @@ #include <linux/input/matrix_keypad.h> #include <linux/spi/spi.h> #include <linux/wl12xx.h> +#include <linux/spi/tsc2005.h> #include <linux/i2c.h> #include <linux/i2c/twl.h> #include <linux/clk.h> @@ -54,6 +55,9 @@ #define RX51_FMTX_RESET_GPIO 163 #define RX51_FMTX_IRQ 53 +#define RX51_TSC2005_RESET_GPIO 104 +#define RX51_TSC2005_IRQ_GPIO 100 + #define RX51_USB_TRANSCEIVER_RST_GPIO 67 /* list all spi devices here */ @@ -64,6 +68,7 @@ enum { }; static struct wl12xx_platform_data wl1251_pdata; +static struct tsc2005_platform_data tsc2005_pdata; #if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE) static struct tsl2563_platform_data rx51_tsl2563_platform_data = { @@ -107,10 +112,10 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = { .modalias = "tsc2005", .bus_num = 1, .chip_select = 0, - /* .irq = OMAP_GPIO_IRQ(RX51_TSC2005_IRQ_GPIO),*/ + .irq = OMAP_GPIO_IRQ(RX51_TSC2005_IRQ_GPIO), .max_speed_hz = 6000000, .controller_data = &tsc2005_mcspi_config, - /* .platform_data = &tsc2005_config,*/ + .platform_data = &tsc2005_pdata, }, }; @@ -183,7 +188,7 @@ static struct gpio_keys_button rx51_gpio_keys[] = { .type = EV_SW, .code = SW_KEYPAD_SLIDE, .gpio = RX51_GPIO_KEYPAD_SLIDE, - .active_low = 1, + .active_low = 0, .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT, }, { .desc = "Proximity Sensor", @@ -902,6 +907,42 @@ static struct omap_onenand_platform_data board_onenand_data[] = { }; #endif +static struct tsc2005_platform_data tsc2005_pdata = { + .ts_pressure_max = 2048, + .ts_pressure_fudge = 2, + .ts_x_max = 4096, + .ts_x_fudge = 4, + .ts_y_max = 4096, + .ts_y_fudge = 7, + .ts_x_plate_ohm = 280, + .esd_timeout_ms = 8000, +}; + +static void rx51_tsc2005_set_reset(bool enable) +{ + gpio_set_value(RX51_TSC2005_RESET_GPIO, enable); +} + +static void __init rx51_init_tsc2005(void) +{ + int r; + + r = gpio_request(RX51_TSC2005_IRQ_GPIO, "tsc2005 IRQ"); + if (r >= 0) + gpio_direction_input(RX51_TSC2005_IRQ_GPIO); + else + printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 IRQ"); + + r = gpio_request(RX51_TSC2005_RESET_GPIO, "tsc2005 reset"); + if (r >= 0) { + gpio_direction_output(RX51_TSC2005_RESET_GPIO, 1); + tsc2005_pdata.set_reset = rx51_tsc2005_set_reset; + } else { + printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 reset"); + tsc2005_pdata.esd_timeout_ms = 0; + } +} + #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) static struct omap_smc91x_platform_data board_smc91x_data = { @@ -978,6 +1019,7 @@ void __init rx51_peripherals_init(void) rx51_add_gpio_keys(); rx51_init_wl1251(); rx51_init_si4713(); + rx51_init_tsc2005(); spi_register_board_info(rx51_peripherals_spi_board_info, ARRAY_SIZE(rx51_peripherals_spi_board_info)); diff --git a/arch/arm/mach-omap2/board-rx51-video.c b/arch/arm/mach-omap2/board-rx51-video.c index 2c1289bd5e6..ddba833ad3a 100644 --- a/arch/arm/mach-omap2/board-rx51-video.c +++ b/arch/arm/mach-omap2/board-rx51-video.c @@ -14,6 +14,7 @@ #include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/mm.h> +#include <linux/pvr.h> #include <asm/mach-types.h> #include <video/omapdss.h> #include <plat/vram.h> @@ -66,6 +67,22 @@ static struct omap_dss_board_info rx51_dss_board_info = { .default_device = &rx51_lcd_device, }; +static struct sgx_platform_data rx51_sgx_data = { + .fclock_max = 110666666, +}; + +static struct platform_device rx51_sgx_device = { + .name = "pvrsrvkm", + .id = -1, + .dev = { + .platform_data = &rx51_sgx_data, + }, +}; + +static struct platform_device *rx51_video_devices[] __initdata = { + &rx51_sgx_device, +}; + static int __init rx51_video_init(void) { if (!machine_is_nokia_rx51()) @@ -83,6 +100,8 @@ static int __init rx51_video_init(void) } omap_display_init(&rx51_dss_board_info); + platform_add_devices(rx51_video_devices, + ARRAY_SIZE(rx51_video_devices)); return 0; } diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c index b0471bb2d47..4046b3f28e0 100644 --- a/arch/arm/plat-omap/omap-pm-noop.c +++ b/arch/arm/plat-omap/omap-pm-noop.c @@ -87,6 +87,7 @@ int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r) return 0; } +EXPORT_SYMBOL(omap_pm_set_min_bus_tput); int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev, long t) diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile index cc9277885dd..bd7fc6683d8 100644 --- a/drivers/gpu/Makefile +++ b/drivers/gpu/Makefile @@ -1 +1 @@ -obj-y += drm/ vga/ stub/ +obj-y += drm/ vga/ stub/ pvr/ diff --git a/drivers/gpu/pvr/COPYING b/drivers/gpu/pvr/COPYING new file mode 100644 index 00000000000..80dd76b2624 --- /dev/null +++ b/drivers/gpu/pvr/COPYING @@ -0,0 +1,351 @@ + +This software is Copyright (C) 2008 Imagination Technologies Ltd. + All rights reserved. + +You may use, distribute and copy this software under the terms of +GNU General Public License version 2, which is displayed below. + +------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +------------------------------------------------------------------------- + diff --git a/drivers/gpu/pvr/Kconfig b/drivers/gpu/pvr/Kconfig new file mode 100644 index 00000000000..949911c86f1 --- /dev/null +++ b/drivers/gpu/pvr/Kconfig @@ -0,0 +1,55 @@ +menuconfig PVR + tristate "PowerVR Services" + depends on OMAP2_DSS + +if PVR + +choice + prompt "Build type" + default PVR_RELEASE +config PVR_RELEASE + bool "Release" +config PVR_DEBUG + bool "Debug" +config PVR_TIMING + bool "Timing" +endchoice + +config PVR_DEBUG_EXTRA + bool "Extra debugging info" + depends on PVR_DEBUG + help + This enables extra debugging facilities on top of what you + get with setting debug build type above. This effectively + changes the driver's ABI, so the user space clients using + the driver need to be built in debug mode as well. + +config PVR_DEBUG_PDUMP + tristate "PDUMP debug support" + depends on PVR + default n + +config PVR_EDM_DEBUG + depends on PVR + bool "Enable EDM trace" + default n + help + EDM trace helps to track down some HW recovery events. You _must_ + also enabled EDM (PVRSRV_USSE_EDM_STATUS_DEBUG) in the userland + libraries otherwise the drivers won't start + +config PVR_NO_HARDWARE + bool + default n + +config PVR_FORCE_CLOCKS_ON + bool "Force clocks on" + depends on !PVR_NO_HARDWARE + default n + +config PVR_EXAMPLES + tristate "Example code" + default n + +endif + diff --git a/drivers/gpu/pvr/Makefile b/drivers/gpu/pvr/Makefile new file mode 100644 index 00000000000..48e37d0b694 --- /dev/null +++ b/drivers/gpu/pvr/Makefile @@ -0,0 +1,44 @@ +obj-$(CONFIG_PVR) += omaplfb.o pvrsrvkm.o + +omaplfb-objs := omaplfb_displayclass.o omaplfb_linux.o + +pvrsrvkm-objs := osfunc.o mmap.o module.o pdump.o proc.o \ + pvr_bridge_k.o mm.o event.o \ + buffer_manager.o devicemem.o deviceclass.o \ + handle.o hash.o pvrsrv.o queue.o ra.o \ + resman.o power.o mem.o bridged_pvr_bridge.o \ + sgxinit.o sgxreset.o sgxutils.o sgxkick.o \ + sgxtransfer.o mmu.o pb.o perproc.o sysconfig.o \ + sysutils.o osperproc.o bridged_support.o \ + bridged_sgx_bridge.o sgxpower.o pdump_common.o \ + pvr_events.o + +pvrsrvkm-objs-$(CONFIG_PVR_DEBUG) += pvr_debug.o +pvrsrvkm-objs-$(CONFIG_PVR_TIMING) += pvr_debug.o + +pvrsrvkm-objs += $(pvrsrvkm-objs-y) $(pvrsrvkm-objs-m) + +obj-$(CONFIG_PVR_EXAMPLES) += bc_example.o + +bc_example-objs := bufferclass_example.o bufferclass_example_linux.o \ + bufferclass_example_private.o + + +obj-$(CONFIG_PVR_DEBUG_PDUMP) += pvrdbg.o + +pvrdbg-objs := tools/main.o tools/dbgdriv.o tools/ioctl.o \ + tools/hostfunc.o tools/hotkey.o + + +DATE := $(shell date "+%a %B %d %Z %Y" ) +CBUILD := -O2 \ + -DPVR_BUILD_DIR="\"$(PVR_BUILD_DIR)\"" \ + -DPVR_BUILD_DATE="\"$(DATE)\"" + +ccflags-y += $(CBUILD) -include $(srctree)/$(src)/pvrconfig.h + +ccflags-$(CONFIG_PVR_DEBUG_PDUMP) += -I $(srctree)/$(src)/tools \ + -I $(srctree)/$(src) +ccflags-y += $(ccflags-m) + + diff --git a/drivers/gpu/pvr/README b/drivers/gpu/pvr/README new file mode 100644 index 00000000000..7da0e623511 --- /dev/null +++ b/drivers/gpu/pvr/README @@ -0,0 +1,27 @@ + +SGX Embedded Systems DDK for Linux kernel. +Copyright (C) 2008 Imagination Technologies Ltd. All rights reserved. +====================================================================== + + +About +------------------------------------------- + +This is the Imagination Technologies SGX DDK for the Linux kernel. + + +License +------------------------------------------- + +You may use, distribute and copy this software under the terms of +GNU General Public License version 2. + +The full GNU General Public License version 2 is included in this +distribution in the file called "COPYING". + + +Contact information: +------------------------------------------- + +Imagination Technologies Ltd. <gpl-support@imgtec.com> +Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK diff --git a/drivers/gpu/pvr/bridged_pvr_bridge.c b/drivers/gpu/pvr/bridged_pvr_bridge.c new file mode 100644 index 00000000000..740981675ce --- /dev/null +++ b/drivers/gpu/pvr/bridged_pvr_bridge.c @@ -0,0 +1,3341 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <stddef.h> + +#include "img_defs.h" +#include "services.h" +#include "pvr_bridge_km.h" +#include "pvr_debug.h" +#include "ra.h" +#include "pvr_bridge.h" +#include "sgx_bridge.h" +#include "perproc.h" +#include "device.h" +#include "buffer_manager.h" + +#include "pdump_km.h" +#include "syscommon.h" + +#include "bridged_pvr_bridge.h" +#include "bridged_sgx_bridge.h" +#include "env_data.h" + +#include "mmap.h" + +#include <linux/kernel.h> +#include <linux/pagemap.h> /* for cache flush */ +#include <linux/mm.h> +#include <linux/sched.h> + +struct PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY + g_BridgeDispatchTable[BRIDGE_DISPATCH_TABLE_ENTRY_COUNT]; + +#if defined(DEBUG_BRIDGE_KM) +struct PVRSRV_BRIDGE_GLOBAL_STATS g_BridgeGlobalStats; +#endif + +static IMG_BOOL abSharedDeviceMemHeap[PVRSRV_MAX_CLIENT_HEAPS]; +static IMG_BOOL *pbSharedDeviceMemHeap = abSharedDeviceMemHeap; + +#if defined(DEBUG_BRIDGE_KM) +enum PVRSRV_ERROR +CopyFromUserWrapper(struct PVRSRV_PER_PROCESS_DATA *pProcData, + u32 ui32BridgeID, void *pvDest, void __user *pvSrc, + u32 ui32Size) +{ + g_BridgeDispatchTable[ui32BridgeID].ui32CopyFromUserTotalBytes += + ui32Size; + g_BridgeGlobalStats.ui32TotalCopyFromUserBytes += ui32Size; + return OSCopyFromUser(pProcData, pvDest, pvSrc, ui32Size); +} + +enum PVRSRV_ERROR CopyToUserWrapper(struct PVRSRV_PER_PROCESS_DATA *pProcData, + u32 ui32BridgeID, void __user *pvDest, void *pvSrc, + u32 ui32Size) +{ + g_BridgeDispatchTable[ui32BridgeID].ui32CopyToUserTotalBytes += + ui32Size; + g_BridgeGlobalStats.ui32TotalCopyToUserBytes += ui32Size; + return OSCopyToUser(pProcData, pvDest, pvSrc, ui32Size); +} +#endif + +static int PVRSRVEnumerateDevicesBW(u32 ui32BridgeID, void *psBridgeIn, + struct PVRSRV_BRIDGE_OUT_ENUMDEVICE *psEnumDeviceOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_ENUM_DEVICES); + + PVR_UNREFERENCED_PARAMETER(psPerProc); + PVR_UNREFERENCED_PARAMETER(psBridgeIn); + + psEnumDeviceOUT->eError = + PVRSRVEnumerateDevicesKM(&psEnumDeviceOUT->ui32NumDevices, + psEnumDeviceOUT->asDeviceIdentifier); + + return 0; +} + +static int PVRSRVAcquireDeviceDataBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_ACQUIRE_DEVICEINFO *psAcquireDevInfoIN, + struct PVRSRV_BRIDGE_OUT_ACQUIRE_DEVICEINFO *psAcquireDevInfoOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_ACQUIRE_DEVICEINFO); + + psAcquireDevInfoOUT->eError = + PVRSRVAcquireDeviceDataKM(psAcquireDevInfoIN->uiDevIndex, + psAcquireDevInfoIN->eDeviceType, + &hDevCookieInt); + if (psAcquireDevInfoOUT->eError != PVRSRV_OK) + return 0; + + psAcquireDevInfoOUT->eError = PVRSRVAllocHandle(psPerProc->psHandleBase, + &psAcquireDevInfoOUT->hDevCookie, + hDevCookieInt, + PVRSRV_HANDLE_TYPE_DEV_NODE, + PVRSRV_HANDLE_ALLOC_FLAG_SHARED); + + return 0; +} + +static int PVRSRVCreateDeviceMemContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_CREATE_DEVMEMCONTEXT *psCreateDevMemContextIN, + struct PVRSRV_BRIDGE_OUT_CREATE_DEVMEMCONTEXT *psCreateDevMemContextOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *hDevMemContextInt; + u32 i; + IMG_BOOL bCreated; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_CREATE_DEVMEMCONTEXT); + + NEW_HANDLE_BATCH_OR_ERROR(psCreateDevMemContextOUT->eError, psPerProc, + PVRSRV_MAX_CLIENT_HEAPS + 1); + + psCreateDevMemContextOUT->eError = PVRSRVLookupHandle( + psPerProc->psHandleBase, &hDevCookieInt, + psCreateDevMemContextIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psCreateDevMemContextOUT->eError != PVRSRV_OK) + return 0; + + psCreateDevMemContextOUT->eError = PVRSRVCreateDeviceMemContextKM( + hDevCookieInt, psPerProc, + &hDevMemContextInt, + &psCreateDevMemContextOUT->ui32ClientHeapCount, + &psCreateDevMemContextOUT->sHeapInfo[0], + &bCreated, pbSharedDeviceMemHeap); + + if (psCreateDevMemContextOUT->eError != PVRSRV_OK) + return 0; + + if (bCreated) { + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psCreateDevMemContextOUT->hDevMemContext, + hDevMemContextInt, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + } else { + psCreateDevMemContextOUT->eError = + PVRSRVFindHandle(psPerProc->psHandleBase, + &psCreateDevMemContextOUT->hDevMemContext, + hDevMemContextInt, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT); + if (psCreateDevMemContextOUT->eError != PVRSRV_OK) + return 0; + } + + for (i = 0; i < psCreateDevMemContextOUT->ui32ClientHeapCount; i++) { + void *hDevMemHeapExt; + + if (abSharedDeviceMemHeap[i]) { + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &hDevMemHeapExt, + psCreateDevMemContextOUT-> + sHeapInfo[i].hDevMemHeap, + PVRSRV_HANDLE_TYPE_DEV_MEM_HEAP, + PVRSRV_HANDLE_ALLOC_FLAG_SHARED); + } else { + if (bCreated) { + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &hDevMemHeapExt, + psCreateDevMemContextOUT->sHeapInfo[i]. + hDevMemHeap, + PVRSRV_HANDLE_TYPE_DEV_MEM_HEAP, + PVRSRV_HANDLE_ALLOC_FLAG_NONE, + psCreateDevMemContextOUT-> + hDevMemContext); + } else { + psCreateDevMemContextOUT->eError = + PVRSRVFindHandle( + psPerProc->psHandleBase, + &hDevMemHeapExt, + psCreateDevMemContextOUT-> + sHeapInfo[i].hDevMemHeap, + PVRSRV_HANDLE_TYPE_DEV_MEM_HEAP); + if (psCreateDevMemContextOUT->eError != + PVRSRV_OK) + return 0; + } + } + psCreateDevMemContextOUT->sHeapInfo[i].hDevMemHeap = + hDevMemHeapExt; + } + + COMMIT_HANDLE_BATCH_OR_ERROR(psCreateDevMemContextOUT->eError, + psPerProc); + + return 0; +} + +static int PVRSRVDestroyDeviceMemContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_DESTROY_DEVMEMCONTEXT *psDestroyDevMemContextIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *hDevMemContextInt; + IMG_BOOL bDestroyed; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_DESTROY_DEVMEMCONTEXT); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psDestroyDevMemContextIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevMemContextInt, + psDestroyDevMemContextIN->hDevMemContext, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVDestroyDeviceMemContextKM(hDevCookieInt, + hDevMemContextInt, &bDestroyed); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + if (bDestroyed) + psRetOUT->eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, + psDestroyDevMemContextIN-> + hDevMemContext, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT); + + return 0; +} + +static int PVRSRVGetDeviceMemHeapInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GET_DEVMEM_HEAPINFO *psGetDevMemHeapInfoIN, + struct PVRSRV_BRIDGE_OUT_GET_DEVMEM_HEAPINFO *psGetDevMemHeapInfoOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *hDevMemContextInt; + u32 i; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_GET_DEVMEM_HEAPINFO); + + NEW_HANDLE_BATCH_OR_ERROR(psGetDevMemHeapInfoOUT->eError, psPerProc, + PVRSRV_MAX_CLIENT_HEAPS); + + psGetDevMemHeapInfoOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psGetDevMemHeapInfoIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psGetDevMemHeapInfoOUT->eError != PVRSRV_OK) + return 0; + + psGetDevMemHeapInfoOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemContextInt, + psGetDevMemHeapInfoIN->hDevMemContext, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT); + + if (psGetDevMemHeapInfoOUT->eError != PVRSRV_OK) + return 0; + + psGetDevMemHeapInfoOUT->eError = + PVRSRVGetDeviceMemHeapInfoKM(hDevCookieInt, + hDevMemContextInt, + &psGetDevMemHeapInfoOUT->ui32ClientHeapCount, + &psGetDevMemHeapInfoOUT->sHeapInfo[0], + pbSharedDeviceMemHeap); + + if (psGetDevMemHeapInfoOUT->eError != PVRSRV_OK) + return 0; + + for (i = 0; i < psGetDevMemHeapInfoOUT->ui32ClientHeapCount; i++) { + void *hDevMemHeapExt; + if (abSharedDeviceMemHeap[i]) { + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &hDevMemHeapExt, + psGetDevMemHeapInfoOUT->sHeapInfo[i].hDevMemHeap, + PVRSRV_HANDLE_TYPE_DEV_MEM_HEAP, + PVRSRV_HANDLE_ALLOC_FLAG_SHARED); + } else { + psGetDevMemHeapInfoOUT->eError = + PVRSRVFindHandle(psPerProc->psHandleBase, + &hDevMemHeapExt, + psGetDevMemHeapInfoOUT-> + sHeapInfo[i].hDevMemHeap, + PVRSRV_HANDLE_TYPE_DEV_MEM_HEAP); + if (psGetDevMemHeapInfoOUT->eError != PVRSRV_OK) + return 0; + } + psGetDevMemHeapInfoOUT->sHeapInfo[i].hDevMemHeap = + hDevMemHeapExt; + } + + COMMIT_HANDLE_BATCH_OR_ERROR(psGetDevMemHeapInfoOUT->eError, psPerProc); + + return 0; +} + +static int PVRSRVAllocDeviceMemBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_ALLOCDEVICEMEM *psAllocDeviceMemIN, + struct PVRSRV_BRIDGE_OUT_ALLOCDEVICEMEM *psAllocDeviceMemOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo; + void *hDevCookieInt; + void *hDevMemHeapInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_ALLOC_DEVICEMEM); + + NEW_HANDLE_BATCH_OR_ERROR(psAllocDeviceMemOUT->eError, psPerProc, 2); + + psAllocDeviceMemOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psAllocDeviceMemIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psAllocDeviceMemOUT->eError != PVRSRV_OK) + return 0; + + psAllocDeviceMemOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemHeapInt, + psAllocDeviceMemIN->hDevMemHeap, + PVRSRV_HANDLE_TYPE_DEV_MEM_HEAP); + + if (psAllocDeviceMemOUT->eError != PVRSRV_OK) + return 0; + + psAllocDeviceMemOUT->eError = + PVRSRVAllocDeviceMemKM(hDevCookieInt, psPerProc, hDevMemHeapInt, + psAllocDeviceMemIN->ui32Attribs, + psAllocDeviceMemIN->ui32Size, + psAllocDeviceMemIN->ui32Alignment, + &psMemInfo); + + if (psAllocDeviceMemOUT->eError != PVRSRV_OK) + return 0; + + OSMemSet(&psAllocDeviceMemOUT->sClientMemInfo, 0, + sizeof(psAllocDeviceMemOUT->sClientMemInfo)); + + psAllocDeviceMemOUT->sClientMemInfo.pvLinAddrKM = + psMemInfo->pvLinAddrKM; + + psAllocDeviceMemOUT->sClientMemInfo.pvLinAddr = NULL; + psAllocDeviceMemOUT->sClientMemInfo.sDevVAddr = psMemInfo->sDevVAddr; + psAllocDeviceMemOUT->sClientMemInfo.ui32Flags = psMemInfo->ui32Flags; + psAllocDeviceMemOUT->sClientMemInfo.ui32AllocSize = + psMemInfo->ui32AllocSize; + psAllocDeviceMemOUT->sClientMemInfo.hMappingInfo = + psMemInfo->sMemBlk.hOSMemHandle; + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psAllocDeviceMemOUT->sClientMemInfo.hKernelMemInfo, + psMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + + if (psAllocDeviceMemIN->ui32Attribs & PVRSRV_MEM_NO_SYNCOBJ) { + OSMemSet(&psAllocDeviceMemOUT->sClientSyncInfo, 0, + sizeof(struct PVRSRV_CLIENT_SYNC_INFO)); + psAllocDeviceMemOUT->sClientMemInfo.psClientSyncInfo = NULL; + psAllocDeviceMemOUT->psKernelSyncInfo = NULL; + } else { + + psAllocDeviceMemOUT->psKernelSyncInfo = + psMemInfo->psKernelSyncInfo; + + psAllocDeviceMemOUT->sClientSyncInfo.psSyncData = + psMemInfo->psKernelSyncInfo->psSyncData; + psAllocDeviceMemOUT->sClientSyncInfo.sWriteOpsCompleteDevVAddr = + psMemInfo->psKernelSyncInfo->sWriteOpsCompleteDevVAddr; + psAllocDeviceMemOUT->sClientSyncInfo.sReadOpsCompleteDevVAddr = + psMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + + psAllocDeviceMemOUT->sClientSyncInfo.hMappingInfo = + psMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk. + hOSMemHandle; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psAllocDeviceMemOUT->sClientSyncInfo. + hKernelSyncInfo, + psMemInfo->psKernelSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE, + psAllocDeviceMemOUT->sClientMemInfo. + hKernelMemInfo); + + psAllocDeviceMemOUT->sClientMemInfo.psClientSyncInfo = + &psAllocDeviceMemOUT->sClientSyncInfo; + + } + + COMMIT_HANDLE_BATCH_OR_ERROR(psAllocDeviceMemOUT->eError, psPerProc); + + return 0; +} + + +static int PVRSRVFreeDeviceMemBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_FREEDEVICEMEM *psFreeDeviceMemIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *pvKernelMemInfo; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_FREE_DEVICEMEM); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psFreeDeviceMemIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &pvKernelMemInfo, + psFreeDeviceMemIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psKernelMemInfo = (struct PVRSRV_KERNEL_MEM_INFO *)pvKernelMemInfo; + if (psKernelMemInfo->ui32RefCount != 1) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVFreeDeviceMemBW: " + "mappings are open in other processes"); + psRetOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + psRetOUT->eError = PVRSRVFreeDeviceMemKM(hDevCookieInt, + pvKernelMemInfo); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, + psFreeDeviceMemIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + + return 0; +} + +static int PVRSRVExportDeviceMemBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_EXPORTDEVICEMEM *psExportDeviceMemIN, + struct PVRSRV_BRIDGE_OUT_EXPORTDEVICEMEM *psExportDeviceMemOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_EXPORT_DEVICEMEM); + + psExportDeviceMemOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psExportDeviceMemIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psExportDeviceMemOUT->eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVExportDeviceMemBW: can't find devcookie"); + return 0; + } + + psExportDeviceMemOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + (void **)&psKernelMemInfo, + psExportDeviceMemIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + + if (psExportDeviceMemOUT->eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVExportDeviceMemBW: can't find kernel meminfo"); + return 0; + } + + psExportDeviceMemOUT->eError = + PVRSRVFindHandle(KERNEL_HANDLE_BASE, + &psExportDeviceMemOUT->hMemInfo, + psKernelMemInfo, PVRSRV_HANDLE_TYPE_MEM_INFO); + if (psExportDeviceMemOUT->eError == PVRSRV_OK) { + PVR_DPF(PVR_DBG_MESSAGE, "PVRSRVExportDeviceMemBW: " + "allocation is already exported"); + return 0; + } + + psExportDeviceMemOUT->eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE, + &psExportDeviceMemOUT->hMemInfo, + psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + if (psExportDeviceMemOUT->eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVExportDeviceMemBW: " + "failed to allocate handle from global handle list"); + return 0; + } + + psKernelMemInfo->ui32Flags |= PVRSRV_MEM_EXPORTED; + + return 0; +} + +static int PVRSRVMapDeviceMemoryBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_MAP_DEV_MEMORY *psMapDevMemIN, + struct PVRSRV_BRIDGE_OUT_MAP_DEV_MEMORY *psMapDevMemOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct PVRSRV_KERNEL_MEM_INFO *psSrcKernelMemInfo = NULL; + struct PVRSRV_KERNEL_MEM_INFO *psDstKernelMemInfo = NULL; + void *hDstDevMemHeap = NULL; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_MAP_DEV_MEMORY); + + NEW_HANDLE_BATCH_OR_ERROR(psMapDevMemOUT->eError, psPerProc, 2); + + psMapDevMemOUT->eError = PVRSRVLookupHandle(KERNEL_HANDLE_BASE, + (void **)&psSrcKernelMemInfo, + psMapDevMemIN->hKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (psMapDevMemOUT->eError != PVRSRV_OK) + return 0; + + psMapDevMemOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDstDevMemHeap, + psMapDevMemIN->hDstDevMemHeap, + PVRSRV_HANDLE_TYPE_DEV_MEM_HEAP); + if (psMapDevMemOUT->eError != PVRSRV_OK) + return 0; + + psMapDevMemOUT->eError = PVRSRVMapDeviceMemoryKM(psPerProc, + psSrcKernelMemInfo, + hDstDevMemHeap, + &psDstKernelMemInfo); + if (psMapDevMemOUT->eError != PVRSRV_OK) + return 0; + + OSMemSet(&psMapDevMemOUT->sDstClientMemInfo, 0, + sizeof(psMapDevMemOUT->sDstClientMemInfo)); + OSMemSet(&psMapDevMemOUT->sDstClientSyncInfo, 0, + sizeof(psMapDevMemOUT->sDstClientSyncInfo)); + + psMapDevMemOUT->sDstClientMemInfo.pvLinAddrKM = + psDstKernelMemInfo->pvLinAddrKM; + + psMapDevMemOUT->sDstClientMemInfo.pvLinAddr = NULL; + psMapDevMemOUT->sDstClientMemInfo.sDevVAddr = + psDstKernelMemInfo->sDevVAddr; + psMapDevMemOUT->sDstClientMemInfo.ui32Flags = + psDstKernelMemInfo->ui32Flags; + psMapDevMemOUT->sDstClientMemInfo.ui32AllocSize = + psDstKernelMemInfo->ui32AllocSize; + psMapDevMemOUT->sDstClientMemInfo.hMappingInfo = + psDstKernelMemInfo->sMemBlk.hOSMemHandle; + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psMapDevMemOUT->sDstClientMemInfo.hKernelMemInfo, + psDstKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + psMapDevMemOUT->sDstClientSyncInfo.hKernelSyncInfo = NULL; + psMapDevMemOUT->psDstKernelSyncInfo = NULL; + + if (psDstKernelMemInfo->psKernelSyncInfo) { + psMapDevMemOUT->psDstKernelSyncInfo = + psDstKernelMemInfo->psKernelSyncInfo; + + psMapDevMemOUT->sDstClientSyncInfo.psSyncData = + psDstKernelMemInfo->psKernelSyncInfo->psSyncData; + psMapDevMemOUT->sDstClientSyncInfo.sWriteOpsCompleteDevVAddr = + psDstKernelMemInfo->psKernelSyncInfo-> + sWriteOpsCompleteDevVAddr; + psMapDevMemOUT->sDstClientSyncInfo.sReadOpsCompleteDevVAddr = + psDstKernelMemInfo->psKernelSyncInfo-> + sReadOpsCompleteDevVAddr; + + psMapDevMemOUT->sDstClientSyncInfo.hMappingInfo = + psDstKernelMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM-> + sMemBlk.hOSMemHandle; + + psMapDevMemOUT->sDstClientMemInfo.psClientSyncInfo = + &psMapDevMemOUT->sDstClientSyncInfo; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psMapDevMemOUT->sDstClientSyncInfo. + hKernelSyncInfo, + psDstKernelMemInfo->psKernelSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI, + psMapDevMemOUT->sDstClientMemInfo. + hKernelMemInfo); + } + + COMMIT_HANDLE_BATCH_OR_ERROR(psMapDevMemOUT->eError, psPerProc); + + return 0; +} + +static int PVRSRVUnmapDeviceMemoryBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_UNMAP_DEV_MEMORY *psUnmapDevMemIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo = NULL; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_UNMAP_DEV_MEMORY); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + (void **) &psKernelMemInfo, + psUnmapDevMemIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVUnmapDeviceMemoryKM(psKernelMemInfo); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, + psUnmapDevMemIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + + return 0; +} + +static int FlushCacheDRI(u32 ui32Type, u32 ui32Virt, u32 ui32Length) +{ + switch (ui32Type) { + case DRM_PVR2D_CFLUSH_FROM_GPU: + PVR_DPF(PVR_DBG_MESSAGE, + "DRM_PVR2D_CFLUSH_FROM_GPU 0x%08x, length 0x%08x\n", + ui32Virt, ui32Length); +#ifdef CONFIG_ARM + dmac_map_area((const void *)ui32Virt, ui32Length, DMA_FROM_DEVICE); +#endif + return 0; + case DRM_PVR2D_CFLUSH_TO_GPU: + PVR_DPF(PVR_DBG_MESSAGE, + "DRM_PVR2D_CFLUSH_TO_GPU 0x%08x, length 0x%08x\n", + ui32Virt, ui32Length); +#ifdef CONFIG_ARM + dmac_map_area((const void *)ui32Virt, ui32Length, DMA_TO_DEVICE); +#endif + return 0; + default: + PVR_DPF(PVR_DBG_ERROR, "Invalid cflush type 0x%x\n", + ui32Type); + return -EINVAL; + } + + return 0; +} + +static int PVRSRVCacheFlushDRIBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_CACHEFLUSHDRMFROMUSER *psCacheFlushIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct vm_area_struct *vma; + unsigned long start; + size_t len; + int type; + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_CACHE_FLUSH_DRM); + + start = psCacheFlushIN->ui32Virt; + len = psCacheFlushIN->ui32Length; + type = psCacheFlushIN->ui32Type; + + down_read(¤t->mm->mmap_sem); + vma = find_vma(current->mm, start); + if (vma == NULL || vma->vm_start > start || + vma->vm_end < start + len) + pr_err("PVR: %s: invalid address %08lx %zu %c\n", + __func__, start, len, + type == DRM_PVR2D_CFLUSH_TO_GPU ? 'c' : + type == DRM_PVR2D_CFLUSH_FROM_GPU ? 'i' : + '?'); + else + psRetOUT->eError = FlushCacheDRI(type, start, len); + + up_read(¤t->mm->mmap_sem); + + return 0; +} + +static int PVRSRVMapDeviceClassMemoryBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_MAP_DEVICECLASS_MEMORY *psMapDevClassMemIN, + struct PVRSRV_BRIDGE_OUT_MAP_DEVICECLASS_MEMORY *psMapDevClassMemOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo; + void *hOSMapInfo; + void *hDeviceClassBufferInt; + void *hDevMemContextInt; + enum PVRSRV_HANDLE_TYPE eHandleType; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_MAP_DEVICECLASS_MEMORY); + + NEW_HANDLE_BATCH_OR_ERROR(psMapDevClassMemOUT->eError, psPerProc, 2); + + psMapDevClassMemOUT->eError = + PVRSRVLookupHandleAnyType(psPerProc->psHandleBase, + &hDeviceClassBufferInt, &eHandleType, + psMapDevClassMemIN->hDeviceClassBuffer); + + if (psMapDevClassMemOUT->eError != PVRSRV_OK) + return 0; + + psMapDevClassMemOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemContextInt, + psMapDevClassMemIN->hDevMemContext, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT); + + if (psMapDevClassMemOUT->eError != PVRSRV_OK) + return 0; + + switch (eHandleType) { + case PVRSRV_HANDLE_TYPE_DISP_BUFFER: + case PVRSRV_HANDLE_TYPE_BUF_BUFFER: + break; + default: + psMapDevClassMemOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + psMapDevClassMemOUT->eError = + PVRSRVMapDeviceClassMemoryKM(psPerProc, hDevMemContextInt, + hDeviceClassBufferInt, &psMemInfo, &hOSMapInfo); + + if (psMapDevClassMemOUT->eError != PVRSRV_OK) + return 0; + + OSMemSet(&psMapDevClassMemOUT->sClientMemInfo, 0, + sizeof(psMapDevClassMemOUT->sClientMemInfo)); + OSMemSet(&psMapDevClassMemOUT->sClientSyncInfo, 0, + sizeof(psMapDevClassMemOUT->sClientSyncInfo)); + + psMapDevClassMemOUT->sClientMemInfo.pvLinAddrKM = + psMemInfo->pvLinAddrKM; + + psMapDevClassMemOUT->sClientMemInfo.pvLinAddr = NULL; + psMapDevClassMemOUT->sClientMemInfo.sDevVAddr = psMemInfo->sDevVAddr; + psMapDevClassMemOUT->sClientMemInfo.ui32Flags = psMemInfo->ui32Flags; + psMapDevClassMemOUT->sClientMemInfo.ui32AllocSize = + psMemInfo->ui32AllocSize; + psMapDevClassMemOUT->sClientMemInfo.hMappingInfo = + psMemInfo->sMemBlk.hOSMemHandle; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psMapDevClassMemOUT->sClientMemInfo.hKernelMemInfo, + psMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE, + psMapDevClassMemIN->hDeviceClassBuffer); + + psMapDevClassMemOUT->sClientSyncInfo.hKernelSyncInfo = NULL; + psMapDevClassMemOUT->psKernelSyncInfo = NULL; + + if (psMemInfo->psKernelSyncInfo) { + psMapDevClassMemOUT->psKernelSyncInfo = + psMemInfo->psKernelSyncInfo; + + psMapDevClassMemOUT->sClientSyncInfo.psSyncData = + psMemInfo->psKernelSyncInfo->psSyncData; + psMapDevClassMemOUT->sClientSyncInfo.sWriteOpsCompleteDevVAddr = + psMemInfo->psKernelSyncInfo->sWriteOpsCompleteDevVAddr; + psMapDevClassMemOUT->sClientSyncInfo.sReadOpsCompleteDevVAddr = + psMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + + psMapDevClassMemOUT->sClientSyncInfo.hMappingInfo = + psMemInfo->psKernelSyncInfo-> + psSyncDataMemInfoKM->sMemBlk.hOSMemHandle; + + psMapDevClassMemOUT->sClientMemInfo.psClientSyncInfo = + &psMapDevClassMemOUT->sClientSyncInfo; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psMapDevClassMemOUT->sClientSyncInfo. + hKernelSyncInfo, + psMemInfo->psKernelSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI, + psMapDevClassMemOUT->sClientMemInfo. + hKernelMemInfo); + } + + COMMIT_HANDLE_BATCH_OR_ERROR(psMapDevClassMemOUT->eError, psPerProc); + + return 0; +} + +static int PVRSRVUnmapDeviceClassMemoryBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_UNMAP_DEVICECLASS_MEMORY *psUnmapDevClassMemIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvKernelMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_UNMAP_DEVICECLASS_MEMORY); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &pvKernelMemInfo, + psUnmapDevClassMemIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVUnmapDeviceClassMemoryKM(pvKernelMemInfo); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVReleaseHandle(psPerProc->psHandleBase, + psUnmapDevClassMemIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + + return 0; +} + +static int PVRSRVWrapExtMemoryBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_WRAP_EXT_MEMORY *psWrapExtMemIN, + struct PVRSRV_BRIDGE_OUT_WRAP_EXT_MEMORY *psWrapExtMemOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *hDevMemContextInt; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo; + u32 ui32PageTableSize = 0; + struct IMG_SYS_PHYADDR *psSysPAddr = NULL; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_WRAP_EXT_MEMORY); + + NEW_HANDLE_BATCH_OR_ERROR(psWrapExtMemOUT->eError, psPerProc, 2); + + psWrapExtMemOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psWrapExtMemIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psWrapExtMemOUT->eError != PVRSRV_OK) + return 0; + + psWrapExtMemOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemContextInt, + psWrapExtMemIN->hDevMemContext, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT); + + if (psWrapExtMemOUT->eError != PVRSRV_OK) + return 0; + + if (psWrapExtMemIN->ui32NumPageTableEntries) { + ui32PageTableSize = psWrapExtMemIN->ui32NumPageTableEntries + * sizeof(struct IMG_SYS_PHYADDR); + + ASSIGN_AND_EXIT_ON_ERROR(psWrapExtMemOUT->eError, + OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + ui32PageTableSize, + (void **)&psSysPAddr, NULL)); + + if (CopyFromUserWrapper(psPerProc, ui32BridgeID, psSysPAddr, + psWrapExtMemIN->psSysPAddr, + ui32PageTableSize) != PVRSRV_OK) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32PageTableSize, + (void *) psSysPAddr, NULL); + return -EFAULT; + } + } + + psWrapExtMemOUT->eError = PVRSRVWrapExtMemoryKM(hDevCookieInt, + psPerProc, hDevMemContextInt, + psWrapExtMemIN->ui32ByteSize, + psWrapExtMemIN->ui32PageOffset, + psWrapExtMemIN->bPhysContig, + psSysPAddr, psWrapExtMemIN->pvLinAddr, + &psMemInfo); + if (psWrapExtMemIN->ui32NumPageTableEntries) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32PageTableSize, + (void *)psSysPAddr, NULL); + if (psWrapExtMemOUT->eError != PVRSRV_OK) + return 0; + + psWrapExtMemOUT->sClientMemInfo.pvLinAddrKM = psMemInfo->pvLinAddrKM; + + psWrapExtMemOUT->sClientMemInfo.pvLinAddr = NULL; + psWrapExtMemOUT->sClientMemInfo.sDevVAddr = psMemInfo->sDevVAddr; + psWrapExtMemOUT->sClientMemInfo.ui32Flags = psMemInfo->ui32Flags; + psWrapExtMemOUT->sClientMemInfo.ui32AllocSize = + psMemInfo->ui32AllocSize; + psWrapExtMemOUT->sClientMemInfo.hMappingInfo = + psMemInfo->sMemBlk.hOSMemHandle; + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psWrapExtMemOUT->sClientMemInfo.hKernelMemInfo, + psMemInfo, PVRSRV_HANDLE_TYPE_MEM_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + + psWrapExtMemOUT->sClientSyncInfo.psSyncData = + psMemInfo->psKernelSyncInfo->psSyncData; + psWrapExtMemOUT->sClientSyncInfo.sWriteOpsCompleteDevVAddr = + psMemInfo->psKernelSyncInfo->sWriteOpsCompleteDevVAddr; + psWrapExtMemOUT->sClientSyncInfo.sReadOpsCompleteDevVAddr = + psMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + + psWrapExtMemOUT->sClientSyncInfo.hMappingInfo = + psMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk. + hOSMemHandle; + + psWrapExtMemOUT->sClientMemInfo.psClientSyncInfo = + &psWrapExtMemOUT->sClientSyncInfo; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psWrapExtMemOUT->sClientSyncInfo. + hKernelSyncInfo, + (void *)psMemInfo->psKernelSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI, + psWrapExtMemOUT->sClientMemInfo.hKernelMemInfo); + + COMMIT_HANDLE_BATCH_OR_ERROR(psWrapExtMemOUT->eError, psPerProc); + + return 0; +} + +static int PVRSRVUnwrapExtMemoryBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_UNWRAP_EXT_MEMORY *psUnwrapExtMemIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_UNWRAP_EXT_MEMORY); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvMemInfo, psUnwrapExtMemIN->hKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVUnwrapExtMemoryKM((struct PVRSRV_KERNEL_MEM_INFO *)pvMemInfo); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, + psUnwrapExtMemIN->hKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + + return 0; +} + +static int PVRSRVGetFreeDeviceMemBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GETFREEDEVICEMEM *psGetFreeDeviceMemIN, + struct PVRSRV_BRIDGE_OUT_GETFREEDEVICEMEM *psGetFreeDeviceMemOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_GETFREE_DEVICEMEM); + + PVR_UNREFERENCED_PARAMETER(psPerProc); + + psGetFreeDeviceMemOUT->eError = + PVRSRVGetFreeDeviceMemKM(psGetFreeDeviceMemIN->ui32Flags, + &psGetFreeDeviceMemOUT->ui32Total, + &psGetFreeDeviceMemOUT->ui32Free, + &psGetFreeDeviceMemOUT->ui32LargestBlock); + + return 0; +} + +static int PVRMMapOSMemHandleToMMapDataBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_MHANDLE_TO_MMAP_DATA *psMMapDataIN, + struct PVRSRV_BRIDGE_OUT_MHANDLE_TO_MMAP_DATA *psMMapDataOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_MHANDLE_TO_MMAP_DATA); + + psMMapDataOUT->eError = + PVRMMapOSMemHandleToMMapData(psPerProc, psMMapDataIN->hMHandle, + &psMMapDataOUT->ui32MMapOffset, + &psMMapDataOUT->ui32ByteOffset, + &psMMapDataOUT->ui32RealByteSize, + &psMMapDataOUT->ui32UserVAddr); + return 0; +} + +static int PVRMMapReleaseMMapDataBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_RELEASE_MMAP_DATA *psMMapDataIN, + struct PVRSRV_BRIDGE_OUT_RELEASE_MMAP_DATA *psMMapDataOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_RELEASE_MMAP_DATA); + + psMMapDataOUT->eError = PVRMMapReleaseMMapData(psPerProc, + psMMapDataIN->hMHandle, + &psMMapDataOUT->bMUnmap, + &psMMapDataOUT->ui32RealByteSize, + &psMMapDataOUT->ui32UserVAddr); + return 0; +} + +#ifdef PDUMP +static int PDumpIsCaptureFrameBW(u32 ui32BridgeID, void *psBridgeIn, + struct PVRSRV_BRIDGE_OUT_PDUMP_ISCAPTURING *psPDumpIsCapturingOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_ISCAPTURING); + PVR_UNREFERENCED_PARAMETER(psBridgeIn); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + psPDumpIsCapturingOUT->bIsCapturing = PDumpIsCaptureFrameKM(); + psPDumpIsCapturingOUT->eError = PVRSRV_OK; + + return 0; +} + +static int PDumpCommentBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_COMMENT *psPDumpCommentIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_COMMENT); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + psRetOUT->eError = PDumpCommentKM(&psPDumpCommentIN->szComment[0], + psPDumpCommentIN->ui32Flags); + return 0; +} + +static int PDumpSetFrameBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_SETFRAME *psPDumpSetFrameIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_SETFRAME); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + psRetOUT->eError = PDumpSetFrameKM(psPDumpSetFrameIN->ui32Frame); + + return 0; +} + +static int PDumpRegWithFlagsBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_DUMPREG *psPDumpRegDumpIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_REG); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + psRetOUT->eError = + PDumpRegWithFlagsKM(psPDumpRegDumpIN->sHWReg.ui32RegAddr, + psPDumpRegDumpIN->sHWReg.ui32RegVal, + psPDumpRegDumpIN->ui32Flags); + + return 0; +} + +static int PDumpRegPolBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_REGPOL *psPDumpRegPolIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_REGPOL); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + psRetOUT->eError = + PDumpRegPolWithFlagsKM(psPDumpRegPolIN->sHWReg.ui32RegAddr, + psPDumpRegPolIN->sHWReg.ui32RegVal, + psPDumpRegPolIN->ui32Mask, + psPDumpRegPolIN->ui32Flags); + + return 0; +} + +static int PDumpMemPolBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_MEMPOL *psPDumpMemPolIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_MEMPOL); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvMemInfo, + psPDumpMemPolIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PDumpMemPolKM(((struct PVRSRV_KERNEL_MEM_INFO *)pvMemInfo), + psPDumpMemPolIN->ui32Offset, + psPDumpMemPolIN->ui32Value, + psPDumpMemPolIN->ui32Mask, + PDUMP_POLL_OPERATOR_EQUAL, + psPDumpMemPolIN->bLastFrame, + psPDumpMemPolIN->bOverwrite, + MAKEUNIQUETAG(pvMemInfo)); + + return 0; +} + +static int PDumpMemBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_DUMPMEM *psPDumpMemDumpIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_DUMPMEM); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvMemInfo, + psPDumpMemDumpIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PDumpMemUM(psPerProc, psPDumpMemDumpIN->pvAltLinAddr, + psPDumpMemDumpIN->pvLinAddr, + pvMemInfo, psPDumpMemDumpIN->ui32Offset, + psPDumpMemDumpIN->ui32Bytes, + psPDumpMemDumpIN->ui32Flags, + MAKEUNIQUETAG(pvMemInfo)); + + return 0; +} + +static int PDumpBitmapBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_BITMAP *psPDumpBitmapIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVR_UNREFERENCED_PARAMETER(psPerProc); + PVR_UNREFERENCED_PARAMETER(ui32BridgeID); + + psRetOUT->eError = PDumpBitmapKM(&psPDumpBitmapIN->szFileName[0], + psPDumpBitmapIN->ui32FileOffset, + psPDumpBitmapIN->ui32Width, + psPDumpBitmapIN->ui32Height, + psPDumpBitmapIN->ui32StrideInBytes, + psPDumpBitmapIN->sDevBaseAddr, + psPDumpBitmapIN->ui32Size, + psPDumpBitmapIN->ePixelFormat, + psPDumpBitmapIN->eMemFormat, + psPDumpBitmapIN->ui32Flags); + + return 0; +} + +static int PDumpReadRegBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_READREG *psPDumpReadRegIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_DUMPREADREG); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + psRetOUT->eError = PDumpReadRegKM(&psPDumpReadRegIN->szFileName[0], + psPDumpReadRegIN->ui32FileOffset, + psPDumpReadRegIN->ui32Address, + psPDumpReadRegIN->ui32Size, + psPDumpReadRegIN->ui32Flags); + + return 0; +} + +static int PDumpDriverInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_DRIVERINFO *psPDumpDriverInfoIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + u32 ui32PDumpFlags; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_DRIVERINFO); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + ui32PDumpFlags = 0; + if (psPDumpDriverInfoIN->bContinuous) + ui32PDumpFlags |= PDUMP_FLAGS_CONTINUOUS; + psRetOUT->eError = PDumpDriverInfoKM(&psPDumpDriverInfoIN->szString[0], + ui32PDumpFlags); + + return 0; +} + +static int PDumpSyncDumpBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_DUMPSYNC *psPDumpSyncDumpIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + u32 ui32Bytes = psPDumpSyncDumpIN->ui32Bytes; + void *pvSyncInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_DUMPSYNC); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &pvSyncInfo, + psPDumpSyncDumpIN->psKernelSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PDumpMemUM(psPerProc, psPDumpSyncDumpIN->pvAltLinAddr, NULL, + ((struct PVRSRV_KERNEL_SYNC_INFO *)pvSyncInfo)-> + psSyncDataMemInfoKM, + psPDumpSyncDumpIN->ui32Offset, ui32Bytes, 0, + MAKEUNIQUETAG(((struct PVRSRV_KERNEL_SYNC_INFO *) + pvSyncInfo)->psSyncDataMemInfoKM)); + + return 0; +} + +static int PDumpSyncPolBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_SYNCPOL *psPDumpSyncPolIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + u32 ui32Offset; + void *pvSyncInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_SYNCPOL); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &pvSyncInfo, + psPDumpSyncPolIN->psKernelSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + if (psPDumpSyncPolIN->bIsRead) + ui32Offset = offsetof(struct PVRSRV_SYNC_DATA, + ui32ReadOpsComplete); + else + ui32Offset = offsetof(struct PVRSRV_SYNC_DATA, + ui32WriteOpsComplete); + + psRetOUT->eError = + PDumpMemPolKM(((struct PVRSRV_KERNEL_SYNC_INFO *)pvSyncInfo)-> + psSyncDataMemInfoKM, ui32Offset, + psPDumpSyncPolIN->ui32Value, + psPDumpSyncPolIN->ui32Mask, PDUMP_POLL_OPERATOR_EQUAL, + IMG_FALSE, IMG_FALSE, + MAKEUNIQUETAG(((struct PVRSRV_KERNEL_SYNC_INFO *) + pvSyncInfo)->psSyncDataMemInfoKM)); + + return 0; +} + +static int PDumpPDRegBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_DUMPPDREG *psPDumpPDRegDumpIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_PDUMP_PDREG); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + PDumpPDReg(psPDumpPDRegDumpIN->sHWReg.ui32RegAddr, + psPDumpPDRegDumpIN->sHWReg.ui32RegVal, PDUMP_PD_UNIQUETAG); + + psRetOUT->eError = PVRSRV_OK; + return 0; +} + +static int PDumpCycleCountRegReadBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_CYCLE_COUNT_REG_READ + *psPDumpCycleCountRegReadIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_PDUMP_CYCLE_COUNT_REG_READ); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + PDumpCycleCountRegRead(psPDumpCycleCountRegReadIN->ui32RegOffset, + psPDumpCycleCountRegReadIN->bLastFrame); + + psRetOUT->eError = PVRSRV_OK; + + return 0; +} + +static int PDumpPDDevPAddrBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_DUMPPDDEVPADDR *psPDumpPDDevPAddrIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_PDUMP_DUMPPDDEVPADDR); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &pvMemInfo, + psPDumpPDDevPAddrIN->hKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PDumpPDDevPAddrKM((struct PVRSRV_KERNEL_MEM_INFO *)pvMemInfo, + psPDumpPDDevPAddrIN->ui32Offset, + psPDumpPDDevPAddrIN->sPDDevPAddr, + MAKEUNIQUETAG(pvMemInfo), PDUMP_PD_UNIQUETAG); + return 0; +} + +static int PDumpStartInitPhaseBW(u32 ui32BridgeID, void *psBridgeIn, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_PDUMP_STARTINITPHASE); + PVR_UNREFERENCED_PARAMETER(psBridgeIn); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + psRetOUT->eError = PDumpStartInitPhaseKM(); + + return 0; +} + +static int PDumpStopInitPhaseBW(u32 ui32BridgeID, void *psBridgeIn, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_PDUMP_STOPINITPHASE); + PVR_UNREFERENCED_PARAMETER(psBridgeIn); + PVR_UNREFERENCED_PARAMETER(psPerProc); + + psRetOUT->eError = PDumpStopInitPhaseKM(); + + return 0; +} + +#endif + +static int PVRSRVGetMiscInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GET_MISC_INFO *psGetMiscInfoIN, + struct PVRSRV_BRIDGE_OUT_GET_MISC_INFO *psGetMiscInfoOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + enum PVRSRV_ERROR eError; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_GET_MISC_INFO); + + OSMemCopy(&psGetMiscInfoOUT->sMiscInfo, &psGetMiscInfoIN->sMiscInfo, + sizeof(struct PVRSRV_MISC_INFO)); + + if (((psGetMiscInfoIN->sMiscInfo.ui32StateRequest & + PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0) && + ((psGetMiscInfoIN->sMiscInfo.ui32StateRequest & + PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0)) { + + psGetMiscInfoOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + return 0; + } + + if (((psGetMiscInfoIN->sMiscInfo.ui32StateRequest & + PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0) || + ((psGetMiscInfoIN->sMiscInfo.ui32StateRequest & + PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0)) { + + ASSIGN_AND_EXIT_ON_ERROR( + psGetMiscInfoOUT->eError, + OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + psGetMiscInfoOUT->sMiscInfo.ui32MemoryStrLen, + (void **)&psGetMiscInfoOUT->sMiscInfo.pszMemoryStr, + NULL)); + + psGetMiscInfoOUT->eError = + PVRSRVGetMiscInfoKM(&psGetMiscInfoOUT->sMiscInfo); + + eError = CopyToUserWrapper(psPerProc, ui32BridgeID, + (void __force __user *) + psGetMiscInfoIN->sMiscInfo.pszMemoryStr, + psGetMiscInfoOUT->sMiscInfo.pszMemoryStr, + psGetMiscInfoOUT->sMiscInfo.ui32MemoryStrLen); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + psGetMiscInfoOUT->sMiscInfo.ui32MemoryStrLen, + (void *)psGetMiscInfoOUT->sMiscInfo.pszMemoryStr, + NULL); + + psGetMiscInfoOUT->sMiscInfo.pszMemoryStr = + psGetMiscInfoIN->sMiscInfo.pszMemoryStr; + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetMiscInfoBW Error copy to user"); + return -EFAULT; + } + } else { + psGetMiscInfoOUT->eError = + PVRSRVGetMiscInfoKM(&psGetMiscInfoOUT->sMiscInfo); + } + + if (psGetMiscInfoOUT->eError != PVRSRV_OK) + return 0; + + if (psGetMiscInfoIN->sMiscInfo.ui32StateRequest & + PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) { + psGetMiscInfoOUT->eError = + PVRSRVAllocHandle(psPerProc->psHandleBase, + &psGetMiscInfoOUT->sMiscInfo. + sGlobalEventObject.hOSEventKM, + psGetMiscInfoOUT->sMiscInfo. + sGlobalEventObject.hOSEventKM, + PVRSRV_HANDLE_TYPE_SHARED_EVENT_OBJECT, + PVRSRV_HANDLE_ALLOC_FLAG_SHARED); + + if (psGetMiscInfoOUT->eError != PVRSRV_OK) + return 0; + } + + if (psGetMiscInfoOUT->sMiscInfo.hSOCTimerRegisterOSMemHandle) { + psGetMiscInfoOUT->eError = + PVRSRVAllocHandle(psPerProc->psHandleBase, + &psGetMiscInfoOUT->sMiscInfo. + hSOCTimerRegisterOSMemHandle, + psGetMiscInfoOUT->sMiscInfo. + hSOCTimerRegisterOSMemHandle, + PVRSRV_HANDLE_TYPE_SOC_TIMER, + PVRSRV_HANDLE_ALLOC_FLAG_SHARED); + + if (psGetMiscInfoOUT->eError != PVRSRV_OK) + return 0; + } + + return 0; +} + +static int PVRSRVConnectBW(u32 ui32BridgeID, void *psBridgeIn, + struct PVRSRV_BRIDGE_OUT_CONNECT_SERVICES *psConnectServicesOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVR_UNREFERENCED_PARAMETER(psBridgeIn); + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_CONNECT_SERVICES); + + psConnectServicesOUT->hKernelServices = psPerProc->hPerProcData; + psConnectServicesOUT->eError = PVRSRV_OK; + +#if defined(PDUMP) + + { + struct SYS_DATA *psSysData; + SysAcquireData(&psSysData); + psSysData->bPowerUpPDumped = IMG_FALSE; + } +#endif + + return 0; +} + +static int PVRSRVDisconnectBW(u32 ui32BridgeID, void *psBridgeIn, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVR_UNREFERENCED_PARAMETER(psPerProc); + PVR_UNREFERENCED_PARAMETER(psBridgeIn); + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_DISCONNECT_SERVICES); + + psRetOUT->eError = PVRSRV_OK; + + return 0; +} + +static int PVRSRVEnumerateDCBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_ENUMCLASS *psEnumDispClassIN, + struct PVRSRV_BRIDGE_OUT_ENUMCLASS *psEnumDispClassOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVR_UNREFERENCED_PARAMETER(psPerProc); + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_ENUM_CLASS); + + psEnumDispClassOUT->eError = + PVRSRVEnumerateDCKM(psEnumDispClassIN->sDeviceClass, + &psEnumDispClassOUT->ui32NumDevices, + &psEnumDispClassOUT->ui32DevID[0]); + + return 0; +} + +static int PVRSRVOpenDCDeviceBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_OPEN_DISPCLASS_DEVICE *psOpenDispClassDeviceIN, + struct PVRSRV_BRIDGE_OUT_OPEN_DISPCLASS_DEVICE *psOpenDispClassDeviceOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *hDispClassInfoInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_OPEN_DISPCLASS_DEVICE); + + NEW_HANDLE_BATCH_OR_ERROR(psOpenDispClassDeviceOUT->eError, psPerProc, + 1); + + psOpenDispClassDeviceOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psOpenDispClassDeviceIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psOpenDispClassDeviceOUT->eError != PVRSRV_OK) + return 0; + + psOpenDispClassDeviceOUT->eError = PVRSRVOpenDCDeviceKM(psPerProc, + psOpenDispClassDeviceIN->ui32DeviceID, + hDevCookieInt, &hDispClassInfoInt); + + if (psOpenDispClassDeviceOUT->eError != PVRSRV_OK) + return 0; + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psOpenDispClassDeviceOUT->hDeviceKM, + hDispClassInfoInt, + PVRSRV_HANDLE_TYPE_DISP_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + COMMIT_HANDLE_BATCH_OR_ERROR(psOpenDispClassDeviceOUT->eError, + psPerProc); + + return 0; +} + +static int PVRSRVCloseDCDeviceBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_CLOSE_DISPCLASS_DEVICE *psCloseDispClassDeviceIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfoInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_CLOSE_DISPCLASS_DEVICE); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfoInt, + psCloseDispClassDeviceIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVCloseDCDeviceKM(pvDispClassInfoInt, IMG_FALSE); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVReleaseHandle(psPerProc->psHandleBase, + psCloseDispClassDeviceIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + return 0; +} + +static int PVRSRVEnumDCFormatsBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_ENUM_DISPCLASS_FORMATS *psEnumDispClassFormatsIN, + struct PVRSRV_BRIDGE_OUT_ENUM_DISPCLASS_FORMATS *psEnumDispClassFormatsOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfoInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_ENUM_DISPCLASS_FORMATS); + + psEnumDispClassFormatsOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfoInt, + psEnumDispClassFormatsIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psEnumDispClassFormatsOUT->eError != PVRSRV_OK) + return 0; + + psEnumDispClassFormatsOUT->eError = + PVRSRVEnumDCFormatsKM(pvDispClassInfoInt, + &psEnumDispClassFormatsOUT->ui32Count, + psEnumDispClassFormatsOUT->asFormat); + + return 0; +} + +static int PVRSRVEnumDCDimsBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_ENUM_DISPCLASS_DIMS *psEnumDispClassDimsIN, + struct PVRSRV_BRIDGE_OUT_ENUM_DISPCLASS_DIMS *psEnumDispClassDimsOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfoInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_ENUM_DISPCLASS_DIMS); + + psEnumDispClassDimsOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfoInt, + psEnumDispClassDimsIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + + if (psEnumDispClassDimsOUT->eError != PVRSRV_OK) + return 0; + + psEnumDispClassDimsOUT->eError = + PVRSRVEnumDCDimsKM(pvDispClassInfoInt, + &psEnumDispClassDimsIN->sFormat, + &psEnumDispClassDimsOUT->ui32Count, + psEnumDispClassDimsOUT->asDim); + + return 0; +} + +static int PVRSRVGetDCSystemBufferBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GET_DISPCLASS_SYSBUFFER *psGetDispClassSysBufferIN, + struct PVRSRV_BRIDGE_OUT_GET_DISPCLASS_SYSBUFFER *psGetDispClassSysBufferOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hBufferInt; + void *pvDispClassInfoInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_GET_DISPCLASS_SYSBUFFER); + + NEW_HANDLE_BATCH_OR_ERROR(psGetDispClassSysBufferOUT->eError, psPerProc, + 1); + + psGetDispClassSysBufferOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfoInt, + psGetDispClassSysBufferIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psGetDispClassSysBufferOUT->eError != PVRSRV_OK) + return 0; + + psGetDispClassSysBufferOUT->eError = + PVRSRVGetDCSystemBufferKM(pvDispClassInfoInt, &hBufferInt); + + if (psGetDispClassSysBufferOUT->eError != PVRSRV_OK) + return 0; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psGetDispClassSysBufferOUT->hBuffer, + hBufferInt, + PVRSRV_HANDLE_TYPE_DISP_BUFFER, + (enum PVRSRV_HANDLE_ALLOC_FLAG) + (PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE | + PVRSRV_HANDLE_ALLOC_FLAG_SHARED), + psGetDispClassSysBufferIN->hDeviceKM); + + COMMIT_HANDLE_BATCH_OR_ERROR(psGetDispClassSysBufferOUT->eError, + psPerProc); + + return 0; +} + +static int PVRSRVGetDCInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GET_DISPCLASS_INFO *psGetDispClassInfoIN, + struct PVRSRV_BRIDGE_OUT_GET_DISPCLASS_INFO *psGetDispClassInfoOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_GET_DISPCLASS_INFO); + + psGetDispClassInfoOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psGetDispClassInfoIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psGetDispClassInfoOUT->eError != PVRSRV_OK) + return 0; + + psGetDispClassInfoOUT->eError = + PVRSRVGetDCInfoKM(pvDispClassInfo, + &psGetDispClassInfoOUT->sDisplayInfo); + + return 0; +} + +static int PVRSRVCreateDCSwapChainBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_CREATE_DISPCLASS_SWAPCHAIN + *psCreateDispClassSwapChainIN, + struct PVRSRV_BRIDGE_OUT_CREATE_DISPCLASS_SWAPCHAIN + *psCreateDispClassSwapChainOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfo; + void *hSwapChainInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_CREATE_DISPCLASS_SWAPCHAIN); + + NEW_HANDLE_BATCH_OR_ERROR(psCreateDispClassSwapChainOUT->eError, + psPerProc, 1); + + psCreateDispClassSwapChainOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psCreateDispClassSwapChainIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + + if (psCreateDispClassSwapChainOUT->eError != PVRSRV_OK) + return 0; + + psCreateDispClassSwapChainOUT->eError = + PVRSRVCreateDCSwapChainKM(psPerProc, pvDispClassInfo, + psCreateDispClassSwapChainIN->ui32Flags, + &psCreateDispClassSwapChainIN->sDstSurfAttrib, + &psCreateDispClassSwapChainIN->sSrcSurfAttrib, + psCreateDispClassSwapChainIN->ui32BufferCount, + psCreateDispClassSwapChainIN->ui32OEMFlags, + &hSwapChainInt, + &psCreateDispClassSwapChainOUT->ui32SwapChainID); + + if (psCreateDispClassSwapChainOUT->eError != PVRSRV_OK) + return 0; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psCreateDispClassSwapChainOUT->hSwapChain, + hSwapChainInt, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN, + PVRSRV_HANDLE_ALLOC_FLAG_NONE, + psCreateDispClassSwapChainIN->hDeviceKM); + + COMMIT_HANDLE_BATCH_OR_ERROR(psCreateDispClassSwapChainOUT->eError, + psPerProc); + + return 0; +} + +static int PVRSRVDestroyDCSwapChainBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_DESTROY_DISPCLASS_SWAPCHAIN + *psDestroyDispClassSwapChainIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvSwapChain; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_DESTROY_DISPCLASS_SWAPCHAIN); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &pvSwapChain, + psDestroyDispClassSwapChainIN->hSwapChain, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVDestroyDCSwapChainKM(pvSwapChain); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVReleaseHandle(psPerProc->psHandleBase, + psDestroyDispClassSwapChainIN->hSwapChain, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN); + + return 0; +} + +static int PVRSRVSetDCDstRectBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SET_DISPCLASS_RECT *psSetDispClassDstRectIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfo; + void *pvSwapChain; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SET_DISPCLASS_DSTRECT); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psSetDispClassDstRectIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvSwapChain, + psSetDispClassDstRectIN->hSwapChain, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVSetDCDstRectKM(pvDispClassInfo, + pvSwapChain, &psSetDispClassDstRectIN->sRect); + + return 0; +} + +static int PVRSRVSetDCSrcRectBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SET_DISPCLASS_RECT *psSetDispClassSrcRectIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfo; + void *pvSwapChain; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SET_DISPCLASS_SRCRECT); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psSetDispClassSrcRectIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvSwapChain, + psSetDispClassSrcRectIN->hSwapChain, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVSetDCSrcRectKM(pvDispClassInfo, + pvSwapChain, &psSetDispClassSrcRectIN->sRect); + + return 0; +} + +static int PVRSRVSetDCDstColourKeyBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SET_DISPCLASS_COLOURKEY *psSetDispClassColKeyIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfo; + void *pvSwapChain; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SET_DISPCLASS_DSTCOLOURKEY); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psSetDispClassColKeyIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvSwapChain, + psSetDispClassColKeyIN->hSwapChain, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVSetDCDstColourKeyKM(pvDispClassInfo, + pvSwapChain, + psSetDispClassColKeyIN->ui32CKColour); + + return 0; +} + +static int PVRSRVSetDCSrcColourKeyBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SET_DISPCLASS_COLOURKEY *psSetDispClassColKeyIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfo; + void *pvSwapChain; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SET_DISPCLASS_SRCCOLOURKEY); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psSetDispClassColKeyIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvSwapChain, + psSetDispClassColKeyIN->hSwapChain, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVSetDCSrcColourKeyKM(pvDispClassInfo, + pvSwapChain, + psSetDispClassColKeyIN->ui32CKColour); + + return 0; +} + +static int PVRSRVGetDCBuffersBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GET_DISPCLASS_BUFFERS *psGetDispClassBuffersIN, + struct PVRSRV_BRIDGE_OUT_GET_DISPCLASS_BUFFERS *psGetDispClassBuffersOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfo; + void *pvSwapChain; + u32 i; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_GET_DISPCLASS_BUFFERS); + + NEW_HANDLE_BATCH_OR_ERROR(psGetDispClassBuffersOUT->eError, psPerProc, + PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS); + + psGetDispClassBuffersOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psGetDispClassBuffersIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psGetDispClassBuffersOUT->eError != PVRSRV_OK) + return 0; + + psGetDispClassBuffersOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvSwapChain, + psGetDispClassBuffersIN->hSwapChain, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN); + if (psGetDispClassBuffersOUT->eError != PVRSRV_OK) + return 0; + + psGetDispClassBuffersOUT->eError = + PVRSRVGetDCBuffersKM(pvDispClassInfo, + pvSwapChain, + &psGetDispClassBuffersOUT->ui32BufferCount, + psGetDispClassBuffersOUT->ahBuffer); + if (psGetDispClassBuffersOUT->eError != PVRSRV_OK) + return 0; + + PVR_ASSERT(psGetDispClassBuffersOUT->ui32BufferCount <= + PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS); + + for (i = 0; i < psGetDispClassBuffersOUT->ui32BufferCount; i++) { + void *hBufferExt; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &hBufferExt, + psGetDispClassBuffersOUT->ahBuffer[i], + PVRSRV_HANDLE_TYPE_DISP_BUFFER, + (enum PVRSRV_HANDLE_ALLOC_FLAG) + (PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE | + PVRSRV_HANDLE_ALLOC_FLAG_SHARED), + psGetDispClassBuffersIN->hSwapChain); + + psGetDispClassBuffersOUT->ahBuffer[i] = hBufferExt; + } + + COMMIT_HANDLE_BATCH_OR_ERROR(psGetDispClassBuffersOUT->eError, + psPerProc); + + return 0; +} + +static int PVRSRVSwapToDCBufferBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SWAP_DISPCLASS_TO_BUFFER *psSwapDispClassBufferIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfo; + void *pvSwapChainBuf; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_BUFFER); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psSwapDispClassBufferIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVLookupSubHandle(psPerProc->psHandleBase, + &pvSwapChainBuf, + psSwapDispClassBufferIN->hBuffer, + PVRSRV_HANDLE_TYPE_DISP_BUFFER, + psSwapDispClassBufferIN->hDeviceKM); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVSwapToDCBufferKM(pvDispClassInfo, + pvSwapChainBuf, + psSwapDispClassBufferIN->ui32SwapInterval, + psSwapDispClassBufferIN->hPrivateTag, + psSwapDispClassBufferIN->ui32ClipRectCount, + psSwapDispClassBufferIN->sClipRect); + + return 0; +} + +static int PVRSRVSwapToDCSystemBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SWAP_DISPCLASS_TO_SYSTEM *psSwapDispClassSystemIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvDispClassInfo; + void *pvSwapChain; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_SYSTEM); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psSwapDispClassSystemIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVLookupSubHandle(psPerProc->psHandleBase, + &pvSwapChain, + psSwapDispClassSystemIN->hSwapChain, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN, + psSwapDispClassSystemIN->hDeviceKM); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + psRetOUT->eError = PVRSRVSwapToDCSystemKM(pvDispClassInfo, pvSwapChain); + + return 0; +} + +static int PVRSRVOpenBCDeviceBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_OPEN_BUFFERCLASS_DEVICE *psOpenBufferClassDeviceIN, + struct PVRSRV_BRIDGE_OUT_OPEN_BUFFERCLASS_DEVICE *psOpenBufferClassDeviceOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *hBufClassInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_OPEN_BUFFERCLASS_DEVICE); + + NEW_HANDLE_BATCH_OR_ERROR(psOpenBufferClassDeviceOUT->eError, psPerProc, + 1); + + psOpenBufferClassDeviceOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psOpenBufferClassDeviceIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psOpenBufferClassDeviceOUT->eError != PVRSRV_OK) + return 0; + + psOpenBufferClassDeviceOUT->eError = + PVRSRVOpenBCDeviceKM(psPerProc, + psOpenBufferClassDeviceIN->ui32DeviceID, + hDevCookieInt, &hBufClassInfo); + if (psOpenBufferClassDeviceOUT->eError != PVRSRV_OK) + return 0; + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psOpenBufferClassDeviceOUT->hDeviceKM, + hBufClassInfo, + PVRSRV_HANDLE_TYPE_BUF_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + + COMMIT_HANDLE_BATCH_OR_ERROR(psOpenBufferClassDeviceOUT->eError, + psPerProc); + + return 0; +} + +static int PVRSRVCloseBCDeviceBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_CLOSE_BUFFERCLASS_DEVICE *psCloseBufferClassDeviceIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvBufClassInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_CLOSE_BUFFERCLASS_DEVICE); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvBufClassInfo, + psCloseBufferClassDeviceIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_BUF_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVCloseBCDeviceKM(pvBufClassInfo, IMG_FALSE); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, + psCloseBufferClassDeviceIN-> + hDeviceKM, + PVRSRV_HANDLE_TYPE_BUF_INFO); + + return 0; +} + +static int PVRSRVGetBCInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GET_BUFFERCLASS_INFO *psGetBufferClassInfoIN, + struct PVRSRV_BRIDGE_OUT_GET_BUFFERCLASS_INFO *psGetBufferClassInfoOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvBufClassInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_GET_BUFFERCLASS_INFO); + + psGetBufferClassInfoOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvBufClassInfo, + psGetBufferClassInfoIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_BUF_INFO); + if (psGetBufferClassInfoOUT->eError != PVRSRV_OK) + return 0; + + psGetBufferClassInfoOUT->eError = + PVRSRVGetBCInfoKM(pvBufClassInfo, + &psGetBufferClassInfoOUT->sBufferInfo); + return 0; +} + +static int PVRSRVGetBCBufferBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GET_BUFFERCLASS_BUFFER *psGetBufferClassBufferIN, + struct PVRSRV_BRIDGE_OUT_GET_BUFFERCLASS_BUFFER *psGetBufferClassBufferOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *pvBufClassInfo; + void *hBufferInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_GET_BUFFERCLASS_BUFFER); + + NEW_HANDLE_BATCH_OR_ERROR(psGetBufferClassBufferOUT->eError, psPerProc, + 1); + + psGetBufferClassBufferOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvBufClassInfo, + psGetBufferClassBufferIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_BUF_INFO); + if (psGetBufferClassBufferOUT->eError != PVRSRV_OK) + return 0; + + psGetBufferClassBufferOUT->eError = + PVRSRVGetBCBufferKM(pvBufClassInfo, + psGetBufferClassBufferIN->ui32BufferIndex, + &hBufferInt); + + if (psGetBufferClassBufferOUT->eError != PVRSRV_OK) + return 0; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psGetBufferClassBufferOUT->hBuffer, + hBufferInt, + PVRSRV_HANDLE_TYPE_BUF_BUFFER, + (enum PVRSRV_HANDLE_ALLOC_FLAG) + (PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE | + PVRSRV_HANDLE_ALLOC_FLAG_SHARED), + psGetBufferClassBufferIN->hDeviceKM); + + COMMIT_HANDLE_BATCH_OR_ERROR(psGetBufferClassBufferOUT->eError, + psPerProc); + + return 0; +} + +static int PVRSRVAllocSharedSysMemoryBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_ALLOC_SHARED_SYS_MEM *psAllocSharedSysMemIN, + struct PVRSRV_BRIDGE_OUT_ALLOC_SHARED_SYS_MEM *psAllocSharedSysMemOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_ALLOC_SHARED_SYS_MEM); + + NEW_HANDLE_BATCH_OR_ERROR(psAllocSharedSysMemOUT->eError, psPerProc, 1); + + psAllocSharedSysMemOUT->eError = + PVRSRVAllocSharedSysMemoryKM(psPerProc, + psAllocSharedSysMemIN->ui32Flags, + psAllocSharedSysMemIN->ui32Size, + &psKernelMemInfo); + if (psAllocSharedSysMemOUT->eError != PVRSRV_OK) + return 0; + + OSMemSet(&psAllocSharedSysMemOUT->sClientMemInfo, + 0, sizeof(psAllocSharedSysMemOUT->sClientMemInfo)); + + psAllocSharedSysMemOUT->sClientMemInfo.pvLinAddrKM = + psKernelMemInfo->pvLinAddrKM; + + psAllocSharedSysMemOUT->sClientMemInfo.pvLinAddr = NULL; + psAllocSharedSysMemOUT->sClientMemInfo.ui32Flags = + psKernelMemInfo->ui32Flags; + psAllocSharedSysMemOUT->sClientMemInfo.ui32AllocSize = + psKernelMemInfo->ui32AllocSize; + psAllocSharedSysMemOUT->sClientMemInfo.hMappingInfo = + psKernelMemInfo->sMemBlk.hOSMemHandle; + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psAllocSharedSysMemOUT->sClientMemInfo.hKernelMemInfo, + psKernelMemInfo, + PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + + COMMIT_HANDLE_BATCH_OR_ERROR(psAllocSharedSysMemOUT->eError, psPerProc); + + return 0; +} + +static int PVRSRVFreeSharedSysMemoryBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_FREE_SHARED_SYS_MEM *psFreeSharedSysMemIN, + struct PVRSRV_BRIDGE_OUT_FREE_SHARED_SYS_MEM *psFreeSharedSysMemOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_FREE_SHARED_SYS_MEM); + + psFreeSharedSysMemOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + (void **)&psKernelMemInfo, + psFreeSharedSysMemIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO); + + if (psFreeSharedSysMemOUT->eError != PVRSRV_OK) + return 0; + + psFreeSharedSysMemOUT->eError = + PVRSRVFreeSharedSysMemoryKM(psKernelMemInfo); + if (psFreeSharedSysMemOUT->eError != PVRSRV_OK) + return 0; + + psFreeSharedSysMemOUT->eError = + PVRSRVReleaseHandle(psPerProc->psHandleBase, + psFreeSharedSysMemIN->psKernelMemInfo, + PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO); + return 0; +} + +static int PVRSRVMapMemInfoMemBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_MAP_MEMINFO_MEM *psMapMemInfoMemIN, + struct PVRSRV_BRIDGE_OUT_MAP_MEMINFO_MEM *psMapMemInfoMemOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + enum PVRSRV_HANDLE_TYPE eHandleType; + void *hParent; + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_MAP_MEMINFO_MEM); + + NEW_HANDLE_BATCH_OR_ERROR(psMapMemInfoMemOUT->eError, psPerProc, 2); + + psMapMemInfoMemOUT->eError = + PVRSRVLookupHandleAnyType(psPerProc->psHandleBase, + (void **)&psKernelMemInfo, &eHandleType, + psMapMemInfoMemIN->hKernelMemInfo); + if (psMapMemInfoMemOUT->eError != PVRSRV_OK) + return 0; + + switch (eHandleType) { + case PVRSRV_HANDLE_TYPE_MEM_INFO: + case PVRSRV_HANDLE_TYPE_MEM_INFO_REF: + case PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO: + break; + default: + psMapMemInfoMemOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + psMapMemInfoMemOUT->eError = + PVRSRVGetParentHandle(psPerProc->psHandleBase, &hParent, + psMapMemInfoMemIN->hKernelMemInfo, + eHandleType); + if (psMapMemInfoMemOUT->eError != PVRSRV_OK) + return 0; + if (hParent == NULL) + hParent = psMapMemInfoMemIN->hKernelMemInfo; + + OSMemSet(&psMapMemInfoMemOUT->sClientMemInfo, + 0, sizeof(psMapMemInfoMemOUT->sClientMemInfo)); + + psMapMemInfoMemOUT->sClientMemInfo.pvLinAddrKM = + psKernelMemInfo->pvLinAddrKM; + + psMapMemInfoMemOUT->sClientMemInfo.pvLinAddr = NULL; + psMapMemInfoMemOUT->sClientMemInfo.sDevVAddr = + psKernelMemInfo->sDevVAddr; + psMapMemInfoMemOUT->sClientMemInfo.ui32Flags = + psKernelMemInfo->ui32Flags; + psMapMemInfoMemOUT->sClientMemInfo.ui32AllocSize = + psKernelMemInfo->ui32AllocSize; + psMapMemInfoMemOUT->sClientMemInfo.hMappingInfo = + psKernelMemInfo->sMemBlk.hOSMemHandle; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psMapMemInfoMemOUT->sClientMemInfo.hKernelMemInfo, + psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO_REF, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI, hParent); + + if (psKernelMemInfo->ui32Flags & PVRSRV_MEM_NO_SYNCOBJ) { + OSMemSet(&psMapMemInfoMemOUT->sClientSyncInfo, 0, + sizeof(struct PVRSRV_CLIENT_SYNC_INFO)); + psMapMemInfoMemOUT->psKernelSyncInfo = NULL; + } else { + psMapMemInfoMemOUT->sClientSyncInfo.psSyncData = + psKernelMemInfo->psKernelSyncInfo->psSyncData; + psMapMemInfoMemOUT->sClientSyncInfo.sWriteOpsCompleteDevVAddr = + psKernelMemInfo->psKernelSyncInfo-> + sWriteOpsCompleteDevVAddr; + psMapMemInfoMemOUT->sClientSyncInfo.sReadOpsCompleteDevVAddr = + psKernelMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + + psMapMemInfoMemOUT->sClientSyncInfo.hMappingInfo = + psKernelMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM-> + sMemBlk.hOSMemHandle; + + psMapMemInfoMemOUT->sClientMemInfo.psClientSyncInfo = + &psMapMemInfoMemOUT->sClientSyncInfo; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psMapMemInfoMemOUT->sClientSyncInfo.hKernelSyncInfo, + psKernelMemInfo->psKernelSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI, + psMapMemInfoMemOUT->sClientMemInfo.hKernelMemInfo); + } + + COMMIT_HANDLE_BATCH_OR_ERROR(psMapMemInfoMemOUT->eError, psPerProc); + + return 0; +} + +static int PVRSRVModifySyncOpsBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_MODIFY_SYNC_OPS *psModifySyncOpsIN, + struct PVRSRV_BRIDGE_OUT_MODIFY_SYNC_OPS *psModifySyncOpsOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hKernelSyncInfo; + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_MODIFY_SYNC_OPS); + + psModifySyncOpsOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hKernelSyncInfo, + psModifySyncOpsIN->hKernelSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if (psModifySyncOpsOUT->eError != PVRSRV_OK) + return 0; + + psKernelSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *)hKernelSyncInfo; + + /* We return PRE-INCREMENTED versions of all sync Op Values */ + + psModifySyncOpsOUT->ui32ReadOpsPending = + psKernelSyncInfo->psSyncData->ui32ReadOpsPending; + + psModifySyncOpsOUT->ui32WriteOpsPending = + psKernelSyncInfo->psSyncData->ui32WriteOpsPending; + + psModifySyncOpsOUT->ui32ReadOpsComplete = + psKernelSyncInfo->psSyncData->ui32ReadOpsComplete; + + psModifySyncOpsOUT->ui32WriteOpsComplete = + psKernelSyncInfo->psSyncData->ui32WriteOpsComplete; + + if (psModifySyncOpsIN->ui32ModifyFlags & + PVRSRV_MODIFYSYNCOPS_FLAGS_WOP_INC) + psKernelSyncInfo->psSyncData->ui32WriteOpsPending++; + + if (psModifySyncOpsIN->ui32ModifyFlags & + PVRSRV_MODIFYSYNCOPS_FLAGS_ROP_INC) + psKernelSyncInfo->psSyncData->ui32ReadOpsPending++; + + if (psModifySyncOpsIN->ui32ModifyFlags & + PVRSRV_MODIFYSYNCOPS_FLAGS_WOC_INC) + psKernelSyncInfo->psSyncData->ui32WriteOpsComplete++; + + if (psModifySyncOpsIN->ui32ModifyFlags & + PVRSRV_MODIFYSYNCOPS_FLAGS_ROC_INC) + psKernelSyncInfo->psSyncData->ui32ReadOpsComplete++; + + return 0; +} + +static int MMU_GetPDDevPAddrBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GETMMU_PD_DEVPADDR *psGetMmuPDDevPAddrIN, + struct PVRSRV_BRIDGE_OUT_GETMMU_PD_DEVPADDR *psGetMmuPDDevPAddrOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevMemContextInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_GETMMU_PD_DEVPADDR); + + psGetMmuPDDevPAddrOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemContextInt, + psGetMmuPDDevPAddrIN->hDevMemContext, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT); + if (psGetMmuPDDevPAddrOUT->eError != PVRSRV_OK) + return 0; + + psGetMmuPDDevPAddrOUT->sPDDevPAddr = + BM_GetDeviceNode(hDevMemContextInt)-> + pfnMMUGetPDDevPAddr(BM_GetMMUContextFromMemContext + (hDevMemContextInt)); + if (psGetMmuPDDevPAddrOUT->sPDDevPAddr.uiAddr) + psGetMmuPDDevPAddrOUT->eError = PVRSRV_OK; + else + psGetMmuPDDevPAddrOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; +} + +int DummyBW(u32 ui32BridgeID, void *psBridgeIn, void *psBridgeOut, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ +#if !defined(CONFIG_PVR_DEBUG_EXTRA) + PVR_UNREFERENCED_PARAMETER(ui32BridgeID); +#endif + PVR_UNREFERENCED_PARAMETER(psBridgeIn); + PVR_UNREFERENCED_PARAMETER(psBridgeOut); + PVR_UNREFERENCED_PARAMETER(psPerProc); + +#if defined(DEBUG_BRIDGE_KM) + PVR_DPF(PVR_DBG_ERROR, "%s: BRIDGE ERROR: BridgeID %lu (%s) mapped to " + "Dummy Wrapper (probably not what you want!)", + __func__, ui32BridgeID, + g_BridgeDispatchTable[ui32BridgeID].pszIOCName); +#else + PVR_DPF(PVR_DBG_ERROR, "%s: BRIDGE ERROR: BridgeID %lu mapped to " + "Dummy Wrapper (probably not what you want!)", + __func__, ui32BridgeID); +#endif + return -ENOTTY; +} + +void _SetDispatchTableEntry(u32 ui32Index, const char *pszIOCName, + int (*pfFunction)(u32 ui32BridgeID, + void *psBridgeIn, + void *psBridgeOut, + struct PVRSRV_PER_PROCESS_DATA + *psPerProc), + const char *pszFunctionName) +{ + static u32 ui32PrevIndex = ~0UL; +#if !defined(CONFIG_PVR_DEBUG_EXTRA) + PVR_UNREFERENCED_PARAMETER(pszIOCName); +#endif +#if !defined(DEBUG_BRIDGE_KM_DISPATCH_TABLE) && !defined(DEBUG_BRIDGE_KM) + PVR_UNREFERENCED_PARAMETER(pszFunctionName); +#endif + + + if (g_BridgeDispatchTable[ui32Index].pfFunction) { +#if defined(DEBUG_BRIDGE_KM) + PVR_DPF(PVR_DBG_ERROR, "%s: BUG!: " + "Adding dispatch table entry for %s " + "clobbers an existing entry for %s", + __func__, pszIOCName, + g_BridgeDispatchTable[ui32Index].pszIOCName); +#else + PVR_DPF(PVR_DBG_ERROR, "%s: BUG!: " + "Adding dispatch table entry for %s " + "clobbers an existing entry (index=%lu)", + __func__, pszIOCName, ui32Index); +#endif + PVR_DPF(PVR_DBG_ERROR, +"NOTE: Enabling DEBUG_BRIDGE_KM_DISPATCH_TABLE may help debug this issue.", + __func__); + } + + if ((ui32PrevIndex != ~0UL) && + ((ui32Index >= ui32PrevIndex + DISPATCH_TABLE_GAP_THRESHOLD) || + (ui32Index <= ui32PrevIndex))) { +#if defined(DEBUG_BRIDGE_KM) + PVR_DPF(PVR_DBG_WARNING, + "%s: There is a gap in the dispatch table " + "between indices %lu (%s) and %lu (%s)", + __func__, ui32PrevIndex, + g_BridgeDispatchTable[ui32PrevIndex].pszIOCName, + ui32Index, pszIOCName); +#else + PVR_DPF(PVR_DBG_WARNING, + "%s: There is a gap in the dispatch table " + "between indices %u and %u (%s)", + __func__, (unsigned)ui32PrevIndex, (unsigned)ui32Index, + pszIOCName); +#endif + PVR_DPF(PVR_DBG_ERROR, + "NOTE: Enabling DEBUG_BRIDGE_KM_DISPATCH_TABLE " + "may help debug this issue.", + __func__); + } + + g_BridgeDispatchTable[ui32Index].pfFunction = pfFunction; +#if defined(DEBUG_BRIDGE_KM) + g_BridgeDispatchTable[ui32Index].pszIOCName = pszIOCName; + g_BridgeDispatchTable[ui32Index].pszFunctionName = pszFunctionName; + g_BridgeDispatchTable[ui32Index].ui32CallCount = 0; + g_BridgeDispatchTable[ui32Index].ui32CopyFromUserTotalBytes = 0; +#endif + + ui32PrevIndex = ui32Index; +} + +static int PVRSRVInitSrvConnectBW(u32 ui32BridgeID, void *psBridgeIn, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVR_UNREFERENCED_PARAMETER(psBridgeIn); + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_INITSRV_CONNECT); + PVR_UNREFERENCED_PARAMETER(psBridgeIn); + + if (!OSProcHasPrivSrvInit() || + PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RUNNING) || + PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RAN)) { + psRetOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_RUNNING, IMG_TRUE); + psPerProc->bInitProcess = IMG_TRUE; + + psRetOUT->eError = PVRSRV_OK; + + return 0; +} + +static int PVRSRVInitSrvDisconnectBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_INITSRV_DISCONNECT *psInitSrvDisconnectIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_INITSRV_DISCONNECT); + + if (!psPerProc->bInitProcess) { + psRetOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + psPerProc->bInitProcess = IMG_FALSE; + + PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_RUNNING, IMG_FALSE); + PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_RAN, IMG_TRUE); + + psRetOUT->eError = + PVRSRVFinaliseSystem(psInitSrvDisconnectIN->bInitSuccesful); + + PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL, + (IMG_BOOL)(((psRetOUT->eError == PVRSRV_OK) && + (psInitSrvDisconnectIN-> + bInitSuccesful)))); + + return 0; +} + +static int PVRSRVEventObjectWaitBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_EVENT_OBJECT_WAIT *psEventObjectWaitIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hOSEventKM; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_EVENT_OBJECT_WAIT); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hOSEventKM, + psEventObjectWaitIN->hOSEventKM, + PVRSRV_HANDLE_TYPE_EVENT_OBJECT_CONNECT); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = OSEventObjectWait(hOSEventKM); + + return 0; +} + +static int PVRSRVEventObjectOpenBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_EVENT_OBJECT_OPEN *psEventObjectOpenIN, + struct PVRSRV_BRIDGE_OUT_EVENT_OBJECT_OPEN *psEventObjectOpenOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_EVENT_OBJECT_OPEN); + + NEW_HANDLE_BATCH_OR_ERROR(psEventObjectOpenOUT->eError, psPerProc, 1); + + psEventObjectOpenOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &psEventObjectOpenIN->sEventObject.hOSEventKM, + psEventObjectOpenIN->sEventObject.hOSEventKM, + PVRSRV_HANDLE_TYPE_SHARED_EVENT_OBJECT); + + if (psEventObjectOpenOUT->eError != PVRSRV_OK) + return 0; + + psEventObjectOpenOUT->eError = + OSEventObjectOpen(&psEventObjectOpenIN->sEventObject, + &psEventObjectOpenOUT->hOSEvent); + + if (psEventObjectOpenOUT->eError != PVRSRV_OK) + return 0; + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psEventObjectOpenOUT->hOSEvent, + psEventObjectOpenOUT->hOSEvent, + PVRSRV_HANDLE_TYPE_EVENT_OBJECT_CONNECT, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI); + + COMMIT_HANDLE_BATCH_OR_ERROR(psEventObjectOpenOUT->eError, psPerProc); + + return 0; +} + +static int PVRSRVEventObjectCloseBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_EVENT_OBJECT_CLOSE *psEventObjectCloseIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hOSEventKM; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_EVENT_OBJECT_CLOSE); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &psEventObjectCloseIN->sEventObject.hOSEventKM, + psEventObjectCloseIN->sEventObject.hOSEventKM, + PVRSRV_HANDLE_TYPE_SHARED_EVENT_OBJECT); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + &hOSEventKM, + psEventObjectCloseIN->hOSEventKM, + PVRSRV_HANDLE_TYPE_EVENT_OBJECT_CONNECT); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + OSEventObjectClose(&psEventObjectCloseIN->sEventObject, hOSEventKM); + + return 0; +} + +enum PVRSRV_ERROR CommonBridgeInit(void) +{ + u32 i; + + SetDispatchTableEntry(PVRSRV_BRIDGE_ENUM_DEVICES, + PVRSRVEnumerateDevicesBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_ACQUIRE_DEVICEINFO, + PVRSRVAcquireDeviceDataBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_RELEASE_DEVICEINFO, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_CREATE_DEVMEMCONTEXT, + PVRSRVCreateDeviceMemContextBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_DESTROY_DEVMEMCONTEXT, + PVRSRVDestroyDeviceMemContextBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_DEVMEM_HEAPINFO, + PVRSRVGetDeviceMemHeapInfoBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_ALLOC_DEVICEMEM, + PVRSRVAllocDeviceMemBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_FREE_DEVICEMEM, + PVRSRVFreeDeviceMemBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_GETFREE_DEVICEMEM, + PVRSRVGetFreeDeviceMemBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_CREATE_COMMANDQUEUE, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_DESTROY_COMMANDQUEUE, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_MHANDLE_TO_MMAP_DATA, + PVRMMapOSMemHandleToMMapDataBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_CONNECT_SERVICES, PVRSRVConnectBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_DISCONNECT_SERVICES, + PVRSRVDisconnectBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_WRAP_DEVICE_MEM, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_DEVICEMEMINFO, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_RESERVE_DEV_VIRTMEM, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_FREE_DEV_VIRTMEM, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_MAP_EXT_MEMORY, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_UNMAP_EXT_MEMORY, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_MAP_DEV_MEMORY, + PVRSRVMapDeviceMemoryBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_UNMAP_DEV_MEMORY, + PVRSRVUnmapDeviceMemoryBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_MAP_DEVICECLASS_MEMORY, + PVRSRVMapDeviceClassMemoryBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_UNMAP_DEVICECLASS_MEMORY, + PVRSRVUnmapDeviceClassMemoryBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_MAP_MEM_INFO_TO_USER, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_UNMAP_MEM_INFO_FROM_USER, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_EXPORT_DEVICEMEM, + PVRSRVExportDeviceMemBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_RELEASE_MMAP_DATA, + PVRMMapReleaseMMapDataBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_CACHE_FLUSH_DRM, + PVRSRVCacheFlushDRIBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_PROCESS_SIMISR_EVENT, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_REGISTER_SIM_PROCESS, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_UNREGISTER_SIM_PROCESS, DummyBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_MAPPHYSTOUSERSPACE, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_UNMAPPHYSTOUSERSPACE, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_GETPHYSTOUSERSPACEMAP, DummyBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_FB_STATS, DummyBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_MISC_INFO, PVRSRVGetMiscInfoBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_RELEASE_MISC_INFO, DummyBW); + + +#if defined(PDUMP) + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_INIT, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_MEMPOL, PDumpMemPolBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_DUMPMEM, PDumpMemBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_REG, PDumpRegWithFlagsBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_REGPOL, PDumpRegPolBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_COMMENT, PDumpCommentBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_SETFRAME, PDumpSetFrameBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_ISCAPTURING, + PDumpIsCaptureFrameBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_DUMPBITMAP, PDumpBitmapBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_DUMPREADREG, PDumpReadRegBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_SYNCPOL, PDumpSyncPolBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_DUMPSYNC, PDumpSyncDumpBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_DRIVERINFO, + PDumpDriverInfoBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_PDREG, PDumpPDRegBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_DUMPPDDEVPADDR, + PDumpPDDevPAddrBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_CYCLE_COUNT_REG_READ, + PDumpCycleCountRegReadBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_STARTINITPHASE, + PDumpStartInitPhaseBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_STOPINITPHASE, + PDumpStopInitPhaseBW); +#endif + + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_OEMJTABLE, DummyBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_ENUM_CLASS, PVRSRVEnumerateDCBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_OPEN_DISPCLASS_DEVICE, + PVRSRVOpenDCDeviceBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_CLOSE_DISPCLASS_DEVICE, + PVRSRVCloseDCDeviceBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_ENUM_DISPCLASS_FORMATS, + PVRSRVEnumDCFormatsBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_ENUM_DISPCLASS_DIMS, + PVRSRVEnumDCDimsBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_DISPCLASS_SYSBUFFER, + PVRSRVGetDCSystemBufferBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_DISPCLASS_INFO, + PVRSRVGetDCInfoBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_CREATE_DISPCLASS_SWAPCHAIN, + PVRSRVCreateDCSwapChainBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_DESTROY_DISPCLASS_SWAPCHAIN, + PVRSRVDestroyDCSwapChainBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SET_DISPCLASS_DSTRECT, + PVRSRVSetDCDstRectBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SET_DISPCLASS_SRCRECT, + PVRSRVSetDCSrcRectBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SET_DISPCLASS_DSTCOLOURKEY, + PVRSRVSetDCDstColourKeyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SET_DISPCLASS_SRCCOLOURKEY, + PVRSRVSetDCSrcColourKeyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_DISPCLASS_BUFFERS, + PVRSRVGetDCBuffersBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_BUFFER, + PVRSRVSwapToDCBufferBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_SYSTEM, + PVRSRVSwapToDCSystemBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_OPEN_BUFFERCLASS_DEVICE, + PVRSRVOpenBCDeviceBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_CLOSE_BUFFERCLASS_DEVICE, + PVRSRVCloseBCDeviceBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_BUFFERCLASS_INFO, + PVRSRVGetBCInfoBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_BUFFERCLASS_BUFFER, + PVRSRVGetBCBufferBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_WRAP_EXT_MEMORY, + PVRSRVWrapExtMemoryBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_UNWRAP_EXT_MEMORY, + PVRSRVUnwrapExtMemoryBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_ALLOC_SHARED_SYS_MEM, + PVRSRVAllocSharedSysMemoryBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_FREE_SHARED_SYS_MEM, + PVRSRVFreeSharedSysMemoryBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_MAP_MEMINFO_MEM, + PVRSRVMapMemInfoMemBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_GETMMU_PD_DEVPADDR, + MMU_GetPDDevPAddrBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_INITSRV_CONNECT, + PVRSRVInitSrvConnectBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_INITSRV_DISCONNECT, + PVRSRVInitSrvDisconnectBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_EVENT_OBJECT_WAIT, + PVRSRVEventObjectWaitBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_EVENT_OBJECT_OPEN, + PVRSRVEventObjectOpenBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_EVENT_OBJECT_CLOSE, + PVRSRVEventObjectCloseBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_MODIFY_SYNC_OPS, + PVRSRVModifySyncOpsBW); + + SetSGXDispatchTableEntry(); + + for (i = 0; i < BRIDGE_DISPATCH_TABLE_ENTRY_COUNT; i++) + if (!g_BridgeDispatchTable[i].pfFunction) { + g_BridgeDispatchTable[i].pfFunction = DummyBW; +#if defined(DEBUG_BRIDGE_KM) + g_BridgeDispatchTable[i].pszIOCName = + "_PVRSRV_BRIDGE_DUMMY"; + g_BridgeDispatchTable[i].pszFunctionName = "DummyBW"; + g_BridgeDispatchTable[i].ui32CallCount = 0; + g_BridgeDispatchTable[i].ui32CopyFromUserTotalBytes = 0; + g_BridgeDispatchTable[i].ui32CopyToUserTotalBytes = 0; +#endif + } + + return PVRSRV_OK; +} + +static int bridged_check_cmd(u32 cmd_id) +{ + if (PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RAN)) { + if (!PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL)) { + PVR_DPF(PVR_DBG_ERROR, + "%s: Initialisation failed. Driver unusable.", + __func__); + return 1; + } + } else { + if (PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RUNNING)) { + PVR_DPF(PVR_DBG_ERROR, + "%s: Initialisation is in progress", + __func__); + return 1; + } else { + switch (cmd_id) { + case PVRSRV_GET_BRIDGE_ID( + PVRSRV_BRIDGE_CONNECT_SERVICES): + case PVRSRV_GET_BRIDGE_ID( + PVRSRV_BRIDGE_DISCONNECT_SERVICES): + case PVRSRV_GET_BRIDGE_ID( + PVRSRV_BRIDGE_INITSRV_CONNECT): + case PVRSRV_GET_BRIDGE_ID( + PVRSRV_BRIDGE_INITSRV_DISCONNECT): + break; + default: + PVR_DPF(PVR_DBG_ERROR, + "%s: Driver initialisation not completed yet.", + __func__); + return 1; + } + } + } + + return 0; +} + +static int bridged_ioctl(struct file *filp, u32 cmd, void *in, void *out, + size_t in_size, + struct PVRSRV_PER_PROCESS_DATA *per_proc) +{ + int err = -EFAULT; + + switch (PVRSRV_IOWR(cmd)) { + case PVRSRV_BRIDGE_ENUM_DEVICES: + err = PVRSRVEnumerateDevicesBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_ACQUIRE_DEVICEINFO: + err = PVRSRVAcquireDeviceDataBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_RELEASE_DEVICEINFO: + err = DummyBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_CREATE_DEVMEMCONTEXT: + err = PVRSRVCreateDeviceMemContextBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_DESTROY_DEVMEMCONTEXT: + err = PVRSRVDestroyDeviceMemContextBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_GET_DEVMEM_HEAPINFO: + err = PVRSRVGetDeviceMemHeapInfoBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_ALLOC_DEVICEMEM: + err = PVRSRVAllocDeviceMemBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_FREE_DEVICEMEM: + err = PVRSRVFreeDeviceMemBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_GETFREE_DEVICEMEM: + err = PVRSRVGetFreeDeviceMemBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_CREATE_COMMANDQUEUE: + case PVRSRV_BRIDGE_DESTROY_COMMANDQUEUE: + err = DummyBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_MHANDLE_TO_MMAP_DATA: + err = PVRMMapOSMemHandleToMMapDataBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_CONNECT_SERVICES: + err = PVRSRVConnectBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_DISCONNECT_SERVICES: + err = PVRSRVDisconnectBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_WRAP_DEVICE_MEM: + case PVRSRV_BRIDGE_GET_DEVICEMEMINFO: + case PVRSRV_BRIDGE_RESERVE_DEV_VIRTMEM: + case PVRSRV_BRIDGE_FREE_DEV_VIRTMEM: + case PVRSRV_BRIDGE_MAP_EXT_MEMORY: + case PVRSRV_BRIDGE_UNMAP_EXT_MEMORY: + err = DummyBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_MAP_DEV_MEMORY: + err = PVRSRVMapDeviceMemoryBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_UNMAP_DEV_MEMORY: + err = PVRSRVUnmapDeviceMemoryBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_MAP_DEVICECLASS_MEMORY: + err = PVRSRVMapDeviceClassMemoryBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_UNMAP_DEVICECLASS_MEMORY: + err = PVRSRVUnmapDeviceClassMemoryBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_MAP_MEM_INFO_TO_USER: + case PVRSRV_BRIDGE_UNMAP_MEM_INFO_FROM_USER: + err = DummyBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_EXPORT_DEVICEMEM: + err = PVRSRVExportDeviceMemBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_RELEASE_MMAP_DATA: + err = PVRMMapReleaseMMapDataBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_CACHE_FLUSH_DRM: + err = PVRSRVCacheFlushDRIBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_PROCESS_SIMISR_EVENT: + case PVRSRV_BRIDGE_REGISTER_SIM_PROCESS: + case PVRSRV_BRIDGE_UNREGISTER_SIM_PROCESS: + case PVRSRV_BRIDGE_MAPPHYSTOUSERSPACE: + case PVRSRV_BRIDGE_UNMAPPHYSTOUSERSPACE: + case PVRSRV_BRIDGE_GETPHYSTOUSERSPACEMAP: + case PVRSRV_BRIDGE_GET_FB_STATS: + err = DummyBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_GET_MISC_INFO: + err = PVRSRVGetMiscInfoBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_RELEASE_MISC_INFO: + err = DummyBW(cmd, in, out, per_proc); + break; + +#if defined(PDUMP) + case PVRSRV_BRIDGE_PDUMP_INIT: + err = DummyBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_MEMPOL: + err = PDumpMemPolBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_DUMPMEM: + err = PDumpMemBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_REG: + err = PDumpRegWithFlagsBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_REGPOL: + err = PDumpRegPolBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_COMMENT: + err = PDumpCommentBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_SETFRAME: + err = PDumpSetFrameBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_ISCAPTURING: + err = PDumpIsCaptureFrameBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_DUMPBITMAP: + err = PDumpBitmapBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_DUMPREADREG: + err = PDumpReadRegBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_SYNCPOL: + err = PDumpSyncPolBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_DUMPSYNC: + err = PDumpSyncDumpBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_DRIVERINFO: + err = PDumpDriverInfoBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_PDREG: + err = PDumpPDRegBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_DUMPPDDEVPADDR: + err = PDumpPDDevPAddrBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_CYCLE_COUNT_REG_READ: + err = PDumpCycleCountRegReadBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_STARTINITPHASE: + err = PDumpStartInitPhaseBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_PDUMP_STOPINITPHASE: + err = PDumpStopInitPhaseBW(cmd, in, out, per_proc); + break; +#endif + + case PVRSRV_BRIDGE_GET_OEMJTABLE: + err = DummyBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_ENUM_CLASS: + err = PVRSRVEnumerateDCBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_OPEN_DISPCLASS_DEVICE: + err = PVRSRVOpenDCDeviceBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_CLOSE_DISPCLASS_DEVICE: + err = PVRSRVCloseDCDeviceBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_ENUM_DISPCLASS_FORMATS: + err = PVRSRVEnumDCFormatsBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_ENUM_DISPCLASS_DIMS: + err = PVRSRVEnumDCDimsBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_GET_DISPCLASS_SYSBUFFER: + err = PVRSRVGetDCSystemBufferBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_GET_DISPCLASS_INFO: + err = PVRSRVGetDCInfoBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_CREATE_DISPCLASS_SWAPCHAIN: + err = PVRSRVCreateDCSwapChainBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_DESTROY_DISPCLASS_SWAPCHAIN: + err = PVRSRVDestroyDCSwapChainBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SET_DISPCLASS_DSTRECT: + err = PVRSRVSetDCDstRectBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SET_DISPCLASS_SRCRECT: + err = PVRSRVSetDCSrcRectBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SET_DISPCLASS_DSTCOLOURKEY: + err = PVRSRVSetDCDstColourKeyBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SET_DISPCLASS_SRCCOLOURKEY: + err = PVRSRVSetDCSrcColourKeyBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_GET_DISPCLASS_BUFFERS: + err = PVRSRVGetDCBuffersBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_BUFFER: + err = PVRSRVSwapToDCBufferBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_SYSTEM: + err = PVRSRVSwapToDCSystemBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_OPEN_BUFFERCLASS_DEVICE: + err = PVRSRVOpenBCDeviceBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_CLOSE_BUFFERCLASS_DEVICE: + err = PVRSRVCloseBCDeviceBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_GET_BUFFERCLASS_INFO: + err = PVRSRVGetBCInfoBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_GET_BUFFERCLASS_BUFFER: + err = PVRSRVGetBCBufferBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_WRAP_EXT_MEMORY: + err = PVRSRVWrapExtMemoryBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_UNWRAP_EXT_MEMORY: + err = PVRSRVUnwrapExtMemoryBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_ALLOC_SHARED_SYS_MEM: + err = PVRSRVAllocSharedSysMemoryBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_FREE_SHARED_SYS_MEM: + err = PVRSRVFreeSharedSysMemoryBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_MAP_MEMINFO_MEM: + err = PVRSRVMapMemInfoMemBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_GETMMU_PD_DEVPADDR: + err = MMU_GetPDDevPAddrBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_INITSRV_CONNECT: + err = PVRSRVInitSrvConnectBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_INITSRV_DISCONNECT: + err = PVRSRVInitSrvDisconnectBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_EVENT_OBJECT_WAIT: + err = PVRSRVEventObjectWaitBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_EVENT_OBJECT_OPEN: + err = PVRSRVEventObjectOpenBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_EVENT_OBJECT_CLOSE: + err = PVRSRVEventObjectCloseBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_MODIFY_SYNC_OPS: + err = PVRSRVModifySyncOpsBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_SGX_GETCLIENTINFO: + err = SGXGetClientInfoBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_RELEASECLIENTINFO: + err = SGXReleaseClientInfoBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_GETINTERNALDEVINFO: + err = SGXGetInternalDevInfoBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_DOKICK: + err = SGXDoKickBW(cmd, in, out, in_size, per_proc); + break; + + case PVRSRV_BRIDGE_SGX_GETPHYSPAGEADDR: + case PVRSRV_BRIDGE_SGX_READREGISTRYDWORD: + case PVRSRV_BRIDGE_SGX_SCHEDULECOMMAND: + err = DummyBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_SGX_2DQUERYBLTSCOMPLETE: + err = SGX2DQueryBlitsCompleteBW(filp, cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_SGX_GETMMUPDADDR: + err = DummyBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_SGX_SUBMITTRANSFER: + err = SGXSubmitTransferBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_GETMISCINFO: + err = SGXGetMiscInfoBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGXINFO_FOR_SRVINIT: + err = SGXGetInfoForSrvinitBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_DEVINITPART2: + err = SGXDevInitPart2BW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_SGX_FINDSHAREDPBDESC: + err = SGXFindSharedPBDescBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_UNREFSHAREDPBDESC: + err = SGXUnrefSharedPBDescBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC: + err = SGXAddSharedPBDescBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_REGISTER_HW_RENDER_CONTEXT: + err = SGXRegisterHWRenderContextBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_FLUSH_HW_RENDER_TARGET: + err = SGXFlushHWRenderTargetBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_UNREGISTER_HW_RENDER_CONTEXT: + err = SGXUnregisterHWRenderContextBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_REGISTER_HW_TRANSFER_CONTEXT: + err = SGXRegisterHWTransferContextBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_UNREGISTER_HW_TRANSFER_CONTEXT: + err = SGXUnregisterHWTransferContextBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_SGX_READ_DIFF_COUNTERS: + err = SGXReadDiffCountersBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_READ_HWPERF_CB: + err = SGXReadHWPerfCBBW(cmd, in, out, per_proc); + break; + + case PVRSRV_BRIDGE_SGX_SCHEDULE_PROCESS_QUEUES: + err = SGXScheduleProcessQueuesBW(cmd, in, out, per_proc); + break; + +#if defined(PDUMP) + case PVRSRV_BRIDGE_SGX_PDUMP_BUFFER_ARRAY: + err = SGXPDumpBufferArrayBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_PDUMP_3D_SIGNATURE_REGISTERS: + err = SGXPDump3DSignatureRegistersBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_PDUMP_COUNTER_REGISTERS: + err = SGXPDumpCounterRegistersBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_PDUMP_TA_SIGNATURE_REGISTERS: + err = SGXPDumpTASignatureRegistersBW(cmd, in, out, per_proc); + break; + case PVRSRV_BRIDGE_SGX_PDUMP_HWPERFCB: + err = SGXPDumpHWPerfCBBW(cmd, in, out, per_proc); + break; +#endif + + default: + PVR_DPF(PVR_DBG_ERROR, "%s: cmd = %d is out if range!", + __func__, cmd); + } + + return err; +} + +int BridgedDispatchKM(struct file *filp, struct PVRSRV_PER_PROCESS_DATA *pd, + struct PVRSRV_BRIDGE_PACKAGE *pkg) +{ + + void *in; + void *out; + u32 bid = pkg->ui32BridgeID; + int err = -EFAULT; + struct SYS_DATA *psSysData; + +#if defined(DEBUG_BRIDGE_KM) + g_BridgeDispatchTable[bid].ui32CallCount++; + g_BridgeGlobalStats.ui32IOCTLCount++; +#endif + if (!pd->bInitProcess && bridged_check_cmd(bid)) + goto return_fault; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + goto return_fault; + + in = ((struct ENV_DATA *)psSysData->pvEnvSpecificData)->pvBridgeData; + out = (void *)((u8 *)in + PVRSRV_MAX_BRIDGE_IN_SIZE); + + if (pkg->ui32InBufferSize > 0 && + CopyFromUserWrapper(pd, bid, in, pkg->pvParamIn, + pkg->ui32InBufferSize) != PVRSRV_OK) + goto return_fault; + + if (bid >= (BRIDGE_DISPATCH_TABLE_ENTRY_COUNT)) { + PVR_DPF(PVR_DBG_ERROR, + "%s: ui32BridgeID = %d is out if range!", __func__, + bid); + goto return_fault; + } + + err = bridged_ioctl(filp, bid, in, out, pkg->ui32InBufferSize, pd); + + if (err < 0) + goto return_fault; + + if (CopyToUserWrapper(pd, bid, pkg->pvParamOut, out, + pkg->ui32OutBufferSize) != PVRSRV_OK) + goto return_fault; + + err = 0; +return_fault: + ReleaseHandleBatch(pd); + return err; +} diff --git a/drivers/gpu/pvr/bridged_pvr_bridge.h b/drivers/gpu/pvr/bridged_pvr_bridge.h new file mode 100644 index 00000000000..188fdedf092 --- /dev/null +++ b/drivers/gpu/pvr/bridged_pvr_bridge.h @@ -0,0 +1,158 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __BRIDGED_PVR_BRIDGE_H__ +#define __BRIDGED_PVR_BRIDGE_H__ + +#include "pvr_bridge.h" + +#define PVRSRV_GET_BRIDGE_ID(X) _IOC_NR(X) + +#if defined(DEBUG_BRIDGE_KM) +enum PVRSRV_ERROR CopyFromUserWrapper(struct PVRSRV_PER_PROCESS_DATA *pProcData, + u32 ui32BridgeID, void *pvDest, + void __user *pvSrc, u32 ui32Size); +enum PVRSRV_ERROR CopyToUserWrapper(struct PVRSRV_PER_PROCESS_DATA *pProcData, + u32 ui32BridgeID, void __user *pvDest, + void *pvSrc, u32 ui32Size); +#else +#define CopyFromUserWrapper(pProcData, ui32BridgeID, pvDest, pvSrc, ui32Size) \ + OSCopyFromUser(pProcData, pvDest, pvSrc, ui32Size) +#define CopyToUserWrapper(pProcData, ui32BridgeID, pvDest, pvSrc, ui32Size) \ + OSCopyToUser(pProcData, pvDest, pvSrc, ui32Size) +#endif + +#define ASSIGN_AND_RETURN_ON_ERROR(error, src, res) \ + do { \ + (error) = (src); \ + if ((error) != PVRSRV_OK) \ + return res; \ + } while (error != PVRSRV_OK) + +#define ASSIGN_AND_EXIT_ON_ERROR(error, src) \ + ASSIGN_AND_RETURN_ON_ERROR(error, src, 0) + +static inline enum PVRSRV_ERROR NewHandleBatch( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, u32 ui32BatchSize) +{ + enum PVRSRV_ERROR eError; + + PVR_ASSERT(!psPerProc->bHandlesBatched); + + eError = PVRSRVNewHandleBatch(psPerProc->psHandleBase, ui32BatchSize); + + if (eError == PVRSRV_OK) + psPerProc->bHandlesBatched = IMG_TRUE; + + return eError; +} + +#define NEW_HANDLE_BATCH_OR_ERROR(error, psPerProc, ui32BatchSize) \ + ASSIGN_AND_EXIT_ON_ERROR(error, NewHandleBatch(psPerProc, \ + ui32BatchSize)) + +static inline enum PVRSRV_ERROR +CommitHandleBatch(struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVR_ASSERT(psPerProc->bHandlesBatched); + + psPerProc->bHandlesBatched = IMG_FALSE; + + return PVRSRVCommitHandleBatch(psPerProc->psHandleBase); +} + +#define COMMIT_HANDLE_BATCH_OR_ERROR(error, psPerProc) \ + ASSIGN_AND_EXIT_ON_ERROR(error, CommitHandleBatch(psPerProc)) + +static inline void ReleaseHandleBatch(struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + if (psPerProc->bHandlesBatched) { + psPerProc->bHandlesBatched = IMG_FALSE; + + PVRSRVReleaseHandleBatch(psPerProc->psHandleBase); + } +} + +int DummyBW(u32 ui32BridgeID, void *psBridgeIn, void *psBridgeOut, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +struct PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY { + int (*pfFunction)(u32 ui32BridgeID, void *psBridgeIn, void *psBridgeOut, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); +#if defined(DEBUG_BRIDGE_KM) + const char *pszIOCName; + const char *pszFunctionName; + u32 ui32CallCount; + u32 ui32CopyFromUserTotalBytes; + u32 ui32CopyToUserTotalBytes; +#endif +}; + +#define BRIDGE_DISPATCH_TABLE_ENTRY_COUNT (PVRSRV_BRIDGE_LAST_SGX_CMD+1) +#define PVRSRV_BRIDGE_LAST_DEVICE_CMD PVRSRV_BRIDGE_LAST_SGX_CMD + +extern struct PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY + g_BridgeDispatchTable[BRIDGE_DISPATCH_TABLE_ENTRY_COUNT]; + +void _SetDispatchTableEntry(u32 ui32Index, + const char *pszIOCName, + int (*pfFunction) (u32 ui32BridgeID, + void *psBridgeIn, + void *psBridgeOut, + struct PVRSRV_PER_PROCESS_DATA * + psPerProc), + const char *pszFunctionName); + +#define SetDispatchTableEntry(ui32Index, pfFunction) \ + _SetDispatchTableEntry(PVRSRV_GET_BRIDGE_ID(ui32Index), #ui32Index, \ + (int (*)(u32 ui32BridgeID, void *psBridgeIn, void *psBridgeOut, \ + struct PVRSRV_PER_PROCESS_DATA *psPerProc))pfFunction, #pfFunction) + +#define DISPATCH_TABLE_GAP_THRESHOLD 5 + +#if defined(CONFIG_PVR_DEBUG_EXTRA) +#define PVRSRV_BRIDGE_ASSERT_CMD(X, Y) PVR_ASSERT(X == PVRSRV_GET_BRIDGE_ID(Y)) +#else +#define PVRSRV_BRIDGE_ASSERT_CMD(X, Y) PVR_UNREFERENCED_PARAMETER(X) +#endif + +#if defined(DEBUG_BRIDGE_KM) +struct PVRSRV_BRIDGE_GLOBAL_STATS { + u32 ui32IOCTLCount; + u32 ui32TotalCopyFromUserBytes; + u32 ui32TotalCopyToUserBytes; +}; + +extern struct PVRSRV_BRIDGE_GLOBAL_STATS g_BridgeGlobalStats; +#endif + +enum PVRSRV_ERROR CommonBridgeInit(void); + +int BridgedDispatchKM(struct file *filp, + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + struct PVRSRV_BRIDGE_PACKAGE *psBridgePackageKM); + +#endif diff --git a/drivers/gpu/pvr/bridged_sgx_bridge.c b/drivers/gpu/pvr/bridged_sgx_bridge.c new file mode 100644 index 00000000000..b2dae3790c6 --- /dev/null +++ b/drivers/gpu/pvr/bridged_sgx_bridge.c @@ -0,0 +1,1871 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/errno.h> + +#include <stddef.h> + +#include "img_defs.h" + +#include "services.h" +#include "pvr_debug.h" +#include "pvr_bridge.h" +#include "sgx_bridge.h" +#include "perproc.h" +#include "power.h" +#include "pvr_bridge_km.h" +#include "sgx_bridge_km.h" +#include "bridged_pvr_bridge.h" +#include "bridged_sgx_bridge.h" +#include "sgxutils.h" +#include "pdump_km.h" +#include "pvr_events.h" + +int SGXGetClientInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GETCLIENTINFO *psGetClientInfoIN, + struct PVRSRV_BRIDGE_OUT_GETCLIENTINFO *psGetClientInfoOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_GETCLIENTINFO); + + psGetClientInfoOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psGetClientInfoIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psGetClientInfoOUT->eError != PVRSRV_OK) + return 0; + + psGetClientInfoOUT->eError = + SGXGetClientInfoKM(hDevCookieInt, &psGetClientInfoOUT->sClientInfo); + return 0; +} + +int SGXReleaseClientInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_RELEASECLIENTINFO *psReleaseClientInfoIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo; + void *hDevCookieInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_RELEASECLIENTINFO); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psReleaseClientInfoIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)((struct PVRSRV_DEVICE_NODE *) + hDevCookieInt)->pvDevice; + + PVR_ASSERT(psDevInfo->ui32ClientRefCount > 0); + + psDevInfo->ui32ClientRefCount--; + + psRetOUT->eError = PVRSRV_OK; + + return 0; +} + +int SGXGetInternalDevInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GETINTERNALDEVINFO *psSGXGetInternalDevInfoIN, + struct PVRSRV_BRIDGE_OUT_GETINTERNALDEVINFO *psSGXGetInternalDevInfoOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_GETINTERNALDEVINFO); + + psSGXGetInternalDevInfoOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psSGXGetInternalDevInfoIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psSGXGetInternalDevInfoOUT->eError != PVRSRV_OK) + return 0; + + psSGXGetInternalDevInfoOUT->eError = + SGXGetInternalDevInfoKM(hDevCookieInt, + &psSGXGetInternalDevInfoOUT->sSGXInternalDevInfo); + + psSGXGetInternalDevInfoOUT->eError = + PVRSRVAllocHandle(psPerProc->psHandleBase, + &psSGXGetInternalDevInfoOUT->sSGXInternalDevInfo. + hHostCtlKernelMemInfoHandle, + psSGXGetInternalDevInfoOUT->sSGXInternalDevInfo. + hHostCtlKernelMemInfoHandle, + PVRSRV_HANDLE_TYPE_MEM_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_SHARED); + + return 0; +} + +/* Convert the IOCTL parameter from "old" to "new" format. */ +static int kick_compat_conv(struct PVRSRV_BRIDGE_IN_DOKICK *kick, + size_t in_size) +{ + struct SGX_CCB_KICK *ccb; + size_t diff; + + ccb = &kick->sCCBKick; + + diff = sizeof(ccb->ah3DStatusSyncInfo[0]) * + (SGX_MAX_3D_STATUS_VALS - SGX_MAX_3D_STATUS_VALS_OLD); + if (sizeof(*kick) - in_size != diff) + return -EINVAL; + + /* Trailing size at the end of struct to move. */ + diff = sizeof(*kick) - offsetof(typeof(*kick), + sCCBKick.ah3DStatusSyncInfo[SGX_MAX_3D_STATUS_VALS]); + memmove(&kick->sCCBKick.ah3DStatusSyncInfo[SGX_MAX_3D_STATUS_VALS], + &kick->sCCBKick.ah3DStatusSyncInfo[SGX_MAX_3D_STATUS_VALS_OLD], + diff); + + return 0; +} + +int SGXDoKickBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_DOKICK *psDoKickIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + size_t in_size, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + int max_3dstat_vals; + u32 i; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_DOKICK); + + max_3dstat_vals = SGX_MAX_3D_STATUS_VALS; + if (unlikely(in_size != sizeof(*psDoKickIN))) { + max_3dstat_vals = SGX_MAX_3D_STATUS_VALS_OLD; + if (kick_compat_conv(psDoKickIN, in_size) != 0) { + psRetOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + return -EINVAL; + } + + } + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psDoKickIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psDoKickIN->sCCBKick.hCCBKernelMemInfo, + psDoKickIN->sCCBKick.hCCBKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + if (psDoKickIN->sCCBKick.hTA3DSyncInfo != NULL) { + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &psDoKickIN->sCCBKick.hTA3DSyncInfo, + psDoKickIN->sCCBKick.hTA3DSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + if (psDoKickIN->sCCBKick.hTASyncInfo != NULL) { + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &psDoKickIN->sCCBKick.hTASyncInfo, + psDoKickIN->sCCBKick.hTASyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + if (psDoKickIN->sCCBKick.h3DSyncInfo != NULL) { + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &psDoKickIN->sCCBKick.h3DSyncInfo, + psDoKickIN->sCCBKick.h3DSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + if (psDoKickIN->sCCBKick.ui32NumSrcSyncs > SGX_MAX_SRC_SYNCS) { + psRetOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + return 0; + } + for (i = 0; i < psDoKickIN->sCCBKick.ui32NumSrcSyncs; i++) { + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &psDoKickIN->sCCBKick. + ahSrcKernelSyncInfo[i], + psDoKickIN->sCCBKick. + ahSrcKernelSyncInfo[i], + PVRSRV_HANDLE_TYPE_SYNC_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + if (psDoKickIN->sCCBKick.ui32NumTAStatusVals > SGX_MAX_TA_STATUS_VALS) { + psRetOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + return 0; + } + for (i = 0; i < psDoKickIN->sCCBKick.ui32NumTAStatusVals; i++) { + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &psDoKickIN->sCCBKick.ahTAStatusSyncInfo[i], + psDoKickIN->sCCBKick.ahTAStatusSyncInfo[i], + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + if (psDoKickIN->sCCBKick.ui32Num3DStatusVals > max_3dstat_vals) { + psRetOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + return 0; + } + for (i = 0; i < psDoKickIN->sCCBKick.ui32Num3DStatusVals; i++) { + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &psDoKickIN->sCCBKick.ah3DStatusSyncInfo[i], + psDoKickIN->sCCBKick.ah3DStatusSyncInfo[i], + PVRSRV_HANDLE_TYPE_SYNC_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + if (psDoKickIN->sCCBKick.ui32NumDstSyncObjects > 0) { + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psDoKickIN->sCCBKick. + hKernelHWSyncListMemInfo, + psDoKickIN->sCCBKick. + hKernelHWSyncListMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psDoKickIN->sCCBKick.sDstSyncHandle, + psDoKickIN->sCCBKick.sDstSyncHandle, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + psRetOUT->eError = SGXDoKickKM(hDevCookieInt, &psDoKickIN->sCCBKick, + max_3dstat_vals); + + return 0; +} + +int SGXScheduleProcessQueuesBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_SCHEDULE_PROCESS_QUEUES *psScheduleProcQIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_SCHEDULE_PROCESS_QUEUES); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psScheduleProcQIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = SGXScheduleProcessQueuesKM(hDevCookieInt); + + return 0; +} + +int SGXSubmitTransferBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SUBMITTRANSFER *psSubmitTransferIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + struct PVRSRV_TRANSFER_SGX_KICK *psKick; + u32 i; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_SUBMITTRANSFER); + PVR_UNREFERENCED_PARAMETER(ui32BridgeID); + + psKick = &psSubmitTransferIN->sKick; + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psSubmitTransferIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psKick->hCCBMemInfo, + psKick->hCCBMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + if (psKick->hTASyncInfo != NULL) { + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psKick->hTASyncInfo, + psKick->hTASyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + if (psKick->h3DSyncInfo != NULL) { + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psKick->h3DSyncInfo, + psKick->h3DSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + if (psKick->ui32NumSrcSync > SGX_MAX_TRANSFER_SYNC_OPS) { + psRetOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + return 0; + } + for (i = 0; i < psKick->ui32NumSrcSync; i++) { + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psKick->ahSrcSyncInfo[i], + psKick->ahSrcSyncInfo[i], + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + if (psKick->ui32NumDstSync > SGX_MAX_TRANSFER_SYNC_OPS) { + psRetOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + return 0; + } + for (i = 0; i < psKick->ui32NumDstSync; i++) { + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psKick->ahDstSyncInfo[i], + psKick->ahDstSyncInfo[i], + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + psRetOUT->eError = SGXSubmitTransferKM(hDevCookieInt, psKick); + + return 0; +} + +int SGXGetMiscInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXGETMISCINFO *psSGXGetMiscInfoIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + struct SGX_MISC_INFO sMiscInfo; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_GETMISCINFO); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psSGXGetMiscInfoIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psDeviceNode = hDevCookieInt; + PVR_ASSERT(psDeviceNode != NULL); + if (psDeviceNode == NULL) + return -EFAULT; + + psDevInfo = psDeviceNode->pvDevice; + + psRetOUT->eError = CopyFromUserWrapper(psPerProc, ui32BridgeID, + &sMiscInfo, + psSGXGetMiscInfoIN->psMiscInfo, + sizeof(struct SGX_MISC_INFO)); + if (psRetOUT->eError != PVRSRV_OK) + return -EFAULT; + + if (sMiscInfo.eRequest == SGX_MISC_INFO_REQUEST_HWPERF_RETRIEVE_CB) { + void *pAllocated; + void *hAllocatedHandle; + void __user *psTmpUserData; + u32 allocatedSize; + + allocatedSize = + (u32) (sMiscInfo.uData.sRetrieveCB.ui32ArraySize * + sizeof(struct PVRSRV_SGX_HWPERF_CBDATA)); + + ASSIGN_AND_EXIT_ON_ERROR(psRetOUT->eError, + OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + allocatedSize, + &pAllocated, + &hAllocatedHandle)); + + psTmpUserData = (void __force __user *) + sMiscInfo.uData.sRetrieveCB.psHWPerfData; + sMiscInfo.uData.sRetrieveCB.psHWPerfData = pAllocated; + + psRetOUT->eError = SGXGetMiscInfoKM(psDevInfo, + &sMiscInfo, psDeviceNode); + if (psRetOUT->eError != PVRSRV_OK) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + allocatedSize, pAllocated, hAllocatedHandle); + return 0; + } + + psRetOUT->eError = CopyToUserWrapper(psPerProc, + ui32BridgeID, psTmpUserData, + sMiscInfo.uData.sRetrieveCB.psHWPerfData, + allocatedSize); + + sMiscInfo.uData.sRetrieveCB.psHWPerfData = + (void __force *)psTmpUserData; + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + allocatedSize, pAllocated, hAllocatedHandle); + + if (psRetOUT->eError != PVRSRV_OK) + return -EFAULT; + } else { + psRetOUT->eError = SGXGetMiscInfoKM(psDevInfo, + &sMiscInfo, psDeviceNode); + + if (psRetOUT->eError != PVRSRV_OK) + return 0; + } + + psRetOUT->eError = CopyToUserWrapper(psPerProc, + ui32BridgeID, + psSGXGetMiscInfoIN->psMiscInfo, + &sMiscInfo, + sizeof(struct SGX_MISC_INFO)); + if (psRetOUT->eError != PVRSRV_OK) + return -EFAULT; + return 0; +} + +int SGXReadDiffCountersBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_READ_DIFF_COUNTERS *psSGXReadDiffCountersIN, + struct PVRSRV_BRIDGE_OUT_SGX_READ_DIFF_COUNTERS + *psSGXReadDiffCountersOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_READ_DIFF_COUNTERS); + + psSGXReadDiffCountersOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psSGXReadDiffCountersIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psSGXReadDiffCountersOUT->eError != PVRSRV_OK) + return 0; + + psSGXReadDiffCountersOUT->eError = SGXReadDiffCountersKM( + hDevCookieInt, + psSGXReadDiffCountersIN->ui32Reg, + &psSGXReadDiffCountersOUT->ui32Old, + psSGXReadDiffCountersIN->bNew, + psSGXReadDiffCountersIN->ui32New, + psSGXReadDiffCountersIN->ui32NewReset, + psSGXReadDiffCountersIN->ui32CountersReg, + &psSGXReadDiffCountersOUT->ui32Time, + &psSGXReadDiffCountersOUT->bActive, + &psSGXReadDiffCountersOUT->sDiffs); + + return 0; +} + +int SGXReadHWPerfCBBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_READ_HWPERF_CB *psSGXReadHWPerfCBIN, + struct PVRSRV_BRIDGE_OUT_SGX_READ_HWPERF_CB *psSGXReadHWPerfCBOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + struct PVRSRV_SGX_HWPERF_CB_ENTRY *psAllocated; + void *hAllocatedHandle; + u32 ui32AllocatedSize; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_READ_HWPERF_CB); + + psSGXReadHWPerfCBOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psSGXReadHWPerfCBIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psSGXReadHWPerfCBOUT->eError != PVRSRV_OK) + return 0; + + ui32AllocatedSize = psSGXReadHWPerfCBIN->ui32ArraySize * + sizeof(psSGXReadHWPerfCBIN->psHWPerfCBData[0]); + ASSIGN_AND_EXIT_ON_ERROR(psSGXReadHWPerfCBOUT->eError, + OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + ui32AllocatedSize, + (void **)&psAllocated, + &hAllocatedHandle)); + + psSGXReadHWPerfCBOUT->eError = SGXReadHWPerfCBKM(hDevCookieInt, + psSGXReadHWPerfCBIN->ui32ArraySize, + psAllocated, + &psSGXReadHWPerfCBOUT->ui32DataCount, + &psSGXReadHWPerfCBOUT->ui32ClockSpeed, + &psSGXReadHWPerfCBOUT->ui32HostTimeStamp); + if (psSGXReadHWPerfCBOUT->eError == PVRSRV_OK) + psSGXReadHWPerfCBOUT->eError = CopyToUserWrapper( + psPerProc, ui32BridgeID, + psSGXReadHWPerfCBIN->psHWPerfCBData, + psAllocated, ui32AllocatedSize); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + ui32AllocatedSize, psAllocated, hAllocatedHandle); + + return 0; +} + +int SGXDevInitPart2BW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXDEVINITPART2 *psSGXDevInitPart2IN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + enum PVRSRV_ERROR eError; + IMG_BOOL bDissociateFailed = IMG_FALSE; + IMG_BOOL bLookupFailed = IMG_FALSE; + IMG_BOOL bReleaseFailed = IMG_FALSE; + void *hDummy; + u32 i; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_DEVINITPART2); + + if (!psPerProc->bInitProcess) { + psRetOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psSGXDevInitPart2IN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bLookupFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBCtlMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bLookupFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBEventKickerMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bLookupFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXHostCtlMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bLookupFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXTA3DCtlMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bLookupFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXMiscMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bLookupFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, + psSGXDevInitPart2IN->sInitInfo. + hKernelHWPerfCBMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bLookupFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + +#if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, + psSGXDevInitPart2IN->sInitInfo. + hKernelEDMStatusBufferMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bLookupFailed |= (IMG_BOOL) (eError != PVRSRV_OK); +#endif + + for (i = 0; i < SGX_MAX_INIT_MEM_HANDLES; i++) { + void *hHandle = + psSGXDevInitPart2IN->sInitInfo.asInitMemHandles[i]; + + if (hHandle == NULL) + continue; + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, + hHandle, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bLookupFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + } + + if (bLookupFailed) { + PVR_DPF(PVR_DBG_ERROR, + "DevInitSGXPart2BW: A handle lookup failed"); + psRetOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + &psSGXDevInitPart2IN->sInitInfo. + hKernelCCBMemInfo, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bReleaseFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + &psSGXDevInitPart2IN->sInitInfo. + hKernelCCBCtlMemInfo, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBCtlMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bReleaseFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + &psSGXDevInitPart2IN->sInitInfo. + hKernelCCBEventKickerMemInfo, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBEventKickerMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bReleaseFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + &psSGXDevInitPart2IN->sInitInfo. + hKernelSGXHostCtlMemInfo, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXHostCtlMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bReleaseFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + &psSGXDevInitPart2IN->sInitInfo. + hKernelSGXTA3DCtlMemInfo, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXTA3DCtlMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bReleaseFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + &psSGXDevInitPart2IN->sInitInfo. + hKernelSGXMiscMemInfo, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXMiscMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bReleaseFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + &psSGXDevInitPart2IN->sInitInfo. + hKernelHWPerfCBMemInfo, + psSGXDevInitPart2IN->sInitInfo. + hKernelHWPerfCBMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bReleaseFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + +#if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) + eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + &psSGXDevInitPart2IN->sInitInfo. + hKernelEDMStatusBufferMemInfo, + psSGXDevInitPart2IN->sInitInfo. + hKernelEDMStatusBufferMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bReleaseFailed |= (IMG_BOOL)(eError != PVRSRV_OK); +#endif + + for (i = 0; i < SGX_MAX_INIT_MEM_HANDLES; i++) { + void **phHandle = + &psSGXDevInitPart2IN->sInitInfo.asInitMemHandles[i]; + + if (*phHandle == NULL) + continue; + + eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, + phHandle, *phHandle, + PVRSRV_HANDLE_TYPE_MEM_INFO); + bReleaseFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + } + + if (bReleaseFailed) { + PVR_DPF(PVR_DBG_ERROR, + "DevInitSGXPart2BW: A handle release failed"); + psRetOUT->eError = PVRSRV_ERROR_GENERIC; + + PVR_DBG_BREAK; + return 0; + } + + eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBMemInfo); + bDissociateFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBCtlMemInfo); + bDissociateFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBEventKickerMemInfo); + bDissociateFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXHostCtlMemInfo); + bDissociateFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXTA3DCtlMemInfo); + bDissociateFailed |= (IMG_BOOL)(eError != PVRSRV_OK); + + eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXMiscMemInfo); + bDissociateFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + + eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelHWPerfCBMemInfo); + bDissociateFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + +#if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) + eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelEDMStatusBufferMemInfo); + bDissociateFailed |= (IMG_BOOL) (eError != PVRSRV_OK); +#endif + + for (i = 0; i < SGX_MAX_INIT_MEM_HANDLES; i++) { + void *hHandle = + psSGXDevInitPart2IN->sInitInfo.asInitMemHandles[i]; + + if (hHandle == NULL) + continue; + + eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, hHandle); + bDissociateFailed |= (IMG_BOOL) (eError != PVRSRV_OK); + } + + if (bDissociateFailed) { + PVRSRVFreeDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBMemInfo); + PVRSRVFreeDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelCCBCtlMemInfo); + PVRSRVFreeDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXHostCtlMemInfo); + PVRSRVFreeDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXTA3DCtlMemInfo); + PVRSRVFreeDeviceMemKM(hDevCookieInt, + psSGXDevInitPart2IN->sInitInfo. + hKernelSGXMiscMemInfo); + + for (i = 0; i < SGX_MAX_INIT_MEM_HANDLES; i++) { + void *hHandle = + psSGXDevInitPart2IN->sInitInfo.asInitMemHandles[i]; + + if (hHandle == NULL) + continue; + + PVRSRVFreeDeviceMemKM(hDevCookieInt, + (struct PVRSRV_KERNEL_MEM_INFO *) + hHandle); + + } + + PVR_DPF(PVR_DBG_ERROR, + "DevInitSGXPart2BW: A dissociate failed"); + + psRetOUT->eError = PVRSRV_ERROR_GENERIC; + + PVR_DBG_BREAK; + return 0; + } + + psRetOUT->eError = DevInitSGXPart2KM(psPerProc, hDevCookieInt, + &psSGXDevInitPart2IN->sInitInfo); + + return 0; +} + +int SGXRegisterHWRenderContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_REGISTER_HW_RENDER_CONTEXT + *psSGXRegHWRenderContextIN, + struct PVRSRV_BRIDGE_OUT_SGX_REGISTER_HW_RENDER_CONTEXT + *psSGXRegHWRenderContextOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *hHWRenderContextInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_REGISTER_HW_RENDER_CONTEXT); + + NEW_HANDLE_BATCH_OR_ERROR(psSGXRegHWRenderContextOUT->eError, psPerProc, + 1); + + psSGXRegHWRenderContextOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psSGXRegHWRenderContextIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psSGXRegHWRenderContextOUT->eError != PVRSRV_OK) + return 0; + + hHWRenderContextInt = + SGXRegisterHWRenderContextKM(hDevCookieInt, + &psSGXRegHWRenderContextIN->sHWRenderContextDevVAddr, + psPerProc); + + if (hHWRenderContextInt == NULL) { + psSGXRegHWRenderContextOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psSGXRegHWRenderContextOUT->hHWRenderContext, + hHWRenderContextInt, + PVRSRV_HANDLE_TYPE_SGX_HW_RENDER_CONTEXT, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + + COMMIT_HANDLE_BATCH_OR_ERROR(psSGXRegHWRenderContextOUT->eError, + psPerProc); + + return 0; +} + +int SGXUnregisterHWRenderContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_UNREGISTER_HW_RENDER_CONTEXT + *psSGXUnregHWRenderContextIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hHWRenderContextInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_UNREGISTER_HW_RENDER_CONTEXT); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &hHWRenderContextInt, + psSGXUnregHWRenderContextIN->hHWRenderContext, + PVRSRV_HANDLE_TYPE_SGX_HW_RENDER_CONTEXT); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = SGXUnregisterHWRenderContextKM(hHWRenderContextInt); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVReleaseHandle(psPerProc->psHandleBase, + psSGXUnregHWRenderContextIN->hHWRenderContext, + PVRSRV_HANDLE_TYPE_SGX_HW_RENDER_CONTEXT); + + return 0; +} + +int SGXRegisterHWTransferContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_REGISTER_HW_TRANSFER_CONTEXT + *psSGXRegHWTransferContextIN, + struct PVRSRV_BRIDGE_OUT_SGX_REGISTER_HW_TRANSFER_CONTEXT + *psSGXRegHWTransferContextOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *hHWTransferContextInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_REGISTER_HW_TRANSFER_CONTEXT); + + NEW_HANDLE_BATCH_OR_ERROR(psSGXRegHWTransferContextOUT->eError, + psPerProc, 1); + + psSGXRegHWTransferContextOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psSGXRegHWTransferContextIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psSGXRegHWTransferContextOUT->eError != PVRSRV_OK) + return 0; + + hHWTransferContextInt = + SGXRegisterHWTransferContextKM(hDevCookieInt, + &psSGXRegHWTransferContextIN-> + sHWTransferContextDevVAddr, + psPerProc); + + if (hHWTransferContextInt == NULL) { + psSGXRegHWTransferContextOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psSGXRegHWTransferContextOUT->hHWTransferContext, + hHWTransferContextInt, + PVRSRV_HANDLE_TYPE_SGX_HW_TRANSFER_CONTEXT, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + + COMMIT_HANDLE_BATCH_OR_ERROR(psSGXRegHWTransferContextOUT->eError, + psPerProc); + + return 0; +} + +int SGXUnregisterHWTransferContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_UNREGISTER_HW_TRANSFER_CONTEXT + *psSGXUnregHWTransferContextIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hHWTransferContextInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_UNREGISTER_HW_TRANSFER_CONTEXT); + + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hHWTransferContextInt, + psSGXUnregHWTransferContextIN-> + hHWTransferContext, + PVRSRV_HANDLE_TYPE_SGX_HW_TRANSFER_CONTEXT); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + SGXUnregisterHWTransferContextKM(hHWTransferContextInt); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psRetOUT->eError = + PVRSRVReleaseHandle(psPerProc->psHandleBase, + psSGXUnregHWTransferContextIN-> + hHWTransferContext, + PVRSRV_HANDLE_TYPE_SGX_HW_TRANSFER_CONTEXT); + + return 0; +} + +int SGXFlushHWRenderTargetBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_FLUSH_HW_RENDER_TARGET + *psSGXFlushHWRenderTargetIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_FLUSH_HW_RENDER_TARGET); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psSGXFlushHWRenderTargetIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + SGXFlushHWRenderTargetKM(hDevCookieInt, + psSGXFlushHWRenderTargetIN->sHWRTDataSetDevVAddr); + + return 0; +} + +int SGX2DQueryBlitsCompleteBW(struct file *filp, u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_2DQUERYBLTSCOMPLETE *ps2DQueryBltsCompleteIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + void *pvSyncInfo; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + struct PVRSRV_FILE_PRIVATE_DATA *priv = filp->private_data; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_2DQUERYBLTSCOMPLETE); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + ps2DQueryBltsCompleteIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + if (ps2DQueryBltsCompleteIN->type == _PVR_SYNC_WAIT_FLIP || + ps2DQueryBltsCompleteIN->type == _PVR_SYNC_WAIT_UPDATE) { + if (pvr_flip_event_req(priv, + (long)ps2DQueryBltsCompleteIN-> + hKernSyncInfo, + ps2DQueryBltsCompleteIN->type, + ps2DQueryBltsCompleteIN->user_data)) + psRetOUT->eError = PVRSRV_ERROR_OUT_OF_MEMORY; + + return 0; + } + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &pvSyncInfo, + ps2DQueryBltsCompleteIN->hKernSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)((struct PVRSRV_DEVICE_NODE *) + hDevCookieInt)->pvDevice; + + if (ps2DQueryBltsCompleteIN->type == _PVR_SYNC_WAIT_EVENT) { + if (pvr_sync_event_req(priv, + (struct PVRSRV_KERNEL_SYNC_INFO *)pvSyncInfo, + ps2DQueryBltsCompleteIN->user_data)) + psRetOUT->eError = PVRSRV_ERROR_OUT_OF_MEMORY; + + return 0; + } + + psRetOUT->eError = + SGX2DQueryBlitsCompleteKM(psDevInfo, + (struct PVRSRV_KERNEL_SYNC_INFO *) + pvSyncInfo, + ps2DQueryBltsCompleteIN->type == _PVR_SYNC_WAIT_BLOCK); + + return 0; +} + +int SGXFindSharedPBDescBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXFINDSHAREDPBDESC *psSGXFindSharedPBDescIN, + struct PVRSRV_BRIDGE_OUT_SGXFINDSHAREDPBDESC *psSGXFindSharedPBDescOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + struct PVRSRV_KERNEL_MEM_INFO *psSharedPBDescKernelMemInfo; + struct PVRSRV_KERNEL_MEM_INFO *psHWPBDescKernelMemInfo; + struct PVRSRV_KERNEL_MEM_INFO *psBlockKernelMemInfo; + struct PVRSRV_KERNEL_MEM_INFO **ppsSharedPBDescSubKernelMemInfos = NULL; + u32 ui32SharedPBDescSubKernelMemInfosCount = 0; + u32 i; + void *hSharedPBDesc = NULL; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_FINDSHAREDPBDESC); + + NEW_HANDLE_BATCH_OR_ERROR(psSGXFindSharedPBDescOUT->eError, psPerProc, + PVRSRV_BRIDGE_SGX_SHAREDPBDESC_MAX_SUBMEMINFOS + + 4); + + psSGXFindSharedPBDescOUT->hSharedPBDesc = NULL; + + psSGXFindSharedPBDescOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psSGXFindSharedPBDescIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psSGXFindSharedPBDescOUT->eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_FINDSHAREDPBDESC_EXIT; + + psSGXFindSharedPBDescOUT->eError = + SGXFindSharedPBDescKM(psPerProc, hDevCookieInt, + psSGXFindSharedPBDescIN->bLockOnFailure, + psSGXFindSharedPBDescIN->ui32TotalPBSize, + &hSharedPBDesc, + &psSharedPBDescKernelMemInfo, + &psHWPBDescKernelMemInfo, + &psBlockKernelMemInfo, + &ppsSharedPBDescSubKernelMemInfos, + &ui32SharedPBDescSubKernelMemInfosCount); + if (psSGXFindSharedPBDescOUT->eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_FINDSHAREDPBDESC_EXIT; + + PVR_ASSERT(ui32SharedPBDescSubKernelMemInfosCount <= + PVRSRV_BRIDGE_SGX_SHAREDPBDESC_MAX_SUBMEMINFOS); + + psSGXFindSharedPBDescOUT->ui32SharedPBDescSubKernelMemInfoHandlesCount = + ui32SharedPBDescSubKernelMemInfosCount; + + if (hSharedPBDesc == NULL) { + psSGXFindSharedPBDescOUT->hSharedPBDescKernelMemInfoHandle = + NULL; + + goto PVRSRV_BRIDGE_SGX_FINDSHAREDPBDESC_EXIT; + } + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psSGXFindSharedPBDescOUT->hSharedPBDesc, + hSharedPBDesc, + PVRSRV_HANDLE_TYPE_SHARED_PB_DESC, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psSGXFindSharedPBDescOUT-> + hSharedPBDescKernelMemInfoHandle, + psSharedPBDescKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO_REF, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI, + psSGXFindSharedPBDescOUT->hSharedPBDesc); + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psSGXFindSharedPBDescOUT-> + hHWPBDescKernelMemInfoHandle, + psHWPBDescKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO_REF, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI, + psSGXFindSharedPBDescOUT->hSharedPBDesc); + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psSGXFindSharedPBDescOUT-> + hBlockKernelMemInfoHandle, + psBlockKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO_REF, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI, + psSGXFindSharedPBDescOUT->hSharedPBDesc); + + for (i = 0; i < ui32SharedPBDescSubKernelMemInfosCount; i++) { + struct PVRSRV_BRIDGE_OUT_SGXFINDSHAREDPBDESC + *psSGXFindSharedPBDescOut = psSGXFindSharedPBDescOUT; + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psSGXFindSharedPBDescOut-> + ahSharedPBDescSubKernelMemInfoHandles[i], + ppsSharedPBDescSubKernelMemInfos[i], + PVRSRV_HANDLE_TYPE_MEM_INFO_REF, + PVRSRV_HANDLE_ALLOC_FLAG_MULTI, + psSGXFindSharedPBDescOUT-> + hSharedPBDescKernelMemInfoHandle); + } + +PVRSRV_BRIDGE_SGX_FINDSHAREDPBDESC_EXIT: + if (ppsSharedPBDescSubKernelMemInfos != NULL) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO *) * + ui32SharedPBDescSubKernelMemInfosCount, + ppsSharedPBDescSubKernelMemInfos, NULL); + + if (psSGXFindSharedPBDescOUT->eError != PVRSRV_OK) { + if (hSharedPBDesc != NULL) + SGXUnrefSharedPBDescKM(hSharedPBDesc); + } else + COMMIT_HANDLE_BATCH_OR_ERROR(psSGXFindSharedPBDescOUT->eError, + psPerProc); + + return 0; +} + +int SGXUnrefSharedPBDescBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXUNREFSHAREDPBDESC *psSGXUnrefSharedPBDescIN, + struct PVRSRV_BRIDGE_OUT_SGXUNREFSHAREDPBDESC + *psSGXUnrefSharedPBDescOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hSharedPBDesc; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_UNREFSHAREDPBDESC); + + psSGXUnrefSharedPBDescOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &hSharedPBDesc, + psSGXUnrefSharedPBDescIN->hSharedPBDesc, + PVRSRV_HANDLE_TYPE_SHARED_PB_DESC); + if (psSGXUnrefSharedPBDescOUT->eError != PVRSRV_OK) + return 0; + + psSGXUnrefSharedPBDescOUT->eError = + SGXUnrefSharedPBDescKM(hSharedPBDesc); + + if (psSGXUnrefSharedPBDescOUT->eError != PVRSRV_OK) + return 0; + + psSGXUnrefSharedPBDescOUT->eError = + PVRSRVReleaseHandle(psPerProc->psHandleBase, + psSGXUnrefSharedPBDescIN->hSharedPBDesc, + PVRSRV_HANDLE_TYPE_SHARED_PB_DESC); + + return 0; +} + +int SGXAddSharedPBDescBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXADDSHAREDPBDESC *psSGXAddSharedPBDescIN, + struct PVRSRV_BRIDGE_OUT_SGXADDSHAREDPBDESC *psSGXAddSharedPBDescOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + struct PVRSRV_KERNEL_MEM_INFO *psSharedPBDescKernelMemInfo; + struct PVRSRV_KERNEL_MEM_INFO *psHWPBDescKernelMemInfo; + struct PVRSRV_KERNEL_MEM_INFO *psBlockKernelMemInfo; + u32 ui32KernelMemInfoHandlesCount = + psSGXAddSharedPBDescIN->ui32KernelMemInfoHandlesCount; + int ret = 0; + void **phKernelMemInfoHandles = NULL; + struct PVRSRV_KERNEL_MEM_INFO **ppsKernelMemInfos = NULL; + u32 i; + enum PVRSRV_ERROR eError; + void *hSharedPBDesc = NULL; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC); + + NEW_HANDLE_BATCH_OR_ERROR(psSGXAddSharedPBDescOUT->eError, psPerProc, + 1); + + psSGXAddSharedPBDescOUT->hSharedPBDesc = NULL; + + PVR_ASSERT(ui32KernelMemInfoHandlesCount <= + PVRSRV_BRIDGE_SGX_SHAREDPBDESC_MAX_SUBMEMINFOS); + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &hDevCookieInt, + psSGXAddSharedPBDescIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + (void **)&psSharedPBDescKernelMemInfo, + psSGXAddSharedPBDescIN-> + hSharedPBDescKernelMemInfo, + PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO); + if (eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + (void **)&psHWPBDescKernelMemInfo, + psSGXAddSharedPBDescIN-> + hHWPBDescKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + (void **)&psBlockKernelMemInfo, + psSGXAddSharedPBDescIN->hBlockKernelMemInfo, + PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO); + if (eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + + if (!OSAccessOK(PVR_VERIFY_READ, + psSGXAddSharedPBDescIN->phKernelMemInfoHandles, + ui32KernelMemInfoHandlesCount * sizeof(void *))) { + PVR_DPF(PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC:" + " Invalid phKernelMemInfos pointer", __func__); + ret = -EFAULT; + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + } + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + ui32KernelMemInfoHandlesCount * sizeof(void *), + (void **)&phKernelMemInfoHandles, NULL); + if (eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + + if (CopyFromUserWrapper(psPerProc, + ui32BridgeID, + phKernelMemInfoHandles, + psSGXAddSharedPBDescIN->phKernelMemInfoHandles, + ui32KernelMemInfoHandlesCount * sizeof(void *)) + != PVRSRV_OK) { + ret = -EFAULT; + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + } + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + ui32KernelMemInfoHandlesCount * + sizeof(struct PVRSRV_KERNEL_MEM_INFO *), + (void **)&ppsKernelMemInfos, NULL); + if (eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + + for (i = 0; i < ui32KernelMemInfoHandlesCount; i++) { + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + (void **)&ppsKernelMemInfos[i], + phKernelMemInfoHandles[i], + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + } + + eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, + psSGXAddSharedPBDescIN-> + hSharedPBDescKernelMemInfo, + PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO); + PVR_ASSERT(eError == PVRSRV_OK); + + eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, + psSGXAddSharedPBDescIN-> + hHWPBDescKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + PVR_ASSERT(eError == PVRSRV_OK); + + eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, + psSGXAddSharedPBDescIN-> + hBlockKernelMemInfo, + PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO); + PVR_ASSERT(eError == PVRSRV_OK); + + for (i = 0; i < ui32KernelMemInfoHandlesCount; i++) { + eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, + phKernelMemInfoHandles[i], + PVRSRV_HANDLE_TYPE_MEM_INFO); + PVR_ASSERT(eError == PVRSRV_OK); + } + + eError = SGXAddSharedPBDescKM(psPerProc, hDevCookieInt, + psSharedPBDescKernelMemInfo, + psHWPBDescKernelMemInfo, + psBlockKernelMemInfo, + psSGXAddSharedPBDescIN->ui32TotalPBSize, + &hSharedPBDesc, + ppsKernelMemInfos, + ui32KernelMemInfoHandlesCount); + + if (eError != PVRSRV_OK) + goto PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT; + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psSGXAddSharedPBDescOUT->hSharedPBDesc, + hSharedPBDesc, + PVRSRV_HANDLE_TYPE_SHARED_PB_DESC, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + +PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC_RETURN_RESULT: + + if (phKernelMemInfoHandles) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + psSGXAddSharedPBDescIN->ui32KernelMemInfoHandlesCount + * sizeof(void *), + (void *)phKernelMemInfoHandles, NULL); + if (ppsKernelMemInfos) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + psSGXAddSharedPBDescIN->ui32KernelMemInfoHandlesCount + * sizeof(struct PVRSRV_KERNEL_MEM_INFO *), + (void *)ppsKernelMemInfos, NULL); + + if (ret == 0 && eError == PVRSRV_OK) + COMMIT_HANDLE_BATCH_OR_ERROR(psSGXAddSharedPBDescOUT->eError, + psPerProc); + + psSGXAddSharedPBDescOUT->eError = eError; + + return ret; +} + +int SGXGetInfoForSrvinitBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXINFO_FOR_SRVINIT *psSGXInfoForSrvinitIN, + struct PVRSRV_BRIDGE_OUT_SGXINFO_FOR_SRVINIT *psSGXInfoForSrvinitOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + void *hDevCookieInt; + u32 i; + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGXINFO_FOR_SRVINIT); + + NEW_HANDLE_BATCH_OR_ERROR(psSGXInfoForSrvinitOUT->eError, psPerProc, + PVRSRV_MAX_CLIENT_HEAPS); + + if (!psPerProc->bInitProcess) { + psSGXInfoForSrvinitOUT->eError = PVRSRV_ERROR_GENERIC; + return 0; + } + + psSGXInfoForSrvinitOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psSGXInfoForSrvinitIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + + if (psSGXInfoForSrvinitOUT->eError != PVRSRV_OK) + return 0; + + psSGXInfoForSrvinitOUT->eError = + SGXGetInfoForSrvinitKM(hDevCookieInt, + &psSGXInfoForSrvinitOUT->sInitInfo); + + if (psSGXInfoForSrvinitOUT->eError != PVRSRV_OK) + return 0; + + for (i = 0; i < PVRSRV_MAX_CLIENT_HEAPS; i++) { + struct PVRSRV_HEAP_INFO *psHeapInfo; + + psHeapInfo = &psSGXInfoForSrvinitOUT->sInitInfo.asHeapInfo[i]; + + if (psHeapInfo->ui32HeapID != (u32)SGX_UNDEFINED_HEAP_ID) { + void *hDevMemHeapExt; + + if (psHeapInfo->hDevMemHeap != NULL) { + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &hDevMemHeapExt, + psHeapInfo->hDevMemHeap, + PVRSRV_HANDLE_TYPE_DEV_MEM_HEAP, + PVRSRV_HANDLE_ALLOC_FLAG_SHARED); + psHeapInfo->hDevMemHeap = hDevMemHeapExt; + } + } + } + + COMMIT_HANDLE_BATCH_OR_ERROR(psSGXInfoForSrvinitOUT->eError, psPerProc); + + return 0; +} + +#if defined(PDUMP) +static void DumpBufferArray(struct PVRSRV_PER_PROCESS_DATA *psPerProc, + struct SGX_KICKTA_DUMP_BUFFER *psBufferArray, + u32 ui32BufferArrayLength, IMG_BOOL bDumpPolls) +{ + u32 i; + + for (i = 0; i < ui32BufferArrayLength; i++) { + struct SGX_KICKTA_DUMP_BUFFER *psBuffer; + struct PVRSRV_KERNEL_MEM_INFO *psCtrlMemInfoKM; + char *pszName; + void *hUniqueTag; + u32 ui32Offset; + + psBuffer = &psBufferArray[i]; + pszName = psBuffer->pszName; + if (!pszName) + pszName = "Nameless buffer"; + + hUniqueTag = + MAKEUNIQUETAG((struct PVRSRV_KERNEL_MEM_INFO *)psBuffer-> + hKernelMemInfo); + + psCtrlMemInfoKM = + ((struct PVRSRV_KERNEL_MEM_INFO *)psBuffer-> + hKernelMemInfo)->psKernelSyncInfo->psSyncDataMemInfoKM; + ui32Offset = + offsetof(struct PVRSRV_SYNC_DATA, ui32ReadOpsComplete); + + if (psBuffer->ui32Start <= psBuffer->ui32End) { + if (bDumpPolls) { + PDUMPCOMMENTWITHFLAGS(0, + "Wait for %s space\r\n", + pszName); + PDUMPCBP(psCtrlMemInfoKM, ui32Offset, + psBuffer->ui32Start, + psBuffer->ui32SpaceUsed, + psBuffer->ui32BufferSize, 0, + MAKEUNIQUETAG(psCtrlMemInfoKM)); + } + + PDUMPCOMMENTWITHFLAGS(0, "%s\r\n", pszName); + PDUMPMEMUM(psPerProc, + NULL, psBuffer->pvLinAddr, + (struct PVRSRV_KERNEL_MEM_INFO *)psBuffer-> + hKernelMemInfo, + psBuffer->ui32Start, + psBuffer->ui32End - psBuffer->ui32Start, 0, + hUniqueTag); + } else { + + if (bDumpPolls) { + PDUMPCOMMENTWITHFLAGS(0, + "Wait for %s space\r\n", + pszName); + PDUMPCBP(psCtrlMemInfoKM, ui32Offset, + psBuffer->ui32Start, + psBuffer->ui32BackEndLength, + psBuffer->ui32BufferSize, 0, + MAKEUNIQUETAG(psCtrlMemInfoKM)); + } + PDUMPCOMMENTWITHFLAGS(0, "%s (part 1)\r\n", pszName); + PDUMPMEMUM(psPerProc, + NULL, psBuffer->pvLinAddr, + (struct PVRSRV_KERNEL_MEM_INFO *)psBuffer-> + hKernelMemInfo, + psBuffer->ui32Start, + psBuffer->ui32BackEndLength, 0, hUniqueTag); + + if (bDumpPolls) { + PDUMPMEMPOL(psCtrlMemInfoKM, ui32Offset, + 0, 0xFFFFFFFF, + PDUMP_POLL_OPERATOR_NOTEQUAL, + IMG_FALSE, IMG_FALSE, + MAKEUNIQUETAG(psCtrlMemInfoKM)); + + PDUMPCOMMENTWITHFLAGS(0, + "Wait for %s space\r\n", + pszName); + PDUMPCBP(psCtrlMemInfoKM, ui32Offset, 0, + psBuffer->ui32End, + psBuffer->ui32BufferSize, 0, + MAKEUNIQUETAG(psCtrlMemInfoKM)); + } + PDUMPCOMMENTWITHFLAGS(0, "%s (part 2)\r\n", pszName); + PDUMPMEMUM(psPerProc, NULL, psBuffer->pvLinAddr, + (struct PVRSRV_KERNEL_MEM_INFO *)psBuffer-> + hKernelMemInfo, + 0, psBuffer->ui32End, 0, hUniqueTag); + } + } +} + +int SGXPDumpBufferArrayBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_BUFFER_ARRAY *psPDumpBufferArrayIN, + void *psBridgeOut, struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + u32 i; + struct SGX_KICKTA_DUMP_BUFFER *psKickTADumpBuffer; + u32 ui32BufferArrayLength = psPDumpBufferArrayIN->ui32BufferArrayLength; + u32 ui32BufferArraySize = + ui32BufferArrayLength * sizeof(struct SGX_KICKTA_DUMP_BUFFER); + enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC; + + PVR_UNREFERENCED_PARAMETER(psBridgeOut); + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_PDUMP_BUFFER_ARRAY); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ui32BufferArraySize, + (void **)&psKickTADumpBuffer, NULL) != PVRSRV_OK) + return -ENOMEM; + + if (CopyFromUserWrapper(psPerProc, ui32BridgeID, psKickTADumpBuffer, + psPDumpBufferArrayIN->psBufferArray, + ui32BufferArraySize) != PVRSRV_OK) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32BufferArraySize, + psKickTADumpBuffer, NULL); + return -EFAULT; + } + + for (i = 0; i < ui32BufferArrayLength; i++) { + void *pvMemInfo; + + eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvMemInfo, + psKickTADumpBuffer[i]. + hKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRV_BRIDGE_SGX_PDUMP_BUFFER_ARRAY: " + "PVRSRVLookupHandle failed (%d)", eError); + break; + } + psKickTADumpBuffer[i].hKernelMemInfo = pvMemInfo; + + } + + if (eError == PVRSRV_OK) + DumpBufferArray(psPerProc, psKickTADumpBuffer, + ui32BufferArrayLength, + psPDumpBufferArrayIN->bDumpPolls); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32BufferArraySize, + psKickTADumpBuffer, NULL); + + return 0; +} + +int SGXPDump3DSignatureRegistersBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_3D_SIGNATURE_REGISTERS + *psPDump3DSignatureRegistersIN, + void *psBridgeOut, struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + u32 ui32RegisterArraySize = + psPDump3DSignatureRegistersIN->ui32NumRegisters * sizeof(u32); + u32 *pui32Registers = NULL; + int ret = -EFAULT; + + PVR_UNREFERENCED_PARAMETER(psBridgeOut); + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_PDUMP_3D_SIGNATURE_REGISTERS); + + if (ui32RegisterArraySize == 0) + goto ExitNoError; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + ui32RegisterArraySize, + (void **)&pui32Registers, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PDump3DSignatureRegistersBW: OSAllocMem failed"); + goto Exit; + } + + if (CopyFromUserWrapper(psPerProc, ui32BridgeID, pui32Registers, + psPDump3DSignatureRegistersIN->pui32Registers, + ui32RegisterArraySize) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PDump3DSignatureRegistersBW: " + "CopyFromUserWrapper failed"); + goto Exit; + } + + PDump3DSignatureRegisters(psPDump3DSignatureRegistersIN-> + ui32DumpFrameNum, + psPDump3DSignatureRegistersIN->bLastFrame, + pui32Registers, + psPDump3DSignatureRegistersIN-> + ui32NumRegisters); + +ExitNoError: + ret = 0; +Exit: + if (pui32Registers != NULL) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32RegisterArraySize, + pui32Registers, NULL); + + return ret; +} + +int SGXPDumpCounterRegistersBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_COUNTER_REGISTERS + *psPDumpCounterRegistersIN, + void *psBridgeOut, struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + u32 ui32RegisterArraySize = + psPDumpCounterRegistersIN->ui32NumRegisters * sizeof(u32); + u32 *pui32Registers = NULL; + int ret = -EFAULT; + + PVR_UNREFERENCED_PARAMETER(psBridgeOut); + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_PDUMP_COUNTER_REGISTERS); + + if (ui32RegisterArraySize == 0) + goto ExitNoError; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ui32RegisterArraySize, + (void **)&pui32Registers, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PDumpCounterRegistersBW: OSAllocMem failed"); + ret = -ENOMEM; + goto Exit; + } + + if (CopyFromUserWrapper(psPerProc, ui32BridgeID, pui32Registers, + psPDumpCounterRegistersIN->pui32Registers, + ui32RegisterArraySize) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PDumpCounterRegistersBW: CopyFromUserWrapper failed"); + goto Exit; + } + + PDumpCounterRegisters(psPDumpCounterRegistersIN->ui32DumpFrameNum, + psPDumpCounterRegistersIN->bLastFrame, + pui32Registers, + psPDumpCounterRegistersIN->ui32NumRegisters); + +ExitNoError: + ret = 0; +Exit: + if (pui32Registers != NULL) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32RegisterArraySize, + pui32Registers, NULL); + + return ret; +} + +int SGXPDumpTASignatureRegistersBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_TA_SIGNATURE_REGISTERS + *psPDumpTASignatureRegistersIN, + void *psBridgeOut, struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + u32 ui32RegisterArraySize = + psPDumpTASignatureRegistersIN->ui32NumRegisters * sizeof(u32); + u32 *pui32Registers = NULL; + int ret = -EFAULT; + + PVR_UNREFERENCED_PARAMETER(psBridgeOut); + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_PDUMP_TA_SIGNATURE_REGISTERS); + + if (ui32RegisterArraySize == 0) + goto ExitNoError; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + ui32RegisterArraySize, + (void **)&pui32Registers, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PDumpTASignatureRegistersBW: OSAllocMem failed"); + ret = -ENOMEM; + goto Exit; + } + + if (CopyFromUserWrapper(psPerProc, ui32BridgeID, pui32Registers, + psPDumpTASignatureRegistersIN->pui32Registers, + ui32RegisterArraySize) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PDumpTASignatureRegistersBW: " + "CopyFromUserWrapper failed"); + goto Exit; + } + + PDumpTASignatureRegisters(psPDumpTASignatureRegistersIN-> + ui32DumpFrameNum, + psPDumpTASignatureRegistersIN-> + ui32TAKickCount, + psPDumpTASignatureRegistersIN->bLastFrame, + pui32Registers, + psPDumpTASignatureRegistersIN-> + ui32NumRegisters); + +ExitNoError: + ret = 0; +Exit: + if (pui32Registers != NULL) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32RegisterArraySize, + pui32Registers, NULL); + + return ret; +} + +int SGXPDumpHWPerfCBBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_HWPERFCB *psPDumpHWPerfCBIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo; + void *hDevCookieInt; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, + PVRSRV_BRIDGE_SGX_PDUMP_HWPERFCB); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, + psPDumpHWPerfCBIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psRetOUT->eError != PVRSRV_OK) + return 0; + + psDevInfo = ((struct PVRSRV_DEVICE_NODE *)hDevCookieInt)->pvDevice; + + PDumpHWPerfCBKM(&psPDumpHWPerfCBIN->szFileName[0], + psPDumpHWPerfCBIN->ui32FileOffset, + psDevInfo->psKernelHWPerfCBMemInfo->sDevVAddr, + psDevInfo->psKernelHWPerfCBMemInfo->ui32AllocSize, + psPDumpHWPerfCBIN->ui32PDumpFlags); + + return 0; +} + +#endif + +void SetSGXDispatchTableEntry(void) +{ + + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_GETCLIENTINFO, + SGXGetClientInfoBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_RELEASECLIENTINFO, + SGXReleaseClientInfoBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_GETINTERNALDEVINFO, + SGXGetInternalDevInfoBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_DOKICK, SGXDoKickBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_GETPHYSPAGEADDR, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_READREGISTRYDWORD, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_SCHEDULECOMMAND, DummyBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_2DQUERYBLTSCOMPLETE, + SGX2DQueryBlitsCompleteBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_GETMMUPDADDR, DummyBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_SUBMITTRANSFER, + SGXSubmitTransferBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_GETMISCINFO, SGXGetMiscInfoBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGXINFO_FOR_SRVINIT, + SGXGetInfoForSrvinitBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_DEVINITPART2, + SGXDevInitPart2BW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_FINDSHAREDPBDESC, + SGXFindSharedPBDescBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_UNREFSHAREDPBDESC, + SGXUnrefSharedPBDescBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC, + SGXAddSharedPBDescBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_REGISTER_HW_RENDER_CONTEXT, + SGXRegisterHWRenderContextBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_FLUSH_HW_RENDER_TARGET, + SGXFlushHWRenderTargetBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_UNREGISTER_HW_RENDER_CONTEXT, + SGXUnregisterHWRenderContextBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_REGISTER_HW_TRANSFER_CONTEXT, + SGXRegisterHWTransferContextBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_UNREGISTER_HW_TRANSFER_CONTEXT, + SGXUnregisterHWTransferContextBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_READ_DIFF_COUNTERS, + SGXReadDiffCountersBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_READ_HWPERF_CB, + SGXReadHWPerfCBBW); + + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_SCHEDULE_PROCESS_QUEUES, + SGXScheduleProcessQueuesBW); + +#if defined(PDUMP) + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_PDUMP_BUFFER_ARRAY, + SGXPDumpBufferArrayBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_PDUMP_3D_SIGNATURE_REGISTERS, + SGXPDump3DSignatureRegistersBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_PDUMP_COUNTER_REGISTERS, + SGXPDumpCounterRegistersBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_PDUMP_TA_SIGNATURE_REGISTERS, + SGXPDumpTASignatureRegistersBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_PDUMP_HWPERFCB, + SGXPDumpHWPerfCBBW); +#endif +} diff --git a/drivers/gpu/pvr/bridged_sgx_bridge.h b/drivers/gpu/pvr/bridged_sgx_bridge.h new file mode 100644 index 00000000000..c2a8c476dd5 --- /dev/null +++ b/drivers/gpu/pvr/bridged_sgx_bridge.h @@ -0,0 +1,167 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __BRIDGED_SGX_BRIDGE_H__ +#define __BRIDGED_SGX_BRIDGE_H__ + +void SetSGXDispatchTableEntry(void); + +int SGXGetClientInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GETCLIENTINFO *psGetClientInfoIN, + struct PVRSRV_BRIDGE_OUT_GETCLIENTINFO *psGetClientInfoOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXReleaseClientInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_RELEASECLIENTINFO *psReleaseClientInfoIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXGetInternalDevInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_GETINTERNALDEVINFO *psSGXGetInternalDevInfoIN, + struct PVRSRV_BRIDGE_OUT_GETINTERNALDEVINFO *psSGXGetInternalDevInfoOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXDoKickBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_DOKICK *psDoKickIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, size_t in_size, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXScheduleProcessQueuesBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_SCHEDULE_PROCESS_QUEUES *psScheduleProcQIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXSubmitTransferBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SUBMITTRANSFER *psSubmitTransferIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXGetMiscInfoBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXGETMISCINFO *psSGXGetMiscInfoIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXReadDiffCountersBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_READ_DIFF_COUNTERS *psSGXReadDiffCountersIN, + struct PVRSRV_BRIDGE_OUT_SGX_READ_DIFF_COUNTERS + *psSGXReadDiffCountersOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXReadHWPerfCBBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_READ_HWPERF_CB *psSGXReadHWPerfCBIN, + struct PVRSRV_BRIDGE_OUT_SGX_READ_HWPERF_CB *psSGXReadHWPerfCBOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXDevInitPart2BW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXDEVINITPART2 *psSGXDevInitPart2IN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXRegisterHWRenderContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_REGISTER_HW_RENDER_CONTEXT + *psSGXRegHWRenderContextIN, + struct PVRSRV_BRIDGE_OUT_SGX_REGISTER_HW_RENDER_CONTEXT + *psSGXRegHWRenderContextOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXUnregisterHWRenderContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_UNREGISTER_HW_RENDER_CONTEXT + *psSGXUnregHWRenderContextIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXRegisterHWTransferContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_REGISTER_HW_TRANSFER_CONTEXT + *psSGXRegHWTransferContextIN, + struct PVRSRV_BRIDGE_OUT_SGX_REGISTER_HW_TRANSFER_CONTEXT + *psSGXRegHWTransferContextOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXUnregisterHWTransferContextBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_UNREGISTER_HW_TRANSFER_CONTEXT + *psSGXUnregHWTransferContextIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXFlushHWRenderTargetBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGX_FLUSH_HW_RENDER_TARGET + *psSGXFlushHWRenderTargetIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGX2DQueryBlitsCompleteBW(struct file *filp, u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_2DQUERYBLTSCOMPLETE *ps2DQueryBltsCompleteIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXFindSharedPBDescBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXFINDSHAREDPBDESC *psSGXFindSharedPBDescIN, + struct PVRSRV_BRIDGE_OUT_SGXFINDSHAREDPBDESC *psSGXFindSharedPBDescOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXUnrefSharedPBDescBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXUNREFSHAREDPBDESC *psSGXUnrefSharedPBDescIN, + struct PVRSRV_BRIDGE_OUT_SGXUNREFSHAREDPBDESC + *psSGXUnrefSharedPBDescOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXAddSharedPBDescBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXADDSHAREDPBDESC *psSGXAddSharedPBDescIN, + struct PVRSRV_BRIDGE_OUT_SGXADDSHAREDPBDESC *psSGXAddSharedPBDescOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXGetInfoForSrvinitBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_SGXINFO_FOR_SRVINIT *psSGXInfoForSrvinitIN, + struct PVRSRV_BRIDGE_OUT_SGXINFO_FOR_SRVINIT *psSGXInfoForSrvinitOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +#if defined(PDUMP) +int SGXPDumpBufferArrayBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_BUFFER_ARRAY *psPDumpBufferArrayIN, + void *psBridgeOut, struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXPDump3DSignatureRegistersBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_3D_SIGNATURE_REGISTERS + *psPDump3DSignatureRegistersIN, + void *psBridgeOut, struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXPDumpCounterRegistersBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_COUNTER_REGISTERS + *psPDumpCounterRegistersIN, + void *psBridgeOut, struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXPDumpTASignatureRegistersBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_TA_SIGNATURE_REGISTERS + *psPDumpTASignatureRegistersIN, + void *psBridgeOut, struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +int SGXPDumpHWPerfCBBW(u32 ui32BridgeID, + struct PVRSRV_BRIDGE_IN_PDUMP_HWPERFCB *psPDumpHWPerfCBIN, + struct PVRSRV_BRIDGE_RETURN *psRetOUT, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +#endif +#endif diff --git a/drivers/gpu/pvr/bridged_support.c b/drivers/gpu/pvr/bridged_support.c new file mode 100644 index 00000000000..499a3df13bb --- /dev/null +++ b/drivers/gpu/pvr/bridged_support.c @@ -0,0 +1,77 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "img_defs.h" +#include "servicesint.h" +#include "bridged_support.h" + +enum PVRSRV_ERROR +PVRSRVLookupOSMemHandle(struct PVRSRV_HANDLE_BASE *psHandleBase, + void **phOSMemHandle, void *hMHandle) +{ + void *hMHandleInt; + enum PVRSRV_HANDLE_TYPE eHandleType; + enum PVRSRV_ERROR eError; + + eError = PVRSRVLookupHandleAnyType(psHandleBase, &hMHandleInt, + &eHandleType, hMHandle); + if (eError != PVRSRV_OK) + return eError; + + switch (eHandleType) { + case PVRSRV_HANDLE_TYPE_MEM_INFO: + case PVRSRV_HANDLE_TYPE_MEM_INFO_REF: + case PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO: + { + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)hMHandleInt; + + *phOSMemHandle = psMemInfo->sMemBlk.hOSMemHandle; + + break; + } + case PVRSRV_HANDLE_TYPE_SYNC_INFO: + { + struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)hMHandleInt; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = + psSyncInfo->psSyncDataMemInfoKM; + + *phOSMemHandle = psMemInfo->sMemBlk.hOSMemHandle; + + break; + } + case PVRSRV_HANDLE_TYPE_SOC_TIMER: + { + *phOSMemHandle = (void *)hMHandleInt; + break; + } + default: + return PVRSRV_ERROR_BAD_MAPPING; + } + + return PVRSRV_OK;; +} diff --git a/drivers/gpu/pvr/bridged_support.h b/drivers/gpu/pvr/bridged_support.h new file mode 100644 index 00000000000..96b86433e86 --- /dev/null +++ b/drivers/gpu/pvr/bridged_support.h @@ -0,0 +1,35 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __BRIDGED_SUPPORT_H__ +#define __BRIDGED_SUPPORT_H__ + +#include "handle.h" + +enum PVRSRV_ERROR PVRSRVLookupOSMemHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phOSMemHandle, void *hMHandle); + +#endif diff --git a/drivers/gpu/pvr/buffer_manager.c b/drivers/gpu/pvr/buffer_manager.c new file mode 100644 index 00000000000..8f1190c81e7 --- /dev/null +++ b/drivers/gpu/pvr/buffer_manager.c @@ -0,0 +1,1493 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ +#include "services_headers.h" + +#include "sysconfig.h" +#include "hash.h" +#include "ra.h" +#include "pdump_km.h" +#include "mmu.h" + +#define MIN(a, b) (a > b ? b : a) + +static IMG_BOOL ZeroBuf(struct BM_BUF *pBuf, struct BM_MAPPING *pMapping, + u32 ui32Bytes, u32 ui32Flags); +static void BM_FreeMemory(void *pH, u32 base, struct BM_MAPPING *psMapping); +static IMG_BOOL BM_ImportMemory(void *pH, size_t uSize, + size_t *pActualSize, struct BM_MAPPING **ppsMapping, u32 uFlags, + u32 *pBase); + +static IMG_BOOL DevMemoryAlloc(struct BM_CONTEXT *pBMContext, + struct BM_MAPPING *pMapping, u32 uFlags, + u32 dev_vaddr_alignment, struct IMG_DEV_VIRTADDR *pDevVAddr); +static void DevMemoryFree(struct BM_MAPPING *pMapping); + +static IMG_BOOL AllocMemory(struct BM_CONTEXT *pBMContext, + struct BM_HEAP *psBMHeap, struct IMG_DEV_VIRTADDR *psDevVAddr, + size_t uSize, u32 uFlags, u32 uDevVAddrAlignment, + struct BM_BUF *pBuf) +{ + struct BM_MAPPING *pMapping; + u32 uOffset; + struct RA_ARENA *pArena = NULL; + + PVR_DPF(PVR_DBG_MESSAGE, "AllocMemory " + "(pBMContext=%08X, uSize=0x%x, uFlags=0x%x, " + "align=0x%x, pBuf=%08X)", + pBMContext, uSize, uFlags, uDevVAddrAlignment, pBuf); + + if (uFlags & PVRSRV_MEM_RAM_BACKED_ALLOCATION) { + if (uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) { + PVR_DPF(PVR_DBG_ERROR, "AllocMemory: " + "combination of DevVAddr management and " + "RAM backing mode unsupported"); + return IMG_FALSE; + } + + if (psBMHeap->ui32Attribs & + (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG | + PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) { + pArena = psBMHeap->pImportArena; + } else { + PVR_DPF(PVR_DBG_ERROR, "AllocMemory: " + "backing store type doesn't match heap"); + return IMG_FALSE; + } + + if (!RA_Alloc(pArena, uSize, (void *)&pMapping, uFlags, + uDevVAddrAlignment, + (u32 *)&(pBuf->DevVAddr.uiAddr))) { + PVR_DPF(PVR_DBG_ERROR, + "AllocMemory: RA_Alloc(0x%x) FAILED", uSize); + return IMG_FALSE; + } + + uOffset = pBuf->DevVAddr.uiAddr - pMapping->DevVAddr.uiAddr; + if (pMapping->CpuVAddr) { + pBuf->CpuVAddr = + (void *)((u32) pMapping->CpuVAddr + uOffset); + } else { + pBuf->CpuVAddr = NULL; + } + + if (uSize == pMapping->uSize) { + pBuf->hOSMemHandle = pMapping->hOSMemHandle; + } else { + if (OSGetSubMemHandle(pMapping->hOSMemHandle, uOffset, + uSize, psBMHeap->ui32Attribs, + &pBuf->hOSMemHandle) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "AllocMemory: " + "OSGetSubMemHandle FAILED"); + return IMG_FALSE; + } + } + + pBuf->CpuPAddr.uiAddr = pMapping->CpuPAddr.uiAddr + uOffset; + + if (uFlags & PVRSRV_MEM_ZERO) + if (!ZeroBuf(pBuf, pMapping, uSize, + psBMHeap->ui32Attribs | uFlags)) + return IMG_FALSE; + } else { + if (uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) { + PVR_ASSERT(psDevVAddr != NULL); + + if (psDevVAddr == NULL) { + PVR_DPF(PVR_DBG_ERROR, "AllocMemory: " + "invalid parameter - psDevVAddr"); + return IMG_FALSE; + } + + pBMContext->psDeviceNode->pfnMMUAlloc( + psBMHeap->pMMUHeap, uSize, + PVRSRV_MEM_USER_SUPPLIED_DEVVADDR, + uDevVAddrAlignment, psDevVAddr); + pBuf->DevVAddr = *psDevVAddr; + } else { + pBMContext->psDeviceNode->pfnMMUAlloc(psBMHeap-> + pMMUHeap, uSize, 0, + uDevVAddrAlignment, + &pBuf->DevVAddr); + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct BM_MAPPING), + (void **)&pMapping, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "AllocMemory: OSAllocMem(0x%x) FAILED"); + return IMG_FALSE; + } + + pBuf->CpuVAddr = NULL; + pBuf->hOSMemHandle = NULL; + pBuf->CpuPAddr.uiAddr = 0; + + pMapping->CpuVAddr = NULL; + pMapping->CpuPAddr.uiAddr = 0; + pMapping->DevVAddr = pBuf->DevVAddr; + pMapping->psSysAddr = NULL; + pMapping->uSize = uSize; + pMapping->hOSMemHandle = NULL; + } + + pMapping->pArena = pArena; + + pMapping->pBMHeap = psBMHeap; + pBuf->pMapping = pMapping; + + PVR_DPF(PVR_DBG_MESSAGE, "AllocMemory: " + "pMapping=%08X: DevV=%08X CpuV=%08X CpuP=%08X uSize=0x%x", + pMapping, pMapping->DevVAddr.uiAddr, pMapping->CpuVAddr, + pMapping->CpuPAddr.uiAddr, pMapping->uSize); + + PVR_DPF(PVR_DBG_MESSAGE, "AllocMemory: " + "pBuf=%08X: DevV=%08X CpuV=%08X CpuP=%08X uSize=0x%x", + pBuf, pBuf->DevVAddr.uiAddr, pBuf->CpuVAddr, + pBuf->CpuPAddr.uiAddr, uSize); + + PVR_ASSERT(((pBuf->DevVAddr.uiAddr) & (uDevVAddrAlignment - 1)) == 0); + + return IMG_TRUE; +} + +static IMG_BOOL WrapMemory(struct BM_HEAP *psBMHeap, + size_t uSize, u32 ui32BaseOffset, IMG_BOOL bPhysContig, + struct IMG_SYS_PHYADDR *psAddr, void *pvCPUVAddr, u32 uFlags, + struct BM_BUF *pBuf) +{ + struct IMG_DEV_VIRTADDR DevVAddr = { 0 }; + struct BM_MAPPING *pMapping; + IMG_BOOL bResult; + u32 const ui32PageSize = HOST_PAGESIZE(); + + PVR_DPF(PVR_DBG_MESSAGE, + "WrapMemory(psBMHeap=%08X, size=0x%x, offset=0x%x, " + "bPhysContig=0x%x, pvCPUVAddr = 0x%x, flags=0x%x, pBuf=%08X)", + psBMHeap, uSize, ui32BaseOffset, bPhysContig, pvCPUVAddr, + uFlags, pBuf); + + PVR_ASSERT((psAddr->uiAddr & (ui32PageSize - 1)) == 0); + + PVR_ASSERT(((u32) pvCPUVAddr & (ui32PageSize - 1)) == 0); + + uSize += ui32BaseOffset; + uSize = HOST_PAGEALIGN(uSize); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*pMapping), + (void **)&pMapping, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "WrapMemory: OSAllocMem(0x%x) FAILED", + sizeof(*pMapping)); + return IMG_FALSE; + } + + OSMemSet(pMapping, 0, sizeof(*pMapping)); + + pMapping->uSize = uSize; + pMapping->pBMHeap = psBMHeap; + + if (pvCPUVAddr) { + pMapping->CpuVAddr = pvCPUVAddr; + + if (bPhysContig) { + pMapping->eCpuMemoryOrigin = hm_wrapped_virtaddr; + pMapping->CpuPAddr = SysSysPAddrToCpuPAddr(psAddr[0]); + + if (OSRegisterMem(pMapping->CpuPAddr, + pMapping->CpuVAddr, pMapping->uSize, + uFlags, &pMapping->hOSMemHandle) != + PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "WrapMemory: " + "OSRegisterMem Phys=0x%08X, " + "CpuVAddr = 0x%08X, Size=%d) failed", + pMapping->CpuPAddr, pMapping->CpuVAddr, + pMapping->uSize); + goto fail_cleanup; + } + } else { + pMapping->eCpuMemoryOrigin = + hm_wrapped_scatter_virtaddr; + pMapping->psSysAddr = psAddr; + + if (OSRegisterDiscontigMem(pMapping->psSysAddr, + pMapping->CpuVAddr, + pMapping->uSize, + uFlags, + &pMapping->hOSMemHandle) != + PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "WrapMemory: " + "OSRegisterDiscontigMem CpuVAddr = " + "0x%08X, Size=%d) failed", + pMapping->CpuVAddr, pMapping->uSize); + goto fail_cleanup; + } + } + } else { + if (bPhysContig) { + pMapping->eCpuMemoryOrigin = hm_wrapped; + pMapping->CpuPAddr = SysSysPAddrToCpuPAddr(psAddr[0]); + + if (OSReservePhys(pMapping->CpuPAddr, pMapping->uSize, + uFlags, &pMapping->CpuVAddr, + &pMapping->hOSMemHandle) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "WrapMemory: " + "OSReservePhys Phys=0x%08X, Size=%d) " + "failed", + pMapping->CpuPAddr, pMapping->uSize); + goto fail_cleanup; + } + } else { + pMapping->eCpuMemoryOrigin = hm_wrapped_scatter; + pMapping->psSysAddr = psAddr; + + if (OSReserveDiscontigPhys(pMapping->psSysAddr, + pMapping->uSize, uFlags, + &pMapping->CpuVAddr, + &pMapping->hOSMemHandle) != + PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "WrapMemory: " + "OSReserveDiscontigPhys Size=%d) failed", + pMapping->uSize); + goto fail_cleanup; + } + } + } + + bResult = DevMemoryAlloc(psBMHeap->pBMContext, pMapping, + uFlags | PVRSRV_MEM_READ | PVRSRV_MEM_WRITE, + ui32PageSize, &DevVAddr); + if (!bResult) { + PVR_DPF(PVR_DBG_ERROR, + "WrapMemory: DevMemoryAlloc(0x%x) failed", + pMapping->uSize); + goto fail_cleanup; + } + + pBuf->CpuPAddr.uiAddr = pMapping->CpuPAddr.uiAddr + ui32BaseOffset; + if (!ui32BaseOffset) + pBuf->hOSMemHandle = pMapping->hOSMemHandle; + else + if (OSGetSubMemHandle(pMapping->hOSMemHandle, + ui32BaseOffset, + (pMapping->uSize - ui32BaseOffset), + uFlags, + &pBuf->hOSMemHandle) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "WrapMemory: OSGetSubMemHandle failed"); + goto fail_cleanup; + } + if (pMapping->CpuVAddr) + pBuf->CpuVAddr = (void *)((u32) pMapping->CpuVAddr + + ui32BaseOffset); + pBuf->DevVAddr.uiAddr = pMapping->DevVAddr.uiAddr + ui32BaseOffset; + + if (uFlags & PVRSRV_MEM_ZERO) + if (!ZeroBuf(pBuf, pMapping, uSize, uFlags)) + return IMG_FALSE; + + PVR_DPF(PVR_DBG_MESSAGE, "DevVaddr.uiAddr=%08X", DevVAddr.uiAddr); + PVR_DPF(PVR_DBG_MESSAGE, "WrapMemory: pMapping=%08X: DevV=%08X " + "CpuV=%08X CpuP=%08X uSize=0x%x", + pMapping, pMapping->DevVAddr.uiAddr, pMapping->CpuVAddr, + pMapping->CpuPAddr.uiAddr, pMapping->uSize); + PVR_DPF(PVR_DBG_MESSAGE, "WrapMemory: pBuf=%08X: DevV=%08X " + "CpuV=%08X CpuP=%08X uSize=0x%x", + pBuf, pBuf->DevVAddr.uiAddr, pBuf->CpuVAddr, + pBuf->CpuPAddr.uiAddr, uSize); + + pBuf->pMapping = pMapping; + return IMG_TRUE; + +fail_cleanup: + if (ui32BaseOffset && pBuf->hOSMemHandle) + OSReleaseSubMemHandle(pBuf->hOSMemHandle, uFlags); + + if (pMapping->CpuVAddr || pMapping->hOSMemHandle) + switch (pMapping->eCpuMemoryOrigin) { + case hm_wrapped: + OSUnReservePhys(pMapping->CpuVAddr, pMapping->uSize, + uFlags, pMapping->hOSMemHandle); + break; + case hm_wrapped_virtaddr: + OSUnRegisterMem(pMapping->CpuVAddr, pMapping->uSize, + uFlags, pMapping->hOSMemHandle); + break; + case hm_wrapped_scatter: + OSUnReserveDiscontigPhys(pMapping->CpuVAddr, + pMapping->uSize, uFlags, + pMapping->hOSMemHandle); + break; + case hm_wrapped_scatter_virtaddr: + OSUnRegisterDiscontigMem(pMapping->CpuVAddr, + pMapping->uSize, uFlags, + pMapping->hOSMemHandle); + break; + default: + break; + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_MAPPING), pMapping, + NULL); + + return IMG_FALSE; +} + +static IMG_BOOL ZeroBuf(struct BM_BUF *pBuf, struct BM_MAPPING *pMapping, + u32 ui32Bytes, u32 ui32Flags) +{ + void *pvCpuVAddr; + + if (pBuf->CpuVAddr) { + OSMemSet(pBuf->CpuVAddr, 0, ui32Bytes); + } else if (pMapping->eCpuMemoryOrigin == hm_contiguous || + pMapping->eCpuMemoryOrigin == hm_wrapped) { + pvCpuVAddr = (void __force *)OSMapPhysToLin(pBuf->CpuPAddr, + ui32Bytes, + PVRSRV_HAP_KERNEL_ONLY | + (ui32Flags & + PVRSRV_HAP_CACHETYPE_MASK), + NULL); + if (!pvCpuVAddr) { + PVR_DPF(PVR_DBG_ERROR, "ZeroBuf: " + "OSMapPhysToLin for contiguous buffer failed"); + return IMG_FALSE; + } + OSMemSet(pvCpuVAddr, 0, ui32Bytes); + OSUnMapPhysToLin((void __force __iomem *)pvCpuVAddr, ui32Bytes, + PVRSRV_HAP_KERNEL_ONLY | + (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), + NULL); + } else { + u32 ui32BytesRemaining = ui32Bytes; + u32 ui32CurrentOffset = 0; + struct IMG_CPU_PHYADDR CpuPAddr; + + PVR_ASSERT(pBuf->hOSMemHandle); + + while (ui32BytesRemaining > 0) { + u32 ui32BlockBytes = + MIN(ui32BytesRemaining, HOST_PAGESIZE()); + CpuPAddr = + OSMemHandleToCpuPAddr(pBuf->hOSMemHandle, + ui32CurrentOffset); + + if (CpuPAddr.uiAddr & (HOST_PAGESIZE() - 1)) + ui32BlockBytes = + MIN(ui32BytesRemaining, + HOST_PAGEALIGN(CpuPAddr.uiAddr) - + CpuPAddr.uiAddr); + + pvCpuVAddr = (void __force *)OSMapPhysToLin(CpuPAddr, + ui32BlockBytes, + PVRSRV_HAP_KERNEL_ONLY | + (ui32Flags & + PVRSRV_HAP_CACHETYPE_MASK), + NULL); + if (!pvCpuVAddr) { + PVR_DPF(PVR_DBG_ERROR, "ZeroBuf: " + "OSMapPhysToLin while " + "zeroing non-contiguous memory FAILED"); + return IMG_FALSE; + } + OSMemSet(pvCpuVAddr, 0, ui32BlockBytes); + OSUnMapPhysToLin((void __force __iomem *)pvCpuVAddr, + ui32BlockBytes, + PVRSRV_HAP_KERNEL_ONLY | + (ui32Flags & + PVRSRV_HAP_CACHETYPE_MASK), + NULL); + + ui32BytesRemaining -= ui32BlockBytes; + ui32CurrentOffset += ui32BlockBytes; + } + } + + return IMG_TRUE; +} + +static void FreeBuf(struct BM_BUF *pBuf, u32 ui32Flags) +{ + struct BM_MAPPING *pMapping; + + PVR_DPF(PVR_DBG_MESSAGE, + "FreeBuf: pBuf=%08X: DevVAddr=%08X CpuVAddr=%08X CpuPAddr=%08X", + pBuf, pBuf->DevVAddr.uiAddr, pBuf->CpuVAddr, + pBuf->CpuPAddr.uiAddr); + + pMapping = pBuf->pMapping; + + if (ui32Flags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) { + if (ui32Flags & PVRSRV_MEM_RAM_BACKED_ALLOCATION) + PVR_DPF(PVR_DBG_ERROR, "FreeBuf: " + "combination of DevVAddr management " + "and RAM backing mode unsupported"); + else + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct BM_MAPPING), + pMapping, NULL); + } else { + if (pBuf->hOSMemHandle != pMapping->hOSMemHandle) + OSReleaseSubMemHandle(pBuf->hOSMemHandle, ui32Flags); + if (ui32Flags & PVRSRV_MEM_RAM_BACKED_ALLOCATION) { + RA_Free(pBuf->pMapping->pArena, pBuf->DevVAddr.uiAddr, + IMG_FALSE); + } else { + switch (pMapping->eCpuMemoryOrigin) { + case hm_wrapped: + OSUnReservePhys(pMapping->CpuVAddr, + pMapping->uSize, ui32Flags, + pMapping->hOSMemHandle); + break; + case hm_wrapped_virtaddr: + OSUnRegisterMem(pMapping->CpuVAddr, + pMapping->uSize, ui32Flags, + pMapping->hOSMemHandle); + break; + case hm_wrapped_scatter: + OSUnReserveDiscontigPhys(pMapping->CpuVAddr, + pMapping->uSize, + ui32Flags, + pMapping-> + hOSMemHandle); + break; + case hm_wrapped_scatter_virtaddr: + OSUnRegisterDiscontigMem(pMapping->CpuVAddr, + pMapping->uSize, + ui32Flags, + pMapping-> + hOSMemHandle); + break; + default: + break; + } + + DevMemoryFree(pMapping); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct BM_MAPPING), pMapping, NULL); + } + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_BUF), pBuf, NULL); +} + +void BM_DestroyContext(void *hBMContext) +{ + struct BM_CONTEXT *pBMContext = (struct BM_CONTEXT *)hBMContext; + struct BM_HEAP *psBMHeap; + + PVR_DPF(PVR_DBG_MESSAGE, "BM_DestroyContext"); + + for (psBMHeap = pBMContext->psBMHeap; + psBMHeap != NULL; psBMHeap = psBMHeap->psNext) + if (psBMHeap->ui32Attribs & + (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG | + PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) + if (psBMHeap->pImportArena) { + IMG_BOOL bTestDelete = + RA_TestDelete(psBMHeap->pImportArena); + BUG_ON(!bTestDelete); + } + + ResManFreeResByPtr(pBMContext->hResItem); +} + +static enum PVRSRV_ERROR BM_DestroyContextCallBack(void *pvParam, u32 ui32Param) +{ + struct BM_CONTEXT *pBMContext = pvParam; + struct BM_CONTEXT **ppBMContext; + struct BM_HEAP *psBMHeap, *psTmpBMHeap; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + psDeviceNode = pBMContext->psDeviceNode; + + psBMHeap = pBMContext->psBMHeap; + while (psBMHeap) { + if (psBMHeap->ui32Attribs & + (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG | + PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) { + if (psBMHeap->pImportArena) + RA_Delete(psBMHeap->pImportArena); + } else { + PVR_DPF(PVR_DBG_ERROR, "BM_DestroyContext: " + "backing store type unsupported"); + return PVRSRV_ERROR_GENERIC; + } + + psDeviceNode->pfnMMUDelete(psBMHeap->pMMUHeap); + + psTmpBMHeap = psBMHeap; + + psBMHeap = psBMHeap->psNext; + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_HEAP), + psTmpBMHeap, NULL); + } + + if (pBMContext->psMMUContext) + psDeviceNode->pfnMMUFinalise(pBMContext->psMMUContext); + + if (pBMContext->pBufferHash) + HASH_Delete(pBMContext->pBufferHash); + + if (pBMContext == psDeviceNode->sDevMemoryInfo.pBMKernelContext) { + psDeviceNode->sDevMemoryInfo.pBMKernelContext = NULL; + } else { + for (ppBMContext = &psDeviceNode->sDevMemoryInfo.pBMContext; + *ppBMContext; ppBMContext = &((*ppBMContext)->psNext)) + if (*ppBMContext == pBMContext) { + *ppBMContext = pBMContext->psNext; + break; + } + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_CONTEXT), + pBMContext, NULL); + + return PVRSRV_OK; +} + +void *BM_CreateContext(struct PVRSRV_DEVICE_NODE *psDeviceNode, + struct IMG_DEV_PHYADDR *psPDDevPAddr, + struct PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_BOOL *pbCreated) +{ + struct BM_CONTEXT *pBMContext; + struct BM_HEAP *psBMHeap; + struct DEVICE_MEMORY_INFO *psDevMemoryInfo; + IMG_BOOL bKernelContext; + struct RESMAN_CONTEXT *hResManContext; + + PVR_DPF(PVR_DBG_MESSAGE, "BM_CreateContext"); + + if (psPerProc == NULL) { + bKernelContext = IMG_TRUE; + hResManContext = psDeviceNode->hResManContext; + } else { + bKernelContext = IMG_FALSE; + hResManContext = psPerProc->hResManContext; + } + + if (pbCreated != NULL) + *pbCreated = IMG_FALSE; + + psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; + + if (bKernelContext == IMG_FALSE) + for (pBMContext = psDevMemoryInfo->pBMContext; + pBMContext != NULL; pBMContext = pBMContext->psNext) + if (ResManFindResourceByPtr(hResManContext, + pBMContext->hResItem) == + PVRSRV_OK) { + pBMContext->ui32RefCount++; + return (void *)pBMContext; + } + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_CONTEXT), + (void **)&pBMContext, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "BM_CreateContext: Alloc failed"); + return NULL; + } + OSMemSet(pBMContext, 0, sizeof(struct BM_CONTEXT)); + + pBMContext->psDeviceNode = psDeviceNode; + + pBMContext->pBufferHash = HASH_Create(32); + if (pBMContext->pBufferHash == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "BM_CreateContext: HASH_Create failed"); + goto cleanup; + } + + if (psDeviceNode->pfnMMUInitialise(psDeviceNode, + &pBMContext->psMMUContext, + psPDDevPAddr) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "BM_CreateContext: MMUInitialise failed"); + goto cleanup; + } + + if (bKernelContext) { + PVR_ASSERT(psDevMemoryInfo->pBMKernelContext == NULL); + psDevMemoryInfo->pBMKernelContext = pBMContext; + } else { + + PVR_ASSERT(psDevMemoryInfo->pBMKernelContext); + + if (psDevMemoryInfo->pBMKernelContext == NULL) { + PVR_DPF(PVR_DBG_ERROR, "BM_CreateContext: " + "psDevMemoryInfo->pBMKernelContext invalid"); + goto cleanup; + } + + PVR_ASSERT(psDevMemoryInfo->pBMKernelContext->psBMHeap); + + pBMContext->psBMSharedHeap = + psDevMemoryInfo->pBMKernelContext->psBMHeap; + + psBMHeap = pBMContext->psBMSharedHeap; + while (psBMHeap) { + switch (psBMHeap->sDevArena.DevMemHeapType) { + case DEVICE_MEMORY_HEAP_SHARED: + case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: + { + psDeviceNode-> + pfnMMUInsertHeap(pBMContext-> + psMMUContext, + psBMHeap-> + pMMUHeap); + break; + } + } + psBMHeap = psBMHeap->psNext; + } + pBMContext->psNext = psDevMemoryInfo->pBMContext; + psDevMemoryInfo->pBMContext = pBMContext; + } + pBMContext->ui32RefCount++; + pBMContext->hResItem = ResManRegisterRes(hResManContext, + RESMAN_TYPE_DEVICEMEM_CONTEXT, + pBMContext, + 0, BM_DestroyContextCallBack); + if (pBMContext->hResItem == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "BM_CreateContext: ResManRegisterRes failed"); + goto cleanup; + } + + if (pbCreated != NULL) + *pbCreated = IMG_TRUE; + return (void *)pBMContext; + +cleanup: + BM_DestroyContextCallBack(pBMContext, 0); + + return NULL; +} + +void *BM_CreateHeap(void *hBMContext, + struct DEVICE_MEMORY_HEAP_INFO *psDevMemHeapInfo) +{ + struct BM_CONTEXT *pBMContext = (struct BM_CONTEXT *)hBMContext; + struct PVRSRV_DEVICE_NODE *psDeviceNode = pBMContext->psDeviceNode; + struct BM_HEAP *psBMHeap; + + PVR_DPF(PVR_DBG_MESSAGE, "BM_CreateHeap"); + + if (pBMContext->ui32RefCount > 0) { + psBMHeap = pBMContext->psBMHeap; + + while (psBMHeap) { + if (psBMHeap->sDevArena.ui32HeapID == + psDevMemHeapInfo->ui32HeapID) + + return psBMHeap; + psBMHeap = psBMHeap->psNext; + } + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_HEAP), + (void **) &psBMHeap, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "BM_CreateHeap: Alloc failed"); + return NULL; + } + + OSMemSet(psBMHeap, 0, sizeof(struct BM_HEAP)); + + psBMHeap->sDevArena.ui32HeapID = psDevMemHeapInfo->ui32HeapID; + psBMHeap->sDevArena.pszName = psDevMemHeapInfo->pszName; + psBMHeap->sDevArena.BaseDevVAddr = psDevMemHeapInfo->sDevVAddrBase; + psBMHeap->sDevArena.ui32Size = psDevMemHeapInfo->ui32HeapSize; + psBMHeap->sDevArena.DevMemHeapType = psDevMemHeapInfo->DevMemHeapType; + psBMHeap->sDevArena.ui32DataPageSize = + psDevMemHeapInfo->ui32DataPageSize; + psBMHeap->sDevArena.psDeviceMemoryHeapInfo = psDevMemHeapInfo; + psBMHeap->ui32Attribs = psDevMemHeapInfo->ui32Attribs; + + psBMHeap->pBMContext = pBMContext; + + psBMHeap->pMMUHeap = + psDeviceNode->pfnMMUCreate(pBMContext->psMMUContext, + &psBMHeap->sDevArena, + &psBMHeap->pVMArena); + if (!psBMHeap->pMMUHeap) { + PVR_DPF(PVR_DBG_ERROR, "BM_CreateHeap: MMUCreate failed"); + goto ErrorExit; + } + + psBMHeap->pImportArena = RA_Create(psDevMemHeapInfo->pszBSName, + 0, 0, NULL, + psBMHeap->sDevArena.ui32DataPageSize, + BM_ImportMemory, + BM_FreeMemory, NULL, psBMHeap); + if (psBMHeap->pImportArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, "BM_CreateHeap: RA_Create failed"); + goto ErrorExit; + } + + if (psBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) { + + psBMHeap->pLocalDevMemArena = + psDevMemHeapInfo->psLocalDevMemArena; + if (psBMHeap->pLocalDevMemArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "BM_CreateHeap: LocalDevMemArena null"); + goto ErrorExit; + } + } + + psBMHeap->psNext = pBMContext->psBMHeap; + pBMContext->psBMHeap = psBMHeap; + + return (void *)psBMHeap; + +ErrorExit: + + if (psBMHeap->pMMUHeap != NULL) { + psDeviceNode->pfnMMUDelete(psBMHeap->pMMUHeap); + psDeviceNode->pfnMMUFinalise(pBMContext->psMMUContext); + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_HEAP), + psBMHeap, NULL); + + return NULL; +} + +void BM_DestroyHeap(void *hDevMemHeap) +{ + struct BM_HEAP *psBMHeap = (struct BM_HEAP *)hDevMemHeap; + struct PVRSRV_DEVICE_NODE *psDeviceNode = + psBMHeap->pBMContext->psDeviceNode; + struct BM_HEAP **ppsBMHeap; + + PVR_DPF(PVR_DBG_MESSAGE, "BM_DestroyHeap"); + + if (psBMHeap->ui32Attribs & + (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG | + PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) { + if (psBMHeap->pImportArena) + RA_Delete(psBMHeap->pImportArena); + } else { + PVR_DPF(PVR_DBG_ERROR, + "BM_DestroyHeap: backing store type unsupported"); + return; + } + + psDeviceNode->pfnMMUDelete(psBMHeap->pMMUHeap); + + ppsBMHeap = &psBMHeap->pBMContext->psBMHeap; + while (*ppsBMHeap) { + if (*ppsBMHeap == psBMHeap) { + *ppsBMHeap = psBMHeap->psNext; + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct BM_HEAP), psBMHeap, + NULL); + break; + } + ppsBMHeap = &((*ppsBMHeap)->psNext); + } +} + +IMG_BOOL BM_Reinitialise(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + PVR_DPF(PVR_DBG_MESSAGE, "BM_Reinitialise"); + PVR_UNREFERENCED_PARAMETER(psDeviceNode); + + return IMG_TRUE; +} + +IMG_BOOL BM_Alloc(void *hDevMemHeap, struct IMG_DEV_VIRTADDR *psDevVAddr, + size_t uSize, u32 *pui32Flags, u32 uDevVAddrAlignment, + void **phBuf) +{ + struct BM_BUF *pBuf; + struct BM_CONTEXT *pBMContext; + struct BM_HEAP *psBMHeap; + struct SYS_DATA *psSysData; + u32 uFlags; + + if (pui32Flags == NULL) { + PVR_DPF(PVR_DBG_ERROR, "BM_Alloc: invalid parameter"); + PVR_DBG_BREAK; + return IMG_FALSE; + } + + uFlags = *pui32Flags; + + PVR_DPF(PVR_DBG_MESSAGE, + "BM_Alloc (uSize=0x%x, uFlags=0x%x, uDevVAddrAlignment=0x%x)", + uSize, uFlags, uDevVAddrAlignment); + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return IMG_FALSE; + + psBMHeap = (struct BM_HEAP *)hDevMemHeap; + pBMContext = psBMHeap->pBMContext; + + if (uDevVAddrAlignment == 0) + uDevVAddrAlignment = 1; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_BUF), + (void **)&pBuf, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "BM_Alloc: BM_Buf alloc FAILED"); + return IMG_FALSE; + } + OSMemSet(pBuf, 0, sizeof(struct BM_BUF)); + + if (AllocMemory(pBMContext, psBMHeap, psDevVAddr, uSize, uFlags, + uDevVAddrAlignment, pBuf) != IMG_TRUE) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_BUF), pBuf, + NULL); + PVR_DPF(PVR_DBG_ERROR, "BM_Alloc: AllocMemory FAILED"); + return IMG_FALSE; + } + + PVR_DPF(PVR_DBG_MESSAGE, "BM_Alloc (uSize=0x%x, uFlags=0x%x)=%08X", + uSize, uFlags, pBuf); + + pBuf->ui32RefCount = 1; + pvr_get_ctx(pBMContext); + *phBuf = (void *) pBuf; + *pui32Flags = uFlags | psBMHeap->ui32Attribs; + + return IMG_TRUE; +} + +IMG_BOOL BM_Wrap(void *hDevMemHeap, u32 ui32Size, u32 ui32Offset, + IMG_BOOL bPhysContig, struct IMG_SYS_PHYADDR *psSysAddr, + void *pvCPUVAddr, u32 *pui32Flags, void **phBuf) +{ + struct BM_BUF *pBuf; + struct BM_CONTEXT *psBMContext; + struct BM_HEAP *psBMHeap; + struct SYS_DATA *psSysData; + struct IMG_SYS_PHYADDR sHashAddress; + u32 uFlags; + + psBMHeap = (struct BM_HEAP *)hDevMemHeap; + psBMContext = psBMHeap->pBMContext; + + uFlags = psBMHeap->ui32Attribs & + (PVRSRV_HAP_CACHETYPE_MASK | PVRSRV_HAP_MAPTYPE_MASK); + + if (pui32Flags) + uFlags |= *pui32Flags; + + PVR_DPF(PVR_DBG_MESSAGE, "BM_Wrap (uSize=0x%x, uOffset=0x%x, " + "bPhysContig=0x%x, pvCPUVAddr=0x%x, uFlags=0x%x)", + ui32Size, ui32Offset, bPhysContig, pvCPUVAddr, uFlags); + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return IMG_FALSE; + + sHashAddress = psSysAddr[0]; + + sHashAddress.uiAddr += ui32Offset; + + pBuf = (struct BM_BUF *)HASH_Retrieve(psBMContext->pBufferHash, + (u32) sHashAddress.uiAddr); + + if (pBuf) { + u32 ui32MappingSize = + HOST_PAGEALIGN(ui32Size + ui32Offset); + + if (pBuf->pMapping->uSize == ui32MappingSize && + (pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || + pBuf->pMapping->eCpuMemoryOrigin == + hm_wrapped_virtaddr)) { + PVR_DPF(PVR_DBG_MESSAGE, "BM_Wrap " + "(Matched previous Wrap! uSize=0x%x, " + "uOffset=0x%x, SysAddr=%08X)", + ui32Size, ui32Offset, sHashAddress.uiAddr); + + pBuf->ui32RefCount++; + *phBuf = (void *)pBuf; + if (pui32Flags) + *pui32Flags = uFlags; + + return IMG_TRUE; + } + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_BUF), + (void **)&pBuf, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "BM_Wrap: BM_Buf alloc FAILED"); + return IMG_FALSE; + } + OSMemSet(pBuf, 0, sizeof(struct BM_BUF)); + + if (WrapMemory(psBMHeap, ui32Size, ui32Offset, bPhysContig, psSysAddr, + pvCPUVAddr, uFlags, pBuf) != IMG_TRUE) { + PVR_DPF(PVR_DBG_ERROR, "BM_Wrap: WrapMemory FAILED"); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_BUF), pBuf, + NULL); + return IMG_FALSE; + } + + if (pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || + pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr) { + + PVR_ASSERT(SysSysPAddrToCpuPAddr(sHashAddress).uiAddr == + pBuf->CpuPAddr.uiAddr); + + if (!HASH_Insert(psBMContext->pBufferHash, + (u32)sHashAddress.uiAddr, (u32) pBuf)) { + FreeBuf(pBuf, uFlags); + PVR_DPF(PVR_DBG_ERROR, "BM_Wrap: HASH_Insert FAILED"); + return IMG_FALSE; + } + } + + PVR_DPF(PVR_DBG_MESSAGE, + "BM_Wrap (uSize=0x%x, uFlags=0x%x)=%08X(devVAddr=%08X)", + ui32Size, uFlags, pBuf, pBuf->DevVAddr.uiAddr); + + pBuf->ui32RefCount = 1; + pvr_get_ctx(psBMContext); + *phBuf = (void *) pBuf; + if (pui32Flags) + *pui32Flags = (uFlags & ~PVRSRV_HAP_MAPTYPE_MASK) | + PVRSRV_HAP_MULTI_PROCESS; + + return IMG_TRUE; +} + +void BM_Free(void *hBuf, u32 ui32Flags) +{ + struct BM_BUF *pBuf = (struct BM_BUF *)hBuf; + struct SYS_DATA *psSysData; + struct IMG_SYS_PHYADDR sHashAddr; + + PVR_DPF(PVR_DBG_MESSAGE, "BM_Free (h=%08X)", hBuf); + PVR_ASSERT(pBuf != NULL); + + if (pBuf == NULL) { + PVR_DPF(PVR_DBG_ERROR, "BM_Free: invalid parameter"); + return; + } + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return; + + pBuf->ui32RefCount--; + + if (pBuf->ui32RefCount == 0) { + struct BM_MAPPING *map = pBuf->pMapping; + struct BM_CONTEXT *ctx = map->pBMHeap->pBMContext; + + if (map->eCpuMemoryOrigin == hm_wrapped || + map->eCpuMemoryOrigin == hm_wrapped_virtaddr) { + sHashAddr = SysCpuPAddrToSysPAddr(pBuf->CpuPAddr); + + HASH_Remove(ctx->pBufferHash, (u32)sHashAddr.uiAddr); + } + FreeBuf(pBuf, ui32Flags); + pvr_put_ctx(ctx); + } +} + +void *BM_HandleToCpuVaddr(void *hBuf) +{ + struct BM_BUF *pBuf = (struct BM_BUF *)hBuf; + + PVR_ASSERT(pBuf != NULL); + if (pBuf == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "BM_HandleToCpuVaddr: invalid parameter"); + return NULL; + } + + PVR_DPF(PVR_DBG_MESSAGE, + "BM_HandleToCpuVaddr(h=%08X)=%08X", hBuf, pBuf->CpuVAddr); + return pBuf->CpuVAddr; +} + +struct IMG_DEV_VIRTADDR BM_HandleToDevVaddr(void *hBuf) +{ + struct BM_BUF *pBuf = (struct BM_BUF *)hBuf; + + PVR_ASSERT(pBuf != NULL); + if (pBuf == NULL) { + struct IMG_DEV_VIRTADDR DevVAddr = { 0 }; + PVR_DPF(PVR_DBG_ERROR, + "BM_HandleToDevVaddr: invalid parameter"); + return DevVAddr; + } + + PVR_DPF(PVR_DBG_MESSAGE, "BM_HandleToDevVaddr(h=%08X)=%08X", hBuf, + pBuf->DevVAddr); + return pBuf->DevVAddr; +} + +struct IMG_SYS_PHYADDR BM_HandleToSysPaddr(void *hBuf) +{ + struct BM_BUF *pBuf = (struct BM_BUF *)hBuf; + + PVR_ASSERT(pBuf != NULL); + + if (pBuf == NULL) { + struct IMG_SYS_PHYADDR PhysAddr = { 0 }; + PVR_DPF(PVR_DBG_ERROR, + "BM_HandleToSysPaddr: invalid parameter"); + return PhysAddr; + } + + PVR_DPF(PVR_DBG_MESSAGE, "BM_HandleToSysPaddr(h=%08X)=%08X", hBuf, + pBuf->CpuPAddr.uiAddr); + return SysCpuPAddrToSysPAddr(pBuf->CpuPAddr); +} + +void *BM_HandleToOSMemHandle(void *hBuf) +{ + struct BM_BUF *pBuf = (struct BM_BUF *)hBuf; + + PVR_ASSERT(pBuf != NULL); + + if (pBuf == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "BM_HandleToOSMemHandle: invalid parameter"); + return NULL; + } + + PVR_DPF(PVR_DBG_MESSAGE, + "BM_HandleToOSMemHandle(h=%08X)=%08X", + hBuf, pBuf->hOSMemHandle); + return pBuf->hOSMemHandle; +} + +IMG_BOOL BM_ContiguousStatistics(u32 uFlags, u32 *pTotalBytes, + u32 *pAvailableBytes) +{ + if (pAvailableBytes || pTotalBytes || uFlags) + ; + return IMG_FALSE; +} + +static IMG_BOOL DevMemoryAlloc(struct BM_CONTEXT *pBMContext, + struct BM_MAPPING *pMapping, u32 uFlags, u32 dev_vaddr_alignment, + struct IMG_DEV_VIRTADDR *pDevVAddr) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; +#ifdef PDUMP + u32 ui32PDumpSize = pMapping->uSize; +#endif + + psDeviceNode = pBMContext->psDeviceNode; + + if (uFlags & PVRSRV_MEM_INTERLEAVED) + + pMapping->uSize *= 2; +#ifdef PDUMP + if (uFlags & PVRSRV_MEM_DUMMY) + + ui32PDumpSize = pMapping->pBMHeap->sDevArena.ui32DataPageSize; +#endif + + if (!psDeviceNode->pfnMMUAlloc(pMapping->pBMHeap->pMMUHeap, + pMapping->uSize, 0, dev_vaddr_alignment, + &(pMapping->DevVAddr))) { + PVR_DPF(PVR_DBG_ERROR, "DevMemoryAlloc ERROR MMU_Alloc"); + return IMG_FALSE; + } + + PDUMPMALLOCPAGES(psDeviceNode->sDevId.eDeviceType, + pMapping->DevVAddr.uiAddr, pMapping->CpuVAddr, + pMapping->hOSMemHandle, ui32PDumpSize, + pMapping->pBMHeap->sDevArena.ui32DataPageSize, + (void *)pMapping); + + switch (pMapping->eCpuMemoryOrigin) { + case hm_wrapped: + case hm_wrapped_virtaddr: + case hm_contiguous: + { + psDeviceNode->pfnMMUMapPages(pMapping->pBMHeap-> + pMMUHeap, + pMapping->DevVAddr, + SysCpuPAddrToSysPAddr + (pMapping->CpuPAddr), + pMapping->uSize, uFlags, + (void *)pMapping); + + *pDevVAddr = pMapping->DevVAddr; + break; + } + case hm_env: + { + psDeviceNode->pfnMMUMapShadow(pMapping->pBMHeap-> + pMMUHeap, + pMapping->DevVAddr, + pMapping->uSize, + pMapping->CpuVAddr, + pMapping->hOSMemHandle, + pDevVAddr, uFlags, + (void *)pMapping); + break; + } + case hm_wrapped_scatter: + case hm_wrapped_scatter_virtaddr: + { + psDeviceNode->pfnMMUMapScatter(pMapping->pBMHeap-> + pMMUHeap, + pMapping->DevVAddr, + pMapping->psSysAddr, + pMapping->uSize, uFlags, + (void *)pMapping); + + *pDevVAddr = pMapping->DevVAddr; + break; + } + default: + PVR_DPF(PVR_DBG_ERROR, + "Illegal value %d for pMapping->eCpuMemoryOrigin", + pMapping->eCpuMemoryOrigin); + return IMG_FALSE; + } + + + return IMG_TRUE; +} + +static void DevMemoryFree(struct BM_MAPPING *pMapping) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; +#ifdef PDUMP + u32 ui32PSize; +#endif + +#ifdef PDUMP + + if (pMapping->ui32Flags & PVRSRV_MEM_DUMMY) + ui32PSize = pMapping->pBMHeap->sDevArena.ui32DataPageSize; + else + ui32PSize = pMapping->uSize; + + PDUMPFREEPAGES(pMapping->pBMHeap, pMapping->DevVAddr, ui32PSize, + pMapping->pBMHeap->sDevArena.ui32DataPageSize, + (void *)pMapping, (IMG_BOOL)(pMapping-> + ui32Flags & PVRSRV_MEM_INTERLEAVED)); +#endif + + psDeviceNode = pMapping->pBMHeap->pBMContext->psDeviceNode; + + psDeviceNode->pfnMMUFree(pMapping->pBMHeap->pMMUHeap, + pMapping->DevVAddr, pMapping->uSize); +} + +static IMG_BOOL BM_ImportMemory(void *pH, size_t uRequestSize, + size_t *pActualSize, struct BM_MAPPING **ppsMapping, + u32 uFlags, u32 *pBase) +{ + struct BM_MAPPING *pMapping; + struct BM_HEAP *pBMHeap = pH; + struct BM_CONTEXT *pBMContext = pBMHeap->pBMContext; + IMG_BOOL bResult; + size_t uSize; + size_t uPSize; + u32 uDevVAddrAlignment = 0; + + PVR_DPF(PVR_DBG_MESSAGE, + "BM_ImportMemory (pBMContext=%08X, uRequestSize=0x%x, " + "uFlags=0x%x, uAlign=0x%x)", + pBMContext, uRequestSize, uFlags, uDevVAddrAlignment); + + PVR_ASSERT(ppsMapping != NULL); + PVR_ASSERT(pBMContext != NULL); + + if (ppsMapping == NULL) { + PVR_DPF(PVR_DBG_ERROR, "BM_ImportMemory: invalid parameter"); + goto fail_exit; + } + + uSize = HOST_PAGEALIGN(uRequestSize); + PVR_ASSERT(uSize >= uRequestSize); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_MAPPING), + (void **)&pMapping, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "BM_ImportMemory: failed struct BM_MAPPING alloc"); + goto fail_exit; + } + + pMapping->hOSMemHandle = NULL; + pMapping->CpuVAddr = NULL; + pMapping->DevVAddr.uiAddr = 0; + pMapping->CpuPAddr.uiAddr = 0; + pMapping->uSize = uSize; + pMapping->pBMHeap = pBMHeap; + pMapping->ui32Flags = uFlags; + + if (pActualSize) + *pActualSize = uSize; + + if (pMapping->ui32Flags & PVRSRV_MEM_DUMMY) + uPSize = pBMHeap->sDevArena.ui32DataPageSize; + else + uPSize = pMapping->uSize; + + if (pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) { + if (OSAllocPages(pBMHeap->ui32Attribs, uPSize, + pBMHeap->sDevArena.ui32DataPageSize, + (void **)&pMapping->CpuVAddr, + &pMapping->hOSMemHandle) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "BM_ImportMemory: OSAllocPages(0x%x) failed", + uPSize); + goto fail_mapping_alloc; + } + + pMapping->eCpuMemoryOrigin = hm_env; + } else if (pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) { + struct IMG_SYS_PHYADDR sSysPAddr; + + PVR_ASSERT(pBMHeap->pLocalDevMemArena != NULL); + + if (!RA_Alloc(pBMHeap->pLocalDevMemArena, uPSize, NULL, 0, + pBMHeap->sDevArena.ui32DataPageSize, + (u32 *)&sSysPAddr.uiAddr)) { + PVR_DPF(PVR_DBG_ERROR, + "BM_ImportMemory: RA_Alloc(0x%x) FAILED", + uPSize); + goto fail_mapping_alloc; + } + + pMapping->CpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); + if (OSReservePhys(pMapping->CpuPAddr, uPSize, + pBMHeap->ui32Attribs, &pMapping->CpuVAddr, + &pMapping->hOSMemHandle) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "BM_ImportMemory: OSReservePhys failed"); + goto fail_dev_mem_alloc; + } + + pMapping->eCpuMemoryOrigin = hm_contiguous; + } else { + PVR_DPF(PVR_DBG_ERROR, + "BM_ImportMemory: Invalid backing store type"); + goto fail_mapping_alloc; + } + + bResult = DevMemoryAlloc(pBMContext, pMapping, uFlags, + uDevVAddrAlignment, &pMapping->DevVAddr); + if (!bResult) { + PVR_DPF(PVR_DBG_ERROR, + "BM_ImportMemory: DevMemoryAlloc(0x%x) failed", + pMapping->uSize); + goto fail_dev_mem_alloc; + } + + PVR_ASSERT(uDevVAddrAlignment > 1 ? + (pMapping->DevVAddr.uiAddr % uDevVAddrAlignment) == 0 : 1); + + *pBase = pMapping->DevVAddr.uiAddr; + *ppsMapping = pMapping; + + PVR_DPF(PVR_DBG_MESSAGE, "BM_ImportMemory: IMG_TRUE"); + return IMG_TRUE; + +fail_dev_mem_alloc: + if (pMapping->CpuVAddr || pMapping->hOSMemHandle) { + if (pMapping->ui32Flags & PVRSRV_MEM_INTERLEAVED) + pMapping->uSize /= 2; + + if (pMapping->ui32Flags & PVRSRV_MEM_DUMMY) + uPSize = pBMHeap->sDevArena.ui32DataPageSize; + else + uPSize = pMapping->uSize; + + if (pBMHeap->ui32Attribs & + PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) { + OSFreePages(pBMHeap->ui32Attribs, uPSize, + (void *)pMapping->CpuVAddr, + pMapping->hOSMemHandle); + } else { + struct IMG_SYS_PHYADDR sSysPAddr; + + if (pMapping->CpuVAddr) + OSUnReservePhys(pMapping->CpuVAddr, uPSize, + pBMHeap->ui32Attribs, + pMapping->hOSMemHandle); + sSysPAddr = SysCpuPAddrToSysPAddr(pMapping->CpuPAddr); + RA_Free(pBMHeap->pLocalDevMemArena, sSysPAddr.uiAddr, + IMG_FALSE); + } + } +fail_mapping_alloc: + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_MAPPING), pMapping, + NULL); +fail_exit: + return IMG_FALSE; +} + +static void BM_FreeMemory(void *h, u32 _base, struct BM_MAPPING *psMapping) +{ + struct BM_HEAP *pBMHeap = h; + size_t uPSize; + + PVR_UNREFERENCED_PARAMETER(_base); + + PVR_DPF(PVR_DBG_MESSAGE, + "BM_FreeMemory (h=%08X, base=0x%x, psMapping=0x%x)", h, _base, + psMapping); + + PVR_ASSERT(psMapping != NULL); + + if (psMapping == NULL) { + PVR_DPF(PVR_DBG_ERROR, "BM_FreeMemory: invalid parameter"); + return; + } + + DevMemoryFree(psMapping); + + if ((psMapping->ui32Flags & PVRSRV_MEM_INTERLEAVED) != 0) + psMapping->uSize /= 2; + + if (psMapping->ui32Flags & PVRSRV_MEM_DUMMY) + uPSize = psMapping->pBMHeap->sDevArena.ui32DataPageSize; + else + uPSize = psMapping->uSize; + + if (pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) { + OSFreePages(pBMHeap->ui32Attribs, uPSize, + (void *)psMapping->CpuVAddr, + psMapping->hOSMemHandle); + } else if (pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) { + struct IMG_SYS_PHYADDR sSysPAddr; + + OSUnReservePhys(psMapping->CpuVAddr, uPSize, + pBMHeap->ui32Attribs, psMapping->hOSMemHandle); + + sSysPAddr = SysCpuPAddrToSysPAddr(psMapping->CpuPAddr); + + RA_Free(pBMHeap->pLocalDevMemArena, sSysPAddr.uiAddr, + IMG_FALSE); + } else { + PVR_DPF(PVR_DBG_ERROR, + "BM_FreeMemory: Invalid backing store type"); + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_MAPPING), psMapping, + NULL); + + PVR_DPF(PVR_DBG_MESSAGE, + "..BM_FreeMemory (h=%08X, base=0x%x, psMapping=0x%x)", + h, _base, psMapping); +} + +enum PVRSRV_ERROR BM_GetPhysPageAddr(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, + struct IMG_DEV_VIRTADDR sDevVPageAddr, + struct IMG_DEV_PHYADDR *psDevPAddr) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + + PVR_DPF(PVR_DBG_MESSAGE, "BM_GetPhysPageAddr"); + + if (!psMemInfo || !psDevPAddr) { + PVR_DPF(PVR_DBG_ERROR, "BM_GetPhysPageAddr: Invalid params"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + PVR_ASSERT((sDevVPageAddr.uiAddr & 0xFFF) == 0); + + psDeviceNode = + ((struct BM_BUF *)psMemInfo->sMemBlk.hBuffer)->pMapping->pBMHeap-> + pBMContext->psDeviceNode; + + *psDevPAddr = psDeviceNode->pfnMMUGetPhysPageAddr(((struct BM_BUF *) + psMemInfo->sMemBlk.hBuffer)-> + pMapping->pBMHeap->pMMUHeap, sDevVPageAddr); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR BM_GetHeapInfo(void *hDevMemHeap, + struct PVRSRV_HEAP_INFO *psHeapInfo) +{ + struct BM_HEAP *psBMHeap = (struct BM_HEAP *)hDevMemHeap; + + PVR_DPF(PVR_DBG_VERBOSE, "BM_GetHeapInfo"); + + psHeapInfo->hDevMemHeap = hDevMemHeap; + psHeapInfo->sDevVAddrBase = psBMHeap->sDevArena.BaseDevVAddr; + psHeapInfo->ui32HeapByteSize = psBMHeap->sDevArena.ui32Size; + psHeapInfo->ui32Attribs = psBMHeap->ui32Attribs; + + return PVRSRV_OK; +} + +struct MMU_CONTEXT *BM_GetMMUContext(void *hDevMemHeap) +{ + struct BM_HEAP *pBMHeap = (struct BM_HEAP *)hDevMemHeap; + + PVR_DPF(PVR_DBG_VERBOSE, "BM_GetMMUContext"); + + return pBMHeap->pBMContext->psMMUContext; +} + +struct MMU_CONTEXT *BM_GetMMUContextFromMemContext(void *hDevMemContext) +{ + struct BM_CONTEXT *pBMContext = (struct BM_CONTEXT *)hDevMemContext; + + PVR_DPF(PVR_DBG_VERBOSE, "BM_GetMMUContextFromMemContext"); + + return pBMContext->psMMUContext; +} + +void *BM_GetMMUHeap(void *hDevMemHeap) +{ + PVR_DPF(PVR_DBG_VERBOSE, "BM_GetMMUHeap"); + + return (void *)((struct BM_HEAP *)hDevMemHeap)->pMMUHeap; +} + +struct PVRSRV_DEVICE_NODE *BM_GetDeviceNode(void *hDevMemContext) +{ + PVR_DPF(PVR_DBG_VERBOSE, "BM_GetDeviceNode"); + + return ((struct BM_CONTEXT *)hDevMemContext)->psDeviceNode; +} + +void *BM_GetMappingHandle(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ + PVR_DPF(PVR_DBG_VERBOSE, "BM_GetMappingHandle"); + + return ((struct BM_BUF *) + psMemInfo->sMemBlk.hBuffer)->pMapping->hOSMemHandle; +} + +struct BM_CONTEXT *bm_find_context(struct BM_CONTEXT *head_context, + u32 page_dir) +{ + struct BM_CONTEXT *context = head_context; + + /* Walk all the contexts until we find the right one */ + while (context) { + if (mmu_get_page_dir(context->psMMUContext) == page_dir) + break; + context = context->psNext; + } + return context; +} diff --git a/drivers/gpu/pvr/buffer_manager.h b/drivers/gpu/pvr/buffer_manager.h new file mode 100644 index 00000000000..39472b1ed3e --- /dev/null +++ b/drivers/gpu/pvr/buffer_manager.h @@ -0,0 +1,171 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _BUFFER_MANAGER_H_ +#define _BUFFER_MANAGER_H_ + +#include "img_types.h" +#include "ra.h" +#include "perproc.h" + + +struct BM_HEAP; + +struct BM_MAPPING { + enum { + hm_wrapped = 1, + hm_wrapped_scatter, + hm_wrapped_virtaddr, + hm_wrapped_scatter_virtaddr, + hm_env, + hm_contiguous + } eCpuMemoryOrigin; + + struct BM_HEAP *pBMHeap; + struct RA_ARENA *pArena; + + void *CpuVAddr; + struct IMG_CPU_PHYADDR CpuPAddr; + struct IMG_DEV_VIRTADDR DevVAddr; + struct IMG_SYS_PHYADDR *psSysAddr; + size_t uSize; + void *hOSMemHandle; + u32 ui32Flags; +}; + +struct BM_BUF { + void **CpuVAddr; + void *hOSMemHandle; + struct IMG_CPU_PHYADDR CpuPAddr; + struct IMG_DEV_VIRTADDR DevVAddr; + + struct BM_MAPPING *pMapping; + u32 ui32RefCount; +}; + +struct BM_HEAP { + u32 ui32Attribs; + struct BM_CONTEXT *pBMContext; + struct RA_ARENA *pImportArena; + struct RA_ARENA *pLocalDevMemArena; + struct RA_ARENA *pVMArena; + struct DEV_ARENA_DESCRIPTOR sDevArena; + struct MMU_HEAP *pMMUHeap; + + struct BM_HEAP *psNext; +}; + +struct BM_CONTEXT { + struct MMU_CONTEXT *psMMUContext; + struct BM_HEAP *psBMHeap; + struct BM_HEAP *psBMSharedHeap; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct HASH_TABLE *pBufferHash; + void *hResItem; + u32 ui32RefCount; + struct BM_CONTEXT *psNext; +}; + +#define BP_POOL_MASK 0x7 + +#define BP_CONTIGUOUS (1 << 3) +#define BP_PARAMBUFFER (1 << 4) + +#define BM_MAX_DEVMEM_ARENAS 2 + +void *BM_CreateContext(struct PVRSRV_DEVICE_NODE *psDeviceNode, + struct IMG_DEV_PHYADDR *psPDDevPAddr, + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + IMG_BOOL *pbCreated); + +void BM_DestroyContext(void *hBMContext); + +static inline void pvr_get_ctx(struct BM_CONTEXT *ctx) +{ + WARN_ON(!ctx->ui32RefCount); + ctx->ui32RefCount++; +} + +static inline bool pvr_put_ctx(struct BM_CONTEXT *ctx) +{ + BUG_ON(!ctx->ui32RefCount); + ctx->ui32RefCount--; + if (!ctx->ui32RefCount) { + BM_DestroyContext(ctx); + + return true; + } + + return false; +} + +void *BM_CreateHeap(void *hBMContext, + struct DEVICE_MEMORY_HEAP_INFO *psDevMemHeapInfo); +void BM_DestroyHeap(void *hDevMemHeap); +IMG_BOOL BM_Reinitialise(struct PVRSRV_DEVICE_NODE *psDeviceNode); + +IMG_BOOL BM_Alloc(void *hDevMemHeap, + struct IMG_DEV_VIRTADDR *psDevVAddr, + size_t uSize, u32 *pui32Flags, u32 uDevVAddrAlignment, void **phBuf); + +IMG_BOOL BM_Wrap(void *hDevMemHeap, + u32 ui32Size, + u32 ui32Offset, + IMG_BOOL bPhysContig, + struct IMG_SYS_PHYADDR *psSysAddr, + void *pvCPUVAddr, u32 *pui32Flags, void **phBuf); + +void BM_Free(void *hBuf, u32 ui32Flags); +void *BM_HandleToCpuVaddr(void *hBuf); +struct IMG_DEV_VIRTADDR BM_HandleToDevVaddr(void *hBuf); + +struct IMG_SYS_PHYADDR BM_HandleToSysPaddr(void *hBuf); + +void *BM_HandleToOSMemHandle(void *hBuf); + +IMG_BOOL BM_ContiguousStatistics(u32 uFlags, u32 *pTotalBytes, + u32 *pAvailableBytes); + +enum PVRSRV_ERROR BM_GetPhysPageAddr(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, + struct IMG_DEV_VIRTADDR sDevVPageAddr, + struct IMG_DEV_PHYADDR *psDevPAddr); + +enum PVRSRV_ERROR BM_GetHeapInfo(void *hDevMemHeap, + struct PVRSRV_HEAP_INFO *psHeapInfo); + +struct MMU_CONTEXT *BM_GetMMUContext(void *hDevMemHeap); + +struct MMU_CONTEXT *BM_GetMMUContextFromMemContext(void *hDevMemContext); + +void *BM_GetMMUHeap(void *hDevMemHeap); + +struct PVRSRV_DEVICE_NODE *BM_GetDeviceNode(void *hDevMemContext); + +void *BM_GetMappingHandle(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo); + +struct BM_CONTEXT *bm_find_context(struct BM_CONTEXT *head_context, + u32 page_dir); +#endif diff --git a/drivers/gpu/pvr/bufferclass_example.c b/drivers/gpu/pvr/bufferclass_example.c new file mode 100644 index 00000000000..4f7a8eaccd1 --- /dev/null +++ b/drivers/gpu/pvr/bufferclass_example.c @@ -0,0 +1,266 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "bufferclass_example.h" + +static void *gpvAnchor; +static IMG_BOOL(*pfnGetPVRJTable)(struct PVRSRV_BC_BUFFER2SRV_KMJTABLE *); + +struct BC_EXAMPLE_DEVINFO *GetAnchorPtr(void) +{ + return (struct BC_EXAMPLE_DEVINFO *)gpvAnchor; +} + +static void SetAnchorPtr(struct BC_EXAMPLE_DEVINFO *psDevInfo) +{ + gpvAnchor = (void *) psDevInfo; +} + +static enum PVRSRV_ERROR OpenBCDevice(void **phDevice) +{ + struct BC_EXAMPLE_DEVINFO *psDevInfo; + + psDevInfo = GetAnchorPtr(); + + *phDevice = (void *) psDevInfo; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR CloseBCDevice(void *hDevice) +{ + PVR_UNREFERENCED_PARAMETER(hDevice); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR GetBCBuffer(void *hDevice, + u32 ui32BufferNumber, + struct PVRSRV_SYNC_DATA *psSyncData, + void **phBuffer) +{ + struct BC_EXAMPLE_DEVINFO *psDevInfo; + + if (!hDevice || !phBuffer) + return PVRSRV_ERROR_INVALID_PARAMS; + + psDevInfo = (struct BC_EXAMPLE_DEVINFO *)hDevice; + + if (ui32BufferNumber < psDevInfo->sBufferInfo.ui32BufferCount) { + psDevInfo->psSystemBuffer[ui32BufferNumber].psSyncData = + psSyncData; + *phBuffer = + (void *) &psDevInfo->psSystemBuffer[ui32BufferNumber]; + } else { + return PVRSRV_ERROR_INVALID_PARAMS; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR GetBCInfo(void *hDevice, struct BUFFER_INFO *psBCInfo) +{ + struct BC_EXAMPLE_DEVINFO *psDevInfo; + + if (!hDevice || !psBCInfo) + return PVRSRV_ERROR_INVALID_PARAMS; + + psDevInfo = (struct BC_EXAMPLE_DEVINFO *)hDevice; + + *psBCInfo = psDevInfo->sBufferInfo; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR GetBCBufferAddr(void *hDevice, void *hBuffer, + struct IMG_SYS_PHYADDR **ppsSysAddr, + u32 *pui32ByteSize, void __iomem **ppvCpuVAddr, + void **phOSMapInfo, IMG_BOOL *pbIsContiguous) +{ + struct BC_EXAMPLE_BUFFER *psBuffer; + + if (!hDevice || !hBuffer || !ppsSysAddr || !pui32ByteSize) + return PVRSRV_ERROR_INVALID_PARAMS; + + psBuffer = (struct BC_EXAMPLE_BUFFER *)hBuffer; + + *ppsSysAddr = &psBuffer->sPageAlignSysAddr; + *ppvCpuVAddr = psBuffer->sCPUVAddr; + + *pui32ByteSize = psBuffer->ui32Size; + + *phOSMapInfo = NULL; + *pbIsContiguous = IMG_TRUE; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR BC_Example_Init(void) +{ + struct BC_EXAMPLE_DEVINFO *psDevInfo; + struct IMG_CPU_PHYADDR sSystemBufferCPUPAddr; + u32 i; + + psDevInfo = GetAnchorPtr(); + + if (psDevInfo == NULL) { + + psDevInfo = (struct BC_EXAMPLE_DEVINFO *) + BCAllocKernelMem(sizeof(struct BC_EXAMPLE_DEVINFO)); + + if (!psDevInfo) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + SetAnchorPtr((void *) psDevInfo); + + psDevInfo->ui32RefCount = 0; + + if (BCOpenPVRServices(&psDevInfo->hPVRServices) != PVRSRV_OK) + return PVRSRV_ERROR_INIT_FAILURE; + if (BCGetLibFuncAddr + (psDevInfo->hPVRServices, "PVRGetBufferClassJTable", + &pfnGetPVRJTable) != PVRSRV_OK) + return PVRSRV_ERROR_INIT_FAILURE; + + if (!(*pfnGetPVRJTable) (&psDevInfo->sPVRJTable)) + return PVRSRV_ERROR_INIT_FAILURE; + + psDevInfo->ui32NumBuffers = 0; + + psDevInfo->psSystemBuffer = + BCAllocKernelMem(sizeof(struct BC_EXAMPLE_BUFFER) * + BC_EXAMPLE_NUM_BUFFERS); + + if (!psDevInfo->psSystemBuffer) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + psDevInfo->sBufferInfo.pixelformat = BC_EXAMPLE_PIXELFORMAT; + psDevInfo->sBufferInfo.ui32Width = BC_EXAMPLE_WIDTH; + psDevInfo->sBufferInfo.ui32Height = BC_EXAMPLE_HEIGHT; + psDevInfo->sBufferInfo.ui32ByteStride = BC_EXAMPLE_STRIDE; + psDevInfo->sBufferInfo.ui32BufferDeviceID = BC_EXAMPLE_DEVICEID; + psDevInfo->sBufferInfo.ui32Flags = + PVRSRV_BC_FLAGS_YUVCSC_FULL_RANGE | + PVRSRV_BC_FLAGS_YUVCSC_BT601; + + for (i = 0; i < BC_EXAMPLE_NUM_BUFFERS; i++) { + u32 ui32Size = + BC_EXAMPLE_HEIGHT * BC_EXAMPLE_STRIDE; + + if (psDevInfo->sBufferInfo.pixelformat == + PVRSRV_PIXEL_FORMAT_NV12) + + ui32Size += + ((BC_EXAMPLE_STRIDE >> 1) * + (BC_EXAMPLE_HEIGHT >> 1) << 1); + + if (BCAllocContigMemory(ui32Size, + &psDevInfo->psSystemBuffer[i]. + hMemHandle, + &psDevInfo->psSystemBuffer[i]. + sCPUVAddr, + &sSystemBufferCPUPAddr) != + PVRSRV_OK) + break; + + psDevInfo->ui32NumBuffers++; + + psDevInfo->psSystemBuffer[i].ui32Size = ui32Size; + psDevInfo->psSystemBuffer[i].sSysAddr = + CpuPAddrToSysPAddrBC(sSystemBufferCPUPAddr); + psDevInfo->psSystemBuffer[i].sPageAlignSysAddr.uiAddr = + (psDevInfo->psSystemBuffer[i].sSysAddr. + uiAddr & 0xFFFFF000); + psDevInfo->psSystemBuffer[i].psSyncData = NULL; + } + + psDevInfo->sBufferInfo.ui32BufferCount = + psDevInfo->ui32NumBuffers; + + psDevInfo->sBCJTable.ui32TableSize = + sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE); + psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice; + psDevInfo->sBCJTable.pfnCloseBCDevice = CloseBCDevice; + psDevInfo->sBCJTable.pfnGetBCBuffer = GetBCBuffer; + psDevInfo->sBCJTable.pfnGetBCInfo = GetBCInfo; + psDevInfo->sBCJTable.pfnGetBufferAddr = GetBCBufferAddr; + + if (psDevInfo->sPVRJTable. + pfnPVRSRVRegisterBCDevice(&psDevInfo->sBCJTable, + &psDevInfo->ui32DeviceID) != + PVRSRV_OK) + return PVRSRV_ERROR_DEVICE_REGISTER_FAILED; + } + + psDevInfo->ui32RefCount++; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR BC_Example_Deinit(void) +{ + struct BC_EXAMPLE_DEVINFO *psDevInfo; + u32 i; + psDevInfo = GetAnchorPtr(); + + if (psDevInfo == NULL) + return PVRSRV_ERROR_GENERIC; + + psDevInfo->ui32RefCount--; + + if (psDevInfo->ui32RefCount == 0) { + + struct PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable = + &psDevInfo->sPVRJTable; + + if (psJTable-> + pfnPVRSRVRemoveBCDevice(psDevInfo->ui32DeviceID) != + PVRSRV_OK) + return PVRSRV_ERROR_GENERIC; + + if (BCClosePVRServices(psDevInfo->hPVRServices) != PVRSRV_OK) { + psDevInfo->hPVRServices = NULL; + return PVRSRV_ERROR_GENERIC; + } + + for (i = 0; i < psDevInfo->ui32NumBuffers; i++) + BCFreeContigMemory(psDevInfo->psSystemBuffer[i]. + ui32Size, + psDevInfo->psSystemBuffer[i]. + hMemHandle, + psDevInfo->psSystemBuffer[i]. + sCPUVAddr, + SysPAddrToCpuPAddrBC(psDevInfo-> + psSystemBuffer + [i].sSysAddr)); + + BCFreeKernelMem(psDevInfo); + + SetAnchorPtr(NULL); + } + + return PVRSRV_OK; +} diff --git a/drivers/gpu/pvr/bufferclass_example.h b/drivers/gpu/pvr/bufferclass_example.h new file mode 100644 index 00000000000..c9dd0946b1d --- /dev/null +++ b/drivers/gpu/pvr/bufferclass_example.h @@ -0,0 +1,104 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __BC_EXAMPLE_H__ +#define __BC_EXAMPLE_H__ + +#include "img_defs.h" +#include "servicesext.h" +#include "kernelbuffer.h" + +extern IMG_BOOL PVRGetBufferClassJTable( + struct PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable); + +#define BC_EXAMPLE_NUM_BUFFERS 3 + +#define YUV420 1 +#ifdef YUV420 + +#define BC_EXAMPLE_WIDTH 320 +#define BC_EXAMPLE_HEIGHT 160 +#define BC_EXAMPLE_STRIDE 320 +#define BC_EXAMPLE_PIXELFORMAT PVRSRV_PIXEL_FORMAT_NV12 + +#else + +#define BC_EXAMPLE_WIDTH 320 +#define BC_EXAMPLE_HEIGHT 160 +#define BC_EXAMPLE_STRIDE (320 * 2) +#define BC_EXAMPLE_PIXELFORMAT PVRSRV_PIXEL_FORMAT_RGB565 + +#endif + +#define BC_EXAMPLE_DEVICEID 0 + +struct BC_EXAMPLE_BUFFER { + u32 ui32Size; + void *hMemHandle; + struct IMG_SYS_PHYADDR sSysAddr; + struct IMG_SYS_PHYADDR sPageAlignSysAddr; + void __iomem *sCPUVAddr; + struct PVRSRV_SYNC_DATA *psSyncData; + struct BC_EXAMPLE_BUFFER *psNext; +}; + +struct BC_EXAMPLE_DEVINFO { + u32 ui32DeviceID; + struct BC_EXAMPLE_BUFFER *psSystemBuffer; + struct BUFFER_INFO sBufferInfo; + u32 ui32NumBuffers; + struct PVRSRV_BC_BUFFER2SRV_KMJTABLE sPVRJTable; + struct PVRSRV_BC_SRV2BUFFER_KMJTABLE sBCJTable; + void *hPVRServices; + u32 ui32RefCount; +}; + +enum PVRSRV_ERROR BC_Example_Init(void); +enum PVRSRV_ERROR BC_Example_Deinit(void); + +enum PVRSRV_ERROR BCOpenPVRServices(void **phPVRServices); +enum PVRSRV_ERROR BCClosePVRServices(void *hPVRServices); + +void *BCAllocKernelMem(u32 ui32Size); +void BCFreeKernelMem(void *pvMem); + +enum PVRSRV_ERROR BCAllocContigMemory(u32 ui32Size, void **phMemHandle, + void __iomem **pLinAddr, + struct IMG_CPU_PHYADDR *pPhysAddr); +void BCFreeContigMemory(u32 ui32Size, void *hMemHandle, void __iomem *LinAddr, + struct IMG_CPU_PHYADDR PhysAddr); + +struct IMG_SYS_PHYADDR CpuPAddrToSysPAddrBC(struct IMG_CPU_PHYADDR cpu_paddr); +struct IMG_CPU_PHYADDR SysPAddrToCpuPAddrBC(struct IMG_SYS_PHYADDR sys_paddr); + +void *MapPhysAddr(struct IMG_SYS_PHYADDR sSysAddr, u32 ui32Size); +void UnMapPhysAddr(void *pvAddr, u32 ui32Size); + +enum PVRSRV_ERROR BCGetLibFuncAddr(void *hExtDrv, char *szFunctionName, + IMG_BOOL (**ppfnFuncTable)(struct PVRSRV_BC_BUFFER2SRV_KMJTABLE *)); +struct BC_EXAMPLE_DEVINFO *GetAnchorPtr(void); + +#endif diff --git a/drivers/gpu/pvr/bufferclass_example_linux.c b/drivers/gpu/pvr/bufferclass_example_linux.c new file mode 100644 index 00000000000..924a27ead18 --- /dev/null +++ b/drivers/gpu/pvr/bufferclass_example_linux.c @@ -0,0 +1,202 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/io.h> + +#include <linux/dma-mapping.h> + +#include "kernelbuffer.h" +#include "bufferclass_example.h" +#include "bufferclass_example_linux.h" +#include "bufferclass_example_private.h" +#include "pvrmodule.h" + +#define DEVNAME "bc_example" +#define DRVNAME DEVNAME + +MODULE_SUPPORTED_DEVICE(DEVNAME); + +static int AssignedMajorNumber; + +#define unref__ __attribute__ ((unused)) + + + +void *BCAllocKernelMem(u32 ui32Size) +{ + return kmalloc(ui32Size, GFP_KERNEL); +} + +void BCFreeKernelMem(void *pvMem) +{ + kfree(pvMem); +} + +enum PVRSRV_ERROR BCAllocContigMemory(u32 ui32Size, void *unref__ * phMemHandle, + void __iomem **pLinAddr, + struct IMG_CPU_PHYADDR *pPhysAddr) +{ + dma_addr_t dma; + void *pvLinAddr; + + pvLinAddr = dma_alloc_coherent(NULL, ui32Size, &dma, GFP_KERNEL); + + if (pvLinAddr == NULL) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + pPhysAddr->uiAddr = dma; + *pLinAddr = (void __force __iomem *)pvLinAddr; + + return PVRSRV_OK; +} + +void BCFreeContigMemory(u32 ui32Size, void *unref__ hMemHandle, + void __iomem *LinAddr, struct IMG_CPU_PHYADDR PhysAddr) +{ + dma_free_coherent(NULL, ui32Size, (void __force *)LinAddr, + (dma_addr_t)PhysAddr.uiAddr); +} + +struct IMG_SYS_PHYADDR CpuPAddrToSysPAddrBC(struct IMG_CPU_PHYADDR cpu_paddr) +{ + struct IMG_SYS_PHYADDR sys_paddr; + + sys_paddr.uiAddr = cpu_paddr.uiAddr; + return sys_paddr; +} + +struct IMG_CPU_PHYADDR SysPAddrToCpuPAddrBC(struct IMG_SYS_PHYADDR sys_paddr) +{ + + struct IMG_CPU_PHYADDR cpu_paddr; + + cpu_paddr.uiAddr = sys_paddr.uiAddr; + return cpu_paddr; +} + +enum PVRSRV_ERROR BCOpenPVRServices(void **phPVRServices) +{ + + *phPVRServices = NULL; + return PVRSRV_OK; +} + +enum PVRSRV_ERROR BCClosePVRServices(void *unref__ hPVRServices) +{ + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR BCGetLibFuncAddr(void *unref__ hExtDrv, char *szFunctionName, + IMG_BOOL (**ppfnFuncTable)(struct PVRSRV_BC_BUFFER2SRV_KMJTABLE *)) +{ + if (strcmp("PVRGetBufferClassJTable", szFunctionName) != 0) + return PVRSRV_ERROR_INVALID_PARAMS; + + *ppfnFuncTable = PVRGetBufferClassJTable; + + return PVRSRV_OK; +} + +static int BC_Example_Bridge(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int err = -EFAULT; + int command = _IOC_NR(cmd); + struct BC_Example_ioctl_package __user *psBridge = + (struct BC_Example_ioctl_package __user *)arg; + + if (!access_ok + (VERIFY_WRITE, psBridge, sizeof(struct BC_Example_ioctl_package))) + return err; + + switch (command) { + case _IOC_NR(BC_Example_ioctl_fill_buffer): + if (FillBuffer(psBridge->inputparam) == -1) + return err; + break; + case _IOC_NR(BC_Example_ioctl_get_buffer_count): + if (GetBufferCount(&psBridge->outputparam) == -1) + return err; + break; + default: + return err; + } + + return 0; +} + +static const struct file_operations bufferclass_example_fops = { + .ioctl = BC_Example_Bridge, +}; + +static int __init BC_Example_ModInit(void) +{ + AssignedMajorNumber = + register_chrdev(0, DEVNAME, &bufferclass_example_fops); + + if (AssignedMajorNumber <= 0) { + printk(KERN_ERR DRVNAME + ": BC_Example_ModInit: unable to get major number\n"); + + goto ExitDisable; + } +#if defined(CONFIG_PVR_DEBUG_EXTRA) + printk(KERN_ERR DRVNAME ": BC_Example_ModInit: major device %d\n", + AssignedMajorNumber); +#endif + + + if (BC_Example_Init() != PVRSRV_OK) { + printk(KERN_ERR DRVNAME + ": BC_Example_ModInit: can't init device\n"); + goto ExitUnregister; + } + + return 0; + +ExitUnregister: + unregister_chrdev(AssignedMajorNumber, DEVNAME); +ExitDisable: + return -EBUSY; +} + +static void __exit BC_Example_ModCleanup(void) +{ + unregister_chrdev(AssignedMajorNumber, DEVNAME); + + if (BC_Example_Deinit() != PVRSRV_OK) + printk(KERN_ERR DRVNAME + ": BC_Example_ModCleanup: can't deinit device\n"); + +} + +module_init(BC_Example_ModInit); +module_exit(BC_Example_ModCleanup); diff --git a/drivers/gpu/pvr/bufferclass_example_linux.h b/drivers/gpu/pvr/bufferclass_example_linux.h new file mode 100644 index 00000000000..8e17fdf7650 --- /dev/null +++ b/drivers/gpu/pvr/bufferclass_example_linux.h @@ -0,0 +1,46 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __BC_EXAMPLE_LINUX_H__ +#define __BC_EXAMPLE_LINUX_H__ + +#include <linux/ioctl.h> + +struct BC_Example_ioctl_package { + int inputparam; + int outputparam; + +}; + +#define BC_EXAMPLE_IOC_GID 'g' + +#define BC_EXAMPLE_IOWR(INDEX) \ + _IOWR(BC_EXAMPLE_IOC_GID, INDEX, struct BC_Example_ioctl_package) + +#define BC_Example_ioctl_fill_buffer BC_EXAMPLE_IOWR(0) +#define BC_Example_ioctl_get_buffer_count BC_EXAMPLE_IOWR(1) + +#endif diff --git a/drivers/gpu/pvr/bufferclass_example_private.c b/drivers/gpu/pvr/bufferclass_example_private.c new file mode 100644 index 00000000000..360524e23fe --- /dev/null +++ b/drivers/gpu/pvr/bufferclass_example_private.c @@ -0,0 +1,194 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "bufferclass_example.h" +#include "bufferclass_example_private.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static void FillYUV420Image(void __iomem *pvDest, int width, int height, + int bytestride) +{ + static int iPhase; + int i, j; + unsigned char u, v, y; + unsigned char *pui8y = (unsigned char __force *)pvDest; + unsigned short *pui16uv; + unsigned int count = 0; + + for (j = 0; j < height; j++) + for (i = 0; i < width; i++) { + y = (((i + iPhase) >> 6) % (2) == 0) ? 0x7f : 0x00; + + pui8y[count++] = y; + } + + pui16uv = (unsigned short *) + ((unsigned char __force *)pvDest + (width * height)); + count = 0; + + for (j = 0; j < height; j += 2) + for (i = 0; i < width; i += 2) { + u = (j < (height / 2)) ? + ((i < (width / 2)) ? 0xFF : 0x33) : + ((i < (width / 2)) ? 0x33 : 0xAA); + v = (j < (height / 2)) ? + ((i < (width / 2)) ? 0xAC : 0x0) : + ((i < (width / 2)) ? 0x03 : 0xEE); + + pui16uv[count++] = (v << 8) | u; + + } + + iPhase++; +} + +static void FillYUV422Image(void __iomem *pvDest, int width, int height, + int bytestride) +{ + static int iPhase; + int x, y; + unsigned char u, v, y0, y1; + unsigned int *pui32yuv = (unsigned int __force *)pvDest; + unsigned int count = 0; + + for (y = 0; y < height; y++) + for (x = 0; x < width; x += 2) { + u = (y < (height / 2)) ? + ((x < (width / 2)) ? 0xFF : 0x33) : + ((x < (width / 2)) ? 0x33 : 0xAA); + v = (y < (height / 2)) ? + ((x < (width / 2)) ? 0xAA : 0x0) : + ((x < (width / 2)) ? 0x03 : 0xEE); + + y0 = y1 = + (((x + iPhase) >> 6) % (2) == 0) ? 0x7f : 0x00; + + pui32yuv[count++] = + (y1 << 24) | (v << 16) | (y0 << 8) | u; + + } + + iPhase++; +} + +static void FillRGB565Image(void __iomem *pvDest, int width, int height, + int bytestride) +{ + int i, Count; + unsigned long *pui32Addr = (unsigned long __force *)pvDest; + unsigned short *pui16Addr = (unsigned short __force *)pvDest; + unsigned long Colour32; + unsigned short Colour16; + static unsigned char Colour8; + + Colour16 = (Colour8 >> 3) | ((Colour8 >> 2) << 5) | + ((Colour8 >> 3) << 11); + Colour32 = Colour16 | Colour16 << 16; + + Count = (height * bytestride) >> 2; + + for (i = 0; i < Count; i++) + pui32Addr[i] = Colour32; + + Count = height; + + pui16Addr = (unsigned short *) + ((unsigned char __force *)pvDest + (2 * Colour8)); + + for (i = 0; i < Count; i++) { + *pui16Addr = 0xF800; + + pui16Addr = + (unsigned short *)((unsigned char *)pui16Addr + bytestride); + } + Count = bytestride >> 2; + + pui32Addr = (unsigned long *)((unsigned char __force *)pvDest + + (bytestride * (MIN(height - 1, 0xFF) - Colour8))); + + for (i = 0; i < Count; i++) + pui32Addr[i] = 0x001F001F; + + Colour8 = (Colour8 + 1) % MIN(height - 1, 0xFF); +} + +int FillBuffer(unsigned int ui32BufferIndex) +{ + struct BC_EXAMPLE_DEVINFO *psDevInfo = GetAnchorPtr(); + struct BC_EXAMPLE_BUFFER *psBuffer; + struct BUFFER_INFO *psBufferInfo; + struct PVRSRV_SYNC_DATA *psSyncData; + + if (psDevInfo == NULL) + return -1; + + psBuffer = &psDevInfo->psSystemBuffer[ui32BufferIndex]; + psBufferInfo = &psDevInfo->sBufferInfo; + + psSyncData = psBuffer->psSyncData; + + if (psSyncData) { + if (psSyncData->ui32ReadOpsPending != + psSyncData->ui32ReadOpsComplete) + return -1; + + psSyncData->ui32WriteOpsPending++; + } + + switch (psBufferInfo->pixelformat) { + case PVRSRV_PIXEL_FORMAT_RGB565: + default: + FillRGB565Image(psBuffer->sCPUVAddr, BC_EXAMPLE_WIDTH, + BC_EXAMPLE_HEIGHT, BC_EXAMPLE_STRIDE); + break; + case PVRSRV_PIXEL_FORMAT_FOURCC_ORG_UYVY: + FillYUV422Image(psBuffer->sCPUVAddr, BC_EXAMPLE_WIDTH, + BC_EXAMPLE_HEIGHT, BC_EXAMPLE_STRIDE); + break; + case PVRSRV_PIXEL_FORMAT_NV12: + FillYUV420Image(psBuffer->sCPUVAddr, BC_EXAMPLE_WIDTH, + BC_EXAMPLE_HEIGHT, BC_EXAMPLE_STRIDE); + break; + } + + if (psSyncData) + psSyncData->ui32WriteOpsComplete++; + + return 0; +} + +int GetBufferCount(unsigned int *pui32BufferCount) +{ + struct BC_EXAMPLE_DEVINFO *psDevInfo = GetAnchorPtr(); + + if (psDevInfo == NULL) + return -1; + + *pui32BufferCount = psDevInfo->sBufferInfo.ui32BufferCount; + + return 0; +} diff --git a/drivers/gpu/pvr/bufferclass_example_private.h b/drivers/gpu/pvr/bufferclass_example_private.h new file mode 100644 index 00000000000..527c782d2ac --- /dev/null +++ b/drivers/gpu/pvr/bufferclass_example_private.h @@ -0,0 +1,33 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __BC_EXAMPLE_PRIVATE_H__ +#define __BC_EXAMPLE_PRIVATE_H__ + +int FillBuffer(unsigned int ui32BufferIndex); +int GetBufferCount(unsigned int *pui32BufferCount); + +#endif diff --git a/drivers/gpu/pvr/dbgdrvif.h b/drivers/gpu/pvr/dbgdrvif.h new file mode 100644 index 00000000000..d8ace97e331 --- /dev/null +++ b/drivers/gpu/pvr/dbgdrvif.h @@ -0,0 +1,318 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _DBGDRVIF_ +#define _DBGDRVIF_ + +#include "ioctldef.h" + +#define DEBUG_CAPMODE_FRAMED 0x00000001 +#define DEBUG_CAPMODE_CONTINUOUS 0x00000002 +#define DEBUG_CAPMODE_HOTKEY 0x00000004 + +#define DEBUG_OUTMODE_STANDARDDBG 0x00000001 +#define DEBUG_OUTMODE_MONO 0x00000002 +#define DEBUG_OUTMODE_STREAMENABLE 0x00000004 +#define DEBUG_OUTMODE_ASYNC 0x00000008 +#define DEBUG_OUTMODE_SGXVGA 0x00000010 + +#define DEBUG_FLAGS_USE_NONPAGED_MEM 0x00000001 +#define DEBUG_FLAGS_NO_BUF_EXPANDSION 0x00000002 +#define DEBUG_FLAGS_ENABLESAMPLE 0x00000004 + +#define DEBUG_FLAGS_TEXTSTREAM 0x80000000 + +#define DEBUG_LEVEL_0 0x00000001 +#define DEBUG_LEVEL_1 0x00000003 +#define DEBUG_LEVEL_2 0x00000007 +#define DEBUG_LEVEL_3 0x0000000F +#define DEBUG_LEVEL_4 0x0000001F +#define DEBUG_LEVEL_5 0x0000003F +#define DEBUG_LEVEL_6 0x0000007F +#define DEBUG_LEVEL_7 0x000000FF +#define DEBUG_LEVEL_8 0x000001FF +#define DEBUG_LEVEL_9 0x000003FF +#define DEBUG_LEVEL_10 0x000007FF +#define DEBUG_LEVEL_11 0x00000FFF + +#define DEBUG_LEVEL_SEL0 0x00000001 +#define DEBUG_LEVEL_SEL1 0x00000002 +#define DEBUG_LEVEL_SEL2 0x00000004 +#define DEBUG_LEVEL_SEL3 0x00000008 +#define DEBUG_LEVEL_SEL4 0x00000010 +#define DEBUG_LEVEL_SEL5 0x00000020 +#define DEBUG_LEVEL_SEL6 0x00000040 +#define DEBUG_LEVEL_SEL7 0x00000080 +#define DEBUG_LEVEL_SEL8 0x00000100 +#define DEBUG_LEVEL_SEL9 0x00000200 +#define DEBUG_LEVEL_SEL10 0x00000400 +#define DEBUG_LEVEL_SEL11 0x00000800 + +#define DEBUG_SERVICE_IOCTL_BASE 0x800 +#define DEBUG_SERVICE_CREATESTREAM \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x01, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_DESTROYSTREAM \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x02, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_GETSTREAM \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x03, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_WRITESTRING \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x04, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_READSTRING \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x05, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_WRITE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x06, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_READ \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x07, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_SETDEBUGMODE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x08, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_SETDEBUGOUTMODE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x09, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_SETDEBUGLEVEL \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x0A, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_SETFRAME \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x0B, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_GETFRAME \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x0C, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_OVERRIDEMODE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x0D, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_DEFAULTMODE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x0E, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_GETSERVICETABLE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x0F, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_WRITE2 \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x10, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_WRITESTRINGCM \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x11, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_WRITECM \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x12, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_SETMARKER \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x13, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_GETMARKER \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x14, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_ISCAPTUREFRAME \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x15, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_WRITELF \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x16, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_READLF \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x17, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define DEBUG_SERVICE_WAITFOREVENT \ + CTL_CODE(FILE_DEVICE_UNKNOWN, DEBUG_SERVICE_IOCTL_BASE + 0x18, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) + +enum DBG_EVENT { + DBG_EVENT_STREAM_DATA = 1 +}; + +struct DBG_IN_CREATESTREAM { + u32 ui32Pages; + u32 ui32CapMode; + u32 ui32OutMode; + char *pszName; +}; + +struct DBG_IN_FINDSTREAM { + IMG_BOOL bResetStream; + char *pszName; +}; + +struct DBG_IN_WRITESTRING { + void *pvStream; + u32 ui32Level; + char *pszString; +}; + +struct DBG_IN_READSTRING { + void *pvStream; + u32 ui32StringLen; + char *pszString; +}; + +struct DBG_IN_SETDEBUGMODE { + void *pvStream; + u32 ui32Mode; + u32 ui32Start; + u32 ui32End; + u32 ui32SampleRate; +}; + +struct DBG_IN_SETDEBUGOUTMODE { + void *pvStream; + u32 ui32Mode; +}; + +struct DBG_IN_SETDEBUGLEVEL { + void *pvStream; + u32 ui32Level; +}; + +struct DBG_IN_SETFRAME { + void *pvStream; + u32 ui32Frame; +}; + +struct DBG_IN_WRITE { + void *pvStream; + u32 ui32Level; + u32 ui32TransferSize; + u8 *pui8InBuffer; +}; + +struct DBG_IN_READ { + void *pvStream; + IMG_BOOL bReadInitBuffer; + u32 ui32OutBufferSize; + u8 *pui8OutBuffer; +}; + +struct DBG_IN_OVERRIDEMODE { + void *pvStream; + u32 ui32Mode; +}; + +struct DBG_IN_ISCAPTUREFRAME { + void *pvStream; + IMG_BOOL bCheckPreviousFrame; +}; + +struct DBG_IN_SETMARKER { + void *pvStream; + u32 ui32Marker; +}; + +struct DBG_IN_WRITE_LF { + u32 ui32Flags; + void *pvStream; + u32 ui32Level; + u32 ui32BufferSize; + u8 *pui8InBuffer; +}; + +#define WRITELF_FLAGS_RESETBUF 0x00000001 + +struct DBG_STREAM { + struct DBG_STREAM *psNext; + struct DBG_STREAM *psInitStream; + IMG_BOOL bInitPhaseComplete; + u32 ui32Flags; + u32 ui32Base; + u32 ui32Size; + u32 ui32RPtr; + u32 ui32WPtr; + u32 ui32DataWritten; + u32 ui32CapMode; + u32 ui32OutMode; + u32 ui32DebugLevel; + u32 ui32DefaultMode; + u32 ui32Start; + u32 ui32End; + u32 ui32Current; + u32 ui32Access; + u32 ui32SampleRate; + u32 ui32Reserved; + u32 ui32Timeout; + u32 ui32Marker; + char szName[30]; +}; + +struct DBGKM_SERVICE_TABLE { + u32 ui32Size; + void *(*pfnCreateStream)(char *pszName, u32 ui32CapMode, + u32 ui32OutMode, u32 ui32Flags, u32 ui32Pages); + void (*pfnDestroyStream)(struct DBG_STREAM *psStream); + void *(*pfnFindStream)(char *pszName, IMG_BOOL bResetInitBuffer); + u32 (*pfnWriteString)(struct DBG_STREAM *psStream, char *pszString, + u32 ui32Level); + u32 (*pfnReadString)(struct DBG_STREAM *psStream, char *pszString, + u32 ui32Limit); + u32 (*pfnWriteBIN)(struct DBG_STREAM *psStream, u8 *pui8InBuf, + u32 ui32InBuffSize, u32 ui32Level); + u32 (*pfnReadBIN)(struct DBG_STREAM *psStream, + IMG_BOOL bReadInitBuffer, u32 ui32OutBufferSize, + u8 *pui8OutBuf); + void (*pfnSetCaptureMode)(struct DBG_STREAM *psStream, + u32 ui32CapMode, u32 ui32Start, u32 ui32Stop, + u32 ui32SampleRate); + void (*pfnSetOutputMode)(struct DBG_STREAM *psStream, + u32 ui32OutMode); + void (*pfnSetDebugLevel)(struct DBG_STREAM *psStream, + u32 ui32DebugLevel); + void (*pfnSetFrame)(struct DBG_STREAM *psStream, + u32 ui32Frame); + u32 (*pfnGetFrame)(struct DBG_STREAM *psStream); + void (*pfnOverrideMode)(struct DBG_STREAM *psStream, + u32 ui32Mode); + void (*pfnDefaultMode)(struct DBG_STREAM *psStream); + u32 (*pfnDBGDrivWrite2)(struct DBG_STREAM *psStream, + u8 *pui8InBuf, u32 ui32InBuffSize, u32 ui32Level); + u32 (*pfnWriteStringCM)(struct DBG_STREAM *psStream, char *pszString, + u32 ui32Level); + u32 (*pfnWriteBINCM)(struct DBG_STREAM *psStream, u8 *pui8InBuf, + u32 ui32InBuffSize, u32 ui32Level); + void (*pfnSetMarker)(struct DBG_STREAM *psStream, u32 ui32Marker); + u32 (*pfnGetMarker)(struct DBG_STREAM *psStream); + void (*pfnStartInitPhase) (struct DBG_STREAM *psStream); + void (*pfnStopInitPhase) (struct DBG_STREAM *psStream); + u32 (*pfnIsCaptureFrame)(struct DBG_STREAM *psStream, + IMG_BOOL bCheckPreviousFrame); + u32 (*pfnWriteLF)(struct DBG_STREAM *psStream, u8 *pui8InBuf, + u32 ui32InBuffSize, u32 ui32Level, u32 ui32Flags); + u32 (*pfnReadLF)(struct DBG_STREAM *psStream, u32 ui32OutBuffSize, + u8 *pui8OutBuf); + u32 (*pfnGetStreamOffset)(struct DBG_STREAM *psStream); + void (*pfnSetStreamOffset)(struct DBG_STREAM *psStream, + u32 ui32StreamOffset); + u32 (*pfnIsLastCaptureFrame)(struct DBG_STREAM *psStream); + void (*pfnWaitForEvent) (enum DBG_EVENT eEvent); +}; + +extern struct DBGKM_SERVICE_TABLE g_sDBGKMServices; + +void DBGDrvGetServiceTable(void **fn_table); + +#endif diff --git a/drivers/gpu/pvr/device.h b/drivers/gpu/pvr/device.h new file mode 100644 index 00000000000..43a37e00d07 --- /dev/null +++ b/drivers/gpu/pvr/device.h @@ -0,0 +1,187 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + +#include "ra.h" +#include "resman.h" + +struct BM_CONTEXT; + +struct MMU_HEAP; +struct MMU_CONTEXT; + +#define PVRSRV_BACKINGSTORE_SYSMEM_CONTIG \ + (1<<(PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT+0)) +#define PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG \ + (1<<(PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT+1)) +#define PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG \ + (1<<(PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT+2)) +#define PVRSRV_BACKINGSTORE_LOCALMEM_NONCONTIG \ + (1<<(PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT+3)) + +#define DEVICE_MEMORY_HEAP_PERCONTEXT 0 +#define DEVICE_MEMORY_HEAP_KERNEL 1 +#define DEVICE_MEMORY_HEAP_SHARED 2 +#define DEVICE_MEMORY_HEAP_SHARED_EXPORTED 3 + +#define PVRSRV_DEVICE_NODE_FLAGS_PORT80DISPLAY 1 +#define PVRSRV_DEVICE_NODE_FLAGS_MMU_OPT_INV 2 + +struct DEVICE_MEMORY_HEAP_INFO { + u32 ui32HeapID; + char *pszName; + char *pszBSName; + struct IMG_DEV_VIRTADDR sDevVAddrBase; + u32 ui32HeapSize; + u32 ui32Attribs; + u32 DevMemHeapType; + void *hDevMemHeap; + struct RA_ARENA *psLocalDevMemArena; + + u32 ui32DataPageSize; + +}; + +struct DEVICE_MEMORY_INFO { + u32 ui32AddressSpaceSizeLog2; + u32 ui32Flags; + u32 ui32HeapCount; + u32 ui32SyncHeapID; + u32 ui32MappingHeapID; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + struct BM_CONTEXT *pBMKernelContext; + struct BM_CONTEXT *pBMContext; +}; + +struct DEV_ARENA_DESCRIPTOR { + u32 ui32HeapID; + char *pszName; + struct IMG_DEV_VIRTADDR BaseDevVAddr; + u32 ui32Size; + u32 DevMemHeapType; + + u32 ui32DataPageSize; + + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeapInfo; +}; + +struct SYS_DATA; + +struct PVRSRV_DEVICE_NODE { + struct PVRSRV_DEVICE_IDENTIFIER sDevId; + u32 ui32RefCount; + + enum PVRSRV_ERROR (*pfnInitDevice)(void *); + enum PVRSRV_ERROR (*pfnDeInitDevice)(void *); + + enum PVRSRV_ERROR (*pfnInitDeviceCompatCheck)( + struct PVRSRV_DEVICE_NODE *); + + enum PVRSRV_ERROR (*pfnMMUInitialise)(struct PVRSRV_DEVICE_NODE *, + struct MMU_CONTEXT **, + struct IMG_DEV_PHYADDR *); + void (*pfnMMUFinalise)(struct MMU_CONTEXT *); + void (*pfnMMUInsertHeap)(struct MMU_CONTEXT *, struct MMU_HEAP *); + struct MMU_HEAP *(*pfnMMUCreate)(struct MMU_CONTEXT *, + struct DEV_ARENA_DESCRIPTOR *, struct RA_ARENA **); + void (*pfnMMUDelete)(struct MMU_HEAP *); + IMG_BOOL (*pfnMMUAlloc)(struct MMU_HEAP *pMMU, size_t uSize, u32 uFlags, + u32 uDevVAddrAlignment, + struct IMG_DEV_VIRTADDR *pDevVAddr); + void (*pfnMMUFree)(struct MMU_HEAP *, struct IMG_DEV_VIRTADDR, u32); + void (*pfnMMUEnable)(struct MMU_HEAP *); + void (*pfnMMUDisable)(struct MMU_HEAP *); + void (*pfnMMUMapPages)(struct MMU_HEAP *pMMU, + struct IMG_DEV_VIRTADDR devVAddr, + struct IMG_SYS_PHYADDR SysPAddr, + size_t uSize, u32 ui32MemFlags, void *hUniqueTag); + void (*pfnMMUMapShadow)(struct MMU_HEAP *pMMU, + struct IMG_DEV_VIRTADDR MapBaseDevVAddr, + size_t uSize, void *CpuVAddr, void *hOSMemHandle, + struct IMG_DEV_VIRTADDR *pDevVAddr, u32 ui32MemFlags, + void *hUniqueTag); + void (*pfnMMUUnmapPages)(struct MMU_HEAP *pMMU, + struct IMG_DEV_VIRTADDR dev_vaddr, u32 ui32PageCount, + void *hUniqueTag); + + void (*pfnMMUMapScatter)(struct MMU_HEAP *pMMU, + struct IMG_DEV_VIRTADDR DevVAddr, + struct IMG_SYS_PHYADDR *psSysAddr, + size_t uSize, u32 ui32MemFlags, void *hUniqueTag); + + struct IMG_DEV_PHYADDR(*pfnMMUGetPhysPageAddr)( + struct MMU_HEAP *pMMUHeap, + struct IMG_DEV_VIRTADDR sDevVPageAddr); + struct IMG_DEV_PHYADDR(*pfnMMUGetPDDevPAddr)( + struct MMU_CONTEXT *pMMUContext); + + IMG_BOOL (*pfnDeviceISR)(void *); + + void *pvISRData; + u32 ui32SOCInterruptBit; + + void (*pfnDeviceMISR)(void *); + void (*pfnDeviceCommandComplete)(struct PVRSRV_DEVICE_NODE * + psDeviceNode); + + IMG_BOOL bReProcessDeviceCommandComplete; + struct DEVICE_MEMORY_INFO sDevMemoryInfo; + void *pvDevice; + u32 ui32pvDeviceSize; + + struct RESMAN_CONTEXT *hResManContext; + struct SYS_DATA *psSysData; + struct RA_ARENA *psLocalDevMemArena; + u32 ui32Flags; + struct HASH_TABLE *sync_table; + struct PVRSRV_DEVICE_NODE *psNext; +}; + +enum PVRSRV_ERROR PVRSRVRegisterDevice(struct SYS_DATA *psSysData, + enum PVRSRV_ERROR (*pfnRegisterDevice)(struct PVRSRV_DEVICE_NODE *), + u32 ui32SOCInterruptBit, u32 *pui32DeviceIndex); + +enum PVRSRV_ERROR PVRSRVInitialiseDevice(u32 ui32DevIndex); +enum PVRSRV_ERROR PVRSRVFinaliseSystem(IMG_BOOL bInitSuccesful); + +enum PVRSRV_ERROR PVRSRVDevInitCompatCheck(struct PVRSRV_DEVICE_NODE + *psDeviceNode); + +enum PVRSRV_ERROR PVRSRVDeinitialiseDevice(u32 ui32DevIndex); + + +enum PVRSRV_ERROR PollForValueKM(u32 __iomem *pui32LinMemAddr, + u32 ui32Value, u32 ui32Mask, u32 ui32Waitus, u32 ui32Tries); + +enum PVRSRV_ERROR PVRSRVInit(struct SYS_DATA *psSysData); +void PVRSRVDeInit(struct SYS_DATA *psSysData); +IMG_BOOL PVRSRVDeviceLISR(struct PVRSRV_DEVICE_NODE *psDeviceNode); +IMG_BOOL PVRSRVSystemLISR(void *pvSysData); +void PVRSRVMISR(void *pvSysData); + +#endif diff --git a/drivers/gpu/pvr/deviceclass.c b/drivers/gpu/pvr/deviceclass.c new file mode 100644 index 00000000000..c5374e52382 --- /dev/null +++ b/drivers/gpu/pvr/deviceclass.c @@ -0,0 +1,1522 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ +#include <linux/module.h> + +#include "services_headers.h" +#include "buffer_manager.h" +#include "kernelbuffer.h" +#include "pvr_bridge_km.h" + +struct PVRSRV_DC_SRV2DISP_KMJTABLE; + +struct PVRSRV_DC_BUFFER { + struct PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; +}; + +struct PVRSRV_DC_SWAPCHAIN { + void *hExtSwapChain; + struct PVRSRV_QUEUE_INFO *psQueue; + struct PVRSRV_DC_BUFFER asBuffer[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS]; + u32 ui32BufferCount; + struct PVRSRV_DC_BUFFER *psLastFlipBuffer; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + void *hResItem; +}; + +struct PVRSRV_DISPLAYCLASS_INFO { + u32 ui32RefCount; + u32 ui32DeviceID; + void *hExtDevice; + struct PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable; + void *hDevMemContext; + struct PVRSRV_DC_BUFFER sSystemBuffer; +}; + +struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO { + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct RESMAN_ITEM *hResItem; +}; + +struct PVRSRV_BC_SRV2BUFFER_KMJTABLE; + +struct PVRSRV_BC_BUFFER { + struct PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer; + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; +}; + +struct PVRSRV_BUFFERCLASS_INFO { + u32 ui32RefCount; + u32 ui32DeviceID; + void *hExtDevice; + struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTable; + void *hDevMemContext; + + u32 ui32BufferCount; + struct PVRSRV_BC_BUFFER *psBuffer; + +}; + +struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO { + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + void *hResItem; +}; + +static struct PVRSRV_DISPLAYCLASS_INFO *DCDeviceHandleToDCInfo(void *hDeviceKM) +{ + struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; + + psDCPerContextInfo = (struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *) + hDeviceKM; + + return psDCPerContextInfo->psDCInfo; +} + +static struct PVRSRV_BUFFERCLASS_INFO *BCDeviceHandleToBCInfo(void *hDeviceKM) +{ + struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; + + psBCPerContextInfo = (struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *) + hDeviceKM; + + return psBCPerContextInfo->psBCInfo; +} + +enum PVRSRV_ERROR PVRSRVEnumerateDCKM(enum PVRSRV_DEVICE_CLASS DeviceClass, + u32 *pui32DevCount, u32 *pui32DevID) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + unsigned ui32DevCount = 0; + struct SYS_DATA *psSysData; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumerateDCKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + if ((psDeviceNode->sDevId.eDeviceClass == DeviceClass) && + (psDeviceNode->sDevId.eDeviceType == + PVRSRV_DEVICE_TYPE_EXT)) { + ui32DevCount++; + if (pui32DevID) { + *pui32DevID++ = + psDeviceNode->sDevId.ui32DeviceIndex; + } + } + psDeviceNode = psDeviceNode->psNext; + } + + if (pui32DevCount) { + *pui32DevCount = ui32DevCount; + } else if (pui32DevID == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumerateDCKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR PVRSRVRegisterDCDeviceKM( + struct PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable, + u32 *pui32DeviceID) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo = NULL; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterDCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(*psDCInfo), + (void **) &psDCInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterDCDeviceKM: Failed psDCInfo alloc"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psDCInfo, 0, sizeof(*psDCInfo)); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE), + (void **)&psDCInfo->psFuncTable, + NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterDCDeviceKM: Failed psFuncTable alloc"); + goto ErrorExit; + } + OSMemSet(psDCInfo->psFuncTable, 0, + sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE)); + + *psDCInfo->psFuncTable = *psFuncTable; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), + (void **) &psDeviceNode, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterDCDeviceKM: Failed psDeviceNode alloc"); + goto ErrorExit; + } + OSMemSet(psDeviceNode, 0, sizeof(struct PVRSRV_DEVICE_NODE)); + + psDeviceNode->pvDevice = (void *) psDCInfo; + psDeviceNode->ui32pvDeviceSize = sizeof(*psDCInfo); + psDeviceNode->ui32RefCount = 1; + psDeviceNode->sDevId.eDeviceType = PVRSRV_DEVICE_TYPE_EXT; + psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_DISPLAY; + psDeviceNode->psSysData = psSysData; + + AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex); + psDCInfo->ui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; + if (pui32DeviceID) + *pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; + + SysRegisterExternalDevice(psDeviceNode); + + psDeviceNode->psNext = psSysData->psDeviceNodeList; + psSysData->psDeviceNodeList = psDeviceNode; + + return PVRSRV_OK; + +ErrorExit: + + if (psDCInfo->psFuncTable) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE), + psDCInfo->psFuncTable, NULL); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DISPLAYCLASS_INFO), + psDCInfo, NULL); + + return PVRSRV_ERROR_OUT_OF_MEMORY; +} + +static enum PVRSRV_ERROR PVRSRVRemoveDCDeviceKM(u32 ui32DevIndex) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_DEVICE_NODE **ppsDeviceNode, *psDeviceNode; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveDCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + ppsDeviceNode = &psSysData->psDeviceNodeList; + while (*ppsDeviceNode) { + switch ((*ppsDeviceNode)->sDevId.eDeviceClass) { + case PVRSRV_DEVICE_CLASS_DISPLAY: + { + if ((*ppsDeviceNode)->sDevId.ui32DeviceIndex == + ui32DevIndex) + goto FoundDevice; + break; + } + default: + { + break; + } + } + ppsDeviceNode = &((*ppsDeviceNode)->psNext); + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveDCDeviceKM: requested device %d not present", + ui32DevIndex); + + return PVRSRV_ERROR_GENERIC; + +FoundDevice: + + psDeviceNode = *ppsDeviceNode; + + psDCInfo = (struct PVRSRV_DISPLAYCLASS_INFO *)psDeviceNode->pvDevice; + + if (psDCInfo->ui32RefCount == 0) { + *ppsDeviceNode = psDeviceNode->psNext; + SysRemoveExternalDevice(psDeviceNode); + PVR_ASSERT(psDCInfo->ui32RefCount == 0); + FreeDeviceID(psSysData, ui32DevIndex); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE), + psDCInfo->psFuncTable, NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DISPLAYCLASS_INFO), psDCInfo, + NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), psDeviceNode, + NULL); + } else { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRemoveDCDeviceKM: " + "failed as %d Services DC API " + "connections are still open", + psDCInfo->ui32RefCount); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR PVRSRVRegisterBCDeviceKM( + struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTable, + u32 *pui32DeviceID) +{ + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo = NULL; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterBCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(*psBCInfo), + (void **) &psBCInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterBCDeviceKM: Failed psBCInfo alloc"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psBCInfo, 0, sizeof(*psBCInfo)); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE), + (void **) &psBCInfo->psFuncTable, + NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterBCDeviceKM: Failed psFuncTable alloc"); + goto ErrorExit; + } + OSMemSet(psBCInfo->psFuncTable, 0, + sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE)); + + *psBCInfo->psFuncTable = *psFuncTable; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), + (void **) &psDeviceNode, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterBCDeviceKM: Failed psDeviceNode alloc"); + goto ErrorExit; + } + OSMemSet(psDeviceNode, 0, sizeof(struct PVRSRV_DEVICE_NODE)); + + psDeviceNode->pvDevice = (void *) psBCInfo; + psDeviceNode->ui32pvDeviceSize = sizeof(*psBCInfo); + psDeviceNode->ui32RefCount = 1; + psDeviceNode->sDevId.eDeviceType = PVRSRV_DEVICE_TYPE_EXT; + psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_BUFFER; + psDeviceNode->psSysData = psSysData; + + AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex); + psBCInfo->ui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; + if (pui32DeviceID) + *pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; + + psDeviceNode->psNext = psSysData->psDeviceNodeList; + psSysData->psDeviceNodeList = psDeviceNode; + + return PVRSRV_OK; + +ErrorExit: + + if (psBCInfo->psFuncTable) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *), + psBCInfo->psFuncTable, NULL); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BUFFERCLASS_INFO), psBCInfo, NULL); + + return PVRSRV_ERROR_OUT_OF_MEMORY; +} + +static enum PVRSRV_ERROR PVRSRVRemoveBCDeviceKM(u32 ui32DevIndex) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_DEVICE_NODE **ppsDevNode, *psDevNode; + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveBCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + ppsDevNode = &psSysData->psDeviceNodeList; + while (*ppsDevNode) { + switch ((*ppsDevNode)->sDevId.eDeviceClass) { + case PVRSRV_DEVICE_CLASS_BUFFER: + { + if ((*ppsDevNode)->sDevId.ui32DeviceIndex == + ui32DevIndex) + goto FoundDevice; + break; + } + default: + { + break; + } + } + ppsDevNode = &(*ppsDevNode)->psNext; + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveBCDeviceKM: requested device %d not present", + ui32DevIndex); + + return PVRSRV_ERROR_GENERIC; + +FoundDevice: + + psDevNode = *(ppsDevNode); + + psBCInfo = (struct PVRSRV_BUFFERCLASS_INFO *)psDevNode->pvDevice; + + if (psBCInfo->ui32RefCount == 0) { + *ppsDevNode = psDevNode->psNext; + FreeDeviceID(psSysData, ui32DevIndex); + psBCInfo = + (struct PVRSRV_BUFFERCLASS_INFO *)psDevNode->pvDevice; + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE), + psBCInfo->psFuncTable, NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BUFFERCLASS_INFO), psBCInfo, + NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), psDevNode, NULL); + } else { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRemoveBCDeviceKM: " + "failed as %d Services BC API " + "connections are still open", + psBCInfo->ui32RefCount); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVCloseDCDeviceKM(void *hDeviceKM, + IMG_BOOL bResManCallback) +{ + struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; + + PVR_UNREFERENCED_PARAMETER(bResManCallback); + + psDCPerContextInfo = (struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *) + hDeviceKM; + + ResManFreeResByPtr(psDCPerContextInfo->hResItem); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR CloseDCDeviceCallBack(void *pvParam, u32 ui32Param) +{ + struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + psDCPerContextInfo = (struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *) + pvParam; + psDCInfo = psDCPerContextInfo->psDCInfo; + + psDCInfo->ui32RefCount--; + if (psDCInfo->ui32RefCount == 0) { + struct PVRSRV_DC_SRV2DISP_KMJTABLE *jtbl; + + jtbl = psDCInfo->psFuncTable; + + jtbl->pfnCloseDCDevice(psDCInfo->hExtDevice); + + PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer.sDeviceClassBuffer. + psKernelSyncInfo); + + psDCInfo->hDevMemContext = NULL; + psDCInfo->hExtDevice = NULL; + + module_put(jtbl->owner); + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO), + psDCPerContextInfo, NULL); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVOpenDCDeviceKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + u32 ui32DeviceID, void *hDevCookie, + void **phDeviceKM) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + + if (!phDeviceKM || !hDevCookie) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenDCDeviceKM: Invalid params"); + return PVRSRV_ERROR_GENERIC; + } + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenDCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + if ((psDeviceNode->sDevId.eDeviceClass == + PVRSRV_DEVICE_CLASS_DISPLAY) && + (psDeviceNode->sDevId.ui32DeviceIndex == ui32DeviceID)) { + + psDCInfo = (struct PVRSRV_DISPLAYCLASS_INFO *) + psDeviceNode->pvDevice; + goto FoundDevice; + } + psDeviceNode = psDeviceNode->psNext; + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenDCDeviceKM: no devnode matching index %d", + ui32DeviceID); + + return PVRSRV_ERROR_GENERIC; + +FoundDevice: + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psDCPerContextInfo), + (void **)&psDCPerContextInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenDCDeviceKM: " + "Failed psDCPerContextInfo alloc"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psDCPerContextInfo, 0, sizeof(*psDCPerContextInfo)); + + if (psDCInfo->ui32RefCount++ == 0) { + enum PVRSRV_ERROR eError; + struct PVRSRV_DC_SRV2DISP_KMJTABLE *jtbl; + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie; + + jtbl = psDCInfo->psFuncTable; + if (!try_module_get(jtbl->owner)) { + PVR_DPF(PVR_DBG_ERROR, "%s: can't get DC module"); + return PVRSRV_ERROR_INVALID_DEVICE; + } + + psDCInfo->hDevMemContext = + (void *) psDeviceNode->sDevMemoryInfo.pBMKernelContext; + + eError = PVRSRVAllocSyncInfoKM(NULL, + (void *)psDeviceNode-> + sDevMemoryInfo.pBMKernelContext, + &psDCInfo->sSystemBuffer. + sDeviceClassBuffer. + psKernelSyncInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenDCDeviceKM: Failed sync info alloc"); + psDCInfo->ui32RefCount--; + module_put(jtbl->owner); + return eError; + } + + eError = jtbl->pfnOpenDCDevice(ui32DeviceID, + &psDCInfo->hExtDevice, + (struct PVRSRV_SYNC_DATA *)psDCInfo->sSystemBuffer. + sDeviceClassBuffer.psKernelSyncInfo-> + psSyncDataMemInfoKM->pvLinAddrKM); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenDCDeviceKM: " + "Failed to open external DC device"); + psDCInfo->ui32RefCount--; + module_put(jtbl->owner); + PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer. + sDeviceClassBuffer.psKernelSyncInfo); + return eError; + } + } + + psDCPerContextInfo->psDCInfo = psDCInfo; + psDCPerContextInfo->hResItem = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_DISPLAYCLASS_DEVICE, + psDCPerContextInfo, 0, CloseDCDeviceCallBack); + + *phDeviceKM = (void *) psDCPerContextInfo; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVEnumDCFormatsKM(void *hDeviceKM, + u32 *pui32Count, + struct DISPLAY_FORMAT *psFormat) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + + if (!hDeviceKM || !pui32Count || !psFormat) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumDCFormatsKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + return psDCInfo->psFuncTable->pfnEnumDCFormats(psDCInfo->hExtDevice, + pui32Count, psFormat); +} + +enum PVRSRV_ERROR PVRSRVEnumDCDimsKM(void *hDeviceKM, + struct DISPLAY_FORMAT *psFormat, + u32 *pui32Count, struct DISPLAY_DIMS *psDim) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + + if (!hDeviceKM || !pui32Count || !psFormat) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumDCDimsKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + return psDCInfo->psFuncTable->pfnEnumDCDims(psDCInfo->hExtDevice, + psFormat, pui32Count, psDim); +} + +enum PVRSRV_ERROR PVRSRVGetDCSystemBufferKM(void *hDeviceKM, void **phBuffer) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + void *hExtBuffer; + + if (!hDeviceKM || !phBuffer) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetDCSystemBufferKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + eError = + psDCInfo->psFuncTable->pfnGetDCSystemBuffer(psDCInfo->hExtDevice, + &hExtBuffer); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVGetDCSystemBufferKM: " + "Failed to get valid buffer handle from external driver"); + return eError; + } + + psDCInfo->sSystemBuffer.sDeviceClassBuffer.pfnGetBufferAddr = + psDCInfo->psFuncTable->pfnGetBufferAddr; + psDCInfo->sSystemBuffer.sDeviceClassBuffer.hDevMemContext = + psDCInfo->hDevMemContext; + psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtDevice = + psDCInfo->hExtDevice; + psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer = hExtBuffer; + + psDCInfo->sSystemBuffer.psDCInfo = psDCInfo; + + *phBuffer = (void *) &(psDCInfo->sSystemBuffer); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVGetDCInfoKM(void *hDeviceKM, + struct DISPLAY_INFO *psDisplayInfo) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + enum PVRSRV_ERROR eError; + + if (!hDeviceKM || !psDisplayInfo) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetDCInfoKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + eError = psDCInfo->psFuncTable->pfnGetDCInfo(psDCInfo->hExtDevice, + psDisplayInfo); + if (eError != PVRSRV_OK) + return eError; + + if (psDisplayInfo->ui32MaxSwapChainBuffers > + PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS) { + psDisplayInfo->ui32MaxSwapChainBuffers = + PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVDestroyDCSwapChainKM(void *hSwapChain) +{ + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDestroyDCSwapChainKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psSwapChain = hSwapChain; + + ResManFreeResByPtr(psSwapChain->hResItem); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR DestroyDCSwapChainCallBack(void *pvParam, + u32 ui32Param) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain = pvParam; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo = psSwapChain->psDCInfo; + u32 i; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + PVRSRVDestroyCommandQueueKM(psSwapChain->psQueue); + + eError = + psDCInfo->psFuncTable->pfnDestroyDCSwapChain(psDCInfo->hExtDevice, + psSwapChain-> + hExtSwapChain); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "DestroyDCSwapChainCallBack: " + "Failed to destroy DC swap chain"); + return eError; + } + + for (i = 0; i < psSwapChain->ui32BufferCount; i++) + if (psSwapChain->asBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo) + PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct PVRSRV_DC_SWAPCHAIN), + psSwapChain, NULL); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVCreateDCSwapChainKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDeviceKM, u32 ui32Flags, + struct DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib, + struct DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib, + u32 ui32BufferCount, u32 ui32OEMFlags, + void **phSwapChain, u32 *pui32SwapChainID) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain = NULL; + struct PVRSRV_SYNC_DATA *apsSyncData[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS]; + struct PVRSRV_QUEUE_INFO *psQueue = NULL; + enum PVRSRV_ERROR eError; + u32 i; + + if (!hDeviceKM || !psDstSurfAttrib || !psSrcSurfAttrib || + !phSwapChain || !pui32SwapChainID) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + if (ui32BufferCount > PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Too many buffers"); + return PVRSRV_ERROR_TOOMANYBUFFERS; + } + + if (ui32BufferCount < 2) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Too few buffers"); + return PVRSRV_ERROR_TOO_FEW_BUFFERS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SWAPCHAIN), + (void **) &psSwapChain, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Failed psSwapChain alloc"); + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorExit; + } + OSMemSet(psSwapChain, 0, sizeof(struct PVRSRV_DC_SWAPCHAIN)); + + eError = PVRSRVCreateCommandQueueKM(1024, &psQueue); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Failed to create CmdQueue"); + goto ErrorExit; + } + + psSwapChain->psQueue = psQueue; + + for (i = 0; i < ui32BufferCount; i++) { + eError = PVRSRVAllocSyncInfoKM(NULL, + psDCInfo->hDevMemContext, + &psSwapChain->asBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateDCSwapChainKM: " + "Failed to alloc syninfo for psSwapChain"); + goto ErrorExit; + } + + psSwapChain->asBuffer[i].sDeviceClassBuffer.pfnGetBufferAddr = + psDCInfo->psFuncTable->pfnGetBufferAddr; + psSwapChain->asBuffer[i].sDeviceClassBuffer.hDevMemContext = + psDCInfo->hDevMemContext; + psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtDevice = + psDCInfo->hExtDevice; + + psSwapChain->asBuffer[i].psDCInfo = psDCInfo; + psSwapChain->asBuffer[i].psSwapChain = psSwapChain; + + apsSyncData[i] = + (struct PVRSRV_SYNC_DATA *)psSwapChain->asBuffer[i]. + sDeviceClassBuffer.psKernelSyncInfo-> + psSyncDataMemInfoKM->pvLinAddrKM; + } + + psSwapChain->ui32BufferCount = ui32BufferCount; + psSwapChain->psDCInfo = psDCInfo; + + eError = + psDCInfo->psFuncTable->pfnCreateDCSwapChain(psDCInfo->hExtDevice, + ui32Flags, + psDstSurfAttrib, + psSrcSurfAttrib, + ui32BufferCount, + apsSyncData, + ui32OEMFlags, + &psSwapChain->hExtSwapChain, + pui32SwapChainID); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateDCSwapChainKM: " + "Failed to create 3rd party SwapChain"); + goto ErrorExit; + } + + *phSwapChain = (void *) psSwapChain; + + psSwapChain->hResItem = ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN, + psSwapChain, 0, + DestroyDCSwapChainCallBack); + + return eError; + +ErrorExit: + + for (i = 0; i < ui32BufferCount; i++) { + if (psSwapChain->asBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo) { + PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + } + } + + if (psQueue) + PVRSRVDestroyCommandQueueKM(psQueue); + + if (psSwapChain) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SWAPCHAIN), psSwapChain, + NULL); + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVSetDCDstRectKM(void *hDeviceKM, void *hSwapChain, + struct IMG_RECT *psRect) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCDstRectKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + return psDCInfo->psFuncTable->pfnSetDCDstRect(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, psRect); +} + +enum PVRSRV_ERROR PVRSRVSetDCSrcRectKM(void *hDeviceKM, void *hSwapChain, + struct IMG_RECT *psRect) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCSrcRectKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + return psDCInfo->psFuncTable->pfnSetDCSrcRect(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, psRect); +} + +enum PVRSRV_ERROR PVRSRVSetDCDstColourKeyKM(void *hDeviceKM, void *hSwapChain, + u32 ui32CKColour) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCDstColourKeyKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + return psDCInfo->psFuncTable->pfnSetDCDstColourKey(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, ui32CKColour); +} + +enum PVRSRV_ERROR PVRSRVSetDCSrcColourKeyKM(void *hDeviceKM, void *hSwapChain, + u32 ui32CKColour) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCSrcColourKeyKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + return psDCInfo->psFuncTable->pfnSetDCSrcColourKey(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, ui32CKColour); +} + +enum PVRSRV_ERROR PVRSRVGetDCBuffersKM(void *hDeviceKM, void *hSwapChain, + u32 *pui32BufferCount, void **phBuffer) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + void *ahExtBuffer[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS]; + enum PVRSRV_ERROR eError; + u32 i; + + if (!hDeviceKM || !hSwapChain || !phBuffer) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetDCBuffersKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + eError = psDCInfo->psFuncTable->pfnGetDCBuffers(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, + pui32BufferCount, ahExtBuffer); + + PVR_ASSERT(*pui32BufferCount <= PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS); + + for (i = 0; i < *pui32BufferCount; i++) { + psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtBuffer = + ahExtBuffer[i]; + phBuffer[i] = (void *)&psSwapChain->asBuffer[i]; + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVSwapToDCBufferKM(void *hDeviceKM, void *hBuffer, + u32 ui32SwapInterval, void *hPrivateTag, + u32 ui32ClipRectCount, + struct IMG_RECT *psClipRect) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_BUFFER *psBuffer; + struct PVRSRV_QUEUE_INFO *psQueue; + struct DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; + u32 i; + u32 ui32NumSrcSyncs = 1; + struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[2]; + struct PVRSRV_COMMAND *psCommand; + + if (!hDeviceKM || !hBuffer || !psClipRect) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCBufferKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psBuffer = (struct PVRSRV_DC_BUFFER *)hBuffer; + + psQueue = psBuffer->psSwapChain->psQueue; + + apsSrcSync[0] = psBuffer->sDeviceClassBuffer.psKernelSyncInfo; + if (psBuffer->psSwapChain->psLastFlipBuffer && + psBuffer != psBuffer->psSwapChain->psLastFlipBuffer) { + apsSrcSync[1] = + psBuffer->psSwapChain->psLastFlipBuffer->sDeviceClassBuffer. + psKernelSyncInfo; + ui32NumSrcSyncs++; + } + + eError = PVRSRVInsertCommandKM(psQueue, &psCommand, + psDCInfo->ui32DeviceID, DC_FLIP_COMMAND, + 0, NULL, ui32NumSrcSyncs, apsSrcSync, + sizeof(struct DISPLAYCLASS_FLIP_COMMAND) + + (sizeof(struct IMG_RECT) * + ui32ClipRectCount)); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCBufferKM: Failed to get space in queue"); + goto Exit; + } + + psFlipCmd = (struct DISPLAYCLASS_FLIP_COMMAND *)psCommand->pvData; + psFlipCmd->hExtDevice = psDCInfo->hExtDevice; + psFlipCmd->hExtSwapChain = psBuffer->psSwapChain->hExtSwapChain; + psFlipCmd->hExtBuffer = psBuffer->sDeviceClassBuffer.hExtBuffer; + psFlipCmd->hPrivateTag = hPrivateTag; + psFlipCmd->ui32ClipRectCount = ui32ClipRectCount; + psFlipCmd->psClipRect = + (struct IMG_RECT *)((u8 *) psFlipCmd + + sizeof(struct DISPLAYCLASS_FLIP_COMMAND)); + + for (i = 0; i < ui32ClipRectCount; i++) + psFlipCmd->psClipRect[i] = psClipRect[i]; + + psFlipCmd->ui32SwapInterval = ui32SwapInterval; + + eError = PVRSRVSubmitCommandKM(psQueue, psCommand); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCBufferKM: Failed to submit command"); + goto Exit; + } + + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + if (PVRSRVProcessQueues(IMG_FALSE) != + PVRSRV_ERROR_PROCESSING_BLOCKED) { + goto ProcessedQueues; + } + OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT); + } + END_LOOP_UNTIL_TIMEOUT(); + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCBufferKM: Failed to process queues"); + + eError = PVRSRV_ERROR_GENERIC; + goto Exit; + +ProcessedQueues: + + psBuffer->psSwapChain->psLastFlipBuffer = psBuffer; + +Exit: + return eError; +} + +enum PVRSRV_ERROR PVRSRVSwapToDCSystemKM(void *hDeviceKM, void *hSwapChain) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_QUEUE_INFO *psQueue; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + struct DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; + u32 ui32NumSrcSyncs = 1; + struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[2]; + struct PVRSRV_COMMAND *psCommand; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCSystemKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + psQueue = psSwapChain->psQueue; + + apsSrcSync[0] = + psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo; + if (psSwapChain->psLastFlipBuffer) { + if (apsSrcSync[0] != + psSwapChain->psLastFlipBuffer->sDeviceClassBuffer. + psKernelSyncInfo) { + apsSrcSync[1] = + psSwapChain->psLastFlipBuffer->sDeviceClassBuffer. + psKernelSyncInfo; + ui32NumSrcSyncs++; + } + } + + eError = PVRSRVInsertCommandKM(psQueue, &psCommand, + psDCInfo->ui32DeviceID, DC_FLIP_COMMAND, + 0, NULL, ui32NumSrcSyncs, apsSrcSync, + sizeof(struct DISPLAYCLASS_FLIP_COMMAND)); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCSystemKM: Failed to get space in queue"); + goto Exit; + } + + psFlipCmd = (struct DISPLAYCLASS_FLIP_COMMAND *)psCommand->pvData; + psFlipCmd->hExtDevice = psDCInfo->hExtDevice; + psFlipCmd->hExtSwapChain = psSwapChain->hExtSwapChain; + psFlipCmd->hExtBuffer = + psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer; + psFlipCmd->hPrivateTag = NULL; + psFlipCmd->ui32ClipRectCount = 0; + psFlipCmd->ui32SwapInterval = 1; + + eError = PVRSRVSubmitCommandKM(psQueue, psCommand); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCSystemKM: Failed to submit command"); + goto Exit; + } + + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + if (PVRSRVProcessQueues(IMG_FALSE) != + PVRSRV_ERROR_PROCESSING_BLOCKED) { + goto ProcessedQueues; + } + OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT); + } + END_LOOP_UNTIL_TIMEOUT(); + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCSystemKM: Failed to process queues"); + eError = PVRSRV_ERROR_GENERIC; + goto Exit; + +ProcessedQueues: + + psSwapChain->psLastFlipBuffer = &psDCInfo->sSystemBuffer; + + eError = PVRSRV_OK; + +Exit: + return eError; +} + +static enum PVRSRV_ERROR PVRSRVRegisterSystemISRHandler( + IMG_BOOL (*pfnISRHandler)(void *), + void *pvISRHandlerData, + u32 ui32ISRSourceMask, + u32 ui32DeviceID) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_DEVICE_NODE *psDevNode; + + PVR_UNREFERENCED_PARAMETER(ui32ISRSourceMask); + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterSystemISRHandler: " + "Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + psDevNode = psSysData->psDeviceNodeList; + while (psDevNode) { + if (psDevNode->sDevId.ui32DeviceIndex == ui32DeviceID) + break; + psDevNode = psDevNode->psNext; + } + + if (psDevNode == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterSystemISRHandler: " + "Failed to get psDevNode"); + PVR_DBG_BREAK; + return PVRSRV_ERROR_GENERIC; + } + + psDevNode->pvISRData = (void *) pvISRHandlerData; + + psDevNode->pfnDeviceISR = pfnISRHandler; + + return PVRSRV_OK; +} + +void PVRSRVSetDCState(u32 ui32State) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCState: Failed to get SysData"); + return; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode != NULL) { + if (psDeviceNode->sDevId.eDeviceClass == + PVRSRV_DEVICE_CLASS_DISPLAY) { + psDCInfo = (struct PVRSRV_DISPLAYCLASS_INFO *) + psDeviceNode->pvDevice; + if (psDCInfo->psFuncTable->pfnSetDCState && + psDCInfo->hExtDevice) + psDCInfo->psFuncTable->pfnSetDCState( + psDCInfo->hExtDevice, + ui32State); + } + psDeviceNode = psDeviceNode->psNext; + } +} + +IMG_BOOL PVRGetDisplayClassJTable(struct PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable) +{ + psJTable->ui32TableSize = sizeof(struct PVRSRV_DC_DISP2SRV_KMJTABLE); + psJTable->pfnPVRSRVRegisterDCDevice = PVRSRVRegisterDCDeviceKM; + psJTable->pfnPVRSRVRemoveDCDevice = PVRSRVRemoveDCDeviceKM; + psJTable->pfnPVRSRVOEMFunction = SysOEMFunction; + psJTable->pfnPVRSRVRegisterCmdProcList = PVRSRVRegisterCmdProcListKM; + psJTable->pfnPVRSRVRemoveCmdProcList = PVRSRVRemoveCmdProcListKM; + psJTable->pfnPVRSRVCmdComplete = PVRSRVCommandCompleteKM; + psJTable->pfnPVRSRVRegisterSystemISRHandler = + PVRSRVRegisterSystemISRHandler; + psJTable->pfnPVRSRVRegisterPowerDevice = PVRSRVRegisterPowerDevice; + + return IMG_TRUE; +} +EXPORT_SYMBOL(PVRGetDisplayClassJTable); + +enum PVRSRV_ERROR PVRSRVCloseBCDeviceKM(void *hDeviceKM, + IMG_BOOL bResManCallback) +{ + struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; + + PVR_UNREFERENCED_PARAMETER(bResManCallback); + + psBCPerContextInfo = (struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *) + hDeviceKM; + + ResManFreeResByPtr(psBCPerContextInfo->hResItem); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR CloseBCDeviceCallBack(void *pvParam, u32 ui32Param) +{ + struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + psBCPerContextInfo = (struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *) + pvParam; + psBCInfo = psBCPerContextInfo->psBCInfo; + + psBCInfo->ui32RefCount--; + if (psBCInfo->ui32RefCount == 0) { + u32 i; + + psBCInfo->psFuncTable->pfnCloseBCDevice(psBCInfo->hExtDevice); + + for (i = 0; i < psBCInfo->ui32BufferCount; i++) + if (psBCInfo->psBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo) + PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + + if (psBCInfo->psBuffer) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_BUFFER), + psBCInfo->psBuffer, NULL); + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO), + psBCPerContextInfo, NULL); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVOpenBCDeviceKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + u32 ui32DeviceID, void *hDevCookie, + void **phDeviceKM) +{ + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + u32 i; + enum PVRSRV_ERROR eError; + + if (!phDeviceKM || !hDevCookie) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenBCDeviceKM: Invalid params"); + return PVRSRV_ERROR_GENERIC; + } + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenBCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + if ((psDeviceNode->sDevId.eDeviceClass == + PVRSRV_DEVICE_CLASS_BUFFER) && + (psDeviceNode->sDevId.ui32DeviceIndex == ui32DeviceID)) { + + psBCInfo = (struct PVRSRV_BUFFERCLASS_INFO *) + psDeviceNode->pvDevice; + goto FoundDevice; + } + psDeviceNode = psDeviceNode->psNext; + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenBCDeviceKM: No devnode matching index %d", + ui32DeviceID); + + return PVRSRV_ERROR_GENERIC; + +FoundDevice: + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(*psBCPerContextInfo), + (void **)&psBCPerContextInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed psBCPerContextInfo alloc"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psBCPerContextInfo, 0, sizeof(*psBCPerContextInfo)); + + if (psBCInfo->ui32RefCount++ == 0) { + struct BUFFER_INFO sBufferInfo; + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie; + + psBCInfo->hDevMemContext = + (void *) psDeviceNode->sDevMemoryInfo.pBMKernelContext; + + eError = + psBCInfo->psFuncTable->pfnOpenBCDevice(&psBCInfo-> + hExtDevice); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed to open external BC device"); + return eError; + } + + eError = + psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice, + &sBufferInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenBCDeviceKM : Failed to get BC Info"); + return eError; + } + + psBCInfo->ui32BufferCount = sBufferInfo.ui32BufferCount; + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_BUFFER) * + sBufferInfo.ui32BufferCount, + (void **) &psBCInfo->psBuffer, + NULL); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed to allocate BC buffers"); + return eError; + } + OSMemSet(psBCInfo->psBuffer, 0, + sizeof(struct PVRSRV_BC_BUFFER) * + sBufferInfo.ui32BufferCount); + + for (i = 0; i < psBCInfo->ui32BufferCount; i++) { + + eError = PVRSRVAllocSyncInfoKM(NULL, + psBCInfo->hDevMemContext, + &psBCInfo->psBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed sync info alloc"); + goto ErrorExit; + } + + eError = psBCInfo->psFuncTable->pfnGetBCBuffer( + psBCInfo->hExtDevice, i, + psBCInfo->psBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo-> + psSyncData, + &psBCInfo->psBuffer[i].sDeviceClassBuffer. + hExtBuffer); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed to get BC buffers"); + goto ErrorExit; + } + + psBCInfo->psBuffer[i].sDeviceClassBuffer. + pfnGetBufferAddr = + psBCInfo->psFuncTable->pfnGetBufferAddr; + psBCInfo->psBuffer[i].sDeviceClassBuffer. + hDevMemContext = psBCInfo->hDevMemContext; + psBCInfo->psBuffer[i].sDeviceClassBuffer.hExtDevice = + psBCInfo->hExtDevice; + } + } + + psBCPerContextInfo->psBCInfo = psBCInfo; + psBCPerContextInfo->hResItem = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_BUFFERCLASS_DEVICE, + psBCPerContextInfo, 0, CloseBCDeviceCallBack); + + *phDeviceKM = (void *)psBCPerContextInfo; + + return PVRSRV_OK; + +ErrorExit: + + for (i = 0; i < psBCInfo->ui32BufferCount; i++) { + if (psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { + PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + } + } + + if (psBCInfo->psBuffer) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_BUFFER), psBCInfo->psBuffer, + NULL); + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVGetBCInfoKM(void *hDeviceKM, + struct BUFFER_INFO *psBufferInfo) +{ + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + enum PVRSRV_ERROR eError; + + if (!hDeviceKM || !psBufferInfo) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetBCInfoKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psBCInfo = BCDeviceHandleToBCInfo(hDeviceKM); + + eError = + psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice, + psBufferInfo); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetBCInfoKM : Failed to get BC Info"); + return eError; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVGetBCBufferKM(void *hDeviceKM, u32 ui32BufferIndex, + void **phBuffer) +{ + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + + if (!hDeviceKM || !phBuffer) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetBCBufferKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psBCInfo = BCDeviceHandleToBCInfo(hDeviceKM); + + if (ui32BufferIndex < psBCInfo->ui32BufferCount) { + *phBuffer = (void *)&psBCInfo->psBuffer[ui32BufferIndex]; + } else { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVGetBCBufferKM: " + "Buffer index %d out of range (%d)", + ui32BufferIndex, psBCInfo->ui32BufferCount); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + return PVRSRV_OK; +} + +IMG_BOOL PVRGetBufferClassJTable(struct PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable) +{ + psJTable->ui32TableSize = sizeof(struct PVRSRV_BC_BUFFER2SRV_KMJTABLE); + + psJTable->pfnPVRSRVRegisterBCDevice = PVRSRVRegisterBCDeviceKM; + psJTable->pfnPVRSRVRemoveBCDevice = PVRSRVRemoveBCDeviceKM; + + return IMG_TRUE; +} +EXPORT_SYMBOL(PVRGetBufferClassJTable); + diff --git a/drivers/gpu/pvr/devicemem.c b/drivers/gpu/pvr/devicemem.c new file mode 100644 index 00000000000..3912f2bc117 --- /dev/null +++ b/drivers/gpu/pvr/devicemem.c @@ -0,0 +1,1208 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <stddef.h> + +#include "services_headers.h" +#include "buffer_manager.h" +#include "pdump_km.h" +#include "pvr_bridge_km.h" + +#include <linux/pagemap.h> + +static enum PVRSRV_ERROR AllocDeviceMem(void *hDevCookie, void *hDevMemHeap, + u32 ui32Flags, u32 ui32Size, u32 ui32Alignment, + struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo); + +struct RESMAN_MAP_DEVICE_MEM_DATA { + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo; + struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo; +}; + +static inline void get_page_details(u32 vaddr, size_t byte_size, + u32 *page_offset_out, int *page_count_out) +{ + size_t host_page_size; + u32 page_offset; + int page_count; + + host_page_size = PAGE_SIZE; + page_offset = vaddr & (host_page_size - 1); + page_count = PAGE_ALIGN(byte_size + page_offset) / host_page_size; + + *page_offset_out = page_offset; + *page_count_out = page_count; +} + +static inline int get_page_count(u32 vaddr, size_t byte_size) +{ + u32 page_offset; + int page_count; + + get_page_details(vaddr, byte_size, &page_offset, &page_count); + + return page_count; +} + +enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapsKM(void *hDevCookie, + struct PVRSRV_HEAP_INFO *psHeapInfo) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + u32 ui32HeapCount; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + u32 i; + + if (hDevCookie == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetDeviceMemHeapsKM: hDevCookie invalid"); + PVR_DBG_BREAK; + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie; + + ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount; + psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; + + PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS); + + for (i = 0; i < ui32HeapCount; i++) { + psHeapInfo[i].ui32HeapID = psDeviceMemoryHeap[i].ui32HeapID; + psHeapInfo[i].hDevMemHeap = psDeviceMemoryHeap[i].hDevMemHeap; + psHeapInfo[i].sDevVAddrBase = + psDeviceMemoryHeap[i].sDevVAddrBase; + psHeapInfo[i].ui32HeapByteSize = + psDeviceMemoryHeap[i].ui32HeapSize; + psHeapInfo[i].ui32Attribs = psDeviceMemoryHeap[i].ui32Attribs; + } + + for (; i < PVRSRV_MAX_CLIENT_HEAPS; i++) { + OSMemSet(psHeapInfo + i, 0, sizeof(*psHeapInfo)); + psHeapInfo[i].ui32HeapID = (u32) PVRSRV_UNDEFINED_HEAP_ID; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVCreateDeviceMemContextKM(void *hDevCookie, + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void **phDevMemContext, + u32 *pui32ClientHeapCount, + struct PVRSRV_HEAP_INFO *psHeapInfo, + IMG_BOOL *pbCreated, IMG_BOOL *pbShared) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + u32 ui32HeapCount, ui32ClientHeapCount = 0; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + void *hDevMemContext; + void *hDevMemHeap; + struct IMG_DEV_PHYADDR sPDDevPAddr; + u32 i; + + if (hDevCookie == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDeviceMemContextKM: hDevCookie invalid"); + PVR_DBG_BREAK; + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie; + + ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount; + psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; + + PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS); + + hDevMemContext = BM_CreateContext(psDeviceNode, + &sPDDevPAddr, psPerProc, pbCreated); + if (hDevMemContext == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDeviceMemContextKM: Failed BM_CreateContext"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + for (i = 0; i < ui32HeapCount; i++) { + switch (psDeviceMemoryHeap[i].DevMemHeapType) { + case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: + psHeapInfo[ui32ClientHeapCount].ui32HeapID = + psDeviceMemoryHeap[i].ui32HeapID; + psHeapInfo[ui32ClientHeapCount].hDevMemHeap = + psDeviceMemoryHeap[i].hDevMemHeap; + psHeapInfo[ui32ClientHeapCount].sDevVAddrBase = + psDeviceMemoryHeap[i].sDevVAddrBase; + psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize = + psDeviceMemoryHeap[i].ui32HeapSize; + psHeapInfo[ui32ClientHeapCount].ui32Attribs = + psDeviceMemoryHeap[i].ui32Attribs; + pbShared[ui32ClientHeapCount] = IMG_TRUE; + ui32ClientHeapCount++; + break; + case DEVICE_MEMORY_HEAP_PERCONTEXT: + hDevMemHeap = BM_CreateHeap(hDevMemContext, + &psDeviceMemoryHeap[i]); + + psHeapInfo[ui32ClientHeapCount].ui32HeapID = + psDeviceMemoryHeap[i].ui32HeapID; + psHeapInfo[ui32ClientHeapCount].hDevMemHeap = + hDevMemHeap; + psHeapInfo[ui32ClientHeapCount].sDevVAddrBase = + psDeviceMemoryHeap[i].sDevVAddrBase; + psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize = + psDeviceMemoryHeap[i].ui32HeapSize; + psHeapInfo[ui32ClientHeapCount].ui32Attribs = + psDeviceMemoryHeap[i].ui32Attribs; + pbShared[ui32ClientHeapCount] = IMG_FALSE; + + ui32ClientHeapCount++; + break; + } + } + + *pui32ClientHeapCount = ui32ClientHeapCount; + *phDevMemContext = hDevMemContext; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVDestroyDeviceMemContextKM(void *hDevCookie, + void *hDevMemContext, + IMG_BOOL *pbDestroyed) +{ + int destroyed; + + PVR_UNREFERENCED_PARAMETER(hDevCookie); + + destroyed = pvr_put_ctx(hDevMemContext); + if (pbDestroyed) + *pbDestroyed = destroyed ? IMG_TRUE : IMG_FALSE; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapInfoKM(void *hDevCookie, + void *hDevMemContext, + u32 *pui32ClientHeapCount, + struct PVRSRV_HEAP_INFO *psHeapInfo, + IMG_BOOL *pbShared) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + u32 ui32HeapCount, ui32ClientHeapCount = 0; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + void *hDevMemHeap; + u32 i; + + if (hDevCookie == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetDeviceMemHeapInfoKM: hDevCookie invalid"); + PVR_DBG_BREAK; + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie; + + ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount; + psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; + + PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS); + + for (i = 0; i < ui32HeapCount; i++) { + switch (psDeviceMemoryHeap[i].DevMemHeapType) { + case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: + psHeapInfo[ui32ClientHeapCount].ui32HeapID = + psDeviceMemoryHeap[i].ui32HeapID; + psHeapInfo[ui32ClientHeapCount].hDevMemHeap = + psDeviceMemoryHeap[i].hDevMemHeap; + psHeapInfo[ui32ClientHeapCount].sDevVAddrBase = + psDeviceMemoryHeap[i].sDevVAddrBase; + psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize = + psDeviceMemoryHeap[i].ui32HeapSize; + psHeapInfo[ui32ClientHeapCount].ui32Attribs = + psDeviceMemoryHeap[i].ui32Attribs; + pbShared[ui32ClientHeapCount] = IMG_TRUE; + ui32ClientHeapCount++; + break; + case DEVICE_MEMORY_HEAP_PERCONTEXT: + hDevMemHeap = BM_CreateHeap(hDevMemContext, + &psDeviceMemoryHeap[i]); + psHeapInfo[ui32ClientHeapCount].ui32HeapID = + psDeviceMemoryHeap[i].ui32HeapID; + psHeapInfo[ui32ClientHeapCount].hDevMemHeap = + hDevMemHeap; + psHeapInfo[ui32ClientHeapCount].sDevVAddrBase = + psDeviceMemoryHeap[i].sDevVAddrBase; + psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize = + psDeviceMemoryHeap[i].ui32HeapSize; + psHeapInfo[ui32ClientHeapCount].ui32Attribs = + psDeviceMemoryHeap[i].ui32Attribs; + pbShared[ui32ClientHeapCount] = IMG_FALSE; + + ui32ClientHeapCount++; + break; + } + } + *pui32ClientHeapCount = ui32ClientHeapCount; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR AllocDeviceMem(void *hDevCookie, void *hDevMemHeap, + u32 ui32Flags, u32 ui32Size, + u32 ui32Alignment, + struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo) +{ + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo; + void *hBuffer; + + struct PVRSRV_MEMBLK *psMemBlock; + IMG_BOOL bBMError; + + PVR_UNREFERENCED_PARAMETER(hDevCookie); + + *ppsMemInfo = NULL; + + if (OSAllocMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), + (void **) &psMemInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "AllocDeviceMem: Failed to alloc memory for block"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + OSMemSet(psMemInfo, 0, sizeof(*psMemInfo)); + + psMemBlock = &(psMemInfo->sMemBlk); + + psMemInfo->ui32Flags = ui32Flags | PVRSRV_MEM_RAM_BACKED_ALLOCATION; + + bBMError = BM_Alloc(hDevMemHeap, NULL, ui32Size, + &psMemInfo->ui32Flags, ui32Alignment, &hBuffer); + + if (!bBMError) { + PVR_DPF(PVR_DBG_ERROR, "AllocDeviceMem: BM_Alloc Failed"); + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo, + NULL); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer); + psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer); + + psMemBlock->hBuffer = (void *)hBuffer; + psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer); + psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; + psMemInfo->ui32AllocSize = ui32Size; + + psMemInfo->pvSysBackupBuffer = NULL; + + *ppsMemInfo = psMemInfo; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR FreeDeviceMem(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ + void *hBuffer; + + if (!psMemInfo) + return PVRSRV_ERROR_INVALID_PARAMS; + + hBuffer = psMemInfo->sMemBlk.hBuffer; + BM_Free(hBuffer, psMemInfo->ui32Flags); + + if (psMemInfo->pvSysBackupBuffer) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, psMemInfo->ui32AllocSize, + psMemInfo->pvSysBackupBuffer, NULL); + + OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct PVRSRV_KERNEL_MEM_INFO), + psMemInfo, NULL); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVAllocSyncInfoKM(void *hDevCookie, void *hDevMemContext, + struct PVRSRV_KERNEL_SYNC_INFO **ppsKernelSyncInfo) +{ + void *hSyncDevMemHeap; + struct DEVICE_MEMORY_INFO *psDevMemoryInfo; + struct BM_CONTEXT *pBMContext; + enum PVRSRV_ERROR eError; + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; + struct PVRSRV_SYNC_DATA *psSyncData; + + eError = OSAllocMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_KERNEL_SYNC_INFO), + (void **) &psKernelSyncInfo, NULL); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVAllocSyncInfoKM: Failed to alloc memory"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + pBMContext = (struct BM_CONTEXT *)hDevMemContext; + psDevMemoryInfo = &pBMContext->psDeviceNode->sDevMemoryInfo; + + hSyncDevMemHeap = psDevMemoryInfo->psDeviceMemoryHeap[psDevMemoryInfo-> + ui32SyncHeapID].hDevMemHeap; + + eError = AllocDeviceMem(hDevCookie, hSyncDevMemHeap, + PVRSRV_MEM_CACHE_CONSISTENT, + sizeof(struct PVRSRV_SYNC_DATA), sizeof(u32), + &psKernelSyncInfo->psSyncDataMemInfoKM); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVAllocSyncInfoKM: Failed to alloc memory"); + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_KERNEL_SYNC_INFO), + psKernelSyncInfo, NULL); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + psKernelSyncInfo->psSyncData = + psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM; + psSyncData = psKernelSyncInfo->psSyncData; + + psSyncData->ui32WriteOpsPending = 0; + psSyncData->ui32WriteOpsComplete = 0; + psSyncData->ui32ReadOpsPending = 0; + psSyncData->ui32ReadOpsComplete = 0; + psSyncData->ui32LastOpDumpVal = 0; + psSyncData->ui32LastReadOpDumpVal = 0; + +#if defined(PDUMP) + PDUMPMEM(psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM, + psKernelSyncInfo->psSyncDataMemInfoKM, 0, + psKernelSyncInfo->psSyncDataMemInfoKM->ui32AllocSize, + 0, MAKEUNIQUETAG(psKernelSyncInfo->psSyncDataMemInfoKM)); +#endif + + psKernelSyncInfo->sWriteOpsCompleteDevVAddr.uiAddr = + psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr + + offsetof(struct PVRSRV_SYNC_DATA, ui32WriteOpsComplete); + psKernelSyncInfo->sReadOpsCompleteDevVAddr.uiAddr = + psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr + + offsetof(struct PVRSRV_SYNC_DATA, ui32ReadOpsComplete); + + psKernelSyncInfo->psSyncDataMemInfoKM->psKernelSyncInfo = NULL; + + *ppsKernelSyncInfo = psKernelSyncInfo; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVFreeSyncInfoKM( + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo) +{ + FreeDeviceMem(psKernelSyncInfo->psSyncDataMemInfoKM); + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo, + NULL); + + return PVRSRV_OK; +} + +static inline +void get_syncinfo(struct PVRSRV_KERNEL_SYNC_INFO *syncinfo) +{ + syncinfo->refcount++; +} + +static inline +void put_syncinfo(struct PVRSRV_KERNEL_SYNC_INFO *syncinfo) +{ + struct PVRSRV_DEVICE_NODE *dev = syncinfo->dev_cookie; + + syncinfo->refcount--; + + if (!syncinfo->refcount) { + HASH_Remove(dev->sync_table, + syncinfo->phys_addr.uiAddr); + PVRSRVFreeSyncInfoKM(syncinfo); + } +} + +static inline +enum PVRSRV_ERROR alloc_or_reuse_syncinfo(void *dev_cookie, + void *mem_context_handle, + struct PVRSRV_KERNEL_SYNC_INFO **syncinfo, + struct IMG_SYS_PHYADDR *phys_addr) +{ + enum PVRSRV_ERROR error; + struct PVRSRV_DEVICE_NODE *dev; + + dev = (struct PVRSRV_DEVICE_NODE *) dev_cookie; + + *syncinfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + HASH_Retrieve(dev->sync_table, + phys_addr->uiAddr); + + if (!*syncinfo) { + /* Dont' have one so create one */ + error = PVRSRVAllocSyncInfoKM(dev_cookie, mem_context_handle, + syncinfo); + + if (error != PVRSRV_OK) + return error; + + /* Setup our extra data */ + (*syncinfo)->phys_addr.uiAddr = phys_addr->uiAddr; + (*syncinfo)->dev_cookie = dev_cookie; + (*syncinfo)->refcount = 1; + + if (!HASH_Insert(dev->sync_table, phys_addr->uiAddr, + (u32) *syncinfo)) { + PVR_DPF(PVR_DBG_ERROR, "alloc_or_reuse_syncinfo: " + "Failed to add syncobject to hash table"); + return PVRSRV_ERROR_GENERIC; + } + } else + get_syncinfo(*syncinfo); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR FreeDeviceMemCallBack(void *pvParam, u32 ui32Param) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + psMemInfo->ui32RefCount--; + + if (psMemInfo->ui32Flags & PVRSRV_MEM_EXPORTED) { + void *hMemInfo = NULL; + + if (psMemInfo->ui32RefCount != 0) { + PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: " + "mappings are open in other processes"); + return PVRSRV_ERROR_GENERIC; + } + + eError = PVRSRVFindHandle(KERNEL_HANDLE_BASE, + &hMemInfo, + psMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: " + "can't find exported meminfo in the " + "global handle list"); + return eError; + } + + eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE, + hMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: " + "PVRSRVReleaseHandle failed for exported meminfo"); + return eError; + } + } + + PVR_ASSERT(psMemInfo->ui32RefCount == 0); + + if (psMemInfo->psKernelSyncInfo) + eError = PVRSRVFreeSyncInfoKM(psMemInfo->psKernelSyncInfo); + + if (eError == PVRSRV_OK) + eError = FreeDeviceMem(psMemInfo); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVFreeDeviceMemKM(void *hDevCookie, + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ + PVR_UNREFERENCED_PARAMETER(hDevCookie); + + if (!psMemInfo) + return PVRSRV_ERROR_INVALID_PARAMS; + + if (psMemInfo->sMemBlk.hResItem != NULL) + ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem); + else + FreeDeviceMemCallBack(psMemInfo, 0); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVAllocDeviceMemKM(void *hDevCookie, + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevMemHeap, u32 ui32Flags, + u32 ui32Size, u32 ui32Alignment, + struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo) +{ + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo; + enum PVRSRV_ERROR eError; + struct BM_HEAP *psBMHeap; + void *hDevMemContext; + + if (!hDevMemHeap || (ui32Size == 0)) + return PVRSRV_ERROR_INVALID_PARAMS; + + eError = AllocDeviceMem(hDevCookie, hDevMemHeap, ui32Flags, ui32Size, + ui32Alignment, &psMemInfo); + + if (eError != PVRSRV_OK) + return eError; + + if (ui32Flags & PVRSRV_MEM_NO_SYNCOBJ) { + psMemInfo->psKernelSyncInfo = NULL; + } else { + psBMHeap = (struct BM_HEAP *)hDevMemHeap; + hDevMemContext = (void *) psBMHeap->pBMContext; + eError = PVRSRVAllocSyncInfoKM(hDevCookie, + hDevMemContext, + &psMemInfo->psKernelSyncInfo); + if (eError != PVRSRV_OK) + goto free_mainalloc; + } + + *ppsMemInfo = psMemInfo; + + if (ui32Flags & PVRSRV_MEM_NO_RESMAN) { + psMemInfo->sMemBlk.hResItem = NULL; + } else { + psMemInfo->sMemBlk.hResItem = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_DEVICEMEM_ALLOCATION, + psMemInfo, 0, FreeDeviceMemCallBack); + if (psMemInfo->sMemBlk.hResItem == NULL) { + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto free_mainalloc; + } + } + + psMemInfo->ui32RefCount++; + + return PVRSRV_OK; + +free_mainalloc: + FreeDeviceMem(psMemInfo); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVDissociateDeviceMemKM(void *hDevCookie, + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevCookie; + + PVR_UNREFERENCED_PARAMETER(hDevCookie); + + if (!psMemInfo) + return PVRSRV_ERROR_INVALID_PARAMS; + + eError = ResManDissociateRes(psMemInfo->sMemBlk.hResItem, + psDeviceNode->hResManContext); + + PVR_ASSERT(eError == PVRSRV_OK); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVGetFreeDeviceMemKM(u32 ui32Flags, u32 *pui32Total, + u32 *pui32Free, u32 *pui32LargestBlock) +{ + + PVR_UNREFERENCED_PARAMETER(ui32Flags); + PVR_UNREFERENCED_PARAMETER(pui32Total); + PVR_UNREFERENCED_PARAMETER(pui32Free); + PVR_UNREFERENCED_PARAMETER(pui32LargestBlock); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVUnwrapExtMemoryKM( + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ + if (!psMemInfo) + return PVRSRV_ERROR_INVALID_PARAMS; + + ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR UnwrapExtMemoryCallBack(void *pvParam, u32 ui32Param) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam; + void *hOSWrapMem; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + hOSWrapMem = psMemInfo->sMemBlk.hOSWrapMem; + + if (psMemInfo->psKernelSyncInfo) + put_syncinfo(psMemInfo->psKernelSyncInfo); + + if (psMemInfo->sMemBlk.psIntSysPAddr) { + int page_count; + + page_count = get_page_count((u32)psMemInfo->pvLinAddrKM, + psMemInfo->ui32AllocSize); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + page_count * sizeof(struct IMG_SYS_PHYADDR), + psMemInfo->sMemBlk.psIntSysPAddr, NULL); + } + + if (eError == PVRSRV_OK) { + psMemInfo->ui32RefCount--; + eError = FreeDeviceMem(psMemInfo); + } + + if (hOSWrapMem) + OSReleasePhysPageAddr(hOSWrapMem); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVWrapExtMemoryKM(void *hDevCookie, + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevMemContext, u32 ui32ByteSize, + u32 ui32PageOffset, IMG_BOOL bPhysContig, + struct IMG_SYS_PHYADDR *psExtSysPAddr, + void *pvLinAddr, + struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo) +{ + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = NULL; + struct DEVICE_MEMORY_INFO *psDevMemoryInfo; + u32 ui32HostPageSize = HOST_PAGESIZE(); + void *hDevMemHeap = NULL; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + void *hBuffer; + struct PVRSRV_MEMBLK *psMemBlock; + IMG_BOOL bBMError; + struct BM_HEAP *psBMHeap; + enum PVRSRV_ERROR eError; + void *pvPageAlignedCPUVAddr; + struct IMG_SYS_PHYADDR *psIntSysPAddr = NULL; + void *hOSWrapMem = NULL; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + int page_count = 0; + u32 i; + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie; + PVR_ASSERT(psDeviceNode != NULL); + + if (psDeviceNode == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVWrapExtMemoryKM: invalid parameter"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + if (pvLinAddr) { + get_page_details((u32)pvLinAddr, ui32ByteSize, + &ui32PageOffset, &page_count); + pvPageAlignedCPUVAddr = (void *)((u8 *) pvLinAddr - + ui32PageOffset); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + page_count * sizeof(struct IMG_SYS_PHYADDR), + (void **)&psIntSysPAddr, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM: " + "Failed to alloc memory for block"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + eError = OSAcquirePhysPageAddr(pvPageAlignedCPUVAddr, + page_count * ui32HostPageSize, + psIntSysPAddr, &hOSWrapMem); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM:" + " Failed to alloc memory for block"); + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorExitPhase1; + } + psExtSysPAddr = psIntSysPAddr; + bPhysContig = IMG_FALSE; + } + + psDevMemoryInfo = + &((struct BM_CONTEXT *)hDevMemContext)->psDeviceNode-> + sDevMemoryInfo; + psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap; + for (i = 0; i < PVRSRV_MAX_CLIENT_HEAPS; i++) { + if (HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) == + psDevMemoryInfo->ui32MappingHeapID) { + if (psDeviceMemoryHeap[i].DevMemHeapType == + DEVICE_MEMORY_HEAP_PERCONTEXT) { + hDevMemHeap = + BM_CreateHeap(hDevMemContext, + &psDeviceMemoryHeap[i]); + } else { + hDevMemHeap = + psDevMemoryInfo->psDeviceMemoryHeap[i]. + hDevMemHeap; + } + break; + } + } + + if (hDevMemHeap == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVWrapExtMemoryKM: unable to find mapping heap"); + eError = PVRSRV_ERROR_GENERIC; + goto ErrorExitPhase2; + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), + (void **) &psMemInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM: " + "Failed to alloc memory for block"); + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorExitPhase2; + } + + OSMemSet(psMemInfo, 0, sizeof(*psMemInfo)); + psMemBlock = &(psMemInfo->sMemBlk); + + bBMError = BM_Wrap(hDevMemHeap, + ui32ByteSize, + ui32PageOffset, + bPhysContig, + psExtSysPAddr, + NULL, &psMemInfo->ui32Flags, &hBuffer); + if (!bBMError) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVWrapExtMemoryKM: BM_Wrap Failed"); + eError = PVRSRV_ERROR_BAD_MAPPING; + goto ErrorExitPhase3; + } + + psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer); + psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer); + psMemBlock->hOSWrapMem = hOSWrapMem; + psMemBlock->psIntSysPAddr = psIntSysPAddr; + + psMemBlock->hBuffer = (void *) hBuffer; + + psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer); + psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; + psMemInfo->ui32AllocSize = ui32ByteSize; + + psMemInfo->pvSysBackupBuffer = NULL; + + psBMHeap = (struct BM_HEAP *)hDevMemHeap; + hDevMemContext = (void *) psBMHeap->pBMContext; + eError = alloc_or_reuse_syncinfo(hDevCookie, + hDevMemContext, + &psMemInfo->psKernelSyncInfo, + psExtSysPAddr); + if (eError != PVRSRV_OK) + goto ErrorExitPhase4; + + psMemInfo->ui32RefCount++; + + psMemInfo->sMemBlk.hResItem = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_DEVICEMEM_WRAP, psMemInfo, 0, + UnwrapExtMemoryCallBack); + + *ppsMemInfo = psMemInfo; + + return PVRSRV_OK; + +ErrorExitPhase4: + FreeDeviceMem(psMemInfo); + psMemInfo = NULL; + +ErrorExitPhase3: + if (psMemInfo) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo, + NULL); + } + +ErrorExitPhase2: + if (hOSWrapMem) + OSReleasePhysPageAddr(hOSWrapMem); + +ErrorExitPhase1: + if (psIntSysPAddr) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + page_count * sizeof(struct IMG_SYS_PHYADDR), + psIntSysPAddr, NULL); + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVUnmapDeviceMemoryKM( + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ + if (!psMemInfo) + return PVRSRV_ERROR_INVALID_PARAMS; + + ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR UnmapDeviceMemoryCallBack(void *pvParam, u32 ui32Param) +{ + enum PVRSRV_ERROR eError; + struct RESMAN_MAP_DEVICE_MEM_DATA *psMapData = pvParam; + int page_count; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + page_count = get_page_count((u32)psMapData->psMemInfo->pvLinAddrKM, + psMapData->psMemInfo->ui32AllocSize); + + if (psMapData->psMemInfo->sMemBlk.psIntSysPAddr) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + page_count * sizeof(struct IMG_SYS_PHYADDR), + psMapData->psMemInfo->sMemBlk.psIntSysPAddr, NULL); + + eError = FreeDeviceMem(psMapData->psMemInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "UnmapDeviceMemoryCallBack: " + "Failed to free DST meminfo"); + return eError; + } + + psMapData->psSrcMemInfo->ui32RefCount--; + + PVR_ASSERT(psMapData->psSrcMemInfo->ui32RefCount != (u32) (-1)); +/* + * Don't free the source MemInfo as we didn't allocate it + * and it's not our job as the process the allocated + * should also free it when it's finished + */ + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), psMapData, NULL); + + return eError; +} + +static inline int bm_is_continuous(const struct BM_BUF *buf) +{ + return buf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr; +} + +enum PVRSRV_ERROR PVRSRVMapDeviceMemoryKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo, + void *hDstDevMemHeap, + struct PVRSRV_KERNEL_MEM_INFO **ppsDstMemInfo) +{ + enum PVRSRV_ERROR eError; + u32 ui32PageOffset; + u32 ui32HostPageSize = HOST_PAGESIZE(); + int page_count; + int i; + struct IMG_SYS_PHYADDR *psSysPAddr = NULL; + struct IMG_DEV_PHYADDR sDevPAddr; + struct BM_BUF *psBuf; + struct IMG_DEV_VIRTADDR sDevVAddr; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = NULL; + void *hBuffer; + struct PVRSRV_MEMBLK *psMemBlock; + IMG_BOOL bBMError; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + void *pvPageAlignedCPUVAddr; + struct RESMAN_MAP_DEVICE_MEM_DATA *psMapData = NULL; + + if (!psSrcMemInfo || !hDstDevMemHeap || !ppsDstMemInfo) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVMapDeviceMemoryKM: invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + *ppsDstMemInfo = NULL; + + get_page_details((u32)psSrcMemInfo->pvLinAddrKM, + psSrcMemInfo->ui32AllocSize, + &ui32PageOffset, &page_count); + pvPageAlignedCPUVAddr = + (void *) ((u8 *) psSrcMemInfo->pvLinAddrKM - + ui32PageOffset); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + page_count * sizeof(struct IMG_SYS_PHYADDR), + (void **) &psSysPAddr, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: " + "Failed to alloc memory for block"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + psBuf = psSrcMemInfo->sMemBlk.hBuffer; + + psDeviceNode = psBuf->pMapping->pBMHeap->pBMContext->psDeviceNode; + + sDevVAddr.uiAddr = psSrcMemInfo->sDevVAddr.uiAddr - ui32PageOffset; + for (i = 0; i < page_count; i++) { + eError = + BM_GetPhysPageAddr(psSrcMemInfo, sDevVAddr, &sDevPAddr); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: " + "Failed to retrieve page list from device"); + goto ErrorExit; + } + + psSysPAddr[i] = + SysDevPAddrToSysPAddr(psDeviceNode->sDevId.eDeviceType, + sDevPAddr); + + sDevVAddr.uiAddr += ui32HostPageSize; + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), + (void **)&psMapData, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: " + "Failed to alloc resman map data"); + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorExit; + } + + if (OSAllocMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), + (void **)&psMemInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: " + "Failed to alloc memory for block"); + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorExit; + } + + OSMemSet(psMemInfo, 0, sizeof(*psMemInfo)); + + psMemBlock = &(psMemInfo->sMemBlk); + + bBMError = BM_Wrap(hDstDevMemHeap, psSrcMemInfo->ui32AllocSize, + ui32PageOffset, bm_is_continuous(psBuf), psSysPAddr, + pvPageAlignedCPUVAddr, &psMemInfo->ui32Flags, + &hBuffer); + + if (!bBMError) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVMapDeviceMemoryKM: BM_Wrap Failed"); + eError = PVRSRV_ERROR_BAD_MAPPING; + goto ErrorExit; + } + + psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer); + psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer); + + psMemBlock->hBuffer = (void *) hBuffer; + + psMemBlock->psIntSysPAddr = psSysPAddr; + + psMemInfo->pvLinAddrKM = psSrcMemInfo->pvLinAddrKM; + + psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; + psMemInfo->ui32AllocSize = psSrcMemInfo->ui32AllocSize; + psMemInfo->psKernelSyncInfo = psSrcMemInfo->psKernelSyncInfo; + + psMemInfo->pvSysBackupBuffer = NULL; + + psSrcMemInfo->ui32RefCount++; + + psMapData->psMemInfo = psMemInfo; + psMapData->psSrcMemInfo = psSrcMemInfo; + + psMemInfo->sMemBlk.hResItem = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_DEVICEMEM_MAPPING, psMapData, 0, + UnmapDeviceMemoryCallBack); + + *ppsDstMemInfo = psMemInfo; + + return PVRSRV_OK; + +ErrorExit: + + if (psSysPAddr) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct IMG_SYS_PHYADDR), psSysPAddr, NULL); + } + + if (psMemInfo) { + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo, + NULL); + } + + if (psMapData) { + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), psMapData, + NULL); + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVUnmapDeviceClassMemoryKM( + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ + if (!psMemInfo) + return PVRSRV_ERROR_INVALID_PARAMS; + + ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR UnmapDeviceClassMemoryCallBack(void *pvParam, + u32 ui32Param) +{ + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + return FreeDeviceMem(psMemInfo); +} + +enum PVRSRV_ERROR PVRSRVMapDeviceClassMemoryKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevMemContext, void *hDeviceClassBuffer, + struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo, + void **phOSMapInfo) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo; + struct PVRSRV_DEVICECLASS_BUFFER *psDeviceClassBuffer; + struct IMG_SYS_PHYADDR *psSysPAddr; + void *pvCPUVAddr, *pvPageAlignedCPUVAddr; + IMG_BOOL bPhysContig; + struct BM_CONTEXT *psBMContext; + struct DEVICE_MEMORY_INFO *psDevMemoryInfo; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + void *hDevMemHeap = NULL; + u32 ui32ByteSize; + u32 ui32Offset; + u32 ui32PageSize = HOST_PAGESIZE(); + void *hBuffer; + struct PVRSRV_MEMBLK *psMemBlock; + IMG_BOOL bBMError; + u32 i; + + if (!hDeviceClassBuffer || !ppsMemInfo || !phOSMapInfo || + !hDevMemContext) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVMapDeviceClassMemoryKM: invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDeviceClassBuffer = (struct PVRSRV_DEVICECLASS_BUFFER *) + hDeviceClassBuffer; + + eError = + psDeviceClassBuffer->pfnGetBufferAddr(psDeviceClassBuffer-> + hExtDevice, + psDeviceClassBuffer-> + hExtBuffer, &psSysPAddr, + &ui32ByteSize, + (void __iomem **)&pvCPUVAddr, + phOSMapInfo, &bPhysContig); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: " + "unable to get buffer address"); + return PVRSRV_ERROR_GENERIC; + } + + psBMContext = (struct BM_CONTEXT *)psDeviceClassBuffer->hDevMemContext; + psDevMemoryInfo = &psBMContext->psDeviceNode->sDevMemoryInfo; + psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap; + for (i = 0; i < PVRSRV_MAX_CLIENT_HEAPS; i++) { + if (HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) == + psDevMemoryInfo->ui32MappingHeapID) { + if (psDeviceMemoryHeap[i].DevMemHeapType == + DEVICE_MEMORY_HEAP_PERCONTEXT) + hDevMemHeap = + BM_CreateHeap(hDevMemContext, + &psDeviceMemoryHeap[i]); + else + hDevMemHeap = + psDevMemoryInfo->psDeviceMemoryHeap[i]. + hDevMemHeap; + break; + } + } + + if (hDevMemHeap == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: " + "unable to find mapping heap"); + return PVRSRV_ERROR_GENERIC; + } + + ui32Offset = ((u32)pvCPUVAddr) & (ui32PageSize - 1); + pvPageAlignedCPUVAddr = (void *)((u8 *)pvCPUVAddr - ui32Offset); + + if (OSAllocMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), + (void **)&psMemInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: " + "Failed to alloc memory for block"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + OSMemSet(psMemInfo, 0, sizeof(*psMemInfo)); + + psMemBlock = &(psMemInfo->sMemBlk); + + bBMError = BM_Wrap(hDevMemHeap, ui32ByteSize, ui32Offset, bPhysContig, + psSysPAddr, pvPageAlignedCPUVAddr, + &psMemInfo->ui32Flags, &hBuffer); + + if (!bBMError) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVMapDeviceClassMemoryKM: BM_Wrap Failed"); + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo, + NULL); + return PVRSRV_ERROR_BAD_MAPPING; + } + + psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer); + psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer); + + psMemBlock->hBuffer = (void *) hBuffer; + + psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer); + + psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; + psMemInfo->ui32AllocSize = ui32ByteSize; + psMemInfo->psKernelSyncInfo = psDeviceClassBuffer->psKernelSyncInfo; + + psMemInfo->pvSysBackupBuffer = NULL; + + psMemInfo->sMemBlk.hResItem = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_DEVICECLASSMEM_MAPPING, psMemInfo, 0, + UnmapDeviceClassMemoryCallBack); + + *ppsMemInfo = psMemInfo; + + return PVRSRV_OK; +} diff --git a/drivers/gpu/pvr/env_data.h b/drivers/gpu/pvr/env_data.h new file mode 100644 index 00000000000..7317a51bbdd --- /dev/null +++ b/drivers/gpu/pvr/env_data.h @@ -0,0 +1,57 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _ENV_DATA_ +#define _ENV_DATA_ + +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/workqueue.h> + +#define PVRSRV_MAX_BRIDGE_IN_SIZE 0x1000 +#define PVRSRV_MAX_BRIDGE_OUT_SIZE 0x1000 + +struct PVR_PCI_DEV { + struct pci_dev *psPCIDev; + enum HOST_PCI_INIT_FLAGS ePCIFlags; + IMG_BOOL abPCIResourceInUse[DEVICE_COUNT_RESOURCE]; +}; + +struct ENV_DATA { + void *pvBridgeData; + struct pm_dev *psPowerDevice; + IMG_BOOL bLISRInstalled; + IMG_BOOL bMISRInstalled; + u32 ui32IRQ; + void *pvISRCookie; + struct workqueue_struct *psMISRWorkqueue; + struct work_struct sMISRWork; + void *pvSysData; + struct workqueue_struct *psPerfWorkqueue; + struct delayed_work sPerfWork; +}; + +#endif diff --git a/drivers/gpu/pvr/env_perproc.h b/drivers/gpu/pvr/env_perproc.h new file mode 100644 index 00000000000..7f092f6565c --- /dev/null +++ b/drivers/gpu/pvr/env_perproc.h @@ -0,0 +1,51 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __ENV_PERPROC_H__ +#define __ENV_PERPROC_H__ + +#include "linux/list.h" +#include "linux/proc_fs.h" + +#include "img_types.h" + +struct PVRSRV_ENV_PER_PROCESS_DATA { + void *hBlockAlloc; + struct proc_dir_entry *psProcDir; +}; + +void RemovePerProcessProcDir(struct PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc); + +enum PVRSRV_ERROR LinuxMMapPerProcessConnect( + struct PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc); + +void LinuxMMapPerProcessDisconnect( + struct PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc); + +enum PVRSRV_ERROR LinuxMMapPerProcessHandleOptions( + struct PVRSRV_HANDLE_BASE *psHandleBase); + +#endif diff --git a/drivers/gpu/pvr/event.c b/drivers/gpu/pvr/event.c new file mode 100644 index 00000000000..5ce55aa025b --- /dev/null +++ b/drivers/gpu/pvr/event.c @@ -0,0 +1,274 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/version.h> +#include <linux/io.h> +#include <asm/page.h> +#include <asm/system.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/hardirq.h> +#include <linux/timer.h> +#include <linux/capability.h> +#include <linux/sched.h> +#include <linux/uaccess.h> + +#include "img_types.h" +#include "services_headers.h" +#include "mm.h" +#include "pvrmmap.h" +#include "mmap.h" +#include "env_data.h" +#include "proc.h" +#include "event.h" +#include "pvr_bridge_km.h" + +struct PVRSRV_LINUX_EVENT_OBJECT_LIST { + rwlock_t sLock; + struct list_head sList; + +}; + +struct PVRSRV_LINUX_EVENT_OBJECT { + atomic_t sTimeStamp; + u32 ui32TimeStampPrevious; +#if defined(CONFIG_PVR_DEBUG_EXTRA) + unsigned ui32Stats; +#endif + wait_queue_head_t sWait; + struct list_head sList; + void *hResItem; + struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList; +}; + +enum PVRSRV_ERROR LinuxEventObjectListCreate(void **phEventObjectList) +{ + struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList; + + if (OSAllocMem + (PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_LINUX_EVENT_OBJECT_LIST), + (void **) &psEvenObjectList, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "LinuxEventObjectCreate: " + "failed to allocate memory for event list"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + INIT_LIST_HEAD(&psEvenObjectList->sList); + + rwlock_init(&psEvenObjectList->sLock); + + *phEventObjectList = (void **) psEvenObjectList; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR LinuxEventObjectListDestroy(void *hEventObjectList) +{ + struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList = + (struct PVRSRV_LINUX_EVENT_OBJECT_LIST *)hEventObjectList; + + if (psEvenObjectList) { + if (!list_empty(&psEvenObjectList->sList)) { + PVR_DPF(PVR_DBG_ERROR, + "LinuxEventObjectListDestroy: Event List is not empty"); + return PVRSRV_ERROR_GENERIC; + } + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_LINUX_EVENT_OBJECT_LIST), + psEvenObjectList, NULL); + } + return PVRSRV_OK; +} + +enum PVRSRV_ERROR LinuxEventObjectDelete(void *hOSEventObjectList, + void *hOSEventObject) +{ + if (hOSEventObjectList) + if (hOSEventObject) { + struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = + (struct PVRSRV_LINUX_EVENT_OBJECT *)hOSEventObject; +#if defined(CONFIG_PVR_DEBUG_EXTRA) + PVR_DPF(PVR_DBG_MESSAGE, + "LinuxEventObjectListDelete: Event object waits: %lu", + psLinuxEventObject->ui32Stats); +#endif + ResManFreeResByPtr(psLinuxEventObject->hResItem); + + return PVRSRV_OK; + } + return PVRSRV_ERROR_GENERIC; + +} + +static enum PVRSRV_ERROR LinuxEventObjectDeleteCallback(void *pvParam, + u32 ui32Param) +{ + struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = pvParam; + struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = + psLinuxEventObject->psLinuxEventObjectList; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + write_lock_bh(&psLinuxEventObjectList->sLock); + list_del(&psLinuxEventObject->sList); + write_unlock_bh(&psLinuxEventObjectList->sLock); + +#if defined(CONFIG_PVR_DEBUG_EXTRA) + PVR_DPF(PVR_DBG_MESSAGE, + "LinuxEventObjectDeleteCallback: Event object waits: %lu", + psLinuxEventObject->ui32Stats); +#endif + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_LINUX_EVENT_OBJECT), psLinuxEventObject, + NULL); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR LinuxEventObjectAdd(void *hOSEventObjectList, + void **phOSEventObject) +{ + struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject; + struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = + (struct PVRSRV_LINUX_EVENT_OBJECT_LIST *)hOSEventObjectList; + u32 ui32PID = OSGetCurrentProcessIDKM(); + struct PVRSRV_PER_PROCESS_DATA *psPerProc; + + psPerProc = PVRSRVPerProcessData(ui32PID); + if (psPerProc == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "LinuxEventObjectAdd: Couldn't find per-process data"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_LINUX_EVENT_OBJECT), + (void **) &psLinuxEventObject, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "LinuxEventObjectAdd: failed to allocate memory "); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + INIT_LIST_HEAD(&psLinuxEventObject->sList); + + atomic_set(&psLinuxEventObject->sTimeStamp, 0); + psLinuxEventObject->ui32TimeStampPrevious = 0; + +#if defined(CONFIG_PVR_DEBUG_EXTRA) + psLinuxEventObject->ui32Stats = 0; +#endif + init_waitqueue_head(&psLinuxEventObject->sWait); + + psLinuxEventObject->psLinuxEventObjectList = psLinuxEventObjectList; + + psLinuxEventObject->hResItem = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_EVENT_OBJECT, psLinuxEventObject, 0, + &LinuxEventObjectDeleteCallback); + + write_lock_bh(&psLinuxEventObjectList->sLock); + list_add(&psLinuxEventObject->sList, &psLinuxEventObjectList->sList); + write_unlock_bh(&psLinuxEventObjectList->sLock); + + *phOSEventObject = psLinuxEventObject; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR LinuxEventObjectSignal(void *hOSEventObjectList) +{ + struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject; + struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList = + (struct PVRSRV_LINUX_EVENT_OBJECT_LIST *)hOSEventObjectList; + struct list_head *psListEntry, *psListEntryTemp, *psList; + psList = &psLinuxEventObjectList->sList; + + list_for_each_safe(psListEntry, psListEntryTemp, psList) { + + psLinuxEventObject = + (struct PVRSRV_LINUX_EVENT_OBJECT *)list_entry(psListEntry, + struct PVRSRV_LINUX_EVENT_OBJECT, + sList); + + atomic_inc(&psLinuxEventObject->sTimeStamp); + wake_up_interruptible(&psLinuxEventObject->sWait); + } + + return PVRSRV_OK; + +} + +enum PVRSRV_ERROR LinuxEventObjectWait(void *hOSEventObject, u32 ui32MSTimeout) +{ + u32 ui32TimeStamp; + DEFINE_WAIT(sWait); + + struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = + (struct PVRSRV_LINUX_EVENT_OBJECT *)hOSEventObject; + + u32 ui32TimeOutJiffies = msecs_to_jiffies(ui32MSTimeout); + + do { + prepare_to_wait(&psLinuxEventObject->sWait, &sWait, + TASK_INTERRUPTIBLE); + ui32TimeStamp = atomic_read(&psLinuxEventObject->sTimeStamp); + + if (psLinuxEventObject->ui32TimeStampPrevious != ui32TimeStamp) + break; + + pvr_unlock(); + + ui32TimeOutJiffies = + (u32) schedule_timeout((s32) ui32TimeOutJiffies); + + pvr_lock(); + + if (pvr_is_disabled()) { + ui32TimeOutJiffies = 1; + break; + } +#if defined(CONFIG_PVR_DEBUG_EXTRA) + psLinuxEventObject->ui32Stats++; +#endif + + } while (ui32TimeOutJiffies); + + finish_wait(&psLinuxEventObject->sWait, &sWait); + + psLinuxEventObject->ui32TimeStampPrevious = ui32TimeStamp; + + return ui32TimeOutJiffies ? PVRSRV_OK : PVRSRV_ERROR_TIMEOUT; + +} diff --git a/drivers/gpu/pvr/event.h b/drivers/gpu/pvr/event.h new file mode 100644 index 00000000000..54de8089191 --- /dev/null +++ b/drivers/gpu/pvr/event.h @@ -0,0 +1,35 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +enum PVRSRV_ERROR LinuxEventObjectListCreate(void **phEventObjectList); +enum PVRSRV_ERROR LinuxEventObjectListDestroy(void *hEventObjectList); +enum PVRSRV_ERROR LinuxEventObjectAdd(void *hOSEventObjectList, + void **phOSEventObject); +enum PVRSRV_ERROR LinuxEventObjectDelete(void *hOSEventObjectList, + void *hOSEventObject); +enum PVRSRV_ERROR LinuxEventObjectSignal(void *hOSEventObjectList); +enum PVRSRV_ERROR LinuxEventObjectWait(void *hOSEventObject, u32 ui32MSTimeout); + diff --git a/drivers/gpu/pvr/handle.c b/drivers/gpu/pvr/handle.c new file mode 100644 index 00000000000..f1c8f83bc5e --- /dev/null +++ b/drivers/gpu/pvr/handle.c @@ -0,0 +1,1442 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <stddef.h> + +#include "services_headers.h" +#include "handle.h" + +#ifdef CONFIG_PVR_DEBUG_EXTRA +#define HANDLE_BLOCK_SIZE 1 +#else +#define HANDLE_BLOCK_SIZE 256 +#endif + +#define HANDLE_HASH_TAB_INIT_SIZE 32 + +#define DEFAULT_MAX_INDEX_PLUS_ONE 0xfffffffful +#define DEFAULT_MAX_HANDLE DEFAULT_MAX_INDEX_PLUS_ONE + +#define INDEX_IS_VALID(psBase, i) ((i) < (psBase)->ui32TotalHandCount) + +#define INDEX_TO_HANDLE(psBase, idx) ((void *)((idx) + 1)) +#define HANDLE_TO_INDEX(psBase, hand) ((u32)(hand) - 1) + +#define INDEX_TO_HANDLE_PTR(psBase, i) (((psBase)->psHandleArray) + (i)) + +#define HANDLE_TO_HANDLE_PTR(psBase, h) \ + (INDEX_TO_HANDLE_PTR(psBase, HANDLE_TO_INDEX(psBase, h))) + +#define HANDLE_PTR_TO_INDEX(psBase, psHandle) \ + ((psHandle) - ((psBase)->psHandleArray)) + +#define HANDLE_PTR_TO_HANDLE(psBase, psHandle) \ + INDEX_TO_HANDLE(psBase, HANDLE_PTR_TO_INDEX(psBase, psHandle)) + +#define ROUND_UP_TO_MULTIPLE(a, b) ((((a) + (b) - 1) / (b)) * (b)) + +#define HANDLES_BATCHED(psBase) ((psBase)->ui32HandBatchSize != 0) + +#define SET_FLAG(v, f) ((void)((v) |= (f))) +#define CLEAR_FLAG(v, f) ((void)((v) &= ~(f))) +#define TEST_FLAG(v, f) ((IMG_BOOL)(((v) & (f)) != 0)) + +#define TEST_ALLOC_FLAG(psHandle, f) \ + TEST_FLAG((psHandle)->eFlag, f) + +#define SET_INTERNAL_FLAG(psHandle, f) \ + SET_FLAG((psHandle)->eInternalFlag, f) +#define CLEAR_INTERNAL_FLAG(psHandle, f) \ + CLEAR_FLAG((psHandle)->eInternalFlag, f) +#define TEST_INTERNAL_FLAG(psHandle, f) \ + TEST_FLAG((psHandle)->eInternalFlag, f) + +#define BATCHED_HANDLE(psHandle) \ + TEST_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED) + +#define SET_BATCHED_HANDLE(psHandle) \ + SET_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED) + +#define SET_UNBATCHED_HANDLE(psHandle) \ + CLEAR_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED) + +#define BATCHED_HANDLE_PARTIALLY_FREE(psHandle) \ + TEST_INTERNAL_FLAG(psHandle, \ + INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE) + +#define SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle) \ + SET_INTERNAL_FLAG(psHandle, \ + INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE) + +#define HANDLE_STRUCT_IS_FREE(psHandle) \ + ((psHandle)->eType == PVRSRV_HANDLE_TYPE_NONE && \ + (psHandle)->eInternalFlag == INTERNAL_HANDLE_FLAG_NONE) + +#ifdef MIN +#undef MIN +#endif + +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +struct sHandleList { + u32 ui32Prev; + u32 ui32Next; + void *hParent; +}; + +enum ePVRSRVInternalHandleFlag { + INTERNAL_HANDLE_FLAG_NONE = 0x00, + INTERNAL_HANDLE_FLAG_BATCHED = 0x01, + INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE = 0x02, +}; + +struct sHandle { + enum PVRSRV_HANDLE_TYPE eType; + void *pvData; + u32 ui32NextIndexPlusOne; + enum ePVRSRVInternalHandleFlag eInternalFlag; + enum PVRSRV_HANDLE_ALLOC_FLAG eFlag; + + u32 ui32Index; + struct sHandleList sChildren; + struct sHandleList sSiblings; +}; + +struct PVRSRV_HANDLE_BASE { + void *hBaseBlockAlloc; + + void *hHandBlockAlloc; + + struct sHandle *psHandleArray; + struct HASH_TABLE *psHashTab; + u32 ui32FreeHandCount; + u32 ui32FirstFreeIndex; + + u32 ui32MaxIndexPlusOne; + + u32 ui32TotalHandCount; + u32 ui32LastFreeIndexPlusOne; + u32 ui32HandBatchSize; + u32 ui32TotalHandCountPreBatch; + u32 ui32FirstBatchIndexPlusOne; + u32 ui32BatchHandAllocFailures; + + IMG_BOOL bPurgingEnabled; +}; + +enum eHandKey { + HAND_KEY_DATA = 0, + HAND_KEY_TYPE, + HAND_KEY_PARENT, + HAND_KEY_LEN +}; + +struct PVRSRV_HANDLE_BASE *gpsKernelHandleBase; + +static inline void HandleListInit(u32 ui32Index, struct sHandleList *psList, + void *hParent) +{ + psList->ui32Next = ui32Index; + psList->ui32Prev = ui32Index; + psList->hParent = hParent; +} + +static inline void InitParentList(struct PVRSRV_HANDLE_BASE *psBase, + struct sHandle *psHandle) +{ + u32 ui32Parent = HANDLE_PTR_TO_INDEX(psBase, psHandle); + + HandleListInit(ui32Parent, &psHandle->sChildren, + INDEX_TO_HANDLE(psBase, ui32Parent)); +} + +static inline void InitChildEntry(struct PVRSRV_HANDLE_BASE *psBase, + struct sHandle *psHandle) +{ + HandleListInit(HANDLE_PTR_TO_INDEX(psBase, psHandle), + &psHandle->sSiblings, NULL); +} + +static inline IMG_BOOL HandleListIsEmpty(u32 ui32Index, + struct sHandleList *psList) +{ + IMG_BOOL bIsEmpty; + + bIsEmpty = (IMG_BOOL) (psList->ui32Next == ui32Index); + +#ifdef CONFIG_PVR_DEBUG_EXTRA + { + IMG_BOOL bIsEmpty2; + + bIsEmpty2 = (IMG_BOOL) (psList->ui32Prev == ui32Index); + PVR_ASSERT(bIsEmpty == bIsEmpty2); + } +#endif + + return bIsEmpty; +} + +#ifdef CONFIG_PVR_DEBUG +static inline IMG_BOOL NoChildren(struct PVRSRV_HANDLE_BASE *psBase, + struct sHandle *psHandle) +{ + PVR_ASSERT(psHandle->sChildren.hParent == + HANDLE_PTR_TO_HANDLE(psBase, psHandle)); + + return HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psBase, psHandle), + &psHandle->sChildren); +} + +static inline IMG_BOOL NoParent(struct PVRSRV_HANDLE_BASE *psBase, + struct sHandle *psHandle) +{ + if (HandleListIsEmpty + (HANDLE_PTR_TO_INDEX(psBase, psHandle), &psHandle->sSiblings)) { + PVR_ASSERT(psHandle->sSiblings.hParent == NULL); + + return IMG_TRUE; + } else { + PVR_ASSERT(psHandle->sSiblings.hParent != NULL); + } + return IMG_FALSE; +} +#endif +static inline void *ParentHandle(struct sHandle *psHandle) +{ + return psHandle->sSiblings.hParent; +} + +#define LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, i, p, po, eo) \ + ((struct sHandleList *) \ + ((char *)(INDEX_TO_HANDLE_PTR(psBase, i)) + \ + (((i) == (p)) ? (po) : (eo)))) + +static inline void HandleListInsertBefore(struct PVRSRV_HANDLE_BASE *psBase, + u32 ui32InsIndex, struct sHandleList *psIns, + size_t uiParentOffset, u32 ui32EntryIndex, + struct sHandleList *psEntry, + size_t uiEntryOffset, u32 ui32ParentIndex) +{ + struct sHandleList *psPrevIns = + LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psIns->ui32Prev, + ui32ParentIndex, uiParentOffset, + uiEntryOffset); + + PVR_ASSERT(psEntry->hParent == NULL); + PVR_ASSERT(ui32InsIndex == psPrevIns->ui32Next); + PVR_ASSERT(LIST_PTR_FROM_INDEX_AND_OFFSET + (psBase, ui32ParentIndex, ui32ParentIndex, uiParentOffset, + uiParentOffset)->hParent == INDEX_TO_HANDLE(psBase, + ui32ParentIndex)); + + psEntry->ui32Prev = psIns->ui32Prev; + psIns->ui32Prev = ui32EntryIndex; + psEntry->ui32Next = ui32InsIndex; + psPrevIns->ui32Next = ui32EntryIndex; + + psEntry->hParent = INDEX_TO_HANDLE(psBase, ui32ParentIndex); +} + +static inline void AdoptChild(struct PVRSRV_HANDLE_BASE *psBase, + struct sHandle *psParent, struct sHandle *psChild) +{ + u32 ui32Parent = + HANDLE_TO_INDEX(psBase, psParent->sChildren.hParent); + + PVR_ASSERT(ui32Parent == + (u32) HANDLE_PTR_TO_INDEX(psBase, psParent)); + + HandleListInsertBefore(psBase, ui32Parent, &psParent->sChildren, + offsetof(struct sHandle, sChildren), + HANDLE_PTR_TO_INDEX(psBase, psChild), + &psChild->sSiblings, offsetof(struct sHandle, + sSiblings), + ui32Parent); + +} + +static inline void HandleListRemove(struct PVRSRV_HANDLE_BASE *psBase, + u32 ui32EntryIndex, struct sHandleList *psEntry, + size_t uiEntryOffset, size_t uiParentOffset) +{ + if (!HandleListIsEmpty(ui32EntryIndex, psEntry)) { + struct sHandleList *psPrev = + LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Prev, + HANDLE_TO_INDEX(psBase, + psEntry-> + hParent), + uiParentOffset, + uiEntryOffset); + struct sHandleList *psNext = + LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Next, + HANDLE_TO_INDEX(psBase, + psEntry-> + hParent), + uiParentOffset, + uiEntryOffset); + + PVR_ASSERT(psEntry->hParent != NULL); + + psPrev->ui32Next = psEntry->ui32Next; + psNext->ui32Prev = psEntry->ui32Prev; + + HandleListInit(ui32EntryIndex, psEntry, NULL); + } +} + +static inline void UnlinkFromParent(struct PVRSRV_HANDLE_BASE *psBase, + struct sHandle *psHandle) +{ + HandleListRemove(psBase, HANDLE_PTR_TO_INDEX(psBase, psHandle), + &psHandle->sSiblings, offsetof(struct sHandle, + sSiblings), + offsetof(struct sHandle, sChildren)); +} + +static inline enum PVRSRV_ERROR HandleListIterate( + struct PVRSRV_HANDLE_BASE *psBase, struct sHandleList *psHead, + size_t uiParentOffset, size_t uiEntryOffset, + enum PVRSRV_ERROR(*pfnIterFunc)(struct PVRSRV_HANDLE_BASE *, + struct sHandle *)) +{ + u32 ui32Index; + u32 ui32Parent = HANDLE_TO_INDEX(psBase, psHead->hParent); + + PVR_ASSERT(psHead->hParent != NULL); + + for (ui32Index = psHead->ui32Next; ui32Index != ui32Parent;) { + struct sHandle *psHandle = + INDEX_TO_HANDLE_PTR(psBase, ui32Index); + struct sHandleList *psEntry = + LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32Index, + ui32Parent, uiParentOffset, + uiEntryOffset); + enum PVRSRV_ERROR eError; + + PVR_ASSERT(psEntry->hParent == psHead->hParent); + + ui32Index = psEntry->ui32Next; + + eError = (*pfnIterFunc)(psBase, psHandle); + if (eError != PVRSRV_OK) + return eError; + } + + return PVRSRV_OK; +} + +static inline enum PVRSRV_ERROR IterateOverChildren( + struct PVRSRV_HANDLE_BASE *psBase, + struct sHandle *psParent, + enum PVRSRV_ERROR(*pfnIterFunc) + (struct PVRSRV_HANDLE_BASE *, struct sHandle *)) +{ + return HandleListIterate(psBase, &psParent->sChildren, + offsetof(struct sHandle, sChildren), + offsetof(struct sHandle, sSiblings), + pfnIterFunc); +} + +static inline enum PVRSRV_ERROR GetHandleStructure( + struct PVRSRV_HANDLE_BASE *psBase, + struct sHandle **ppsHandle, void *hHandle, + enum PVRSRV_HANDLE_TYPE eType) +{ + u32 ui32Index = HANDLE_TO_INDEX(psBase, hHandle); + struct sHandle *psHandle; + + if (!INDEX_IS_VALID(psBase, ui32Index)) { + PVR_DPF(PVR_DBG_ERROR, + "GetHandleStructure: Handle index out of range (%u >= %u)", + ui32Index, psBase->ui32TotalHandCount); + return PVRSRV_ERROR_GENERIC; + } + + psHandle = INDEX_TO_HANDLE_PTR(psBase, ui32Index); + if (psHandle->eType == PVRSRV_HANDLE_TYPE_NONE) { + PVR_DPF(PVR_DBG_ERROR, + "GetHandleStructure: Handle not allocated (index: %u)", + ui32Index); + return PVRSRV_ERROR_GENERIC; + } + + if (eType != PVRSRV_HANDLE_TYPE_NONE && eType != psHandle->eType) { + PVR_DPF(PVR_DBG_ERROR, + "GetHandleStructure: Handle type mismatch (%d != %d)", + eType, psHandle->eType); + return PVRSRV_ERROR_GENERIC; + } + + *ppsHandle = psHandle; + + return PVRSRV_OK; +} + +static inline void *ParentIfPrivate(struct sHandle *psHandle) +{ + return TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ? + ParentHandle(psHandle) : NULL; +} + +static inline void InitKey(u32 aKey[HAND_KEY_LEN], + struct PVRSRV_HANDLE_BASE *psBase, + void *pvData, enum PVRSRV_HANDLE_TYPE eType, + void *hParent) +{ + PVR_UNREFERENCED_PARAMETER(psBase); + + aKey[HAND_KEY_DATA] = (u32) pvData; + aKey[HAND_KEY_TYPE] = (u32) eType; + aKey[HAND_KEY_PARENT] = (u32) hParent; +} + +static void FreeHandleArray(struct PVRSRV_HANDLE_BASE *psBase) +{ + if (psBase->psHandleArray != NULL) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + psBase->ui32TotalHandCount * + sizeof(struct sHandle), + psBase->psHandleArray, + psBase->hHandBlockAlloc); + psBase->psHandleArray = NULL; + } +} + +static enum PVRSRV_ERROR FreeHandle(struct PVRSRV_HANDLE_BASE *psBase, + struct sHandle *psHandle) +{ + u32 aKey[HAND_KEY_LEN]; + u32 ui32Index = HANDLE_PTR_TO_INDEX(psBase, psHandle); + enum PVRSRV_ERROR eError; + + InitKey(aKey, psBase, psHandle->pvData, psHandle->eType, + ParentIfPrivate(psHandle)); + + if (!TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_MULTI) && + !BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) { + void *hHandle; + hHandle = (void *)HASH_Remove_Extended(psBase->psHashTab, aKey); + + PVR_ASSERT(hHandle != NULL); + PVR_ASSERT(hHandle == INDEX_TO_HANDLE(psBase, ui32Index)); + PVR_UNREFERENCED_PARAMETER(hHandle); + } + + UnlinkFromParent(psBase, psHandle); + + eError = IterateOverChildren(psBase, psHandle, FreeHandle); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "FreeHandle: Error whilst freeing subhandles (%d)", + eError); + return eError; + } + + psHandle->eType = PVRSRV_HANDLE_TYPE_NONE; + + if (BATCHED_HANDLE(psHandle) && + !BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) { + SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle); + return PVRSRV_OK; + } + + if (!psBase->bPurgingEnabled) { + if (psBase->ui32FreeHandCount == 0) { + PVR_ASSERT(psBase->ui32FirstFreeIndex == 0); + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0); + + psBase->ui32FirstFreeIndex = ui32Index; + } else { + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0); + PVR_ASSERT(INDEX_TO_HANDLE_PTR + (psBase, + psBase->ui32LastFreeIndexPlusOne - + 1)->ui32NextIndexPlusOne == 0); + INDEX_TO_HANDLE_PTR(psBase, + psBase->ui32LastFreeIndexPlusOne - + 1)->ui32NextIndexPlusOne = + ui32Index + 1; + } + PVR_ASSERT(psHandle->ui32NextIndexPlusOne == 0); + psBase->ui32LastFreeIndexPlusOne = ui32Index + 1; + } + + psBase->ui32FreeHandCount++; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR FreeAllHandles(struct PVRSRV_HANDLE_BASE *psBase) +{ + u32 i; + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (psBase->ui32FreeHandCount == psBase->ui32TotalHandCount) + return eError; + + for (i = 0; i < psBase->ui32TotalHandCount; i++) { + struct sHandle *psHandle; + + psHandle = INDEX_TO_HANDLE_PTR(psBase, i); + + if (psHandle->eType != PVRSRV_HANDLE_TYPE_NONE) { + eError = FreeHandle(psBase, psHandle); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "FreeAllHandles: FreeHandle failed (%d)", + eError); + break; + } + + if (psBase->ui32FreeHandCount == + psBase->ui32TotalHandCount) + break; + } + } + + return eError; +} + +static enum PVRSRV_ERROR FreeHandleBase(struct PVRSRV_HANDLE_BASE *psBase) +{ + enum PVRSRV_ERROR eError; + + if (HANDLES_BATCHED(psBase)) { + PVR_DPF(PVR_DBG_WARNING, + "FreeHandleBase: Uncommitted/Unreleased handle batch"); + PVRSRVReleaseHandleBatch(psBase); + } + + eError = FreeAllHandles(psBase); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "FreeHandleBase: Couldn't free handles (%d)", eError); + return eError; + } + + FreeHandleArray(psBase); + + if (psBase->psHashTab != NULL) + HASH_Delete(psBase->psHashTab); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psBase), psBase, + psBase->hBaseBlockAlloc); + + return PVRSRV_OK; +} + +static inline void *FindHandle(struct PVRSRV_HANDLE_BASE *psBase, void *pvData, + enum PVRSRV_HANDLE_TYPE eType, void *hParent) +{ + u32 aKey[HAND_KEY_LEN]; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + InitKey(aKey, psBase, pvData, eType, hParent); + + return (void *)HASH_Retrieve_Extended(psBase->psHashTab, aKey); +} + +static enum PVRSRV_ERROR ReallocMem(void **ppvMem, void **phBlockAlloc, + u32 ui32NewSize, u32 ui32OldSize) +{ + void *pvOldMem = *ppvMem; + void *hOldBlockAlloc = *phBlockAlloc; + u32 ui32CopySize = MIN(ui32NewSize, ui32OldSize); + void *pvNewMem = NULL; + void *hNewBlockAlloc = NULL; + enum PVRSRV_ERROR eError; + + if (ui32NewSize == ui32OldSize) + return PVRSRV_OK; + + if (ui32NewSize != 0) { + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + ui32NewSize, &pvNewMem, &hNewBlockAlloc); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "ReallocMem: Couldn't allocate new memory area (%d)", + eError); + return eError; + } + if (ui32OldSize != 0) + OSMemCopy(pvNewMem, pvOldMem, ui32CopySize); + } + + if (ui32OldSize != 0) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32OldSize, pvOldMem, + hOldBlockAlloc); + + *ppvMem = pvNewMem; + *phBlockAlloc = hNewBlockAlloc; + + return PVRSRV_OK; +} + +static inline enum PVRSRV_ERROR ReallocHandleArray(struct PVRSRV_HANDLE_BASE + *psBase, u32 ui32NewCount, + u32 ui32OldCount) +{ + return ReallocMem((void **)&psBase->psHandleArray, + &psBase->hHandBlockAlloc, + ui32NewCount * sizeof(struct sHandle), + ui32OldCount * sizeof(struct sHandle)); +} + +static enum PVRSRV_ERROR IncreaseHandleArraySize(struct PVRSRV_HANDLE_BASE + *psBase, u32 ui32Delta) +{ + enum PVRSRV_ERROR eError; + struct sHandle *psHandle; + u32 ui32DeltaAdjusted = + ROUND_UP_TO_MULTIPLE(ui32Delta, HANDLE_BLOCK_SIZE); + u32 ui32NewTotalHandCount = + psBase->ui32TotalHandCount + ui32DeltaAdjusted; + + PVR_ASSERT(ui32Delta != 0); + + if (ui32NewTotalHandCount > psBase->ui32MaxIndexPlusOne || + ui32NewTotalHandCount <= psBase->ui32TotalHandCount) { + ui32NewTotalHandCount = psBase->ui32MaxIndexPlusOne; + + ui32DeltaAdjusted = + ui32NewTotalHandCount - psBase->ui32TotalHandCount; + + if (ui32DeltaAdjusted < ui32Delta) { + PVR_DPF(PVR_DBG_ERROR, "IncreaseHandleArraySize: " + "Maximum handle limit reached (%d)", + psBase->ui32MaxIndexPlusOne); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + } + + PVR_ASSERT(ui32DeltaAdjusted >= ui32Delta); + + eError = ReallocHandleArray(psBase, ui32NewTotalHandCount, + psBase->ui32TotalHandCount); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "IncreaseHandleArraySize: " + "ReallocHandleArray failed (%d)", + eError); + return eError; + } + + for (psHandle = psBase->psHandleArray + psBase->ui32TotalHandCount; + psHandle < psBase->psHandleArray + ui32NewTotalHandCount; + psHandle++) { + psHandle->eType = PVRSRV_HANDLE_TYPE_NONE; + psHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE; + psHandle->ui32NextIndexPlusOne = 0; + } + + psBase->ui32FreeHandCount += ui32DeltaAdjusted; + + if (psBase->ui32FirstFreeIndex == 0) { + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0); + + psBase->ui32FirstFreeIndex = psBase->ui32TotalHandCount; + } else { + if (!psBase->bPurgingEnabled) { + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0); + PVR_ASSERT(INDEX_TO_HANDLE_PTR + (psBase, + psBase->ui32LastFreeIndexPlusOne - + 1)->ui32NextIndexPlusOne == 0); + + INDEX_TO_HANDLE_PTR(psBase, + psBase->ui32LastFreeIndexPlusOne - + 1)->ui32NextIndexPlusOne = + psBase->ui32TotalHandCount + 1; + } + } + + if (!psBase->bPurgingEnabled) + psBase->ui32LastFreeIndexPlusOne = ui32NewTotalHandCount; + + psBase->ui32TotalHandCount = ui32NewTotalHandCount; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR EnsureFreeHandles(struct PVRSRV_HANDLE_BASE *psBase, + u32 ui32Free) +{ + enum PVRSRV_ERROR eError; + + if (ui32Free > psBase->ui32FreeHandCount) { + u32 ui32FreeHandDelta = + ui32Free - psBase->ui32FreeHandCount; + eError = IncreaseHandleArraySize(psBase, ui32FreeHandDelta); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "EnsureFreeHandles: " + "Couldn't allocate %u handles to ensure %u " + "free handles (IncreaseHandleArraySize " + "failed with error %d)", + ui32FreeHandDelta, ui32Free, eError); + + return eError; + } + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR AllocHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phHandle, void *pvData, + enum PVRSRV_HANDLE_TYPE eType, + enum PVRSRV_HANDLE_ALLOC_FLAG eFlag, + void *hParent) +{ + u32 ui32NewIndex; + struct sHandle *psNewHandle = NULL; + void *hHandle; + u32 aKey[HAND_KEY_LEN]; + enum PVRSRV_ERROR eError; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + PVR_ASSERT(psBase->psHashTab != NULL); + + if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) + PVR_ASSERT(FindHandle(psBase, pvData, eType, hParent) == NULL); + + if (psBase->ui32FreeHandCount == 0 && HANDLES_BATCHED(psBase)) + PVR_DPF(PVR_DBG_WARNING, "AllocHandle: " + "Handle batch size (%u) was too small, " + "allocating additional space", + psBase->ui32HandBatchSize); + + eError = EnsureFreeHandles(psBase, 1); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "AllocHandle: EnsureFreeHandles failed (%d)", eError); + return eError; + } + PVR_ASSERT(psBase->ui32FreeHandCount != 0); + + if (!psBase->bPurgingEnabled) { + ui32NewIndex = psBase->ui32FirstFreeIndex; + psNewHandle = INDEX_TO_HANDLE_PTR(psBase, ui32NewIndex); + } else { + for (ui32NewIndex = psBase->ui32FirstFreeIndex; + ui32NewIndex < psBase->ui32TotalHandCount; + ui32NewIndex++) { + psNewHandle = INDEX_TO_HANDLE_PTR(psBase, ui32NewIndex); + if (HANDLE_STRUCT_IS_FREE(psNewHandle)) + break; + + } + psBase->ui32FirstFreeIndex = 0; + PVR_ASSERT(ui32NewIndex < psBase->ui32TotalHandCount); + } + PVR_ASSERT(psNewHandle != NULL); + + hHandle = INDEX_TO_HANDLE(psBase, ui32NewIndex); + + if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) { + + InitKey(aKey, psBase, pvData, eType, hParent); + + if (!HASH_Insert_Extended + (psBase->psHashTab, aKey, (u32) hHandle)) { + PVR_DPF(PVR_DBG_ERROR, "AllocHandle: " + "Couldn't add handle to hash table"); + + return PVRSRV_ERROR_GENERIC; + } + } + + psBase->ui32FreeHandCount--; + + if (!psBase->bPurgingEnabled) { + if (psBase->ui32FreeHandCount == 0) { + PVR_ASSERT(psBase->ui32FirstFreeIndex == ui32NewIndex); + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == + (ui32NewIndex + 1)); + + psBase->ui32LastFreeIndexPlusOne = 0; + psBase->ui32FirstFreeIndex = 0; + } else { + psBase->ui32FirstFreeIndex = + (psNewHandle->ui32NextIndexPlusOne == + 0) ? ui32NewIndex + + 1 : psNewHandle->ui32NextIndexPlusOne - 1; + } + } + + psNewHandle->eType = eType; + psNewHandle->pvData = pvData; + psNewHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE; + psNewHandle->eFlag = eFlag; + psNewHandle->ui32Index = ui32NewIndex; + + InitParentList(psBase, psNewHandle); + PVR_ASSERT(NoChildren(psBase, psNewHandle)); + + InitChildEntry(psBase, psNewHandle); + PVR_ASSERT(NoParent(psBase, psNewHandle)); + + if (HANDLES_BATCHED(psBase)) { + + psNewHandle->ui32NextIndexPlusOne = + psBase->ui32FirstBatchIndexPlusOne; + + psBase->ui32FirstBatchIndexPlusOne = ui32NewIndex + 1; + + SET_BATCHED_HANDLE(psNewHandle); + } else { + psNewHandle->ui32NextIndexPlusOne = 0; + } + + *phHandle = hHandle; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVAllocHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phHandle, void *pvData, + enum PVRSRV_HANDLE_TYPE eType, + enum PVRSRV_HANDLE_ALLOC_FLAG eFlag) +{ + void *hHandle; + enum PVRSRV_ERROR eError; + + *phHandle = NULL; + + if (HANDLES_BATCHED(psBase)) + psBase->ui32BatchHandAllocFailures++; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) { + hHandle = FindHandle(psBase, pvData, eType, NULL); + if (hHandle != NULL) { + struct sHandle *psHandle; + + eError = + GetHandleStructure(psBase, &psHandle, hHandle, + eType); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVAllocHandle: " + "Lookup of existing handle failed"); + return eError; + } + + if (TEST_FLAG(psHandle->eFlag & eFlag, + PVRSRV_HANDLE_ALLOC_FLAG_SHARED)) { + *phHandle = hHandle; + eError = PVRSRV_OK; + goto exit_ok; + } + return PVRSRV_ERROR_GENERIC; + } + } + + eError = AllocHandle(psBase, phHandle, pvData, eType, eFlag, NULL); + +exit_ok: + if (HANDLES_BATCHED(psBase) && (eError == PVRSRV_OK)) + psBase->ui32BatchHandAllocFailures--; + + return eError; +} + +enum PVRSRV_ERROR PVRSRVAllocSubHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phHandle, void *pvData, + enum PVRSRV_HANDLE_TYPE eType, + enum PVRSRV_HANDLE_ALLOC_FLAG eFlag, + void *hParent) +{ + struct sHandle *psPHand; + struct sHandle *psCHand; + enum PVRSRV_ERROR eError; + void *hParentKey; + void *hHandle; + + *phHandle = NULL; + + if (HANDLES_BATCHED(psBase)) + + psBase->ui32BatchHandAllocFailures++; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + hParentKey = TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ? + hParent : NULL; + + eError = GetHandleStructure(psBase, &psPHand, hParent, + PVRSRV_HANDLE_TYPE_NONE); + if (eError != PVRSRV_OK) + return PVRSRV_ERROR_GENERIC; + + if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) { + + hHandle = FindHandle(psBase, pvData, eType, hParentKey); + if (hHandle != NULL) { + struct sHandle *psCHandle; + enum PVRSRV_ERROR eErr; + + eErr = GetHandleStructure(psBase, &psCHandle, hHandle, + eType); + if (eErr != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocSubHandle: " + "Lookup of existing handle failed"); + return eErr; + } + + PVR_ASSERT(hParentKey != NULL && + ParentHandle(HANDLE_TO_HANDLE_PTR + (psBase, hHandle)) == hParent); + + if (TEST_FLAG(psCHandle->eFlag & eFlag, + PVRSRV_HANDLE_ALLOC_FLAG_SHARED) && + ParentHandle(HANDLE_TO_HANDLE_PTR(psBase, hHandle)) + == hParent) { + *phHandle = hHandle; + goto exit_ok; + } + return PVRSRV_ERROR_GENERIC; + } + } + + eError = AllocHandle(psBase, &hHandle, pvData, eType, eFlag, + hParentKey); + if (eError != PVRSRV_OK) + return eError; + + psPHand = HANDLE_TO_HANDLE_PTR(psBase, hParent); + + psCHand = HANDLE_TO_HANDLE_PTR(psBase, hHandle); + + AdoptChild(psBase, psPHand, psCHand); + + *phHandle = hHandle; + +exit_ok: + if (HANDLES_BATCHED(psBase)) + psBase->ui32BatchHandAllocFailures--; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVFindHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phHandle, void *pvData, + enum PVRSRV_HANDLE_TYPE eType) +{ + void *hHandle; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + hHandle = (void *)FindHandle(psBase, pvData, eType, NULL); + if (hHandle == NULL) + return PVRSRV_ERROR_GENERIC; + + *phHandle = hHandle; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVLookupHandleAnyType(struct PVRSRV_HANDLE_BASE *psBase, + void **ppvData, + enum PVRSRV_HANDLE_TYPE *peType, + void *hHandle) +{ + struct sHandle *psHandle; + enum PVRSRV_ERROR eError; + + eError = GetHandleStructure(psBase, &psHandle, hHandle, + PVRSRV_HANDLE_TYPE_NONE); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupHandleAnyType: " + "Error looking up handle (%d)", + eError); + return eError; + } + + *ppvData = psHandle->pvData; + *peType = psHandle->eType; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVLookupHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **ppvData, void *hHandle, + enum PVRSRV_HANDLE_TYPE eType) +{ + struct sHandle *psHandle; + enum PVRSRV_ERROR eError; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVLookupHandle: Error looking up handle (%d)", + eError); + return eError; + } + + *ppvData = psHandle->pvData; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVLookupSubHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **ppvData, void *hHandle, + enum PVRSRV_HANDLE_TYPE eType, + void *hAncestor) +{ + struct sHandle *psPHand; + struct sHandle *psCHand; + enum PVRSRV_ERROR eError; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + eError = GetHandleStructure(psBase, &psCHand, hHandle, eType); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupSubHandle: " + "Error looking up subhandle (%d)", + eError); + return eError; + } + + for (psPHand = psCHand; ParentHandle(psPHand) != hAncestor;) { + eError = + GetHandleStructure(psBase, &psPHand, ParentHandle(psPHand), + PVRSRV_HANDLE_TYPE_NONE); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupSubHandle: " + "Subhandle doesn't belong to given ancestor"); + return PVRSRV_ERROR_GENERIC; + } + } + + *ppvData = psCHand->pvData; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVGetParentHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phParent, void *hHandle, + enum PVRSRV_HANDLE_TYPE eType) +{ + struct sHandle *psHandle; + enum PVRSRV_ERROR eError; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVGetParentHandle: " + "Error looking up subhandle (%d)", + eError); + return eError; + } + + *phParent = ParentHandle(psHandle); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVLookupAndReleaseHandle( + struct PVRSRV_HANDLE_BASE *psBase, + void **ppvData, void *hHandle, + enum PVRSRV_HANDLE_TYPE eType) +{ + struct sHandle *psHandle; + enum PVRSRV_ERROR eError; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupAndReleaseHandle: " + "Error looking up handle (%d)", + eError); + return eError; + } + + *ppvData = psHandle->pvData; + + eError = FreeHandle(psBase, psHandle); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVReleaseHandle(struct PVRSRV_HANDLE_BASE *psBase, + void *hHandle, enum PVRSRV_HANDLE_TYPE eType) +{ + struct sHandle *psHandle; + enum PVRSRV_ERROR eError; + + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + + eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVReleaseHandle: Error looking up handle (%d)", + eError); + return eError; + } + + eError = FreeHandle(psBase, psHandle); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVNewHandleBatch(struct PVRSRV_HANDLE_BASE *psBase, + u32 ui32BatchSize) +{ + enum PVRSRV_ERROR eError; + + if (HANDLES_BATCHED(psBase)) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVNewHandleBatch: " + "There is a handle batch already in use (size %u)", + psBase->ui32HandBatchSize); + return PVRSRV_ERROR_GENERIC; + } + + if (ui32BatchSize == 0) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVNewHandleBatch: Invalid batch size (%u)", + ui32BatchSize); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + eError = EnsureFreeHandles(psBase, ui32BatchSize); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVNewHandleBatch: " + "EnsureFreeHandles failed (error %d)", + eError); + return eError; + } + + psBase->ui32HandBatchSize = ui32BatchSize; + psBase->ui32TotalHandCountPreBatch = psBase->ui32TotalHandCount; + + PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0); + PVR_ASSERT(psBase->ui32FirstBatchIndexPlusOne == 0); + PVR_ASSERT(HANDLES_BATCHED(psBase)); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease( + struct PVRSRV_HANDLE_BASE *psBase, IMG_BOOL bCommit) +{ + u32 ui32IndexPlusOne; + IMG_BOOL bCommitBatch = bCommit; + + if (!HANDLES_BATCHED(psBase)) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: " + "There is no handle batch"); + return PVRSRV_ERROR_INVALID_PARAMS; + + } + + if (psBase->ui32BatchHandAllocFailures != 0) { + if (bCommit) + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVHandleBatchCommitOrRelease: " + "Attempting to commit batch with handle " + "allocation failures."); + bCommitBatch = IMG_FALSE; + } + + PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0 || !bCommit); + + ui32IndexPlusOne = psBase->ui32FirstBatchIndexPlusOne; + while (ui32IndexPlusOne != 0) { + struct sHandle *psHandle = + INDEX_TO_HANDLE_PTR(psBase, ui32IndexPlusOne - 1); + u32 ui32NextIndexPlusOne = + psHandle->ui32NextIndexPlusOne; + PVR_ASSERT(BATCHED_HANDLE(psHandle)); + + psHandle->ui32NextIndexPlusOne = 0; + + if (!bCommitBatch || BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) { + enum PVRSRV_ERROR eError; + + if (!BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) + SET_UNBATCHED_HANDLE(psHandle); + + eError = FreeHandle(psBase, psHandle); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVHandleBatchCommitOrRelease: " + "Error freeing handle (%d)", + eError); + PVR_ASSERT(eError == PVRSRV_OK); + } else { + SET_UNBATCHED_HANDLE(psHandle); + } + + ui32IndexPlusOne = ui32NextIndexPlusOne; + } + +#ifdef CONFIG_PVR_DEBUG_EXTRA + if (psBase->ui32TotalHandCountPreBatch != psBase->ui32TotalHandCount) { + u32 ui32Delta = + psBase->ui32TotalHandCount - + psBase->ui32TotalHandCountPreBatch; + + PVR_ASSERT(psBase->ui32TotalHandCount > + psBase->ui32TotalHandCountPreBatch); + + PVR_DPF(PVR_DBG_WARNING, + "PVRSRVHandleBatchCommitOrRelease: " + "The batch size was too small. " + "Batch size was %u, but needs to be %u", + psBase->ui32HandBatchSize, + psBase->ui32HandBatchSize + ui32Delta); + + } +#endif + + psBase->ui32HandBatchSize = 0; + psBase->ui32FirstBatchIndexPlusOne = 0; + psBase->ui32TotalHandCountPreBatch = 0; + psBase->ui32BatchHandAllocFailures = 0; + + if (psBase->ui32BatchHandAllocFailures != 0 && bCommit) { + PVR_ASSERT(!bCommitBatch); + + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVCommitHandleBatch(struct PVRSRV_HANDLE_BASE *psBase) +{ + return PVRSRVHandleBatchCommitOrRelease(psBase, IMG_TRUE); +} + +void PVRSRVReleaseHandleBatch(struct PVRSRV_HANDLE_BASE *psBase) +{ + (void)PVRSRVHandleBatchCommitOrRelease(psBase, IMG_FALSE); +} + +enum PVRSRV_ERROR PVRSRVSetMaxHandle(struct PVRSRV_HANDLE_BASE *psBase, + u32 ui32MaxHandle) +{ + if (HANDLES_BATCHED(psBase)) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVSetMaxHandle: " + "Limit cannot be set whilst in batch mode"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + if (ui32MaxHandle == 0 || ui32MaxHandle > DEFAULT_MAX_HANDLE) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVSetMaxHandle: " + "Limit must be between %u and %u, inclusive", + 0, DEFAULT_MAX_HANDLE); + + return PVRSRV_ERROR_INVALID_PARAMS; + } + + if (psBase->ui32TotalHandCount != 0) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVSetMaxHandle: " + "Limit cannot be set becuase handles " + "have already been allocated"); + + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psBase->ui32MaxIndexPlusOne = ui32MaxHandle; + + return PVRSRV_OK; +} + +u32 PVRSRVGetMaxHandle(struct PVRSRV_HANDLE_BASE *psBase) +{ + return psBase->ui32MaxIndexPlusOne; +} + +enum PVRSRV_ERROR PVRSRVEnableHandlePurging(struct PVRSRV_HANDLE_BASE *psBase) +{ + if (psBase->bPurgingEnabled) { + PVR_DPF(PVR_DBG_WARNING, + "PVRSRVEnableHandlePurging: Purging already enabled"); + return PVRSRV_OK; + } + + if (psBase->ui32TotalHandCount != 0) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVEnableHandlePurging: " + "Handles have already been allocated"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psBase->bPurgingEnabled = IMG_TRUE; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVPurgeHandles(struct PVRSRV_HANDLE_BASE *psBase) +{ + u32 ui32Handle; + u32 ui32NewHandCount; + + if (!psBase->bPurgingEnabled) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPurgeHandles: " + "Purging not enabled for this handle base"); + return PVRSRV_ERROR_NOT_SUPPORTED; + } + + if (HANDLES_BATCHED(psBase)) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPurgeHandles: " + "Purging not allowed whilst in batch mode"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + for (ui32Handle = psBase->ui32TotalHandCount; ui32Handle != 0; + ui32Handle--) { + struct sHandle *psHandle = + HANDLE_TO_HANDLE_PTR(psBase, ui32Handle); + if (!HANDLE_STRUCT_IS_FREE(psHandle)) + break; + } + + ui32NewHandCount = ROUND_UP_TO_MULTIPLE(ui32Handle, HANDLE_BLOCK_SIZE); + + if (ui32NewHandCount >= ui32Handle + && ui32NewHandCount <= (psBase->ui32TotalHandCount / 2)) { + u32 ui32Delta = psBase->ui32TotalHandCount - ui32NewHandCount; + enum PVRSRV_ERROR eError; + + eError = + ReallocHandleArray(psBase, ui32NewHandCount, + psBase->ui32TotalHandCount); + if (eError != PVRSRV_OK) + return eError; + + psBase->ui32TotalHandCount = ui32NewHandCount; + psBase->ui32FreeHandCount -= ui32Delta; + psBase->ui32FirstFreeIndex = 0; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVAllocHandleBase(struct PVRSRV_HANDLE_BASE **ppsBase) +{ + struct PVRSRV_HANDLE_BASE *psBase; + void *hBlockAlloc; + enum PVRSRV_ERROR eError; + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(*psBase), (void **)&psBase, &hBlockAlloc); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocHandleBase: " + "Couldn't allocate handle base (%d)", + eError); + return eError; + } + OSMemSet(psBase, 0, sizeof(*psBase)); + + psBase->psHashTab = + HASH_Create_Extended(HANDLE_HASH_TAB_INIT_SIZE, + HAND_KEY_LEN * sizeof(u32), + HASH_Func_Default, HASH_Key_Comp_Default); + if (psBase->psHashTab == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocHandleBase: " + "Couldn't create data pointer hash table\n"); + goto failure; + } + + psBase->hBaseBlockAlloc = hBlockAlloc; + + psBase->ui32MaxIndexPlusOne = DEFAULT_MAX_INDEX_PLUS_ONE; + + *ppsBase = psBase; + + return PVRSRV_OK; +failure: + (void)PVRSRVFreeHandleBase(psBase); + return PVRSRV_ERROR_GENERIC; +} + +enum PVRSRV_ERROR PVRSRVFreeHandleBase(struct PVRSRV_HANDLE_BASE *psBase) +{ + enum PVRSRV_ERROR eError; + + PVR_ASSERT(psBase != gpsKernelHandleBase); + + eError = FreeHandleBase(psBase); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVFreeHandleBase: FreeHandleBase failed (%d)", + eError); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVHandleInit(void) +{ + enum PVRSRV_ERROR eError; + + PVR_ASSERT(gpsKernelHandleBase == NULL); + + eError = PVRSRVAllocHandleBase(&gpsKernelHandleBase); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVHandleInit: PVRSRVAllocHandleBase failed (%d)", + eError); + goto error; + } + + eError = PVRSRVEnableHandlePurging(gpsKernelHandleBase); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVHandleInit: " + "PVRSRVEnableHandlePurging failed (%d)", + eError); + goto error; + } + + return PVRSRV_OK; +error: + (void)PVRSRVHandleDeInit(); + return eError; +} + +enum PVRSRV_ERROR PVRSRVHandleDeInit(void) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (gpsKernelHandleBase != NULL) { + eError = FreeHandleBase(gpsKernelHandleBase); + if (eError == PVRSRV_OK) { + gpsKernelHandleBase = NULL; + } else { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVHandleDeInit: " + "FreeHandleBase failed (%d)", + eError); + } + } + + return eError; +} diff --git a/drivers/gpu/pvr/handle.h b/drivers/gpu/pvr/handle.h new file mode 100644 index 00000000000..668e5d8ceb1 --- /dev/null +++ b/drivers/gpu/pvr/handle.h @@ -0,0 +1,150 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __HANDLE_H__ +#define __HANDLE_H__ + +#include "img_types.h" +#include "hash.h" +#include "resman.h" + +enum PVRSRV_HANDLE_TYPE { + PVRSRV_HANDLE_TYPE_NONE = 0, + PVRSRV_HANDLE_TYPE_PERPROC_DATA, + PVRSRV_HANDLE_TYPE_DEV_NODE, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT, + PVRSRV_HANDLE_TYPE_DEV_MEM_HEAP, + PVRSRV_HANDLE_TYPE_MEM_INFO, + PVRSRV_HANDLE_TYPE_SYNC_INFO, + PVRSRV_HANDLE_TYPE_DISP_INFO, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN, + PVRSRV_HANDLE_TYPE_BUF_INFO, + PVRSRV_HANDLE_TYPE_DISP_BUFFER, + PVRSRV_HANDLE_TYPE_BUF_BUFFER, + PVRSRV_HANDLE_TYPE_SGX_HW_RENDER_CONTEXT, + PVRSRV_HANDLE_TYPE_SGX_HW_TRANSFER_CONTEXT, + PVRSRV_HANDLE_TYPE_SGX_HW_2D_CONTEXT, + PVRSRV_HANDLE_TYPE_SHARED_PB_DESC, + PVRSRV_HANDLE_TYPE_MEM_INFO_REF, + PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO, + PVRSRV_HANDLE_TYPE_SHARED_EVENT_OBJECT, + PVRSRV_HANDLE_TYPE_EVENT_OBJECT_CONNECT, + PVRSRV_HANDLE_TYPE_MMAP_INFO, + PVRSRV_HANDLE_TYPE_SOC_TIMER +}; + +enum PVRSRV_HANDLE_ALLOC_FLAG { + PVRSRV_HANDLE_ALLOC_FLAG_NONE = 0, + + PVRSRV_HANDLE_ALLOC_FLAG_SHARED = 0x01, + + PVRSRV_HANDLE_ALLOC_FLAG_MULTI = 0x02, + + PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE = 0x04 +}; + +struct PVRSRV_HANDLE_BASE; +struct PVRSRV_HANDLE_BASE; + +extern struct PVRSRV_HANDLE_BASE *gpsKernelHandleBase; + +#define KERNEL_HANDLE_BASE (gpsKernelHandleBase) + +enum PVRSRV_ERROR PVRSRVAllocHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phHandle, void *pvData, + enum PVRSRV_HANDLE_TYPE eType, + enum PVRSRV_HANDLE_ALLOC_FLAG eFlag); + +enum PVRSRV_ERROR PVRSRVAllocSubHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phHandle, + void *pvData, + enum PVRSRV_HANDLE_TYPE eType, + enum PVRSRV_HANDLE_ALLOC_FLAG eFlag, + void *hParent); + +enum PVRSRV_ERROR PVRSRVFindHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phHandle, void *pvData, + enum PVRSRV_HANDLE_TYPE eType); + +enum PVRSRV_ERROR PVRSRVLookupHandleAnyType(struct PVRSRV_HANDLE_BASE *psBase, + void **ppvData, + enum PVRSRV_HANDLE_TYPE *peType, + void *hHandle); + +enum PVRSRV_ERROR PVRSRVLookupHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **ppvData, void *hHandle, + enum PVRSRV_HANDLE_TYPE eType); + +enum PVRSRV_ERROR PVRSRVLookupSubHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **ppvData, void *hHandle, + enum PVRSRV_HANDLE_TYPE eType, void *hAncestor); + +enum PVRSRV_ERROR PVRSRVGetParentHandle(struct PVRSRV_HANDLE_BASE *psBase, + void **phParent, void *hHandle, + enum PVRSRV_HANDLE_TYPE eType); + +enum PVRSRV_ERROR PVRSRVLookupAndReleaseHandle( + struct PVRSRV_HANDLE_BASE *psBase, + void **ppvData, void *hHandle, + enum PVRSRV_HANDLE_TYPE eType); + +enum PVRSRV_ERROR PVRSRVReleaseHandle(struct PVRSRV_HANDLE_BASE *psBase, + void *hHandle, + enum PVRSRV_HANDLE_TYPE eType); + +enum PVRSRV_ERROR PVRSRVNewHandleBatch(struct PVRSRV_HANDLE_BASE *psBase, + u32 ui32BatchSize); + +enum PVRSRV_ERROR PVRSRVCommitHandleBatch(struct PVRSRV_HANDLE_BASE *psBase); + +void PVRSRVReleaseHandleBatch(struct PVRSRV_HANDLE_BASE *psBase); + +enum PVRSRV_ERROR PVRSRVSetMaxHandle(struct PVRSRV_HANDLE_BASE *psBase, + u32 ui32MaxHandle); + +u32 PVRSRVGetMaxHandle(struct PVRSRV_HANDLE_BASE *psBase); + +enum PVRSRV_ERROR PVRSRVEnableHandlePurging(struct PVRSRV_HANDLE_BASE *psBase); + +enum PVRSRV_ERROR PVRSRVPurgeHandles(struct PVRSRV_HANDLE_BASE *psBase); + +enum PVRSRV_ERROR PVRSRVAllocHandleBase(struct PVRSRV_HANDLE_BASE **ppsBase); + +enum PVRSRV_ERROR PVRSRVFreeHandleBase(struct PVRSRV_HANDLE_BASE *psBase); + +enum PVRSRV_ERROR PVRSRVHandleInit(void); + +enum PVRSRV_ERROR PVRSRVHandleDeInit(void); + + +#define PVRSRVAllocHandleNR(psBase, phHandle, pvData, eType, eFlag) \ + (void)PVRSRVAllocHandle(psBase, phHandle, pvData, eType, eFlag) + +#define PVRSRVAllocSubHandleNR(psBase, phHandle, pvData, eType, eFlag, hParent)\ + (void)PVRSRVAllocSubHandle(psBase, phHandle, pvData, eType, \ + eFlag, hParent) + +#endif diff --git a/drivers/gpu/pvr/hash.c b/drivers/gpu/pvr/hash.c new file mode 100644 index 00000000000..56eacb7e107 --- /dev/null +++ b/drivers/gpu/pvr/hash.c @@ -0,0 +1,379 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "pvr_debug.h" +#include "img_defs.h" +#include "services.h" +#include "servicesint.h" +#include "hash.h" +#include "osfunc.h" + +#define PRIVATE_MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define KEY_TO_INDEX(pHash, key, uSize) \ + ((pHash)->pfnHashFunc((pHash)->uKeySize, key, uSize) % uSize) + +#define KEY_COMPARE(pHash, pKey1, pKey2) \ + ((pHash)->pfnKeyComp((pHash)->uKeySize, pKey1, pKey2)) + +struct BUCKET { + struct BUCKET *pNext; + u32 v; + u32 k[]; +}; +struct BUCKET; + +struct HASH_TABLE { + struct BUCKET **ppBucketTable; + u32 uSize; + u32 uCount; + u32 uMinimumSize; + u32 uKeySize; + u32 (*pfnHashFunc)(size_t uKeySize, void *pkey, u32 uHashTabLen); + IMG_BOOL (*pfnKeyComp)(size_t uKeySize, void *pKey1, void *pkey2); +}; + +u32 HASH_Func_Default(size_t uKeySize, void *pKey, u32 uHashTabLen) +{ + u32 *p = (u32 *) pKey; + u32 uKeyLen = uKeySize / sizeof(u32); + u32 ui; + u32 uHashKey = 0; + + PVR_UNREFERENCED_PARAMETER(uHashTabLen); + + PVR_ASSERT((uKeySize % sizeof(u32)) == 0); + + for (ui = 0; ui < uKeyLen; ui++) { + u32 uHashPart = (u32) *p++; + + uHashPart += (uHashPart << 12); + uHashPart ^= (uHashPart >> 22); + uHashPart += (uHashPart << 4); + uHashPart ^= (uHashPart >> 9); + uHashPart += (uHashPart << 10); + uHashPart ^= (uHashPart >> 2); + uHashPart += (uHashPart << 7); + uHashPart ^= (uHashPart >> 12); + + uHashKey += uHashPart; + } + + return uHashKey; +} + +IMG_BOOL HASH_Key_Comp_Default(size_t uKeySize, void *pKey1, void *pKey2) +{ + u32 *p1 = (u32 *) pKey1; + u32 *p2 = (u32 *) pKey2; + u32 uKeyLen = uKeySize / sizeof(u32); + u32 ui; + + PVR_ASSERT((uKeySize % sizeof(u32)) == 0); + + for (ui = 0; ui < uKeyLen; ui++) + if (*p1++ != *p2++) + return IMG_FALSE; + + return IMG_TRUE; +} + +static enum PVRSRV_ERROR _ChainInsert(struct HASH_TABLE *pHash, + struct BUCKET *pBucket, + struct BUCKET **ppBucketTable, u32 uSize) +{ + u32 uIndex; + + PVR_ASSERT(pBucket != NULL); + PVR_ASSERT(ppBucketTable != NULL); + PVR_ASSERT(uSize != 0); + + if ((pBucket == NULL) || (ppBucketTable == NULL) || (uSize == 0)) { + PVR_DPF(PVR_DBG_ERROR, "_ChainInsert: invalid parameter"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + uIndex = KEY_TO_INDEX(pHash, pBucket->k, uSize); + pBucket->pNext = ppBucketTable[uIndex]; + ppBucketTable[uIndex] = pBucket; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR _Rehash(struct HASH_TABLE *pHash, + struct BUCKET **ppOldTable, u32 uOldSize, + struct BUCKET **ppNewTable, u32 uNewSize) +{ + u32 uIndex; + for (uIndex = 0; uIndex < uOldSize; uIndex++) { + struct BUCKET *pBucket; + pBucket = ppOldTable[uIndex]; + while (pBucket != NULL) { + struct BUCKET *pNextBucket = pBucket->pNext; + if (_ChainInsert(pHash, pBucket, ppNewTable, uNewSize) + != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "_Rehash: call to _ChainInsert failed"); + return PVRSRV_ERROR_GENERIC; + } + pBucket = pNextBucket; + } + } + return PVRSRV_OK; +} + +static IMG_BOOL _Resize(struct HASH_TABLE *pHash, u32 uNewSize) +{ + if (uNewSize != pHash->uSize) { + struct BUCKET **ppNewTable; + u32 uIndex; + + PVR_DPF(PVR_DBG_MESSAGE, + "HASH_Resize: oldsize=0x%x newsize=0x%x count=0x%x", + pHash->uSize, uNewSize, pHash->uCount); + + if (OSAllocMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct BUCKET *) * uNewSize, + (void **) &ppNewTable, NULL) != PVRSRV_OK) + return IMG_FALSE; + + for (uIndex = 0; uIndex < uNewSize; uIndex++) + ppNewTable[uIndex] = NULL; + + if (_Rehash(pHash, pHash->ppBucketTable, pHash->uSize, + ppNewTable, uNewSize) != PVRSRV_OK) + return IMG_FALSE; + + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct BUCKET *) * pHash->uSize, + pHash->ppBucketTable, NULL); + pHash->ppBucketTable = ppNewTable; + pHash->uSize = uNewSize; + } + return IMG_TRUE; +} + +struct HASH_TABLE *HASH_Create_Extended(u32 uInitialLen, size_t uKeySize, + u32 (*pfnHashFunc)(size_t uKeySize, void *pkey, + u32 uHashTabLen), + IMG_BOOL (*pfnKeyComp)(size_t uKeySize, + void *pKey1, + void *pkey2)) +{ + struct HASH_TABLE *pHash; + u32 uIndex; + + PVR_DPF(PVR_DBG_MESSAGE, "HASH_Create_Extended: InitialSize=0x%x", + uInitialLen); + + if (OSAllocMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct HASH_TABLE), + (void **) &pHash, NULL) != PVRSRV_OK) + return NULL; + + pHash->uCount = 0; + pHash->uSize = uInitialLen; + pHash->uMinimumSize = uInitialLen; + pHash->uKeySize = uKeySize; + pHash->pfnHashFunc = pfnHashFunc; + pHash->pfnKeyComp = pfnKeyComp; + + if (OSAllocMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct BUCKET *) * pHash->uSize, + (void **) &pHash->ppBucketTable, NULL) != PVRSRV_OK) { + OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct HASH_TABLE), + pHash, NULL); + return NULL; + } + + for (uIndex = 0; uIndex < pHash->uSize; uIndex++) + pHash->ppBucketTable[uIndex] = NULL; + return pHash; +} + +struct HASH_TABLE *HASH_Create(u32 uInitialLen) +{ + return HASH_Create_Extended(uInitialLen, sizeof(u32), + &HASH_Func_Default, &HASH_Key_Comp_Default); +} + +void HASH_Delete(struct HASH_TABLE *pHash) +{ + if (pHash != NULL) { + PVR_DPF(PVR_DBG_MESSAGE, "HASH_Delete"); + + PVR_ASSERT(pHash->uCount == 0); + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct BUCKET *) * pHash->uSize, + pHash->ppBucketTable, NULL); + OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct HASH_TABLE), + pHash, NULL); + } +} + +IMG_BOOL HASH_Insert_Extended(struct HASH_TABLE *pHash, void *pKey, u32 v) +{ + struct BUCKET *pBucket; + + PVR_DPF(PVR_DBG_MESSAGE, + "HASH_Insert_Extended: Hash=%08X, pKey=%08X, v=0x%x", pHash, + pKey, v); + + PVR_ASSERT(pHash != NULL); + + if (pHash == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "HASH_Insert_Extended: invalid parameter"); + return IMG_FALSE; + } + + if (OSAllocMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct BUCKET) + pHash->uKeySize, + (void **) &pBucket, NULL) != PVRSRV_OK) + return IMG_FALSE; + + pBucket->v = v; + OSMemCopy(pBucket->k, pKey, pHash->uKeySize); + if (_ChainInsert(pHash, pBucket, pHash->ppBucketTable, pHash->uSize) != + PVRSRV_OK) { + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct BUCKET) + pHash->uKeySize, + pBucket, NULL); + return IMG_FALSE; + } + + pHash->uCount++; + + if (pHash->uCount << 1 > pHash->uSize) + _Resize(pHash, pHash->uSize << 1); + + return IMG_TRUE; +} + +IMG_BOOL HASH_Insert(struct HASH_TABLE *pHash, u32 k, u32 v) +{ + PVR_DPF(PVR_DBG_MESSAGE, + "HASH_Insert: Hash=%08X, k=0x%x, v=0x%x", pHash, k, v); + + return HASH_Insert_Extended(pHash, &k, v); +} + +u32 HASH_Remove_Extended(struct HASH_TABLE *pHash, void *pKey) +{ + struct BUCKET **ppBucket; + u32 uIndex; + + PVR_DPF(PVR_DBG_MESSAGE, "HASH_Remove: Hash=%08X, pKey=%08X", pHash, + pKey); + + PVR_ASSERT(pHash != NULL); + + if (pHash == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "FreeResourceByPtr: invalid parameter"); + return 0; + } + + uIndex = KEY_TO_INDEX(pHash, pKey, pHash->uSize); + + for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != NULL; + ppBucket = &((*ppBucket)->pNext)) + if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey)) { + struct BUCKET *pBucket = *ppBucket; + u32 v = pBucket->v; + (*ppBucket) = pBucket->pNext; + + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct BUCKET) + pHash->uKeySize, + pBucket, NULL); + + pHash->uCount--; + + if (pHash->uSize > (pHash->uCount << 2) && + pHash->uSize > pHash->uMinimumSize) + + _Resize(pHash, + PRIVATE_MAX(pHash->uSize >> 1, + pHash->uMinimumSize)); + + PVR_DPF(PVR_DBG_MESSAGE, + "HASH_Remove_Extended: Hash=%08X, pKey=%08X = 0x%x", + pHash, pKey, v); + return v; + } + PVR_DPF(PVR_DBG_MESSAGE, + "HASH_Remove_Extended: Hash=%08X, pKey=%08X = 0x0 !!!!", pHash, + pKey); + return 0; +} + +u32 HASH_Remove(struct HASH_TABLE *pHash, u32 k) +{ + PVR_DPF(PVR_DBG_MESSAGE, "HASH_Remove: Hash=%08X, k=0x%x", pHash, k); + + return HASH_Remove_Extended(pHash, &k); +} + +u32 HASH_Retrieve_Extended(struct HASH_TABLE *pHash, void *pKey) +{ + struct BUCKET **ppBucket; + u32 uIndex; + + PVR_DPF(PVR_DBG_MESSAGE, "HASH_Retrieve: Hash=%08X, pKey=%08X", pHash, + pKey); + + PVR_ASSERT(pHash != NULL); + + if (pHash == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "HASH_Retrieve_Extended: invalid parameter"); + return 0; + } + + uIndex = KEY_TO_INDEX(pHash, pKey, pHash->uSize); + + for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != NULL; + ppBucket = &((*ppBucket)->pNext)) + if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey)) { + struct BUCKET *pBucket = *ppBucket; + u32 v = pBucket->v; + + PVR_DPF(PVR_DBG_MESSAGE, + "HASH_Retrieve: Hash=%08X, pKey=%08X = 0x%x", + pHash, pKey, v); + return v; + } + PVR_DPF(PVR_DBG_MESSAGE, + "HASH_Retrieve: Hash=%08X, pKey=%08X = 0x0 !!!!", pHash, pKey); + return 0; +} + +u32 HASH_Retrieve(struct HASH_TABLE *pHash, u32 k) +{ + PVR_DPF(PVR_DBG_MESSAGE, "HASH_Retrieve: Hash=%08X, k=0x%x", pHash, k); + return HASH_Retrieve_Extended(pHash, &k); +} + diff --git a/drivers/gpu/pvr/hash.h b/drivers/gpu/pvr/hash.h new file mode 100644 index 00000000000..d0319ad89e1 --- /dev/null +++ b/drivers/gpu/pvr/hash.h @@ -0,0 +1,51 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _HASH_H_ +#define _HASH_H_ + +#include "img_types.h" +#include "osfunc.h" + +struct HASH_TABLE; +u32 HASH_Func_Default(size_t uKeySize, void *pKey, u32 uHashTabLen); +IMG_BOOL HASH_Key_Comp_Default(size_t uKeySize, void *pKey1, void *pKey2); +struct HASH_TABLE *HASH_Create_Extended(u32 uInitialLen, size_t uKeySize, + u32 (*pfnHashFunc)(size_t uKeySize, void *pkey, + u32 uHashTabLen), + IMG_BOOL (*pfnKeyComp)(size_t uKeySize, + void *pKey1, + void *pkey2)); +struct HASH_TABLE *HASH_Create(u32 uInitialLen); +void HASH_Delete(struct HASH_TABLE *pHash); +IMG_BOOL HASH_Insert_Extended(struct HASH_TABLE *pHash, void *pKey, u32 v); +IMG_BOOL HASH_Insert(struct HASH_TABLE *pHash, u32 k, u32 v); +u32 HASH_Remove_Extended(struct HASH_TABLE *pHash, void *pKey); +u32 HASH_Remove(struct HASH_TABLE *pHash, u32 k); +u32 HASH_Retrieve_Extended(struct HASH_TABLE *pHash, void *pKey); +u32 HASH_Retrieve(struct HASH_TABLE *pHash, u32 k); + +#endif diff --git a/drivers/gpu/pvr/img_defs.h b/drivers/gpu/pvr/img_defs.h new file mode 100644 index 00000000000..b0a25c2223f --- /dev/null +++ b/drivers/gpu/pvr/img_defs.h @@ -0,0 +1,46 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__IMG_DEFS_H__) +#define __IMG_DEFS_H__ + +#include "img_types.h" + +#define IMG_SUCCESS 0 + +#define IMG_NO_REG 1 + +#ifndef PVR_UNREFERENCED_PARAMETER +#define PVR_UNREFERENCED_PARAMETER(param) (param) = (param) +#endif + +#ifdef __GNUC__ +#define unref__ __attribute__ ((unused)) +#else +#define unref__ +#endif + +#endif diff --git a/drivers/gpu/pvr/img_types.h b/drivers/gpu/pvr/img_types.h new file mode 100644 index 00000000000..c52ba6ce952 --- /dev/null +++ b/drivers/gpu/pvr/img_types.h @@ -0,0 +1,69 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __IMG_TYPES_H__ +#define __IMG_TYPES_H__ + +#include <linux/types.h> + +#if !defined(IMG_UINT32_MAX) +#define IMG_UINT32_MAX 0xFFFFFFFFUL +#endif + +typedef enum tag_img_bool { + IMG_FALSE = 0, + IMG_TRUE = 1, + IMG_FORCE_ALIGN = 0x7FFFFFFF +} IMG_BOOL, *IMG_PBOOL; + +struct IMG_CPU_PHYADDR { + u32 uiAddr; +}; + +struct IMG_DEV_VIRTADDR { + u32 uiAddr; +}; + +struct IMG_DEV_PHYADDR { + u32 uiAddr; +}; + +struct IMG_SYS_PHYADDR { + u32 uiAddr; +}; + +struct SYSTEM_ADDR { + + u32 ui32PageCount; + union { + struct IMG_SYS_PHYADDR sContig; + struct IMG_SYS_PHYADDR asNonContig[1]; + } u; +}; + +#include "img_defs.h" + +#endif diff --git a/drivers/gpu/pvr/ioctldef.h b/drivers/gpu/pvr/ioctldef.h new file mode 100644 index 00000000000..36a16846781 --- /dev/null +++ b/drivers/gpu/pvr/ioctldef.h @@ -0,0 +1,93 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __IOCTLDEF_H__ +#define __IOCTLDEF_H__ + +#define MAKEIOCTLINDEX(i) (((i) >> 2) & 0xFFF) + +#define DEVICE_TYPE ULONG + +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000a +#define FILE_DEVICE_KEYBOARD 0x0000000b +#define FILE_DEVICE_MAILSLOT 0x0000000c +#define FILE_DEVICE_MIDI_IN 0x0000000d +#define FILE_DEVICE_MIDI_OUT 0x0000000e +#define FILE_DEVICE_MOUSE 0x0000000f +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a +#define FILE_DEVICE_SERIAL_PORT 0x0000001b +#define FILE_DEVICE_SCREEN 0x0000001c +#define FILE_DEVICE_SOUND 0x0000001d +#define FILE_DEVICE_STREAMS 0x0000001e +#define FILE_DEVICE_TAPE 0x0000001f +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002a +#define FILE_DEVICE_MODEM 0x0000002b +#define FILE_DEVICE_VDM 0x0000002c +#define FILE_DEVICE_MASS_STORAGE 0x0000002d + +#define CTL_CODE( DeviceType, Function, Method, Access) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS 0x0001 +#define FILE_WRITE_ACCESS 0x0002 + +#endif diff --git a/drivers/gpu/pvr/kernelbuffer.h b/drivers/gpu/pvr/kernelbuffer.h new file mode 100644 index 00000000000..da69d7e5c87 --- /dev/null +++ b/drivers/gpu/pvr/kernelbuffer.h @@ -0,0 +1,55 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__KERNELBUFFER_H__) +#define __KERNELBUFFER_H__ + +#include "servicesext.h" + +struct PVRSRV_BC_SRV2BUFFER_KMJTABLE { + u32 ui32TableSize; + enum PVRSRV_ERROR (*pfnOpenBCDevice)(void **); + enum PVRSRV_ERROR (*pfnCloseBCDevice)(void *); + enum PVRSRV_ERROR (*pfnGetBCInfo)(void *, struct BUFFER_INFO *); + enum PVRSRV_ERROR (*pfnGetBCBuffer)(void *, u32, + struct PVRSRV_SYNC_DATA *, void **); + enum PVRSRV_ERROR (*pfnGetBufferAddr)(void *, void *, + struct IMG_SYS_PHYADDR **, u32 *, + void __iomem **, void **, IMG_BOOL *); +}; + +struct PVRSRV_BC_BUFFER2SRV_KMJTABLE { + u32 ui32TableSize; + enum PVRSRV_ERROR (*pfnPVRSRVRegisterBCDevice)( + struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *, u32 *); + enum PVRSRV_ERROR (*pfnPVRSRVRemoveBCDevice)(u32); +}; + +IMG_BOOL PVRGetBufferClassJTable( + struct PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable); + + +#endif diff --git a/drivers/gpu/pvr/kerneldisplay.h b/drivers/gpu/pvr/kerneldisplay.h new file mode 100644 index 00000000000..c601906ab14 --- /dev/null +++ b/drivers/gpu/pvr/kerneldisplay.h @@ -0,0 +1,104 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__KERNELDISPLAY_H__) +#define __KERNELDISPLAY_H__ + +#include <linux/module.h> + +#define DC_FLIP_COMMAND 0 + +#define DC_STATE_NO_FLUSH_COMMANDS 0 +#define DC_STATE_FLUSH_COMMANDS 1 + +struct PVRSRV_DC_SRV2DISP_KMJTABLE { + struct module *owner; + u32 ui32TableSize; + enum PVRSRV_ERROR (*pfnOpenDCDevice)(u32, void **, + struct PVRSRV_SYNC_DATA *); + enum PVRSRV_ERROR (*pfnCloseDCDevice)(void *); + enum PVRSRV_ERROR (*pfnEnumDCFormats)(void *, u32 *, + struct DISPLAY_FORMAT *); + enum PVRSRV_ERROR (*pfnEnumDCDims)(void *, struct DISPLAY_FORMAT *, + u32 *, struct DISPLAY_DIMS *); + enum PVRSRV_ERROR (*pfnGetDCSystemBuffer)(void *, void **); + enum PVRSRV_ERROR (*pfnGetDCInfo)(void *, struct DISPLAY_INFO *); + enum PVRSRV_ERROR (*pfnGetBufferAddr)(void *, void *, + struct IMG_SYS_PHYADDR **, u32 *, + void __iomem **, void **, IMG_BOOL *); + enum PVRSRV_ERROR (*pfnCreateDCSwapChain)(void *, u32, + struct DISPLAY_SURF_ATTRIBUTES *, + struct DISPLAY_SURF_ATTRIBUTES *, + u32, struct PVRSRV_SYNC_DATA **, + u32, void **, u32 *); + enum PVRSRV_ERROR (*pfnDestroyDCSwapChain)(void *, void *); + enum PVRSRV_ERROR (*pfnSetDCDstRect)(void *, void *, struct IMG_RECT *); + enum PVRSRV_ERROR (*pfnSetDCSrcRect)(void *, void *, struct IMG_RECT *); + enum PVRSRV_ERROR (*pfnSetDCDstColourKey)(void *, void *, u32); + enum PVRSRV_ERROR (*pfnSetDCSrcColourKey)(void *, void *, u32); + enum PVRSRV_ERROR (*pfnGetDCBuffers)(void *, void *, u32 *, void **); + void (*pfnSetDCState)(void *, u32); +}; + +struct PVRSRV_DC_DISP2SRV_KMJTABLE { + u32 ui32TableSize; + enum PVRSRV_ERROR (*pfnPVRSRVRegisterDCDevice)( + struct PVRSRV_DC_SRV2DISP_KMJTABLE*, u32 *); + enum PVRSRV_ERROR (*pfnPVRSRVRemoveDCDevice)(u32); + enum PVRSRV_ERROR (*pfnPVRSRVOEMFunction)(u32, void *, u32, void *, + u32); + enum PVRSRV_ERROR (*pfnPVRSRVRegisterCmdProcList)(u32, + IMG_BOOL (**)(void *, u32, void *), u32[][2], + u32); + enum PVRSRV_ERROR (*pfnPVRSRVRemoveCmdProcList)(u32, u32); + void (*pfnPVRSRVCmdComplete)(void *, IMG_BOOL); + enum PVRSRV_ERROR (*pfnPVRSRVRegisterSystemISRHandler)( + IMG_BOOL (*)(void *), void *, u32, u32); + enum PVRSRV_ERROR (*pfnPVRSRVRegisterPowerDevice)(u32, + enum PVRSRV_ERROR (*)(void *, enum PVR_POWER_STATE, + enum PVR_POWER_STATE), + enum PVRSRV_ERROR (*)(void *, enum PVR_POWER_STATE, + enum PVR_POWER_STATE), + enum PVRSRV_ERROR (*)(void *, IMG_BOOL, + enum PVR_POWER_STATE), + enum PVRSRV_ERROR (*)(void *, IMG_BOOL, + enum PVR_POWER_STATE), + void *, enum PVR_POWER_STATE, enum PVR_POWER_STATE); +}; + +struct DISPLAYCLASS_FLIP_COMMAND { + void *hExtDevice; + void *hExtSwapChain; + void *hExtBuffer; + void *hPrivateTag; + u32 ui32ClipRectCount; + struct IMG_RECT *psClipRect; + u32 ui32SwapInterval; +}; + +IMG_BOOL PVRGetDisplayClassJTable(struct PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable); + +#endif diff --git a/drivers/gpu/pvr/mem.c b/drivers/gpu/pvr/mem.c new file mode 100644 index 00000000000..6375cad3cf6 --- /dev/null +++ b/drivers/gpu/pvr/mem.c @@ -0,0 +1,130 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "services_headers.h" +#include "sgxapi_km.h" +#include "pvr_bridge_km.h" + +static enum PVRSRV_ERROR FreeSharedSysMemCallBack(void *pvParam, u32 ui32Param) +{ + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo = pvParam; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + OSFreePages(psKernelMemInfo->ui32Flags, + psKernelMemInfo->ui32AllocSize, + psKernelMemInfo->pvLinAddrKM, + psKernelMemInfo->sMemBlk.hOSMemHandle); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), psKernelMemInfo, NULL); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVAllocSharedSysMemoryKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + u32 ui32Flags, u32 ui32Size, + struct PVRSRV_KERNEL_MEM_INFO **ppsKernelMemInfo) +{ + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), + (void **) &psKernelMemInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocSharedSysMemoryKM: " + "Failed to alloc memory for meminfo"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + OSMemSet(psKernelMemInfo, 0, sizeof(*psKernelMemInfo)); + + ui32Flags &= ~PVRSRV_HAP_MAPTYPE_MASK; + ui32Flags |= PVRSRV_HAP_MULTI_PROCESS; + psKernelMemInfo->ui32Flags = ui32Flags; + psKernelMemInfo->ui32AllocSize = ui32Size; + + if (OSAllocPages(psKernelMemInfo->ui32Flags, + psKernelMemInfo->ui32AllocSize, HOST_PAGESIZE(), + &psKernelMemInfo->pvLinAddrKM, + &psKernelMemInfo->sMemBlk.hOSMemHandle) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocSharedSysMemoryKM: " + "Failed to alloc memory for block"); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO), + psKernelMemInfo, NULL); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + psKernelMemInfo->sMemBlk.hResItem = ResManRegisterRes( + psPerProc->hResManContext, + RESMAN_TYPE_SHARED_MEM_INFO, + psKernelMemInfo, 0, + FreeSharedSysMemCallBack); + + *ppsKernelMemInfo = psKernelMemInfo; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVFreeSharedSysMemoryKM( + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (psKernelMemInfo->sMemBlk.hResItem) + ResManFreeResByPtr(psKernelMemInfo->sMemBlk.hResItem); + else + eError = FreeSharedSysMemCallBack(psKernelMemInfo, 0); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVDissociateMemFromResmanKM( + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (!psKernelMemInfo) + return PVRSRV_ERROR_INVALID_PARAMS; + + if (psKernelMemInfo->sMemBlk.hResItem) { + eError = ResManDissociateRes(psKernelMemInfo->sMemBlk.hResItem, + NULL); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDissociateMemFromResmanKM: " + "ResManDissociateRes failed"); + PVR_DBG_BREAK; + return eError; + } + + psKernelMemInfo->sMemBlk.hResItem = NULL; + } + + return eError; +} diff --git a/drivers/gpu/pvr/mm.c b/drivers/gpu/pvr/mm.c new file mode 100644 index 00000000000..c0a92f26580 --- /dev/null +++ b/drivers/gpu/pvr/mm.c @@ -0,0 +1,1499 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/version.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/highmem.h> +#include <linux/sched.h> +#include <linux/dma-mapping.h> + +#include "img_defs.h" +#include "services.h" +#include "servicesint.h" +#include "syscommon.h" +#include "mutils.h" +#include "mm.h" +#include "pvrmmap.h" +#include "mmap.h" +#include "osfunc.h" +#include "pvr_debug.h" +#include "proc.h" + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +enum DEBUG_MEM_ALLOC_TYPE { + DEBUG_MEM_ALLOC_TYPE_KMALLOC, + DEBUG_MEM_ALLOC_TYPE_VMALLOC, + DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, + DEBUG_MEM_ALLOC_TYPE_IOREMAP, + DEBUG_MEM_ALLOC_TYPE_IO, + DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE, + DEBUG_MEM_ALLOC_TYPE_COUNT +}; + +struct DEBUG_MEM_ALLOC_REC { + enum DEBUG_MEM_ALLOC_TYPE eAllocType; + void *pvKey; + void *pvCpuVAddr; + u32 ulCpuPAddr; + void *pvPrivateData; + u32 ui32Bytes; + pid_t pid; + char *pszFileName; + u32 ui32Line; + + struct DEBUG_MEM_ALLOC_REC *psNext; +}; + +static struct DEBUG_MEM_ALLOC_REC *g_MemoryRecords; + +static u32 g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_COUNT]; +static u32 g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_COUNT]; + +static u32 g_SysRAMWaterMark; +static u32 g_SysRAMHighWaterMark; + +static u32 g_IOMemWaterMark; +static u32 g_IOMemHighWaterMark; + +static void DebugMemAllocRecordAdd(enum DEBUG_MEM_ALLOC_TYPE eAllocType, + void *pvKey, void *pvCpuVAddr, + u32 ulCpuPAddr, void *pvPrivateData, + u32 ui32Bytes, char *pszFileName, + u32 ui32Line); + +static void DebugMemAllocRecordRemove(enum DEBUG_MEM_ALLOC_TYPE eAllocType, + void *pvKey, char *pszFileName, + u32 ui32Line); + +static char *DebugMemAllocRecordTypeToString( + enum DEBUG_MEM_ALLOC_TYPE eAllocType); + +static off_t printMemoryRecords(char *buffer, size_t size, off_t off); +#endif + +#if defined(DEBUG_LINUX_MEM_AREAS) +struct DEBUG_LINUX_MEM_AREA_REC { + struct LinuxMemArea *psLinuxMemArea; + u32 ui32Flags; + pid_t pid; + + struct DEBUG_LINUX_MEM_AREA_REC *psNext; +}; + +#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +static struct mutex g_sDebugMutex; +#endif + +static struct DEBUG_LINUX_MEM_AREA_REC *g_LinuxMemAreaRecords; +static u32 g_LinuxMemAreaCount; +static u32 g_LinuxMemAreaWaterMark; +static u32 g_LinuxMemAreaHighWaterMark; + +static off_t printLinuxMemAreaRecords(char *buffer, size_t size, off_t off); +#endif + +static struct kmem_cache *psLinuxMemAreaCache; + + +static struct LinuxMemArea *LinuxMemAreaStructAlloc(void); +static void LinuxMemAreaStructFree(struct LinuxMemArea *psLinuxMemArea); +#if defined(DEBUG_LINUX_MEM_AREAS) +static void DebugLinuxMemAreaRecordAdd(struct LinuxMemArea *psLinuxMemArea, + u32 ui32Flags); +static struct DEBUG_LINUX_MEM_AREA_REC *DebugLinuxMemAreaRecordFind( + struct LinuxMemArea *psLinuxMemArea); +static void DebugLinuxMemAreaRecordRemove(struct LinuxMemArea *psLinuxMemArea); +#endif + +enum PVRSRV_ERROR LinuxMMInit(void) +{ +#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + mutex_init(&g_sDebugMutex); +#endif + +#if defined(DEBUG_LINUX_MEM_AREAS) + { + int iStatus; + iStatus = + CreateProcReadEntry("mem_areas", printLinuxMemAreaRecords); + if (iStatus != 0) + return PVRSRV_ERROR_OUT_OF_MEMORY; + } +#endif + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + { + int iStatus; + iStatus = CreateProcReadEntry("meminfo", printMemoryRecords); + if (iStatus != 0) + return PVRSRV_ERROR_OUT_OF_MEMORY; + } +#endif + psLinuxMemAreaCache = + kmem_cache_create("img-mm", sizeof(struct LinuxMemArea), 0, 0, + NULL); + if (!psLinuxMemAreaCache) { + PVR_DPF(PVR_DBG_ERROR, "%s: failed to allocate kmem_cache", + __func__); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + return PVRSRV_OK; +} + +void LinuxMMCleanup(void) +{ +#if defined(DEBUG_LINUX_MEM_AREAS) + { + struct DEBUG_LINUX_MEM_AREA_REC *psCurrentRecord = + g_LinuxMemAreaRecords, *psNextRecord; + + if (g_LinuxMemAreaCount) + PVR_DPF(PVR_DBG_ERROR, "%s: BUG!: " + "There are %d struct LinuxMemArea " + "allocation unfreed (%ld bytes)", + __func__, g_LinuxMemAreaCount, + g_LinuxMemAreaWaterMark); + + while (psCurrentRecord) { + struct LinuxMemArea *psLinuxMemArea; + + psNextRecord = psCurrentRecord->psNext; + psLinuxMemArea = psCurrentRecord->psLinuxMemArea; + PVR_DPF(PVR_DBG_ERROR, "%s: BUG!: " + "Cleaning up Linux memory area (%p), " + "type=%s, size=%ld bytes", + __func__, psCurrentRecord->psLinuxMemArea, + LinuxMemAreaTypeToString(psCurrentRecord-> + psLinuxMemArea-> + eAreaType), + psCurrentRecord->psLinuxMemArea-> + ui32ByteSize); + + LinuxMemAreaDeepFree(psLinuxMemArea); + + psCurrentRecord = psNextRecord; + } + RemoveProcEntry("mem_areas"); + } +#endif + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + { + struct DEBUG_MEM_ALLOC_REC *psCurrentRecord = + g_MemoryRecords, *psNextRecord; + + while (psCurrentRecord) { + psNextRecord = psCurrentRecord->psNext; + PVR_DPF(PVR_DBG_ERROR, "%s: BUG!: Cleaning up memory: " + "type=%s CpuVAddr=%p CpuPAddr=0x%08lx, " + "allocated @ file=%s,line=%d", + __func__, + DebugMemAllocRecordTypeToString + (psCurrentRecord->eAllocType), + psCurrentRecord->pvCpuVAddr, + psCurrentRecord->ulCpuPAddr, + psCurrentRecord->pszFileName, + psCurrentRecord->ui32Line); + switch (psCurrentRecord->eAllocType) { + case DEBUG_MEM_ALLOC_TYPE_KMALLOC: + KFreeWrapper(psCurrentRecord->pvCpuVAddr); + break; + case DEBUG_MEM_ALLOC_TYPE_IOREMAP: + IOUnmapWrapper((__force __iomem void *) + psCurrentRecord->pvCpuVAddr); + break; + case DEBUG_MEM_ALLOC_TYPE_IO: + + DebugMemAllocRecordRemove + (DEBUG_MEM_ALLOC_TYPE_IO, + psCurrentRecord->pvKey, __FILE__, + __LINE__); + break; + case DEBUG_MEM_ALLOC_TYPE_VMALLOC: + VFreeWrapper(psCurrentRecord->pvCpuVAddr); + break; + case DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES: + + DebugMemAllocRecordRemove + (DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, + psCurrentRecord->pvKey, __FILE__, + __LINE__); + break; + case DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE: + KMemCacheFreeWrapper(psCurrentRecord-> + pvPrivateData, + psCurrentRecord-> + pvCpuVAddr); + break; + default: + PVR_ASSERT(0); + } + psCurrentRecord = psNextRecord; + } + RemoveProcEntry("meminfo"); + } +#endif + + if (psLinuxMemAreaCache) { + kmem_cache_destroy(psLinuxMemAreaCache); + psLinuxMemAreaCache = NULL; + } +} + +void *_KMallocWrapper(u32 ui32ByteSize, char *pszFileName, + u32 ui32Line) +{ + void *pvRet; + pvRet = kmalloc(ui32ByteSize, GFP_KERNEL); +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + if (pvRet) + DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_KMALLOC, + pvRet, pvRet, 0, NULL, ui32ByteSize, + pszFileName, ui32Line); +#endif + return pvRet; +} + +void _KFreeWrapper(void *pvCpuVAddr, char *pszFileName, + u32 ui32Line) +{ +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_KMALLOC, pvCpuVAddr, + pszFileName, ui32Line); +#endif + kfree(pvCpuVAddr); +} + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +static void DebugMemAllocRecordAdd(enum DEBUG_MEM_ALLOC_TYPE eAllocType, + void *pvKey, void *pvCpuVAddr, + u32 ulCpuPAddr, void *pvPrivateData, + u32 ui32Bytes, char *pszFileName, + u32 ui32Line) +{ + struct DEBUG_MEM_ALLOC_REC *psRecord; + + mutex_lock(&g_sDebugMutex); + + psRecord = kmalloc(sizeof(struct DEBUG_MEM_ALLOC_REC), GFP_KERNEL); + + psRecord->eAllocType = eAllocType; + psRecord->pvKey = pvKey; + psRecord->pvCpuVAddr = pvCpuVAddr; + psRecord->ulCpuPAddr = ulCpuPAddr; + psRecord->pvPrivateData = pvPrivateData; + psRecord->pid = current->pid; + psRecord->ui32Bytes = ui32Bytes; + psRecord->pszFileName = pszFileName; + psRecord->ui32Line = ui32Line; + + psRecord->psNext = g_MemoryRecords; + g_MemoryRecords = psRecord; + + g_WaterMarkData[eAllocType] += ui32Bytes; + if (g_WaterMarkData[eAllocType] > g_HighWaterMarkData[eAllocType]) + g_HighWaterMarkData[eAllocType] = g_WaterMarkData[eAllocType]; + + if (eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC || + eAllocType == DEBUG_MEM_ALLOC_TYPE_VMALLOC || + eAllocType == DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES || + eAllocType == DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE) { + g_SysRAMWaterMark += ui32Bytes; + if (g_SysRAMWaterMark > g_SysRAMHighWaterMark) + g_SysRAMHighWaterMark = g_SysRAMWaterMark; + } else if (eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP || + eAllocType == DEBUG_MEM_ALLOC_TYPE_IO) { + g_IOMemWaterMark += ui32Bytes; + if (g_IOMemWaterMark > g_IOMemHighWaterMark) + g_IOMemHighWaterMark = g_IOMemWaterMark; + } + + mutex_unlock(&g_sDebugMutex); +} + +static void DebugMemAllocRecordRemove(enum DEBUG_MEM_ALLOC_TYPE eAllocType, + void *pvKey, char *pszFileName, + u32 ui32Line) +{ + struct DEBUG_MEM_ALLOC_REC **ppsCurrentRecord; + + mutex_lock(&g_sDebugMutex); + + for (ppsCurrentRecord = &g_MemoryRecords; *ppsCurrentRecord; + ppsCurrentRecord = &((*ppsCurrentRecord)->psNext)) + if ((*ppsCurrentRecord)->eAllocType == eAllocType && + (*ppsCurrentRecord)->pvKey == pvKey) { + struct DEBUG_MEM_ALLOC_REC *psNextRecord; + + psNextRecord = (*ppsCurrentRecord)->psNext; + g_WaterMarkData[eAllocType] -= + (*ppsCurrentRecord)->ui32Bytes; + + if (eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC || + eAllocType == DEBUG_MEM_ALLOC_TYPE_VMALLOC || + eAllocType == DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES || + eAllocType == DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE) { + g_SysRAMWaterMark -= + (*ppsCurrentRecord)->ui32Bytes; + } else { + if (eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP + || eAllocType == DEBUG_MEM_ALLOC_TYPE_IO) + g_IOMemWaterMark -= + (*ppsCurrentRecord)->ui32Bytes; + + } + + kfree(*ppsCurrentRecord); + *ppsCurrentRecord = psNextRecord; + goto exit_unlock; + } + + PVR_DPF(PVR_DBG_ERROR, "%s: couldn't find an entry for type=%s " + "with pvKey=%p (called from %s, line %d\n", + __func__, DebugMemAllocRecordTypeToString(eAllocType), pvKey, + pszFileName, ui32Line); + +exit_unlock: + mutex_unlock(&g_sDebugMutex); +} + +static char *DebugMemAllocRecordTypeToString( + enum DEBUG_MEM_ALLOC_TYPE eAllocType) +{ + char *apszDebugMemoryRecordTypes[] = { + "KMALLOC", + "VMALLOC", + "ALLOC_PAGES", + "IOREMAP", + "IO", + "KMEM_CACHE_ALLOC" + }; + return apszDebugMemoryRecordTypes[eAllocType]; +} +#endif + +void *_VMallocWrapper(u32 ui32Bytes, u32 ui32AllocFlags, char *pszFileName, + u32 ui32Line) +{ + pgprot_t PGProtFlags; + void *pvRet; + + switch (ui32AllocFlags & PVRSRV_HAP_CACHETYPE_MASK) { + case PVRSRV_HAP_CACHED: + PGProtFlags = PAGE_KERNEL; + break; + case PVRSRV_HAP_WRITECOMBINE: + PGProtFlags = PGPROT_WC(PAGE_KERNEL); + break; + case PVRSRV_HAP_UNCACHED: + PGProtFlags = PGPROT_UC(PAGE_KERNEL); + break; + default: + PVR_DPF(PVR_DBG_ERROR, + "VMAllocWrapper: unknown mapping flags=0x%08lx", + ui32AllocFlags); + dump_stack(); + return NULL; + } + + pvRet = __vmalloc(ui32Bytes, GFP_KERNEL | __GFP_HIGHMEM, PGProtFlags); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + if (pvRet) + DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_VMALLOC, + pvRet, pvRet, 0, NULL, + PAGE_ALIGN(ui32Bytes), + pszFileName, ui32Line); +#endif + + return pvRet; +} + +void _VFreeWrapper(void *pvCpuVAddr, char *pszFileName, u32 ui32Line) +{ +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_VMALLOC, pvCpuVAddr, + pszFileName, ui32Line); +#endif + vfree(pvCpuVAddr); +} + +struct LinuxMemArea *NewVMallocLinuxMemArea(u32 ui32Bytes, u32 ui32AreaFlags) +{ + struct LinuxMemArea *psLinuxMemArea; + void *pvCpuVAddr; + + psLinuxMemArea = LinuxMemAreaStructAlloc(); + if (!psLinuxMemArea) + goto failed; + + pvCpuVAddr = VMallocWrapper(ui32Bytes, ui32AreaFlags); + if (!pvCpuVAddr) + goto failed; + + psLinuxMemArea->eAreaType = LINUX_MEM_AREA_VMALLOC; + psLinuxMemArea->uData.sVmalloc.pvVmallocAddress = pvCpuVAddr; + psLinuxMemArea->ui32ByteSize = ui32Bytes; + psLinuxMemArea->ui32AreaFlags = ui32AreaFlags; + psLinuxMemArea->bMMapRegistered = IMG_FALSE; + INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags); +#endif + + return psLinuxMemArea; + +failed: + PVR_DPF(PVR_DBG_ERROR, "%s: failed!", __func__); + if (psLinuxMemArea) + LinuxMemAreaStructFree(psLinuxMemArea); + return NULL; +} + +void FreeVMallocLinuxMemArea(struct LinuxMemArea *psLinuxMemArea) +{ + PVR_ASSERT(psLinuxMemArea); + PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_VMALLOC); + PVR_ASSERT(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordRemove(psLinuxMemArea); +#endif + + + PVR_DPF(PVR_DBG_MESSAGE, "%s: pvCpuVAddr: %p", + __func__, + psLinuxMemArea->uData.sVmalloc.pvVmallocAddress); + VFreeWrapper(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress); + + LinuxMemAreaStructFree(psLinuxMemArea); +} + +void __iomem *_IORemapWrapper(struct IMG_CPU_PHYADDR BasePAddr, + u32 ui32Bytes, u32 ui32MappingFlags, + char *pszFileName, u32 ui32Line) +{ + void __iomem *pvIORemapCookie = NULL; + + switch (ui32MappingFlags & PVRSRV_HAP_CACHETYPE_MASK) { + case PVRSRV_HAP_CACHED: + pvIORemapCookie = IOREMAP(BasePAddr.uiAddr, ui32Bytes); + break; + case PVRSRV_HAP_WRITECOMBINE: + pvIORemapCookie = IOREMAP_WC(BasePAddr.uiAddr, ui32Bytes); + break; + case PVRSRV_HAP_UNCACHED: + pvIORemapCookie = IOREMAP_UC(BasePAddr.uiAddr, ui32Bytes); + break; + default: + PVR_DPF(PVR_DBG_ERROR, + "IORemapWrapper: unknown mapping flags"); + return NULL; + } + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + if (pvIORemapCookie) + DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_IOREMAP, + (__force void *)pvIORemapCookie, + (__force void *)pvIORemapCookie, + BasePAddr.uiAddr, + NULL, ui32Bytes, pszFileName, ui32Line); +#endif + + return pvIORemapCookie; +} + +void _IOUnmapWrapper(void __iomem *pvIORemapCookie, char *pszFileName, + u32 ui32Line) +{ +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_IOREMAP, + (__force void *)pvIORemapCookie, + pszFileName, ui32Line); +#endif + iounmap(pvIORemapCookie); +} + +struct LinuxMemArea *NewIORemapLinuxMemArea(struct IMG_CPU_PHYADDR BasePAddr, + u32 ui32Bytes, u32 ui32AreaFlags) +{ + struct LinuxMemArea *psLinuxMemArea; + void __iomem *pvIORemapCookie; + + psLinuxMemArea = LinuxMemAreaStructAlloc(); + if (!psLinuxMemArea) + return NULL; + + pvIORemapCookie = IORemapWrapper(BasePAddr, ui32Bytes, ui32AreaFlags); + if (!pvIORemapCookie) { + LinuxMemAreaStructFree(psLinuxMemArea); + return NULL; + } + + psLinuxMemArea->eAreaType = LINUX_MEM_AREA_IOREMAP; + psLinuxMemArea->uData.sIORemap.pvIORemapCookie = pvIORemapCookie; + psLinuxMemArea->uData.sIORemap.CPUPhysAddr = BasePAddr; + psLinuxMemArea->ui32ByteSize = ui32Bytes; + psLinuxMemArea->ui32AreaFlags = ui32AreaFlags; + psLinuxMemArea->bMMapRegistered = IMG_FALSE; + INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags); +#endif + + return psLinuxMemArea; +} + +void FreeIORemapLinuxMemArea(struct LinuxMemArea *psLinuxMemArea) +{ + PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_IOREMAP); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordRemove(psLinuxMemArea); +#endif + + IOUnmapWrapper(psLinuxMemArea->uData.sIORemap.pvIORemapCookie); + + LinuxMemAreaStructFree(psLinuxMemArea); +} + +static IMG_BOOL PagesAreContiguous(struct IMG_SYS_PHYADDR *psSysPhysAddr, + u32 ui32Bytes) +{ + u32 ui32; + u32 ui32AddrChk; + u32 ui32NumPages = RANGE_TO_PAGES(ui32Bytes); + + for (ui32 = 0, ui32AddrChk = psSysPhysAddr[0].uiAddr; + ui32 < ui32NumPages; ui32++, ui32AddrChk += PAGE_SIZE) + if (psSysPhysAddr[ui32].uiAddr != ui32AddrChk) + return IMG_FALSE; + + return IMG_TRUE; +} + +struct LinuxMemArea *NewExternalKVLinuxMemArea(struct IMG_SYS_PHYADDR + *pBasePAddr, void *pvCPUVAddr, + u32 ui32Bytes, + IMG_BOOL bPhysContig, + u32 ui32AreaFlags) +{ + struct LinuxMemArea *psLinuxMemArea; + + psLinuxMemArea = LinuxMemAreaStructAlloc(); + if (!psLinuxMemArea) + return NULL; + + psLinuxMemArea->eAreaType = LINUX_MEM_AREA_EXTERNAL_KV; + psLinuxMemArea->uData.sExternalKV.pvExternalKV = pvCPUVAddr; + psLinuxMemArea->uData.sExternalKV.bPhysContig = bPhysContig || + PagesAreContiguous(pBasePAddr, ui32Bytes); + + if (psLinuxMemArea->uData.sExternalKV.bPhysContig) + psLinuxMemArea->uData.sExternalKV.uPhysAddr.SysPhysAddr = + *pBasePAddr; + else + psLinuxMemArea->uData.sExternalKV.uPhysAddr.pSysPhysAddr = + pBasePAddr; + psLinuxMemArea->ui32ByteSize = ui32Bytes; + psLinuxMemArea->ui32AreaFlags = ui32AreaFlags; + psLinuxMemArea->bMMapRegistered = IMG_FALSE; + INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags); +#endif + + return psLinuxMemArea; +} + +void FreeExternalKVLinuxMemArea(struct LinuxMemArea *psLinuxMemArea) +{ + PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_EXTERNAL_KV); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordRemove(psLinuxMemArea); +#endif + + LinuxMemAreaStructFree(psLinuxMemArea); +} + +struct LinuxMemArea *NewIOLinuxMemArea(struct IMG_CPU_PHYADDR BasePAddr, + u32 ui32Bytes, u32 ui32AreaFlags) +{ + struct LinuxMemArea *psLinuxMemArea = LinuxMemAreaStructAlloc(); + if (!psLinuxMemArea) + return NULL; + + psLinuxMemArea->eAreaType = LINUX_MEM_AREA_IO; + psLinuxMemArea->uData.sIO.CPUPhysAddr.uiAddr = BasePAddr.uiAddr; + psLinuxMemArea->ui32ByteSize = ui32Bytes; + psLinuxMemArea->ui32AreaFlags = ui32AreaFlags; + psLinuxMemArea->bMMapRegistered = IMG_FALSE; + INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_IO, + (void *)BasePAddr.uiAddr, NULL, + BasePAddr.uiAddr, NULL, ui32Bytes, "unknown", 0); +#endif + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags); +#endif + + return psLinuxMemArea; +} + +void FreeIOLinuxMemArea(struct LinuxMemArea *psLinuxMemArea) +{ + PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_IO); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordRemove(psLinuxMemArea); +#endif + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_IO, + (void *)psLinuxMemArea->uData.sIO. + CPUPhysAddr.uiAddr, __FILE__, __LINE__); +#endif + + LinuxMemAreaStructFree(psLinuxMemArea); +} + +struct LinuxMemArea *NewAllocPagesLinuxMemArea(u32 ui32Bytes, + u32 ui32AreaFlags) +{ + struct LinuxMemArea *psLinuxMemArea; + u32 ui32PageCount; + struct page **pvPageList; + void *hBlockPageList; + s32 i; + enum PVRSRV_ERROR eError; + + psLinuxMemArea = LinuxMemAreaStructAlloc(); + if (!psLinuxMemArea) + goto failed_area_alloc; + + ui32PageCount = RANGE_TO_PAGES(ui32Bytes); + eError = OSAllocMem(0, sizeof(*pvPageList) * ui32PageCount, + (void **)&pvPageList, &hBlockPageList); + if (eError != PVRSRV_OK) + goto failed_page_list_alloc; + + for (i = 0; i < ui32PageCount; i++) { + pvPageList[i] = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0); + if (!pvPageList[i]) + goto failed_alloc_pages; + + } + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, + pvPageList, NULL, 0, NULL, PAGE_ALIGN(ui32Bytes), + "unknown", 0); +#endif + + psLinuxMemArea->eAreaType = LINUX_MEM_AREA_ALLOC_PAGES; + psLinuxMemArea->uData.sPageList.pvPageList = pvPageList; + psLinuxMemArea->uData.sPageList.hBlockPageList = hBlockPageList; + psLinuxMemArea->ui32ByteSize = ui32Bytes; + psLinuxMemArea->ui32AreaFlags = ui32AreaFlags; + psLinuxMemArea->bMMapRegistered = IMG_FALSE; + INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags); +#endif + + return psLinuxMemArea; + +failed_alloc_pages: + for (i--; i >= 0; i--) + __free_pages(pvPageList[i], 0); + OSFreeMem(0, sizeof(*pvPageList) * ui32PageCount, pvPageList, + hBlockPageList); +failed_page_list_alloc: + LinuxMemAreaStructFree(psLinuxMemArea); +failed_area_alloc: + PVR_DPF(PVR_DBG_ERROR, "%s: failed", __func__); + + return NULL; +} + +void FreeAllocPagesLinuxMemArea(struct LinuxMemArea *psLinuxMemArea) +{ + u32 ui32PageCount; + struct page **pvPageList; + void *hBlockPageList; + u32 i; + + PVR_ASSERT(psLinuxMemArea); + PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_ALLOC_PAGES); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordRemove(psLinuxMemArea); +#endif + + ui32PageCount = RANGE_TO_PAGES(psLinuxMemArea->ui32ByteSize); + pvPageList = psLinuxMemArea->uData.sPageList.pvPageList; + hBlockPageList = psLinuxMemArea->uData.sPageList.hBlockPageList; + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, pvPageList, + __FILE__, __LINE__); +#endif + + for (i = 0; i < ui32PageCount; i++) + __free_pages(pvPageList[i], 0); + + OSFreeMem(0, sizeof(*pvPageList) * ui32PageCount, pvPageList, + hBlockPageList); + + LinuxMemAreaStructFree(psLinuxMemArea); +} + +struct page *LinuxMemAreaOffsetToPage(struct LinuxMemArea *psLinuxMemArea, + u32 ui32ByteOffset) +{ + u32 ui32PageIndex; + char *pui8Addr; + + switch (psLinuxMemArea->eAreaType) { + case LINUX_MEM_AREA_ALLOC_PAGES: + ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset); + return + psLinuxMemArea->uData.sPageList.pvPageList[ui32PageIndex]; + break; + case LINUX_MEM_AREA_VMALLOC: + pui8Addr = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress; + pui8Addr += ui32ByteOffset; + return vmalloc_to_page(pui8Addr); + break; + case LINUX_MEM_AREA_SUB_ALLOC: + return LinuxMemAreaOffsetToPage(psLinuxMemArea-> + uData.sSubAlloc.psParentLinuxMemArea, + psLinuxMemArea-> + uData.sSubAlloc.ui32ByteOffset + + ui32ByteOffset); + default: + PVR_DPF(PVR_DBG_ERROR, "%s: Unsupported request for " + "struct page from struct LinuxMemArea with type=%s", + LinuxMemAreaTypeToString(psLinuxMemArea->eAreaType)); + return NULL; + } +} + +void *_KMemCacheAllocWrapper(struct kmem_cache *psCache, + gfp_t Flags, + char *pszFileName, u32 ui32Line) +{ + void *pvRet; + + pvRet = kmem_cache_alloc(psCache, Flags); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE, pvRet, pvRet, + 0, psCache, kmem_cache_size(psCache), + pszFileName, ui32Line); +#endif + + return pvRet; +} + +void _KMemCacheFreeWrapper(struct kmem_cache *psCache, void *pvObject, + char *pszFileName, u32 ui32Line) +{ +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE, pvObject, + pszFileName, ui32Line); +#endif + + kmem_cache_free(psCache, pvObject); +} + +const char *KMemCacheNameWrapper(struct kmem_cache *psCache) +{ + + return ""; +} + +struct LinuxMemArea *NewSubLinuxMemArea(struct LinuxMemArea + *psParentLinuxMemArea, u32 ui32ByteOffset, + u32 ui32Bytes) +{ + struct LinuxMemArea *psLinuxMemArea; + + PVR_ASSERT((ui32ByteOffset + ui32Bytes) <= + psParentLinuxMemArea->ui32ByteSize); + + psLinuxMemArea = LinuxMemAreaStructAlloc(); + if (!psLinuxMemArea) + return NULL; + + psLinuxMemArea->eAreaType = LINUX_MEM_AREA_SUB_ALLOC; + psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea = + psParentLinuxMemArea; + psLinuxMemArea->uData.sSubAlloc.ui32ByteOffset = ui32ByteOffset; + psLinuxMemArea->ui32ByteSize = ui32Bytes; + psLinuxMemArea->ui32AreaFlags = psParentLinuxMemArea->ui32AreaFlags; + psLinuxMemArea->bMMapRegistered = IMG_FALSE; + INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList); + +#if defined(DEBUG_LINUX_MEM_AREAS) + { + struct DEBUG_LINUX_MEM_AREA_REC *psParentRecord; + psParentRecord = + DebugLinuxMemAreaRecordFind(psParentLinuxMemArea); + DebugLinuxMemAreaRecordAdd(psLinuxMemArea, + psParentRecord->ui32Flags); + } +#endif + + return psLinuxMemArea; +} + +static void FreeSubLinuxMemArea(struct LinuxMemArea *psLinuxMemArea) +{ + PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordRemove(psLinuxMemArea); +#endif + + LinuxMemAreaStructFree(psLinuxMemArea); +} + +static struct LinuxMemArea *LinuxMemAreaStructAlloc(void) +{ + return KMemCacheAllocWrapper(psLinuxMemAreaCache, GFP_KERNEL); +} + +static void LinuxMemAreaStructFree(struct LinuxMemArea *psLinuxMemArea) +{ + KMemCacheFreeWrapper(psLinuxMemAreaCache, psLinuxMemArea); + +} + +void LinuxMemAreaDeepFree(struct LinuxMemArea *psLinuxMemArea) +{ + switch (psLinuxMemArea->eAreaType) { + case LINUX_MEM_AREA_VMALLOC: + FreeVMallocLinuxMemArea(psLinuxMemArea); + break; + case LINUX_MEM_AREA_ALLOC_PAGES: + FreeAllocPagesLinuxMemArea(psLinuxMemArea); + break; + case LINUX_MEM_AREA_IOREMAP: + FreeIORemapLinuxMemArea(psLinuxMemArea); + break; + case LINUX_MEM_AREA_EXTERNAL_KV: + FreeExternalKVLinuxMemArea(psLinuxMemArea); + break; + case LINUX_MEM_AREA_IO: + FreeIOLinuxMemArea(psLinuxMemArea); + break; + case LINUX_MEM_AREA_SUB_ALLOC: + FreeSubLinuxMemArea(psLinuxMemArea); + break; + default: + PVR_DPF(PVR_DBG_ERROR, "%s: Unknown are type (%d)\n", + __func__, psLinuxMemArea->eAreaType); + } +} + +#if defined(DEBUG_LINUX_MEM_AREAS) +static void DebugLinuxMemAreaRecordAdd(struct LinuxMemArea *psLinuxMemArea, + u32 ui32Flags) +{ + struct DEBUG_LINUX_MEM_AREA_REC *psNewRecord; + const char *pi8FlagsString; + + mutex_lock(&g_sDebugMutex); + + if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) { + g_LinuxMemAreaWaterMark += psLinuxMemArea->ui32ByteSize; + if (g_LinuxMemAreaWaterMark > g_LinuxMemAreaHighWaterMark) + g_LinuxMemAreaHighWaterMark = g_LinuxMemAreaWaterMark; + } + g_LinuxMemAreaCount++; + + psNewRecord = kmalloc(sizeof(struct DEBUG_LINUX_MEM_AREA_REC), + GFP_KERNEL); + if (psNewRecord) { + psNewRecord->psLinuxMemArea = psLinuxMemArea; + psNewRecord->ui32Flags = ui32Flags; + psNewRecord->pid = current->pid; + psNewRecord->psNext = g_LinuxMemAreaRecords; + g_LinuxMemAreaRecords = psNewRecord; + } else { + PVR_DPF(PVR_DBG_ERROR, + "%s: failed to allocate linux memory area record.", + __func__); + } + + pi8FlagsString = HAPFlagsToString(ui32Flags); + if (strstr(pi8FlagsString, "UNKNOWN")) + PVR_DPF(PVR_DBG_ERROR, "%s: Unexpected flags " + "(0x%08lx) associated with psLinuxMemArea @ 0x%08lx", + __func__, ui32Flags, psLinuxMemArea); + + mutex_unlock(&g_sDebugMutex); +} + +static struct DEBUG_LINUX_MEM_AREA_REC *DebugLinuxMemAreaRecordFind( + struct LinuxMemArea *psLinuxMemArea) +{ + struct DEBUG_LINUX_MEM_AREA_REC *psCurrentRecord; + + mutex_lock(&g_sDebugMutex); + + for (psCurrentRecord = g_LinuxMemAreaRecords; + psCurrentRecord; psCurrentRecord = psCurrentRecord->psNext) + if (psCurrentRecord->psLinuxMemArea == psLinuxMemArea) + goto exit_unlock; + +exit_unlock: + mutex_unlock(&g_sDebugMutex); + + return psCurrentRecord; +} + +static void DebugLinuxMemAreaRecordRemove(struct LinuxMemArea *psLinuxMemArea) +{ + struct DEBUG_LINUX_MEM_AREA_REC **ppsCurrentRecord; + + mutex_lock(&g_sDebugMutex); + + if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) + g_LinuxMemAreaWaterMark -= psLinuxMemArea->ui32ByteSize; + g_LinuxMemAreaCount--; + + for (ppsCurrentRecord = &g_LinuxMemAreaRecords; + *ppsCurrentRecord; + ppsCurrentRecord = &((*ppsCurrentRecord)->psNext)) + if ((*ppsCurrentRecord)->psLinuxMemArea == psLinuxMemArea) { + struct DEBUG_LINUX_MEM_AREA_REC *psNextRecord; + + psNextRecord = (*ppsCurrentRecord)->psNext; + kfree(*ppsCurrentRecord); + *ppsCurrentRecord = psNextRecord; + goto exit_unlock; + } + + PVR_DPF(PVR_DBG_ERROR, + "%s: couldn't find an entry for psLinuxMemArea=%p\n", __func__, + psLinuxMemArea); + +exit_unlock: + mutex_unlock(&g_sDebugMutex); +} +#endif + +void *LinuxMemAreaToCpuVAddr(struct LinuxMemArea *psLinuxMemArea) +{ + switch (psLinuxMemArea->eAreaType) { + case LINUX_MEM_AREA_VMALLOC: + return psLinuxMemArea->uData.sVmalloc.pvVmallocAddress; + case LINUX_MEM_AREA_IOREMAP: + return (void __force *) + psLinuxMemArea->uData.sIORemap.pvIORemapCookie; + case LINUX_MEM_AREA_EXTERNAL_KV: + return psLinuxMemArea->uData.sExternalKV.pvExternalKV; + case LINUX_MEM_AREA_SUB_ALLOC: + { + char *pAddr = + LinuxMemAreaToCpuVAddr(psLinuxMemArea->uData. + sSubAlloc. + psParentLinuxMemArea); + if (!pAddr) + return NULL; + return pAddr + + psLinuxMemArea->uData.sSubAlloc.ui32ByteOffset; + } + default: + return NULL; + } +} + +struct IMG_CPU_PHYADDR LinuxMemAreaToCpuPAddr( + struct LinuxMemArea *psLinuxMemArea, + u32 ui32ByteOffset) +{ + struct IMG_CPU_PHYADDR CpuPAddr; + + CpuPAddr.uiAddr = 0; + + switch (psLinuxMemArea->eAreaType) { + case LINUX_MEM_AREA_IOREMAP: + { + CpuPAddr = psLinuxMemArea->uData.sIORemap.CPUPhysAddr; + CpuPAddr.uiAddr += ui32ByteOffset; + break; + } + case LINUX_MEM_AREA_EXTERNAL_KV: + { + if (psLinuxMemArea->uData.sExternalKV.bPhysContig) { + CpuPAddr = + SysSysPAddrToCpuPAddr( + psLinuxMemArea->uData. + sExternalKV.uPhysAddr. + SysPhysAddr); + CpuPAddr.uiAddr += ui32ByteOffset; + } else { + u32 ui32PageIndex = + PHYS_TO_PFN(ui32ByteOffset); + struct IMG_SYS_PHYADDR SysPAddr = + psLinuxMemArea->uData.sExternalKV.uPhysAddr. + pSysPhysAddr[ui32PageIndex]; + + CpuPAddr = SysSysPAddrToCpuPAddr(SysPAddr); + CpuPAddr.uiAddr += + ADDR_TO_PAGE_OFFSET(ui32ByteOffset); + } + break; + } + case LINUX_MEM_AREA_IO: + { + CpuPAddr = psLinuxMemArea->uData.sIO.CPUPhysAddr; + CpuPAddr.uiAddr += ui32ByteOffset; + break; + } + case LINUX_MEM_AREA_VMALLOC: + { + char *pCpuVAddr; + pCpuVAddr = + (char *) psLinuxMemArea->uData.sVmalloc. + pvVmallocAddress; + pCpuVAddr += ui32ByteOffset; + CpuPAddr.uiAddr = VMallocToPhys(pCpuVAddr); + break; + } + case LINUX_MEM_AREA_ALLOC_PAGES: + { + struct page *page; + u32 ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset); + page = + psLinuxMemArea->uData.sPageList. + pvPageList[ui32PageIndex]; + CpuPAddr.uiAddr = page_to_phys(page); + CpuPAddr.uiAddr += ADDR_TO_PAGE_OFFSET(ui32ByteOffset); + break; + } + case LINUX_MEM_AREA_SUB_ALLOC: + { + CpuPAddr = + OSMemHandleToCpuPAddr(psLinuxMemArea->uData. + sSubAlloc. + psParentLinuxMemArea, + psLinuxMemArea->uData. + sSubAlloc.ui32ByteOffset + + ui32ByteOffset); + break; + } + default: + PVR_DPF(PVR_DBG_ERROR, + "%s: Unknown struct LinuxMemArea type (%d)\n", + __func__, psLinuxMemArea->eAreaType); + } + + PVR_ASSERT(CpuPAddr.uiAddr); + return CpuPAddr; +} + +static void inv_cache_vmalloc(const struct LinuxMemArea *mem_area) +{ + struct page *pg; + void *kaddr; + size_t chunk; + u32 pg_cnt; + u32 pg_ofs; + u32 vaddr, vaddr_end; + + extern void ___dma_single_dev_to_cpu(const void *, size_t, + enum dma_data_direction); + + vaddr = (u32)mem_area->uData.sVmalloc.pvVmallocAddress; + vaddr_end = vaddr + mem_area->ui32ByteSize; + pg_cnt = (PAGE_ALIGN(vaddr_end) - (vaddr & PAGE_MASK)) / PAGE_SIZE; + + while (pg_cnt--) { + pg = pfn_to_page(VMallocToPhys((void *)vaddr) >> PAGE_SHIFT); + kaddr = page_address(pg); + pg_ofs = vaddr & ~PAGE_MASK; + kaddr += pg_ofs; + chunk = min_t(ssize_t, vaddr_end - vaddr, PAGE_SIZE - pg_ofs); + ___dma_single_dev_to_cpu(kaddr, chunk, DMA_FROM_DEVICE); + vaddr += chunk; + } +} + +static void inv_cache_page_list(const struct LinuxMemArea *mem_area) +{ + u32 pg_cnt; + struct page **pg_list; + + extern void ___dma_single_dev_to_cpu(const void *, size_t, + enum dma_data_direction); + + pg_cnt = RANGE_TO_PAGES(mem_area->ui32ByteSize); + pg_list = mem_area->uData.sPageList.pvPageList; + while (pg_cnt--) + ___dma_single_dev_to_cpu(page_address(*pg_list++), PAGE_SIZE, + DMA_FROM_DEVICE); +} + +void inv_cache_mem_area(const struct LinuxMemArea *mem_area) +{ + switch (mem_area->eAreaType) { + case LINUX_MEM_AREA_VMALLOC: + inv_cache_vmalloc(mem_area); + break; + case LINUX_MEM_AREA_ALLOC_PAGES: + inv_cache_page_list(mem_area); + break; + case LINUX_MEM_AREA_IOREMAP: + case LINUX_MEM_AREA_EXTERNAL_KV: + case LINUX_MEM_AREA_IO: + case LINUX_MEM_AREA_SUB_ALLOC: + PVR_DPF(PVR_DBG_ERROR, + "%s: Not implemented for type (%d)\n", + __func__, mem_area->eAreaType); + BUG(); + default: + PVR_DPF(PVR_DBG_ERROR, + "%s: Unknown LinuxMemArea type (%d)\n", + __func__, mem_area->eAreaType); + BUG(); + } +} + +IMG_BOOL LinuxMemAreaPhysIsContig(struct LinuxMemArea *psLinuxMemArea) +{ + switch (psLinuxMemArea->eAreaType) { + case LINUX_MEM_AREA_IOREMAP: + case LINUX_MEM_AREA_IO: + return IMG_TRUE; + + case LINUX_MEM_AREA_EXTERNAL_KV: + return psLinuxMemArea->uData.sExternalKV.bPhysContig; + + case LINUX_MEM_AREA_VMALLOC: + case LINUX_MEM_AREA_ALLOC_PAGES: + return IMG_FALSE; + + case LINUX_MEM_AREA_SUB_ALLOC: + return LinuxMemAreaPhysIsContig(psLinuxMemArea->uData.sSubAlloc. + psParentLinuxMemArea); + + default: + PVR_DPF(PVR_DBG_ERROR, + "%s: Unknown struct LinuxMemArea type (%d)\n", + __func__, psLinuxMemArea->eAreaType); + break; + } + return IMG_FALSE; +} + +const char *LinuxMemAreaTypeToString(enum LINUX_MEM_AREA_TYPE eMemAreaType) +{ + switch (eMemAreaType) { + case LINUX_MEM_AREA_IOREMAP: + return "LINUX_MEM_AREA_IOREMAP"; + case LINUX_MEM_AREA_EXTERNAL_KV: + return "LINUX_MEM_AREA_EXTERNAL_KV"; + case LINUX_MEM_AREA_IO: + return "LINUX_MEM_AREA_IO"; + case LINUX_MEM_AREA_VMALLOC: + return "LINUX_MEM_AREA_VMALLOC"; + case LINUX_MEM_AREA_SUB_ALLOC: + return "LINUX_MEM_AREA_SUB_ALLOC"; + case LINUX_MEM_AREA_ALLOC_PAGES: + return "LINUX_MEM_AREA_ALLOC_PAGES"; + default: + PVR_ASSERT(0); + } + + return ""; +} + +#if defined(DEBUG_LINUX_MEM_AREAS) +static off_t printLinuxMemAreaRecords(char *buffer, size_t count, off_t off) +{ + struct DEBUG_LINUX_MEM_AREA_REC *psRecord; + off_t Ret; + + mutex_lock(&g_sDebugMutex); + + if (!off) { + if (count < 500) { + Ret = 0; + goto unlock_and_return; + } + Ret = printAppend(buffer, count, 0, + "Number of Linux Memory Areas: %u\n" + "At the current water mark these areas " + "correspond to %u bytes " + "(excluding SUB areas)\n" + "At the highest water mark these areas " + "corresponded to %u bytes " + "(excluding SUB areas)\n" + "\nDetails for all Linux Memory Areas:\n" + "%s %-24s %s %s %-8s %-5s %s\n", + g_LinuxMemAreaCount, + g_LinuxMemAreaWaterMark, + g_LinuxMemAreaHighWaterMark, + "psLinuxMemArea", + "LinuxMemType", + "CpuVAddr", + "CpuPAddr", "Bytes", "Pid", "Flags"); + goto unlock_and_return; + } + + for (psRecord = g_LinuxMemAreaRecords; --off && psRecord; + psRecord = psRecord->psNext) + ; + if (!psRecord) { + Ret = END_OF_FILE; + goto unlock_and_return; + } + + if (count < 500) { + Ret = 0; + goto unlock_and_return; + } + + Ret = printAppend(buffer, count, 0, + "%8p %-24s %8p %08x %-8d %-5u %08x=(%s)\n", + psRecord->psLinuxMemArea, + LinuxMemAreaTypeToString(psRecord->psLinuxMemArea-> + eAreaType), + LinuxMemAreaToCpuVAddr(psRecord->psLinuxMemArea), + LinuxMemAreaToCpuPAddr(psRecord->psLinuxMemArea, + 0).uiAddr, + psRecord->psLinuxMemArea->ui32ByteSize, psRecord->pid, + psRecord->ui32Flags, + HAPFlagsToString(psRecord->ui32Flags) + ); + +unlock_and_return: + mutex_unlock(&g_sDebugMutex); + return Ret; +} +#endif + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +static off_t printMemoryRecords(char *buffer, size_t count, off_t off) +{ + struct DEBUG_MEM_ALLOC_REC *psRecord; + off_t Ret; + + mutex_lock(&g_sDebugMutex); + + if (!off) { + if (count < 1000) { + Ret = 0; + goto unlock_and_return; + } + + Ret = printAppend(buffer, count, 0, "%-60s: %d bytes\n", + "Current Water Mark of bytes allocated via kmalloc", + g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMALLOC]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Highest Water Mark of bytes allocated via kmalloc", + g_HighWaterMarkData + [DEBUG_MEM_ALLOC_TYPE_KMALLOC]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Current Water Mark of bytes allocated via vmalloc", + g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMALLOC]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Highest Water Mark of bytes allocated via vmalloc", + g_HighWaterMarkData + [DEBUG_MEM_ALLOC_TYPE_VMALLOC]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Current Water Mark of bytes allocated via alloc_pages", + g_WaterMarkData + [DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Highest Water Mark of bytes allocated via alloc_pages", + g_HighWaterMarkData + [DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Current Water Mark of bytes allocated via ioremap", + g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IOREMAP]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Highest Water Mark of bytes allocated via ioremap", + g_HighWaterMarkData + [DEBUG_MEM_ALLOC_TYPE_IOREMAP]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Current Water Mark of bytes reserved for " + "\"IO\" memory areas", + g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Highest Water Mark of bytes allocated for " + "\"IO\" memory areas", + g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Current Water Mark of bytes allocated via " + "kmem_cache_alloc", + g_WaterMarkData + [DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "Highest Water Mark of bytes allocated via " + "kmem_cache_alloc", + g_HighWaterMarkData + [DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]); + Ret = printAppend(buffer, count, Ret, "\n"); + + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "The Current Water Mark for memory allocated from system RAM", + g_SysRAMWaterMark); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "The Highest Water Mark for memory allocated from system RAM", + g_SysRAMHighWaterMark); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "The Current Water Mark for memory allocated from IO memory", + g_IOMemWaterMark); + Ret = printAppend(buffer, count, Ret, "%-60s: %d bytes\n", + "The Highest Water Mark for memory allocated from IO memory", + g_IOMemHighWaterMark); + + Ret = printAppend(buffer, count, Ret, "\n"); + + Ret = printAppend(buffer, count, Ret, + "Details for all known allocations:\n" + "%-16s %-8s %-8s %-10s %-5s %-10s %s\n", "Type", + "CpuVAddr", "CpuPAddr", "Bytes", "PID", + "PrivateData", "Filename:Line"); + + + goto unlock_and_return; + } + + if (count < 1000) { + Ret = 0; + goto unlock_and_return; + } + + for (psRecord = g_MemoryRecords; --off && psRecord; + psRecord = psRecord->psNext) + ; + if (!psRecord) { + Ret = END_OF_FILE; + goto unlock_and_return; + } + + if (psRecord->eAllocType != DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE) + Ret = printAppend(buffer, count, 0, + "%-16s %-8p %08x %-10d %-5d %-10s %s:%d\n", + DebugMemAllocRecordTypeToString(psRecord->eAllocType), + psRecord->pvCpuVAddr, psRecord->ulCpuPAddr, + psRecord->ui32Bytes, psRecord->pid, "NULL", + psRecord->pszFileName, psRecord->ui32Line); + else + Ret = printAppend(buffer, count, 0, + "%-16s %-8p %08x %-10d %-5d %-10s %s:%d\n", + DebugMemAllocRecordTypeToString(psRecord->eAllocType), + psRecord->pvCpuVAddr, psRecord->ulCpuPAddr, + psRecord->ui32Bytes, psRecord->pid, + KMemCacheNameWrapper(psRecord->pvPrivateData), + psRecord->pszFileName, psRecord->ui32Line); + +unlock_and_return: + mutex_unlock(&g_sDebugMutex); + return Ret; +} +#endif + +#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MMAP_AREAS) +const char *HAPFlagsToString(u32 ui32Flags) +{ + static char szFlags[50]; + s32 i32Pos = 0; + u32 ui32CacheTypeIndex, ui32MapTypeIndex; + char *apszCacheTypes[] = { + "UNCACHED", + "CACHED", + "WRITECOMBINE", + "UNKNOWN" + }; + char *apszMapType[] = { + "KERNEL_ONLY", + "SINGLE_PROCESS", + "MULTI_PROCESS", + "FROM_EXISTING_PROCESS", + "NO_CPU_VIRTUAL", + "UNKNOWN" + }; + + if (ui32Flags & PVRSRV_HAP_UNCACHED) { + ui32CacheTypeIndex = 0; + } else if (ui32Flags & PVRSRV_HAP_CACHED) { + ui32CacheTypeIndex = 1; + } else if (ui32Flags & PVRSRV_HAP_WRITECOMBINE) { + ui32CacheTypeIndex = 2; + } else { + ui32CacheTypeIndex = 3; + PVR_DPF(PVR_DBG_ERROR, "%s: unknown cache type (%u)", + __func__, (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK)); + } + + if (ui32Flags & PVRSRV_HAP_KERNEL_ONLY) { + ui32MapTypeIndex = 0; + } else if (ui32Flags & PVRSRV_HAP_SINGLE_PROCESS) { + ui32MapTypeIndex = 1; + } else if (ui32Flags & PVRSRV_HAP_MULTI_PROCESS) { + ui32MapTypeIndex = 2; + } else if (ui32Flags & PVRSRV_HAP_FROM_EXISTING_PROCESS) { + ui32MapTypeIndex = 3; + } else if (ui32Flags & PVRSRV_HAP_NO_CPU_VIRTUAL) { + ui32MapTypeIndex = 4; + } else { + ui32MapTypeIndex = 5; + PVR_DPF(PVR_DBG_ERROR, "%s: unknown map type (%u)", + __func__, (ui32Flags & PVRSRV_HAP_MAPTYPE_MASK)); + } + + i32Pos = sprintf(szFlags, "%s|", apszCacheTypes[ui32CacheTypeIndex]); + if (i32Pos <= 0) { + PVR_DPF(PVR_DBG_ERROR, + "%s: sprintf for cache type %u failed (%d)", __func__, + ui32CacheTypeIndex, i32Pos); + szFlags[0] = 0; + } else { + sprintf(szFlags + i32Pos, "%s", apszMapType[ui32MapTypeIndex]); + } + + return szFlags; +} +#endif diff --git a/drivers/gpu/pvr/mm.h b/drivers/gpu/pvr/mm.h new file mode 100644 index 00000000000..47c3fbce76a --- /dev/null +++ b/drivers/gpu/pvr/mm.h @@ -0,0 +1,261 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __IMG_LINUX_MM_H__ +#define __IMG_LINUX_MM_H__ + +#include <linux/version.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/list.h> + +#include <linux/io.h> + +#define PHYS_TO_PFN(phys) ((phys) >> PAGE_SHIFT) +#define PFN_TO_PHYS(pfn) ((pfn) << PAGE_SHIFT) + +#define RANGE_TO_PAGES(range) \ + (((range) + (PAGE_SIZE - 1)) >> PAGE_SHIFT) + +#define ADDR_TO_PAGE_OFFSET(addr) (((unsigned long)(addr)) & (PAGE_SIZE - 1)) + +#define REMAP_PFN_RANGE(vma, addr, pfn, size, prot) \ + remap_pfn_range(vma, addr, pfn, size, prot) + +#define IO_REMAP_PFN_RANGE(vma, addr, pfn, size, prot) \ + io_remap_pfn_range(vma, addr, pfn, size, prot) + +#define VM_INSERT_PAGE(vma, addr, page) vm_insert_page(vma, addr, page) + +static inline u32 VMallocToPhys(void *pCpuVAddr) +{ + return page_to_phys(vmalloc_to_page(pCpuVAddr)) + + ADDR_TO_PAGE_OFFSET(pCpuVAddr); + +} + +enum LINUX_MEM_AREA_TYPE { + LINUX_MEM_AREA_IOREMAP, + LINUX_MEM_AREA_EXTERNAL_KV, + LINUX_MEM_AREA_IO, + LINUX_MEM_AREA_VMALLOC, + LINUX_MEM_AREA_ALLOC_PAGES, + LINUX_MEM_AREA_SUB_ALLOC, + LINUX_MEM_AREA_TYPE_COUNT +}; + +struct LinuxMemArea; + +struct LinuxMemArea { + enum LINUX_MEM_AREA_TYPE eAreaType; + union _uData { + struct _sIORemap { + struct IMG_CPU_PHYADDR CPUPhysAddr; + void __iomem *pvIORemapCookie; + } sIORemap; + struct _sExternalKV { + IMG_BOOL bPhysContig; + union { + struct IMG_SYS_PHYADDR SysPhysAddr; + struct IMG_SYS_PHYADDR *pSysPhysAddr; + } uPhysAddr; + void *pvExternalKV; + } sExternalKV; + struct _sIO { + struct IMG_CPU_PHYADDR CPUPhysAddr; + } sIO; + struct _sVmalloc { + void *pvVmallocAddress; + } sVmalloc; + struct _sPageList { + struct page **pvPageList; + void *hBlockPageList; + } sPageList; + struct _sSubAlloc { + struct LinuxMemArea *psParentLinuxMemArea; + u32 ui32ByteOffset; + } sSubAlloc; + } uData; + u32 ui32ByteSize; + u32 ui32AreaFlags; + IMG_BOOL bMMapRegistered; + struct list_head sMMapItem; + struct list_head sMMapOffsetStructList; +}; + +struct kmem_cache; + +enum PVRSRV_ERROR LinuxMMInit(void); + +void LinuxMMCleanup(void); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define KMallocWrapper(ui32ByteSize) \ + _KMallocWrapper(ui32ByteSize, __FILE__, __LINE__) +#else +#define KMallocWrapper(ui32ByteSize) \ + _KMallocWrapper(ui32ByteSize, NULL, 0) +#endif +void *_KMallocWrapper(u32 ui32ByteSize, char *szFileName, u32 ui32Line); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define KFreeWrapper(pvCpuVAddr) _KFreeWrapper(pvCpuVAddr, __FILE__, __LINE__) +#else +#define KFreeWrapper(pvCpuVAddr) _KFreeWrapper(pvCpuVAddr, NULL, 0) +#endif +void _KFreeWrapper(void *pvCpuVAddr, char *pszFileName, u32 ui32Line); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define VMallocWrapper(ui32Bytes, ui32AllocFlags) \ + _VMallocWrapper(ui32Bytes, ui32AllocFlags, __FILE__, __LINE__) +#else +#define VMallocWrapper(ui32Bytes, ui32AllocFlags) \ + _VMallocWrapper(ui32Bytes, ui32AllocFlags, NULL, 0) +#endif +void *_VMallocWrapper(u32 ui32Bytes, u32 ui32AllocFlags, char *pszFileName, + u32 ui32Line); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define VFreeWrapper(pvCpuVAddr) _VFreeWrapper(pvCpuVAddr, __FILE__, __LINE__) +#else +#define VFreeWrapper(pvCpuVAddr) _VFreeWrapper(pvCpuVAddr, NULL, 0) +#endif +void _VFreeWrapper(void *pvCpuVAddr, char *pszFileName, u32 ui32Line); + +struct LinuxMemArea *NewVMallocLinuxMemArea(u32 ui32Bytes, u32 ui32AreaFlags); + +void FreeVMallocLinuxMemArea(struct LinuxMemArea *psLinuxMemArea); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags) \ + _IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags, __FILE__, __LINE__) +#else +#define IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags) \ + _IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags, NULL, 0) +#endif +void __iomem *_IORemapWrapper(struct IMG_CPU_PHYADDR BasePAddr, u32 ui32Bytes, + u32 ui32MappingFlags, char *pszFileName, + u32 ui32Line); + +struct LinuxMemArea *NewIORemapLinuxMemArea(struct IMG_CPU_PHYADDR BasePAddr, + u32 ui32Bytes, u32 ui32AreaFlags); + +void FreeIORemapLinuxMemArea(struct LinuxMemArea *psLinuxMemArea); + +struct LinuxMemArea *NewExternalKVLinuxMemArea( + struct IMG_SYS_PHYADDR *pBasePAddr, void *pvCPUVAddr, + u32 ui32Bytes, IMG_BOOL bPhysContig, u32 ui32AreaFlags); + +void FreeExternalKVLinuxMemArea(struct LinuxMemArea *psLinuxMemArea); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define IOUnmapWrapper(pvIORemapCookie) \ + _IOUnmapWrapper(pvIORemapCookie, __FILE__, __LINE__) +#else +#define IOUnmapWrapper(pvIORemapCookie) \ + _IOUnmapWrapper(pvIORemapCookie, NULL, 0) +#endif +void _IOUnmapWrapper(void __iomem *pvIORemapCookie, char *pszFileName, + u32 ui32Line); + +struct page *LinuxMemAreaOffsetToPage(struct LinuxMemArea *psLinuxMemArea, + u32 ui32ByteOffset); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define KMemCacheAllocWrapper(psCache, Flags) \ + _KMemCacheAllocWrapper(psCache, Flags, __FILE__, __LINE__) +#else +#define KMemCacheAllocWrapper(psCache, Flags) \ + _KMemCacheAllocWrapper(psCache, Flags, NULL, 0) +#endif + +void *_KMemCacheAllocWrapper(struct kmem_cache *psCache, gfp_t Flags, + char *pszFileName, u32 ui32Line); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define KMemCacheFreeWrapper(psCache, pvObject) \ + _KMemCacheFreeWrapper(psCache, pvObject, __FILE__, __LINE__) +#else +#define KMemCacheFreeWrapper(psCache, pvObject) \ + _KMemCacheFreeWrapper(psCache, pvObject, NULL, 0) +#endif +void _KMemCacheFreeWrapper(struct kmem_cache *psCache, void *pvObject, + char *pszFileName, u32 ui32Line); + +const char *KMemCacheNameWrapper(struct kmem_cache *psCache); + +struct LinuxMemArea *NewIOLinuxMemArea(struct IMG_CPU_PHYADDR BasePAddr, + u32 ui32Bytes, u32 ui32AreaFlags); + +void FreeIOLinuxMemArea(struct LinuxMemArea *psLinuxMemArea); + +struct LinuxMemArea *NewAllocPagesLinuxMemArea(u32 ui32Bytes, + u32 ui32AreaFlags); + +void FreeAllocPagesLinuxMemArea(struct LinuxMemArea *psLinuxMemArea); + +struct LinuxMemArea *NewSubLinuxMemArea( + struct LinuxMemArea *psParentLinuxMemArea, + u32 ui32ByteOffset, u32 ui32Bytes); + +void LinuxMemAreaDeepFree(struct LinuxMemArea *psLinuxMemArea); + +void *LinuxMemAreaToCpuVAddr(struct LinuxMemArea *psLinuxMemArea); + +struct IMG_CPU_PHYADDR LinuxMemAreaToCpuPAddr( + struct LinuxMemArea *psLinuxMemArea, + u32 ui32ByteOffset); + +#define LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32ByteOffset) \ + PHYS_TO_PFN(LinuxMemAreaToCpuPAddr(psLinuxMemArea, \ + ui32ByteOffset).uiAddr) + +void inv_cache_mem_area(const struct LinuxMemArea *mem_area); + +IMG_BOOL LinuxMemAreaPhysIsContig(struct LinuxMemArea *psLinuxMemArea); + +static inline struct LinuxMemArea *LinuxMemAreaRoot(struct LinuxMemArea + *psLinuxMemArea) +{ + if (psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC) + return psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea; + else + return psLinuxMemArea; +} + +static inline enum LINUX_MEM_AREA_TYPE LinuxMemAreaRootType(struct LinuxMemArea + *psLinuxMemArea) +{ + return LinuxMemAreaRoot(psLinuxMemArea)->eAreaType; +} + +const char *LinuxMemAreaTypeToString(enum LINUX_MEM_AREA_TYPE eMemAreaType); + +#if defined(CONFIG_PVR_DEBUG_EXTRA) || defined(DEBUG_LINUX_MEM_AREAS) +const char *HAPFlagsToString(u32 ui32Flags); +#endif + +#endif diff --git a/drivers/gpu/pvr/mmap.c b/drivers/gpu/pvr/mmap.c new file mode 100644 index 00000000000..1c094aa5574 --- /dev/null +++ b/drivers/gpu/pvr/mmap.c @@ -0,0 +1,920 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/kernel.h> +#include <linux/version.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <asm/page.h> +#include <asm/shmparam.h> +#include <asm/pgtable.h> +#include <linux/sched.h> +#include <asm/current.h> +#include "img_defs.h" +#include "services.h" +#include "servicesint.h" +#include "pvrmmap.h" +#include "mutils.h" +#include "mmap.h" +#include "mm.h" +#include "pvr_debug.h" +#include "osfunc.h" +#include "proc.h" +#include "handle.h" +#include "perproc.h" +#include "env_perproc.h" +#include "bridged_support.h" + +static struct mutex g_sMMapMutex; + +static struct kmem_cache *g_psMemmapCache; +static LIST_HEAD(g_sMMapAreaList); +static LIST_HEAD(g_sMMapOffsetStructList); +#if defined(DEBUG_LINUX_MMAP_AREAS) +static u32 g_ui32RegisteredAreas; +static u32 g_ui32TotalByteSize; +#endif + +#define LAST_PHYSICAL_PFN 0x7ffffffful +#define FIRST_SPECIAL_PFN (LAST_PHYSICAL_PFN + 1) +#define LAST_SPECIAL_PFN 0xfffffffful + +#define MAX_MMAP_HANDLE 0x7ffffffful + +static inline IMG_BOOL PFNIsPhysical(u32 pfn) +{ + return pfn <= LAST_PHYSICAL_PFN; +} + +static inline IMG_BOOL PFNIsSpecial(u32 pfn) +{ + return pfn >= FIRST_SPECIAL_PFN && pfn <= LAST_SPECIAL_PFN; +} + +static inline void *MMapOffsetToHandle(u32 pfn) +{ + if (PFNIsPhysical(pfn)) { + PVR_ASSERT(PFNIsPhysical(pfn)); + return NULL; + } + + return (void *)(pfn - FIRST_SPECIAL_PFN); +} + +static inline u32 HandleToMMapOffset(void *hHandle) +{ + u32 ulHandle = (u32) hHandle; + + if (PFNIsSpecial(ulHandle)) { + PVR_ASSERT(PFNIsSpecial(ulHandle)); + return 0; + } + + return ulHandle + FIRST_SPECIAL_PFN; + } + +static inline IMG_BOOL LinuxMemAreaUsesPhysicalMap( + struct LinuxMemArea *psLinuxMemArea) +{ + return LinuxMemAreaPhysIsContig(psLinuxMemArea); +} + +static inline u32 GetCurrentThreadID(void) +{ + + return (u32) current->pid; +} + +static struct KV_OFFSET_STRUCT *CreateOffsetStruct(struct LinuxMemArea + *psLinuxMemArea, + u32 ui32Offset, + u32 ui32RealByteSize) +{ + struct KV_OFFSET_STRUCT *psOffsetStruct; +#if defined(CONFIG_PVR_DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS) + const char *pszName = + LinuxMemAreaTypeToString(LinuxMemAreaRootType(psLinuxMemArea)); +#endif + + PVR_DPF(PVR_DBG_MESSAGE, + "%s(%s, psLinuxMemArea: 0x%p, ui32AllocFlags: 0x%8lx)", + __func__, pszName, psLinuxMemArea, + psLinuxMemArea->ui32AreaFlags); + + PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC + || LinuxMemAreaRoot(psLinuxMemArea)->eAreaType != + LINUX_MEM_AREA_SUB_ALLOC); + + PVR_ASSERT(psLinuxMemArea->bMMapRegistered); + + psOffsetStruct = KMemCacheAllocWrapper(g_psMemmapCache, GFP_KERNEL); + if (psOffsetStruct == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PVRMMapRegisterArea: " + "Couldn't alloc another mapping record from cache"); + return NULL; + } + + psOffsetStruct->ui32MMapOffset = ui32Offset; + psOffsetStruct->psLinuxMemArea = psLinuxMemArea; + psOffsetStruct->ui32Mapped = 0; + psOffsetStruct->ui32RealByteSize = ui32RealByteSize; + psOffsetStruct->ui32TID = GetCurrentThreadID(); + psOffsetStruct->ui32PID = OSGetCurrentProcessIDKM(); + psOffsetStruct->bOnMMapList = IMG_FALSE; + psOffsetStruct->ui32RefCount = 0; + psOffsetStruct->ui32UserVAddr = 0; +#if defined(DEBUG_LINUX_MMAP_AREAS) + + psOffsetStruct->pszName = pszName; +#endif + + list_add_tail(&psOffsetStruct->sAreaItem, + &psLinuxMemArea->sMMapOffsetStructList); + + return psOffsetStruct; +} + +static void DestroyOffsetStruct(struct KV_OFFSET_STRUCT *psOffsetStruct) +{ + list_del(&psOffsetStruct->sAreaItem); + + if (psOffsetStruct->bOnMMapList) + list_del(&psOffsetStruct->sMMapItem); + + PVR_DPF(PVR_DBG_MESSAGE, "%s: Table entry: " + "psLinuxMemArea=0x%08lX, CpuPAddr=0x%08lX", __func__, + psOffsetStruct->psLinuxMemArea, + LinuxMemAreaToCpuPAddr(psOffsetStruct->psLinuxMemArea, 0)); + + KMemCacheFreeWrapper(g_psMemmapCache, psOffsetStruct); +} + +static inline void DetermineUsersSizeAndByteOffset(struct LinuxMemArea + *psLinuxMemArea, + u32 *pui32RealByteSize, + u32 *pui32ByteOffset) +{ + u32 ui32PageAlignmentOffset; + struct IMG_CPU_PHYADDR CpuPAddr; + + CpuPAddr = LinuxMemAreaToCpuPAddr(psLinuxMemArea, 0); + ui32PageAlignmentOffset = ADDR_TO_PAGE_OFFSET(CpuPAddr.uiAddr); + + *pui32ByteOffset = ui32PageAlignmentOffset; + + *pui32RealByteSize = + PAGE_ALIGN(psLinuxMemArea->ui32ByteSize + ui32PageAlignmentOffset); +} + +enum PVRSRV_ERROR PVRMMapOSMemHandleToMMapData( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hMHandle, u32 *pui32MMapOffset, + u32 *pui32ByteOffset, u32 *pui32RealByteSize, + u32 *pui32UserVAddr) +{ + struct LinuxMemArea *psLinuxMemArea; + struct KV_OFFSET_STRUCT *psOffsetStruct; + void *hOSMemHandle; + enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC; + + mutex_lock(&g_sMMapMutex); + + PVR_ASSERT(PVRSRVGetMaxHandle(psPerProc->psHandleBase) <= + MAX_MMAP_HANDLE); + + eError = + PVRSRVLookupOSMemHandle(psPerProc->psHandleBase, &hOSMemHandle, + hMHandle); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "%s: Lookup of handle 0x%lx failed", + __func__, hMHandle); + + goto exit_unlock; + } + + psLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle; + + DetermineUsersSizeAndByteOffset(psLinuxMemArea, + pui32RealByteSize, pui32ByteOffset); + + list_for_each_entry(psOffsetStruct, + &psLinuxMemArea->sMMapOffsetStructList, sAreaItem) { + if (psPerProc->ui32PID == psOffsetStruct->ui32PID) { + PVR_ASSERT(*pui32RealByteSize == + psOffsetStruct->ui32RealByteSize); + + *pui32MMapOffset = psOffsetStruct->ui32MMapOffset; + *pui32UserVAddr = psOffsetStruct->ui32UserVAddr; + psOffsetStruct->ui32RefCount++; + + eError = PVRSRV_OK; + goto exit_unlock; + } + } + + *pui32UserVAddr = 0; + + if (LinuxMemAreaUsesPhysicalMap(psLinuxMemArea)) { + *pui32MMapOffset = LinuxMemAreaToCpuPFN(psLinuxMemArea, 0); + PVR_ASSERT(PFNIsPhysical(*pui32MMapOffset)); + } else { + *pui32MMapOffset = HandleToMMapOffset(hMHandle); + PVR_ASSERT(PFNIsSpecial(*pui32MMapOffset)); + } + + psOffsetStruct = CreateOffsetStruct(psLinuxMemArea, *pui32MMapOffset, + *pui32RealByteSize); + if (psOffsetStruct == NULL) { + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto exit_unlock; + } + + list_add_tail(&psOffsetStruct->sMMapItem, &g_sMMapOffsetStructList); + psOffsetStruct->bOnMMapList = IMG_TRUE; + psOffsetStruct->ui32RefCount++; + eError = PVRSRV_OK; + +exit_unlock: + mutex_unlock(&g_sMMapMutex); + + return eError; +} + +enum PVRSRV_ERROR PVRMMapReleaseMMapData( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hMHandle, IMG_BOOL *pbMUnmap, + u32 *pui32RealByteSize, u32 *pui32UserVAddr) +{ + struct LinuxMemArea *psLinuxMemArea; + struct KV_OFFSET_STRUCT *psOffsetStruct; + void *hOSMemHandle; + enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC; + u32 ui32PID = OSGetCurrentProcessIDKM(); + + mutex_lock(&g_sMMapMutex); + + PVR_ASSERT(PVRSRVGetMaxHandle(psPerProc->psHandleBase) <= + MAX_MMAP_HANDLE); + + eError = PVRSRVLookupOSMemHandle(psPerProc->psHandleBase, &hOSMemHandle, + hMHandle); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "%s: Lookup of handle 0x%lx failed", + __func__, hMHandle); + + goto exit_unlock; + } + + psLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle; + + list_for_each_entry(psOffsetStruct, + &psLinuxMemArea->sMMapOffsetStructList, sAreaItem) { + if (psOffsetStruct->ui32PID == ui32PID) { + if (psOffsetStruct->ui32RefCount == 0) { + PVR_DPF(PVR_DBG_ERROR, "%s: Attempt to " + "release mmap data with zero reference " + "count for offset struct 0x%p, " + "memory area 0x%p", + __func__, psOffsetStruct, + psLinuxMemArea); + eError = PVRSRV_ERROR_GENERIC; + goto exit_unlock; + } + + psOffsetStruct->ui32RefCount--; + + *pbMUnmap = (psOffsetStruct->ui32RefCount == 0) + && (psOffsetStruct->ui32UserVAddr != 0); + + *pui32UserVAddr = + (*pbMUnmap) ? psOffsetStruct->ui32UserVAddr : 0; + *pui32RealByteSize = + (*pbMUnmap) ? psOffsetStruct->ui32RealByteSize : 0; + + eError = PVRSRV_OK; + goto exit_unlock; + } + } + + PVR_DPF(PVR_DBG_ERROR, "%s: Mapping data not found for handle " + "0x%lx (memory area 0x%p)", + __func__, hMHandle, psLinuxMemArea); + + eError = PVRSRV_ERROR_GENERIC; + +exit_unlock: + mutex_unlock(&g_sMMapMutex); + + return eError; +} + +static inline struct KV_OFFSET_STRUCT *FindOffsetStructByOffset(u32 ui32Offset, + u32 ui32RealByteSize) +{ + struct KV_OFFSET_STRUCT *psOffsetStruct; + u32 ui32TID = GetCurrentThreadID(); + u32 ui32PID = OSGetCurrentProcessIDKM(); + + list_for_each_entry(psOffsetStruct, &g_sMMapOffsetStructList, + sMMapItem) { + if (ui32Offset == psOffsetStruct->ui32MMapOffset && + ui32RealByteSize == psOffsetStruct->ui32RealByteSize && + psOffsetStruct->ui32PID == ui32PID) + if (!PFNIsPhysical(ui32Offset) || + psOffsetStruct->ui32TID == ui32TID) + return psOffsetStruct; + } + + return NULL; +} + +static IMG_BOOL DoMapToUser(struct LinuxMemArea *psLinuxMemArea, + struct vm_area_struct *ps_vma, u32 ui32ByteOffset) +{ + u32 ui32ByteSize; + + if (psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC) + return DoMapToUser(LinuxMemAreaRoot(psLinuxMemArea), ps_vma, + psLinuxMemArea->uData.sSubAlloc. + ui32ByteOffset + ui32ByteOffset); + + ui32ByteSize = ps_vma->vm_end - ps_vma->vm_start; + PVR_ASSERT(ADDR_TO_PAGE_OFFSET(ui32ByteSize) == 0); + + if (PFNIsPhysical(ps_vma->vm_pgoff)) { + int result; + + PVR_ASSERT(LinuxMemAreaPhysIsContig(psLinuxMemArea)); + PVR_ASSERT(LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32ByteOffset) + == ps_vma->vm_pgoff); + + result = + IO_REMAP_PFN_RANGE(ps_vma, ps_vma->vm_start, + ps_vma->vm_pgoff, ui32ByteSize, + ps_vma->vm_page_prot); + + if (result == 0) + return IMG_TRUE; + + PVR_DPF(PVR_DBG_MESSAGE, + "%s: Failed to map contiguous physical address " + "range (%d), trying non-contiguous path", + __func__, result); + } + + { + u32 ulVMAPos; + u32 ui32ByteEnd = ui32ByteOffset + ui32ByteSize; + u32 ui32PA; + + for (ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; + ui32PA += PAGE_SIZE) { + u32 pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA); + + if (!pfn_valid(pfn)) { + PVR_DPF(PVR_DBG_ERROR, + "%s: Error - PFN invalid: 0x%lx", + __func__, pfn); + return IMG_FALSE; + } + } + + ulVMAPos = ps_vma->vm_start; + for (ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; + ui32PA += PAGE_SIZE) { + u32 pfn; + struct page *psPage; + int result; + + pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA); + PVR_ASSERT(pfn_valid(pfn)); + + psPage = pfn_to_page(pfn); + + result = VM_INSERT_PAGE(ps_vma, ulVMAPos, psPage); + if (result != 0) { + PVR_DPF(PVR_DBG_ERROR, + "%s: Error - VM_INSERT_PAGE failed (%d)", + __func__, result); + return IMG_FALSE; + } + ulVMAPos += PAGE_SIZE; + } + } + + return IMG_TRUE; +} + +static IMG_BOOL CheckSize(struct LinuxMemArea *psLinuxMemArea, u32 ui32ByteSize) +{ + struct IMG_CPU_PHYADDR CpuPAddr; + u32 ui32PageAlignmentOffset; + u32 ui32RealByteSize; + CpuPAddr = LinuxMemAreaToCpuPAddr(psLinuxMemArea, 0); + ui32PageAlignmentOffset = ADDR_TO_PAGE_OFFSET(CpuPAddr.uiAddr); + ui32RealByteSize = + PAGE_ALIGN(psLinuxMemArea->ui32ByteSize + ui32PageAlignmentOffset); + if (ui32RealByteSize < ui32ByteSize) { + PVR_DPF(PVR_DBG_ERROR, "Cannot mmap %ld bytes from: " + "%-8p %-8p %08lx %-8ld %-24s\n", + ui32ByteSize, psLinuxMemArea, + LinuxMemAreaToCpuVAddr(psLinuxMemArea), + LinuxMemAreaToCpuPAddr(psLinuxMemArea, 0).uiAddr, + psLinuxMemArea->ui32ByteSize, + LinuxMemAreaTypeToString(psLinuxMemArea->eAreaType)); + return IMG_FALSE; + } + return IMG_TRUE; +} + +static void MMapVOpenNoLock(struct vm_area_struct *ps_vma) +{ + struct KV_OFFSET_STRUCT *psOffsetStruct = + (struct KV_OFFSET_STRUCT *)ps_vma->vm_private_data; + + PVR_ASSERT(psOffsetStruct != NULL); + psOffsetStruct->ui32Mapped++; + PVR_ASSERT(!psOffsetStruct->bOnMMapList); + + if (psOffsetStruct->ui32Mapped > 1) { + PVR_DPF(PVR_DBG_WARNING, + "%s: Offset structure 0x%p is being shared " + "across processes (psOffsetStruct->ui32Mapped: %lu)", + __func__, psOffsetStruct, psOffsetStruct->ui32Mapped); + PVR_ASSERT((ps_vma->vm_flags & VM_DONTCOPY) == 0); + } +#if defined(DEBUG_LINUX_MMAP_AREAS) + + PVR_DPF(PVR_DBG_MESSAGE, + "%s: psLinuxMemArea 0x%p, KVAddress 0x%p MMapOffset %ld, ui32Mapped %d", + __func__, + psOffsetStruct->psLinuxMemArea, + LinuxMemAreaToCpuVAddr(psOffsetStruct->psLinuxMemArea), + psOffsetStruct->ui32MMapOffset, psOffsetStruct->ui32Mapped); +#endif + +} + +static void MMapVOpen(struct vm_area_struct *ps_vma) +{ + mutex_lock(&g_sMMapMutex); + MMapVOpenNoLock(ps_vma); + mutex_unlock(&g_sMMapMutex); +} + +static void MMapVCloseNoLock(struct vm_area_struct *ps_vma) +{ + struct KV_OFFSET_STRUCT *psOffsetStruct = + (struct KV_OFFSET_STRUCT *)ps_vma->vm_private_data; + + PVR_ASSERT(psOffsetStruct != NULL); +#if defined(DEBUG_LINUX_MMAP_AREAS) + PVR_DPF(PVR_DBG_MESSAGE, "%s: psLinuxMemArea " + "0x%p, CpuVAddr 0x%p ui32MMapOffset %ld, ui32Mapped %d", + __func__, + psOffsetStruct->psLinuxMemArea, + LinuxMemAreaToCpuVAddr(psOffsetStruct->psLinuxMemArea), + psOffsetStruct->ui32MMapOffset, + psOffsetStruct->ui32Mapped); +#endif + + PVR_ASSERT(!psOffsetStruct->bOnMMapList); + psOffsetStruct->ui32Mapped--; + if (psOffsetStruct->ui32Mapped == 0) { + if (psOffsetStruct->ui32RefCount != 0) + PVR_DPF(PVR_DBG_MESSAGE, + "%s: psOffsetStruct 0x%p has non-zero " + "reference count (ui32RefCount = %lu). " + "User mode address of start of mapping: 0x%lx", + __func__, psOffsetStruct, + psOffsetStruct->ui32RefCount, + psOffsetStruct->ui32UserVAddr); + + DestroyOffsetStruct(psOffsetStruct); + } + ps_vma->vm_private_data = NULL; +} + +static void MMapVClose(struct vm_area_struct *ps_vma) +{ + mutex_lock(&g_sMMapMutex); + MMapVCloseNoLock(ps_vma); + mutex_unlock(&g_sMMapMutex); +} + +static struct vm_operations_struct MMapIOOps = { + .open = MMapVOpen, + .close = MMapVClose +}; + +int PVRMMap(struct file *pFile, struct vm_area_struct *ps_vma) +{ + u32 ui32ByteSize; + struct KV_OFFSET_STRUCT *psOffsetStruct = NULL; + int iRetVal = 0; + + PVR_UNREFERENCED_PARAMETER(pFile); + + mutex_lock(&g_sMMapMutex); + + ui32ByteSize = ps_vma->vm_end - ps_vma->vm_start; + + PVR_DPF(PVR_DBG_MESSAGE, + "%s: Received mmap(2) request with ui32MMapOffset 0x%08lx," + " and ui32ByteSize %ld(0x%08lx)", __func__, ps_vma->vm_pgoff, + ui32ByteSize, ui32ByteSize); + + if ((ps_vma->vm_flags & VM_WRITE) && !(ps_vma->vm_flags & VM_SHARED)) { + PVR_DPF(PVR_DBG_ERROR, + "%s: Cannot mmap non-shareable writable areas", + __func__); + iRetVal = -EINVAL; + goto unlock_and_return; + } + + psOffsetStruct = + FindOffsetStructByOffset(ps_vma->vm_pgoff, ui32ByteSize); + if (psOffsetStruct == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "%s: Attempted to mmap unregistered area at vm_pgoff %ld", + __func__, ps_vma->vm_pgoff); + iRetVal = -EINVAL; + goto unlock_and_return; + } + list_del(&psOffsetStruct->sMMapItem); + psOffsetStruct->bOnMMapList = IMG_FALSE; + + PVR_DPF(PVR_DBG_MESSAGE, "%s: Mapped psLinuxMemArea 0x%p\n", + __func__, psOffsetStruct->psLinuxMemArea); + + if (!CheckSize(psOffsetStruct->psLinuxMemArea, ui32ByteSize)) { + iRetVal = -EINVAL; + goto unlock_and_return; + } + + ps_vma->vm_flags |= VM_RESERVED; + ps_vma->vm_flags |= VM_IO; + + ps_vma->vm_flags |= VM_DONTEXPAND; + + ps_vma->vm_flags |= VM_DONTCOPY; + + ps_vma->vm_private_data = (void *)psOffsetStruct; + + switch (psOffsetStruct->psLinuxMemArea-> + ui32AreaFlags & PVRSRV_HAP_CACHETYPE_MASK) { + case PVRSRV_HAP_CACHED: + + break; + case PVRSRV_HAP_WRITECOMBINE: + ps_vma->vm_page_prot = PGPROT_WC(ps_vma->vm_page_prot); + break; + case PVRSRV_HAP_UNCACHED: + ps_vma->vm_page_prot = PGPROT_UC(ps_vma->vm_page_prot); + break; + default: + PVR_DPF(PVR_DBG_ERROR, "%s: unknown cache type", __func__); + iRetVal = -EINVAL; + goto unlock_and_return; + } + + ps_vma->vm_ops = &MMapIOOps; + + if (!DoMapToUser(psOffsetStruct->psLinuxMemArea, ps_vma, 0)) { + iRetVal = -EAGAIN; + goto unlock_and_return; + } + + PVR_ASSERT(psOffsetStruct->ui32UserVAddr == 0); + + psOffsetStruct->ui32UserVAddr = ps_vma->vm_start; + + MMapVOpenNoLock(ps_vma); + + PVR_DPF(PVR_DBG_MESSAGE, "%s: Mapped area at offset 0x%08lx\n", + __func__, ps_vma->vm_pgoff); + +unlock_and_return: + if (iRetVal != 0 && psOffsetStruct != NULL) + DestroyOffsetStruct(psOffsetStruct); + + mutex_unlock(&g_sMMapMutex); + + return iRetVal; +} + +#if defined(DEBUG_LINUX_MMAP_AREAS) +static off_t PrintMMapReg_helper(char *buffer, size_t size, + const struct KV_OFFSET_STRUCT *psOffsetStruct, + struct LinuxMemArea *psLinuxMemArea) +{ + off_t Ret; + u32 ui32RealByteSize; + u32 ui32ByteOffset; + + PVR_ASSERT(psOffsetStruct->psLinuxMemArea == psLinuxMemArea); + + DetermineUsersSizeAndByteOffset(psLinuxMemArea, + &ui32RealByteSize, + &ui32ByteOffset); + + Ret = printAppend(buffer, size, 0, + "%-8p %08x %-8p %08x %08x " + "%-8d %-24s %-5u %-8s %08x(%s)\n", + psLinuxMemArea, + psOffsetStruct->ui32UserVAddr + ui32ByteOffset, + LinuxMemAreaToCpuVAddr(psLinuxMemArea), + LinuxMemAreaToCpuPAddr(psLinuxMemArea, 0).uiAddr, + psOffsetStruct->ui32MMapOffset, + psLinuxMemArea->ui32ByteSize, + LinuxMemAreaTypeToString(psLinuxMemArea->eAreaType), + psOffsetStruct->ui32PID, + psOffsetStruct->pszName, + psLinuxMemArea->ui32AreaFlags, + HAPFlagsToString(psLinuxMemArea->ui32AreaFlags)); + return Ret; + +} + +static off_t PrintMMapRegistrations(char *buffer, size_t size, off_t off) +{ + struct LinuxMemArea *psLinuxMemArea; + off_t Ret; + + mutex_lock(&g_sMMapMutex); + + if (!off) { + Ret = printAppend(buffer, size, 0, + "Allocations registered for mmap: %u\n" + "In total these areas correspond to %u bytes\n" + "psLinuxMemArea UserVAddr KernelVAddr " + "CpuPAddr MMapOffset ByteLength " + "LinuxMemType " + "Pid Name Flags\n", + g_ui32RegisteredAreas, g_ui32TotalByteSize); + + goto unlock_and_return; + } + + if (size < 135) { + Ret = 0; + goto unlock_and_return; + } + + PVR_ASSERT(off != 0); + list_for_each_entry(psLinuxMemArea, &g_sMMapAreaList, sMMapItem) { + struct KV_OFFSET_STRUCT *psOffsetStruct; + + list_for_each_entry(psOffsetStruct, + &psLinuxMemArea->sMMapOffsetStructList, + sAreaItem) { + off--; + if (off == 0) { + Ret = PrintMMapReg_helper(buffer, size, + psOffsetStruct, psLinuxMemArea); + goto unlock_and_return; + } + } + } + Ret = END_OF_FILE; + +unlock_and_return: + mutex_unlock(&g_sMMapMutex); + return Ret; +} +#endif + +enum PVRSRV_ERROR PVRMMapRegisterArea(struct LinuxMemArea *psLinuxMemArea) +{ + enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC; +#if defined(CONFIG_PVR_DEBUG) || defined(DEBUG_LINUX_MMAP_AREAS) + const char *pszName = + LinuxMemAreaTypeToString(LinuxMemAreaRootType(psLinuxMemArea)); +#endif + + mutex_lock(&g_sMMapMutex); + + PVR_DPF(PVR_DBG_MESSAGE, + "%s(%s, psLinuxMemArea 0x%p, ui32AllocFlags 0x%8lx)", + __func__, pszName, psLinuxMemArea, + psLinuxMemArea->ui32AreaFlags); + + PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC + || LinuxMemAreaRoot(psLinuxMemArea)->eAreaType != + LINUX_MEM_AREA_SUB_ALLOC); + + if (psLinuxMemArea->bMMapRegistered) { + PVR_DPF(PVR_DBG_ERROR, + "%s: psLinuxMemArea 0x%p is already registered", + __func__, psLinuxMemArea); + eError = PVRSRV_ERROR_INVALID_PARAMS; + goto exit_unlock; + } + + list_add_tail(&psLinuxMemArea->sMMapItem, &g_sMMapAreaList); + + psLinuxMemArea->bMMapRegistered = IMG_TRUE; + +#if defined(DEBUG_LINUX_MMAP_AREAS) + g_ui32RegisteredAreas++; + + if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) + g_ui32TotalByteSize += psLinuxMemArea->ui32ByteSize; +#endif + + eError = PVRSRV_OK; + +exit_unlock: + mutex_unlock(&g_sMMapMutex); + + return eError; +} + +enum PVRSRV_ERROR PVRMMapRemoveRegisteredArea( + struct LinuxMemArea *psLinuxMemArea) +{ + enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC; + struct KV_OFFSET_STRUCT *psOffsetStruct, *psTmpOffsetStruct; + + mutex_lock(&g_sMMapMutex); + + PVR_ASSERT(psLinuxMemArea->bMMapRegistered); + + list_for_each_entry_safe(psOffsetStruct, psTmpOffsetStruct, + &psLinuxMemArea->sMMapOffsetStructList, + sAreaItem) { + if (psOffsetStruct->ui32Mapped != 0) { + PVR_DPF(PVR_DBG_ERROR, "%s: psOffsetStruct " + "0x%p for memory area " + "0x0x%p is still mapped; " + "psOffsetStruct->ui32Mapped %lu", + __func__, psOffsetStruct, psLinuxMemArea, + psOffsetStruct->ui32Mapped); + eError = PVRSRV_ERROR_GENERIC; + goto exit_unlock; + } else { + + PVR_DPF(PVR_DBG_WARNING, + "%s: psOffsetStruct 0x%p was never mapped", + __func__, psOffsetStruct); + } + + PVR_ASSERT((psOffsetStruct->ui32Mapped == 0) + && psOffsetStruct->bOnMMapList); + + DestroyOffsetStruct(psOffsetStruct); + } + + list_del(&psLinuxMemArea->sMMapItem); + + psLinuxMemArea->bMMapRegistered = IMG_FALSE; + +#if defined(DEBUG_LINUX_MMAP_AREAS) + g_ui32RegisteredAreas--; + if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) + g_ui32TotalByteSize -= psLinuxMemArea->ui32ByteSize; +#endif + + eError = PVRSRV_OK; + +exit_unlock: + mutex_unlock(&g_sMMapMutex); + return eError; +} + +enum PVRSRV_ERROR LinuxMMapPerProcessConnect(struct PVRSRV_ENV_PER_PROCESS_DATA + *psEnvPerProc) +{ + PVR_UNREFERENCED_PARAMETER(psEnvPerProc); + + return PVRSRV_OK; +} + +void LinuxMMapPerProcessDisconnect(struct PVRSRV_ENV_PER_PROCESS_DATA + *psEnvPerProc) +{ + struct KV_OFFSET_STRUCT *psOffsetStruct, *psTmpOffsetStruct; + IMG_BOOL bWarn = IMG_FALSE; + u32 ui32PID = OSGetCurrentProcessIDKM(); + + PVR_UNREFERENCED_PARAMETER(psEnvPerProc); + + mutex_lock(&g_sMMapMutex); + + list_for_each_entry_safe(psOffsetStruct, psTmpOffsetStruct, + &g_sMMapOffsetStructList, sMMapItem) { + if (psOffsetStruct->ui32PID == ui32PID) { + if (!bWarn) { + PVR_DPF(PVR_DBG_WARNING, "%s: process has " + "unmapped offset structures. " + "Removing them", + __func__); + bWarn = IMG_TRUE; + } + PVR_ASSERT(psOffsetStruct->ui32Mapped == 0); + PVR_ASSERT(psOffsetStruct->bOnMMapList); + + DestroyOffsetStruct(psOffsetStruct); + } + } + + mutex_unlock(&g_sMMapMutex); +} + +enum PVRSRV_ERROR LinuxMMapPerProcessHandleOptions(struct PVRSRV_HANDLE_BASE + *psHandleBase) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + eError = PVRSRVSetMaxHandle(psHandleBase, MAX_MMAP_HANDLE); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "%s: failed to set handle limit (%d)", + __func__, eError); + return eError; + } + + return eError; +} + +void PVRMMapInit(void) +{ + mutex_init(&g_sMMapMutex); + + g_psMemmapCache = + kmem_cache_create("img-mmap", sizeof(struct KV_OFFSET_STRUCT), + 0, 0, NULL); + if (!g_psMemmapCache) { + PVR_DPF(PVR_DBG_ERROR, "%s: failed to allocate kmem_cache", + __func__); + goto error; + } +#if defined(DEBUG_LINUX_MMAP_AREAS) + CreateProcReadEntry("mmap", PrintMMapRegistrations); +#endif + + return; + +error: + PVRMMapCleanup(); + return; +} + +void PVRMMapCleanup(void) +{ + enum PVRSRV_ERROR eError; + + if (!list_empty(&g_sMMapAreaList)) { + struct LinuxMemArea *psLinuxMemArea, *psTmpMemArea; + + PVR_DPF(PVR_DBG_ERROR, + "%s: Memory areas are still registered with MMap", + __func__); + + PVR_TRACE("%s: Unregistering memory areas", __func__); + list_for_each_entry_safe(psLinuxMemArea, psTmpMemArea, + &g_sMMapAreaList, sMMapItem) { + eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, + "%s: PVRMMapRemoveRegisteredArea failed (%d)", + __func__, eError); + PVR_ASSERT(eError == PVRSRV_OK); + + LinuxMemAreaDeepFree(psLinuxMemArea); + } + } + PVR_ASSERT(list_empty((&g_sMMapAreaList))); + + RemoveProcEntry("mmap"); + + if (g_psMemmapCache) { + kmem_cache_destroy(g_psMemmapCache); + g_psMemmapCache = NULL; + } +} diff --git a/drivers/gpu/pvr/mmap.h b/drivers/gpu/pvr/mmap.h new file mode 100644 index 00000000000..3ab55ff8bc5 --- /dev/null +++ b/drivers/gpu/pvr/mmap.h @@ -0,0 +1,74 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__MMAP_H__) +#define __MMAP_H__ + +#include <linux/mm.h> +#include <linux/list.h> + +#include "perproc.h" +#include "mm.h" + +struct KV_OFFSET_STRUCT { + u32 ui32Mapped; + u32 ui32MMapOffset; + u32 ui32RealByteSize; + struct LinuxMemArea *psLinuxMemArea; + u32 ui32TID; + u32 ui32PID; + IMG_BOOL bOnMMapList; + u32 ui32RefCount; + u32 ui32UserVAddr; +#if defined(DEBUG_LINUX_MMAP_AREAS) + const char *pszName; +#endif + struct list_head sMMapItem; + struct list_head sAreaItem; +}; + +void PVRMMapInit(void); +void PVRMMapCleanup(void); + +enum PVRSRV_ERROR PVRMMapRegisterArea(struct LinuxMemArea *psLinuxMemArea); + +enum PVRSRV_ERROR PVRMMapRemoveRegisteredArea( + struct LinuxMemArea *psLinuxMemArea); + +enum PVRSRV_ERROR PVRMMapOSMemHandleToMMapData( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hMHandle, u32 *pui32MMapOffset, + u32 *pui32ByteOffset, u32 *pui32RealByteSize, + u32 *pui32UserVAddr); + +enum PVRSRV_ERROR PVRMMapReleaseMMapData( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hMHandle, IMG_BOOL *pbMUnmap, + u32 *pui32RealByteSize, u32 *pui32UserVAddr); + +int PVRMMap(struct file *pFile, struct vm_area_struct *ps_vma); + +#endif diff --git a/drivers/gpu/pvr/mmu.c b/drivers/gpu/pvr/mmu.c new file mode 100644 index 00000000000..7b9f0afbf3e --- /dev/null +++ b/drivers/gpu/pvr/mmu.c @@ -0,0 +1,1439 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "sgxdefs.h" +#include "sgxmmu.h" +#include "services_headers.h" +#include "buffer_manager.h" +#include "hash.h" +#include "ra.h" +#include "pdump_km.h" +#include "sgxapi_km.h" +#include "sgx_bridge_km.h" +#include "sgxinfo.h" +#include "sgxinfokm.h" +#include "mmu.h" + +#define UINT32_MAX_VALUE 0xFFFFFFFFUL + +struct MMU_PT_INFO { + void *hPTPageOSMemHandle; + void *PTPageCpuVAddr; + u32 ui32ValidPTECount; +}; + +struct MMU_CONTEXT { + struct PVRSRV_DEVICE_NODE *psDeviceNode; + void *pvPDCpuVAddr; + struct IMG_DEV_PHYADDR sPDDevPAddr; + void *hPDOSMemHandle; + struct MMU_PT_INFO *apsPTInfoList[1024]; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + struct MMU_CONTEXT *psNext; +}; + +struct MMU_HEAP { + struct MMU_CONTEXT *psMMUContext; + + u32 ui32PTBaseIndex; + u32 ui32PTPageCount; + u32 ui32PTEntryCount; + + struct RA_ARENA *psVMArena; + + struct DEV_ARENA_DESCRIPTOR *psDevArena; +}; + + +#if defined(PDUMP) +static void MMU_PDumpPageTables(struct MMU_HEAP *pMMUHeap, + struct IMG_DEV_VIRTADDR DevVAddr, size_t uSize, + IMG_BOOL bForUnmap, void *hUniqueTag); +#endif + +#define PAGE_TEST 0 + + +void MMU_InvalidateDirectoryCache(struct PVRSRV_SGXDEV_INFO *psDevInfo) +{ + psDevInfo->ui32CacheControl |= SGX_BIF_INVALIDATE_PDCACHE; +} + +static void MMU_InvalidatePageTableCache(struct PVRSRV_SGXDEV_INFO *psDevInfo) +{ + psDevInfo->ui32CacheControl |= SGX_BIF_INVALIDATE_PTCACHE; +} + +static IMG_BOOL _AllocPageTables(struct MMU_HEAP *pMMUHeap) +{ + PVR_DPF(PVR_DBG_MESSAGE, "_AllocPageTables()"); + + PVR_ASSERT(pMMUHeap != NULL); + PVR_ASSERT(HOST_PAGESIZE() == SGX_MMU_PAGE_SIZE); + + if (pMMUHeap == NULL) { + PVR_DPF(PVR_DBG_ERROR, "_AllocPageTables: invalid parameter"); + return IMG_FALSE; + } + + pMMUHeap->ui32PTEntryCount = + pMMUHeap->psDevArena->ui32Size >> SGX_MMU_PAGE_SHIFT; + + pMMUHeap->ui32PTBaseIndex = + (pMMUHeap->psDevArena->BaseDevVAddr. + uiAddr & (SGX_MMU_PD_MASK | SGX_MMU_PT_MASK)) >> + SGX_MMU_PAGE_SHIFT; + + pMMUHeap->ui32PTPageCount = + (pMMUHeap->ui32PTEntryCount + SGX_MMU_PT_SIZE - 1) >> + SGX_MMU_PT_SHIFT; + + return IMG_TRUE; +} + +static void _DeferredFreePageTable(struct MMU_HEAP *pMMUHeap, u32 ui32PTIndex) +{ + u32 *pui32PDEntry; + u32 i; + u32 ui32PDIndex; + struct SYS_DATA *psSysData; + struct MMU_PT_INFO **ppsPTInfoList; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "_DeferredFreePageTables: " + "ERROR call to SysAcquireData failed"); + return; + } + + ui32PDIndex = + pMMUHeap->psDevArena->BaseDevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + + SGX_MMU_PT_SHIFT); + + ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; + + { + PVR_ASSERT(ppsPTInfoList[ui32PTIndex] == NULL || + ppsPTInfoList[ui32PTIndex]->ui32ValidPTECount == + 0); + } + + PDUMPCOMMENT("Free page table (page count == %08X)", + pMMUHeap->ui32PTPageCount); + if (ppsPTInfoList[ui32PTIndex] + && ppsPTInfoList[ui32PTIndex]->PTPageCpuVAddr) + PDUMPFREEPAGETABLE(PVRSRV_DEVICE_TYPE_SGX, + ppsPTInfoList[ui32PTIndex]->PTPageCpuVAddr, + SGX_MMU_PAGE_SIZE, PDUMP_PT_UNIQUETAG); + + switch (pMMUHeap->psDevArena->DevMemHeapType) { + case DEVICE_MEMORY_HEAP_SHARED: + case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: + { + struct MMU_CONTEXT *psMMUContext = + (struct MMU_CONTEXT *) + pMMUHeap->psMMUContext->psDevInfo->pvMMUContextList; + + while (psMMUContext) { + pui32PDEntry = + (u32 *) psMMUContext->pvPDCpuVAddr; + pui32PDEntry += ui32PDIndex; + pui32PDEntry[ui32PTIndex] = 0; + PDUMPMEM2(PVRSRV_DEVICE_TYPE_SGX, + (void *) & + pui32PDEntry[ui32PTIndex], + sizeof(u32), 0, IMG_FALSE, + PDUMP_PT_UNIQUETAG, + PDUMP_PT_UNIQUETAG); + psMMUContext = psMMUContext->psNext; + } + break; + } + case DEVICE_MEMORY_HEAP_PERCONTEXT: + case DEVICE_MEMORY_HEAP_KERNEL: + { + + pui32PDEntry = + (u32 *) pMMUHeap->psMMUContext->pvPDCpuVAddr; + pui32PDEntry += ui32PDIndex; + pui32PDEntry[ui32PTIndex] = 0; + PDUMPMEM2(PVRSRV_DEVICE_TYPE_SGX, + (void *) &pui32PDEntry[ui32PTIndex], + sizeof(u32), 0, IMG_FALSE, + PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); + break; + } + default: + { + PVR_DPF(PVR_DBG_ERROR, + "_DeferredFreePagetable: ERROR invalid heap type"); + return; + } + } + + if (ppsPTInfoList[ui32PTIndex] != NULL) { + if (ppsPTInfoList[ui32PTIndex]->PTPageCpuVAddr != NULL) { + u32 *pui32Tmp; + + pui32Tmp = + (u32 *) ppsPTInfoList[ui32PTIndex]-> + PTPageCpuVAddr; + + for (i = 0; + (i < pMMUHeap->ui32PTEntryCount) && (i < 1024); + i++) + pui32Tmp[i] = 0; + + if (pMMUHeap->psDevArena->psDeviceMemoryHeapInfo-> + psLocalDevMemArena == NULL) { + OSFreePages(PVRSRV_HAP_WRITECOMBINE | + PVRSRV_HAP_KERNEL_ONLY, + SGX_MMU_PAGE_SIZE, + ppsPTInfoList[ui32PTIndex]-> + PTPageCpuVAddr, + ppsPTInfoList[ui32PTIndex]-> + hPTPageOSMemHandle); + } else { + struct IMG_SYS_PHYADDR sSysPAddr; + struct IMG_CPU_PHYADDR sCpuPAddr; + + sCpuPAddr = + OSMapLinToCPUPhys(ppsPTInfoList + [ui32PTIndex]-> + PTPageCpuVAddr); + sSysPAddr = SysCpuPAddrToSysPAddr(sCpuPAddr); + + OSUnMapPhysToLin((void __force __iomem *) + ppsPTInfoList[ui32PTIndex]-> + PTPageCpuVAddr, + SGX_MMU_PAGE_SIZE, + PVRSRV_HAP_WRITECOMBINE | + PVRSRV_HAP_KERNEL_ONLY, + ppsPTInfoList[ui32PTIndex]-> + hPTPageOSMemHandle); + + RA_Free(pMMUHeap->psDevArena-> + psDeviceMemoryHeapInfo-> + psLocalDevMemArena, + sSysPAddr.uiAddr, IMG_FALSE); + } + + pMMUHeap->ui32PTEntryCount -= i; + } else { + pMMUHeap->ui32PTEntryCount -= 1024; + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct MMU_PT_INFO), + ppsPTInfoList[ui32PTIndex], NULL); + ppsPTInfoList[ui32PTIndex] = NULL; + } else { + pMMUHeap->ui32PTEntryCount -= 1024; + } + + PDUMPCOMMENT("Finished free page table (page count == %08X)", + pMMUHeap->ui32PTPageCount); +} + +static void _DeferredFreePageTables(struct MMU_HEAP *pMMUHeap) +{ + u32 i; + + for (i = 0; i < pMMUHeap->ui32PTPageCount; i++) + _DeferredFreePageTable(pMMUHeap, i); + MMU_InvalidateDirectoryCache(pMMUHeap->psMMUContext->psDevInfo); +} + +static IMG_BOOL _DeferredAllocPagetables(struct MMU_HEAP *pMMUHeap, + struct IMG_DEV_VIRTADDR DevVAddr, u32 ui32Size) +{ + u32 ui32PTPageCount; + u32 ui32PDIndex; + u32 i; + u32 *pui32PDEntry; + struct MMU_PT_INFO **ppsPTInfoList; + struct SYS_DATA *psSysData; + struct IMG_DEV_VIRTADDR sHighDevVAddr; + + PVR_ASSERT(DevVAddr.uiAddr < (1 << SGX_FEATURE_ADDRESS_SPACE_SIZE)); + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return IMG_FALSE; + + ui32PDIndex = + DevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); + + if ((UINT32_MAX_VALUE - DevVAddr.uiAddr) < + (ui32Size + (1 << (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT)) - 1)) { + + sHighDevVAddr.uiAddr = UINT32_MAX_VALUE; + } else { + sHighDevVAddr.uiAddr = DevVAddr.uiAddr + ui32Size + + (1 << (SGX_MMU_PAGE_SHIFT + + SGX_MMU_PT_SHIFT)) - 1; + } + + ui32PTPageCount = + sHighDevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); + + ui32PTPageCount -= ui32PDIndex; + + pui32PDEntry = (u32 *) pMMUHeap->psMMUContext->pvPDCpuVAddr; + pui32PDEntry += ui32PDIndex; + + ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; + + PDUMPCOMMENT("Alloc page table (page count == %08X)", ui32PTPageCount); + PDUMPCOMMENT("Page directory mods (page count == %08X)", + ui32PTPageCount); + + for (i = 0; i < ui32PTPageCount; i++) { + if (ppsPTInfoList[i] == NULL) { + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct MMU_PT_INFO), + (void **) &ppsPTInfoList[i], NULL) + != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "_DeferredAllocPagetables: " + "ERROR call to OSAllocMem failed"); + return IMG_FALSE; + } + OSMemSet(ppsPTInfoList[i], 0, + sizeof(struct MMU_PT_INFO)); + } + + if (ppsPTInfoList[i]->hPTPageOSMemHandle == NULL && + ppsPTInfoList[i]->PTPageCpuVAddr == NULL) { + struct IMG_CPU_PHYADDR sCpuPAddr; + struct IMG_DEV_PHYADDR sDevPAddr; + + PVR_ASSERT(pui32PDEntry[i] == 0); + + if (pMMUHeap->psDevArena->psDeviceMemoryHeapInfo-> + psLocalDevMemArena == NULL) { + if (OSAllocPages(PVRSRV_HAP_WRITECOMBINE | + PVRSRV_HAP_KERNEL_ONLY, + SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE, + (void **)&ppsPTInfoList[i]-> + PTPageCpuVAddr, + &ppsPTInfoList[i]-> + hPTPageOSMemHandle) != + PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "_DeferredAllocPagetables: " + "ERROR call to OSAllocPages failed"); + return IMG_FALSE; + } + + if (ppsPTInfoList[i]->PTPageCpuVAddr) { + sCpuPAddr = + OSMapLinToCPUPhys(ppsPTInfoList[i]-> + PTPageCpuVAddr); + } else { + sCpuPAddr = + OSMemHandleToCpuPAddr( + ppsPTInfoList[i]-> + hPTPageOSMemHandle, + 0); + } + sDevPAddr = + SysCpuPAddrToDevPAddr + (PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); + } else { + struct IMG_SYS_PHYADDR sSysPAddr; + + if (RA_Alloc(pMMUHeap->psDevArena-> + psDeviceMemoryHeapInfo->psLocalDevMemArena, + SGX_MMU_PAGE_SIZE, NULL, 0, + SGX_MMU_PAGE_SIZE, + &(sSysPAddr.uiAddr)) != IMG_TRUE) { + PVR_DPF(PVR_DBG_ERROR, + "_DeferredAllocPagetables: " + "ERROR call to RA_Alloc failed"); + return IMG_FALSE; + } + + sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); + ppsPTInfoList[i]->PTPageCpuVAddr = + (void __force *) + OSMapPhysToLin(sCpuPAddr, SGX_MMU_PAGE_SIZE, + PVRSRV_HAP_WRITECOMBINE | + PVRSRV_HAP_KERNEL_ONLY, + &ppsPTInfoList[i]-> + hPTPageOSMemHandle); + if (!ppsPTInfoList[i]->PTPageCpuVAddr) { + PVR_DPF(PVR_DBG_ERROR, + "_DeferredAllocPagetables: " + "ERROR failed to map page tables"); + return IMG_FALSE; + } + + sDevPAddr = SysCpuPAddrToDevPAddr + (PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); + + } + + + OSMemSet(ppsPTInfoList[i]->PTPageCpuVAddr, 0, + SGX_MMU_PAGE_SIZE); + + PDUMPMALLOCPAGETABLE(PVRSRV_DEVICE_TYPE_SGX, + ppsPTInfoList[i]->PTPageCpuVAddr, + SGX_MMU_PAGE_SIZE, + PDUMP_PT_UNIQUETAG); + + PDUMPMEM2(PVRSRV_DEVICE_TYPE_SGX, + ppsPTInfoList[i]->PTPageCpuVAddr, + SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, + PDUMP_PT_UNIQUETAG, PDUMP_PT_UNIQUETAG); + + switch (pMMUHeap->psDevArena->DevMemHeapType) { + case DEVICE_MEMORY_HEAP_SHARED: + case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: + { + struct MMU_CONTEXT *psMMUContext = + (struct MMU_CONTEXT *)pMMUHeap-> + psMMUContext->psDevInfo-> + pvMMUContextList; + + while (psMMUContext) { + pui32PDEntry = + (u32 *)psMMUContext-> + pvPDCpuVAddr; + pui32PDEntry += ui32PDIndex; + + pui32PDEntry[i] = + sDevPAddr.uiAddr | + SGX_MMU_PDE_VALID; + + PDUMPMEM2 + (PVRSRV_DEVICE_TYPE_SGX, + (void *)&pui32PDEntry[i], + sizeof(u32), 0, + IMG_FALSE, + PDUMP_PD_UNIQUETAG, + PDUMP_PT_UNIQUETAG); + + psMMUContext = + psMMUContext->psNext; + } + break; + } + case DEVICE_MEMORY_HEAP_PERCONTEXT: + case DEVICE_MEMORY_HEAP_KERNEL: + { + pui32PDEntry[i] = sDevPAddr.uiAddr | + SGX_MMU_PDE_VALID; + + PDUMPMEM2(PVRSRV_DEVICE_TYPE_SGX, + (void *)&pui32PDEntry[i], + sizeof(u32), 0, + IMG_FALSE, PDUMP_PD_UNIQUETAG, + PDUMP_PT_UNIQUETAG); + + break; + } + default: + { + PVR_DPF(PVR_DBG_ERROR, + "_DeferredAllocPagetables: " + "ERROR invalid heap type"); + return IMG_FALSE; + } + } + + + MMU_InvalidateDirectoryCache(pMMUHeap->psMMUContext-> + psDevInfo); + } else { + + PVR_ASSERT(pui32PDEntry[i] != 0); + } + } + + return IMG_TRUE; +} + +enum PVRSRV_ERROR MMU_Initialise(struct PVRSRV_DEVICE_NODE *psDeviceNode, + struct MMU_CONTEXT **ppsMMUContext, + struct IMG_DEV_PHYADDR *psPDDevPAddr) +{ + u32 *pui32Tmp; + u32 i; + void *pvPDCpuVAddr; + struct IMG_DEV_PHYADDR sPDDevPAddr; + struct IMG_CPU_PHYADDR sCpuPAddr; + struct MMU_CONTEXT *psMMUContext; + void *hPDOSMemHandle; + struct SYS_DATA *psSysData; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + + PVR_DPF(PVR_DBG_MESSAGE, "MMU_Initialise"); + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_Initialise: ERROR call to SysAcquireData failed"); + return PVRSRV_ERROR_GENERIC; + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct MMU_CONTEXT), (void **) &psMMUContext, NULL) + != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_Initialise: ERROR call to OSAllocMem failed"); + return PVRSRV_ERROR_GENERIC; + } + OSMemSet(psMMUContext, 0, sizeof(struct MMU_CONTEXT)); + + psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + psMMUContext->psDevInfo = psDevInfo; + + psMMUContext->psDeviceNode = psDeviceNode; + + if (psDeviceNode->psLocalDevMemArena == NULL) { + if (OSAllocPages + (PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, + SGX_MMU_PAGE_SIZE, SGX_MMU_PAGE_SIZE, &pvPDCpuVAddr, + &hPDOSMemHandle) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "MMU_Initialise: " + "ERROR call to OSAllocPages failed"); + return PVRSRV_ERROR_GENERIC; + } + + if (pvPDCpuVAddr) + sCpuPAddr = OSMapLinToCPUPhys(pvPDCpuVAddr); + else + sCpuPAddr = OSMemHandleToCpuPAddr(hPDOSMemHandle, 0); + sPDDevPAddr = + SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); + } else { + struct IMG_SYS_PHYADDR sSysPAddr; + + if (RA_Alloc(psDeviceNode->psLocalDevMemArena, + SGX_MMU_PAGE_SIZE, NULL, 0, SGX_MMU_PAGE_SIZE, + &(sSysPAddr.uiAddr)) != IMG_TRUE) { + PVR_DPF(PVR_DBG_ERROR, "MMU_Initialise: " + "ERROR call to RA_Alloc failed"); + return PVRSRV_ERROR_GENERIC; + } + + sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); + sPDDevPAddr = + SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sSysPAddr); + pvPDCpuVAddr = (void __force *) + OSMapPhysToLin(sCpuPAddr, SGX_MMU_PAGE_SIZE, + PVRSRV_HAP_WRITECOMBINE | + PVRSRV_HAP_KERNEL_ONLY, &hPDOSMemHandle); + if (!pvPDCpuVAddr) { + PVR_DPF(PVR_DBG_ERROR, "MMU_Initialise: " + "ERROR failed to map page tables"); + return PVRSRV_ERROR_GENERIC; + } + } + + PDUMPCOMMENT("Alloc page directory"); + + PDUMPMALLOCPAGETABLE(PVRSRV_DEVICE_TYPE_SGX, pvPDCpuVAddr, + SGX_MMU_PAGE_SIZE, PDUMP_PD_UNIQUETAG); + + if (pvPDCpuVAddr) { + pui32Tmp = (u32 *) pvPDCpuVAddr; + } else { + PVR_DPF(PVR_DBG_ERROR, + "MMU_Initialise: pvPDCpuVAddr invalid"); + return PVRSRV_ERROR_GENERIC; + } + + for (i = 0; i < SGX_MMU_PD_SIZE; i++) + pui32Tmp[i] = 0; + + PDUMPCOMMENT("Page directory contents"); + PDUMPMEM2(PVRSRV_DEVICE_TYPE_SGX, pvPDCpuVAddr, SGX_MMU_PAGE_SIZE, 0, + IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); + + psMMUContext->pvPDCpuVAddr = pvPDCpuVAddr; + psMMUContext->sPDDevPAddr = sPDDevPAddr; + psMMUContext->hPDOSMemHandle = hPDOSMemHandle; + + *ppsMMUContext = psMMUContext; + + *psPDDevPAddr = sPDDevPAddr; + + psMMUContext->psNext = (struct MMU_CONTEXT *) + psDevInfo->pvMMUContextList; + psDevInfo->pvMMUContextList = (void *) psMMUContext; + + + return PVRSRV_OK; +} + +void MMU_Finalise(struct MMU_CONTEXT *psMMUContext) +{ + u32 *pui32Tmp, i; + struct SYS_DATA *psSysData; + struct MMU_CONTEXT **ppsMMUContext; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_Finalise: ERROR call to SysAcquireData failed"); + return; + } + + PDUMPCOMMENT("Free page directory"); + PDUMPFREEPAGETABLE(PVRSRV_DEVICE_TYPE_SGX, psMMUContext->pvPDCpuVAddr, + SGX_MMU_PAGE_SIZE, PDUMP_PT_UNIQUETAG); + + pui32Tmp = (u32 *) psMMUContext->pvPDCpuVAddr; + + for (i = 0; i < SGX_MMU_PD_SIZE; i++) + pui32Tmp[i] = 0; + + if (psMMUContext->psDeviceNode->psLocalDevMemArena == NULL) { + OSFreePages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, + SGX_MMU_PAGE_SIZE, + psMMUContext->pvPDCpuVAddr, + psMMUContext->hPDOSMemHandle); + + } else { + struct IMG_SYS_PHYADDR sSysPAddr; + struct IMG_CPU_PHYADDR sCpuPAddr; + + sCpuPAddr = OSMapLinToCPUPhys(psMMUContext->pvPDCpuVAddr); + sSysPAddr = SysCpuPAddrToSysPAddr(sCpuPAddr); + + OSUnMapPhysToLin((void __iomem __force *) + psMMUContext->pvPDCpuVAddr, + SGX_MMU_PAGE_SIZE, + PVRSRV_HAP_WRITECOMBINE | + PVRSRV_HAP_KERNEL_ONLY, + psMMUContext->hPDOSMemHandle); + + RA_Free(psMMUContext->psDeviceNode->psLocalDevMemArena, + sSysPAddr.uiAddr, IMG_FALSE); + + } + + PVR_DPF(PVR_DBG_MESSAGE, "MMU_Finalise"); + + ppsMMUContext = + (struct MMU_CONTEXT **) &psMMUContext->psDevInfo->pvMMUContextList; + while (*ppsMMUContext) { + if (*ppsMMUContext == psMMUContext) { + + *ppsMMUContext = psMMUContext->psNext; + break; + } + + ppsMMUContext = &((*ppsMMUContext)->psNext); + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct MMU_CONTEXT), + psMMUContext, NULL); +} + +void MMU_InsertHeap(struct MMU_CONTEXT *psMMUContext, + struct MMU_HEAP *psMMUHeap) +{ + u32 *pui32PDCpuVAddr = (u32 *)psMMUContext->pvPDCpuVAddr; + u32 *pui32KernelPDCpuVAddr = (u32 *) + psMMUHeap->psMMUContext->pvPDCpuVAddr; + u32 ui32PDEntry; + IMG_BOOL bInvalidateDirectoryCache = IMG_FALSE; + + pui32PDCpuVAddr += + psMMUHeap->psDevArena->BaseDevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + + SGX_MMU_PT_SHIFT); + pui32KernelPDCpuVAddr += + psMMUHeap->psDevArena->BaseDevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + + SGX_MMU_PT_SHIFT); + + PDUMPCOMMENT("Page directory shared heap range copy"); + + for (ui32PDEntry = 0; ui32PDEntry < psMMUHeap->ui32PTPageCount; + ui32PDEntry++) { + + PVR_ASSERT(pui32PDCpuVAddr[ui32PDEntry] == 0); + + pui32PDCpuVAddr[ui32PDEntry] = + pui32KernelPDCpuVAddr[ui32PDEntry]; + if (pui32PDCpuVAddr[ui32PDEntry]) { + PDUMPMEM2(PVRSRV_DEVICE_TYPE_SGX, + (void *) &pui32PDCpuVAddr[ui32PDEntry], + sizeof(u32), 0, IMG_FALSE, + PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); + + bInvalidateDirectoryCache = IMG_TRUE; + } + } + + if (bInvalidateDirectoryCache) + MMU_InvalidateDirectoryCache(psMMUContext->psDevInfo); +} + +static void MMU_UnmapPagesAndFreePTs(struct MMU_HEAP *psMMUHeap, + struct IMG_DEV_VIRTADDR sDevVAddr, + u32 ui32PageCount, void *hUniqueTag) +{ + u32 uPageSize = HOST_PAGESIZE(); + struct IMG_DEV_VIRTADDR sTmpDevVAddr; + u32 i; + u32 ui32PDIndex; + u32 ui32PTIndex; + u32 *pui32Tmp; + IMG_BOOL bInvalidateDirectoryCache = IMG_FALSE; + +#if !defined(PDUMP) + PVR_UNREFERENCED_PARAMETER(hUniqueTag); +#endif + + sTmpDevVAddr = sDevVAddr; + + for (i = 0; i < ui32PageCount; i++) { + struct MMU_PT_INFO **ppsPTInfoList; + + ui32PDIndex = + sTmpDevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + + SGX_MMU_PT_SHIFT); + + ppsPTInfoList = + &psMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; + + { + ui32PTIndex = (sTmpDevVAddr.uiAddr & SGX_MMU_PT_MASK) + >> SGX_MMU_PAGE_SHIFT; + + if (!ppsPTInfoList[0]) { + PVR_DPF(PVR_DBG_MESSAGE, + "MMU_UnmapPagesAndFreePTs: " + "Invalid PT for alloc at VAddr:0x%08lX " + "(VaddrIni:0x%08lX AllocPage:%u) " + "PDIdx:%u PTIdx:%u", + sTmpDevVAddr.uiAddr, sDevVAddr.uiAddr, + i, ui32PDIndex, ui32PTIndex); + + sTmpDevVAddr.uiAddr += uPageSize; + + continue; + } + + pui32Tmp = (u32 *)ppsPTInfoList[0]->PTPageCpuVAddr; + + if (!pui32Tmp) + continue; + + if (pui32Tmp[ui32PTIndex] & SGX_MMU_PTE_VALID) { + ppsPTInfoList[0]->ui32ValidPTECount--; + } else { + PVR_DPF(PVR_DBG_MESSAGE, + "MMU_UnmapPagesAndFreePTs: " + "Page is already invalid for alloc at " + "VAddr:0x%08lX " + "(VAddrIni:0x%08lX AllocPage:%u) " + "PDIdx:%u PTIdx:%u", + sTmpDevVAddr.uiAddr, sDevVAddr.uiAddr, + i, ui32PDIndex, ui32PTIndex); + } + + PVR_ASSERT((s32)ppsPTInfoList[0]->ui32ValidPTECount >= + 0); + pui32Tmp[ui32PTIndex] = 0; + } + + if (ppsPTInfoList[0] + && ppsPTInfoList[0]->ui32ValidPTECount == 0) { + _DeferredFreePageTable(psMMUHeap, + ui32PDIndex - (psMMUHeap-> + ui32PTBaseIndex >> + SGX_MMU_PT_SHIFT)); + bInvalidateDirectoryCache = IMG_TRUE; + } + + sTmpDevVAddr.uiAddr += uPageSize; + } + + if (bInvalidateDirectoryCache) { + MMU_InvalidateDirectoryCache(psMMUHeap->psMMUContext-> + psDevInfo); + } else { + MMU_InvalidatePageTableCache(psMMUHeap->psMMUContext-> + psDevInfo); + } + +#if defined(PDUMP) + MMU_PDumpPageTables(psMMUHeap, sDevVAddr, uPageSize * ui32PageCount, + IMG_TRUE, hUniqueTag); +#endif +} + +static void MMU_FreePageTables(void *pvMMUHeap, u32 ui32Start, u32 ui32End, + void *hUniqueTag) +{ + struct MMU_HEAP *pMMUHeap = (struct MMU_HEAP *)pvMMUHeap; + struct IMG_DEV_VIRTADDR Start; + + Start.uiAddr = ui32Start; + + MMU_UnmapPagesAndFreePTs(pMMUHeap, Start, + (ui32End - ui32Start) / SGX_MMU_PAGE_SIZE, + hUniqueTag); +} + +struct MMU_HEAP *MMU_Create(struct MMU_CONTEXT *psMMUContext, + struct DEV_ARENA_DESCRIPTOR *psDevArena, + struct RA_ARENA **ppsVMArena) +{ + struct MMU_HEAP *pMMUHeap; + IMG_BOOL bRes; + + PVR_ASSERT(psDevArena != NULL); + + if (psDevArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, "MMU_Create: invalid parameter"); + return NULL; + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct MMU_HEAP), (void **)&pMMUHeap, NULL) + != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_Create: ERROR call to OSAllocMem failed"); + return NULL; + } + + pMMUHeap->psMMUContext = psMMUContext; + pMMUHeap->psDevArena = psDevArena; + + bRes = _AllocPageTables(pMMUHeap); + if (!bRes) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_Create: ERROR call to _AllocPageTables failed"); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct MMU_HEAP), + pMMUHeap, NULL); + return NULL; + } + + pMMUHeap->psVMArena = RA_Create(psDevArena->pszName, + psDevArena->BaseDevVAddr.uiAddr, + psDevArena->ui32Size, NULL, + SGX_MMU_PAGE_SIZE, NULL, NULL, + MMU_FreePageTables, pMMUHeap); + + if (pMMUHeap->psVMArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_Create: ERROR call to RA_Create failed"); + _DeferredFreePageTables(pMMUHeap); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct MMU_HEAP), + pMMUHeap, NULL); + return NULL; + } + + *ppsVMArena = pMMUHeap->psVMArena; + + return pMMUHeap; +} + +void MMU_Delete(struct MMU_HEAP *pMMUHeap) +{ + if (pMMUHeap != NULL) { + PVR_DPF(PVR_DBG_MESSAGE, "MMU_Delete"); + + if (pMMUHeap->psVMArena) + RA_Delete(pMMUHeap->psVMArena); + _DeferredFreePageTables(pMMUHeap); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct MMU_HEAP), + pMMUHeap, NULL); + } +} + +IMG_BOOL MMU_Alloc(struct MMU_HEAP *pMMUHeap, size_t uSize, u32 uFlags, + u32 uDevVAddrAlignment, struct IMG_DEV_VIRTADDR *psDevVAddr) +{ + IMG_BOOL bStatus; + + PVR_DPF(PVR_DBG_MESSAGE, + "MMU_Alloc: uSize=0x%x, flags=0x%x, align=0x%x", + uSize, uFlags, uDevVAddrAlignment); + + if ((uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) == 0) { + bStatus = RA_Alloc(pMMUHeap->psVMArena, uSize, NULL, 0, + uDevVAddrAlignment, &(psDevVAddr->uiAddr)); + if (!bStatus) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_Alloc: RA_Alloc of VMArena failed"); + return bStatus; + } + } + + bStatus = _DeferredAllocPagetables(pMMUHeap, *psDevVAddr, uSize); + + + if (!bStatus) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_Alloc: _DeferredAllocPagetables failed"); + if ((uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) == 0) + RA_Free(pMMUHeap->psVMArena, psDevVAddr->uiAddr, + IMG_FALSE); + } + + return bStatus; +} + +void MMU_Free(struct MMU_HEAP *pMMUHeap, struct IMG_DEV_VIRTADDR DevVAddr, + u32 ui32Size) +{ + PVR_ASSERT(pMMUHeap != NULL); + + if (pMMUHeap == NULL) { + PVR_DPF(PVR_DBG_ERROR, "MMU_Free: invalid parameter"); + return; + } + + PVR_DPF(PVR_DBG_MESSAGE, + "MMU_Free: mmu=%08X, dev_vaddr=%08X", pMMUHeap, + DevVAddr.uiAddr); + + if ((DevVAddr.uiAddr >= pMMUHeap->psDevArena->BaseDevVAddr.uiAddr) && + (DevVAddr.uiAddr + ui32Size <= + pMMUHeap->psDevArena->BaseDevVAddr.uiAddr + + pMMUHeap->psDevArena->ui32Size)) { + RA_Free(pMMUHeap->psVMArena, DevVAddr.uiAddr, IMG_TRUE); + return; + } + + BUG(); + + PVR_DPF(PVR_DBG_ERROR, + "MMU_Free: Couldn't find DevVAddr %08X in a DevArena", + DevVAddr.uiAddr); +} + +void MMU_Enable(struct MMU_HEAP *pMMUHeap) +{ + PVR_UNREFERENCED_PARAMETER(pMMUHeap); + +} + +void MMU_Disable(struct MMU_HEAP *pMMUHeap) +{ + PVR_UNREFERENCED_PARAMETER(pMMUHeap); + +} + +#if defined(PDUMP) +static void MMU_PDumpPageTables(struct MMU_HEAP *pMMUHeap, + struct IMG_DEV_VIRTADDR DevVAddr, + size_t uSize, IMG_BOOL bForUnmap, void *hUniqueTag) +{ + u32 ui32NumPTEntries; + u32 ui32PTIndex; + u32 *pui32PTEntry; + + struct MMU_PT_INFO **ppsPTInfoList; + u32 ui32PDIndex; + u32 ui32PTDumpCount; + + ui32NumPTEntries = + (uSize + SGX_MMU_PAGE_SIZE - 1) >> SGX_MMU_PAGE_SHIFT; + + ui32PDIndex = + DevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); + + ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; + + ui32PTIndex = (DevVAddr.uiAddr & SGX_MMU_PT_MASK) >> SGX_MMU_PAGE_SHIFT; + + PDUMPCOMMENT("Page table mods (num entries == %08X) %s", + ui32NumPTEntries, bForUnmap ? "(for unmap)" : ""); + + while (ui32NumPTEntries > 0) { + struct MMU_PT_INFO *psPTInfo = *ppsPTInfoList++; + + if (ui32NumPTEntries <= 1024 - ui32PTIndex) + ui32PTDumpCount = ui32NumPTEntries; + else + ui32PTDumpCount = 1024 - ui32PTIndex; + + if (psPTInfo) { + pui32PTEntry = (u32 *)psPTInfo->PTPageCpuVAddr; + PDUMPMEM2(PVRSRV_DEVICE_TYPE_SGX, + (void *)&pui32PTEntry[ui32PTIndex], + ui32PTDumpCount * sizeof(u32), 0, + IMG_FALSE, PDUMP_PT_UNIQUETAG, hUniqueTag); + } + + ui32NumPTEntries -= ui32PTDumpCount; + + ui32PTIndex = 0; + } + + PDUMPCOMMENT("Finished page table mods %s", + bForUnmap ? "(for unmap)" : ""); +} +#endif + +static void MMU_MapPage(struct MMU_HEAP *pMMUHeap, + struct IMG_DEV_VIRTADDR DevVAddr, + struct IMG_DEV_PHYADDR DevPAddr, u32 ui32MemFlags) +{ + u32 ui32Index; + u32 *pui32Tmp; + u32 ui32MMUFlags = 0; + struct MMU_PT_INFO **ppsPTInfoList; + + if (((PVRSRV_MEM_READ | PVRSRV_MEM_WRITE) & ui32MemFlags) == + (PVRSRV_MEM_READ | PVRSRV_MEM_WRITE)) + ui32MMUFlags = 0; + else if (PVRSRV_MEM_READ & ui32MemFlags) + ui32MMUFlags |= SGX_MMU_PTE_READONLY; + else if (PVRSRV_MEM_WRITE & ui32MemFlags) + ui32MMUFlags |= SGX_MMU_PTE_WRITEONLY; + + if (PVRSRV_MEM_CACHE_CONSISTENT & ui32MemFlags) + ui32MMUFlags |= SGX_MMU_PTE_CACHECONSISTENT; + + if (PVRSRV_MEM_EDM_PROTECT & ui32MemFlags) + ui32MMUFlags |= SGX_MMU_PTE_EDMPROTECT; + + ui32Index = DevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); + + ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32Index]; + + ui32Index = (DevVAddr.uiAddr & SGX_MMU_PT_MASK) >> SGX_MMU_PAGE_SHIFT; + + pui32Tmp = (u32 *) ppsPTInfoList[0]->PTPageCpuVAddr; + + + if (pui32Tmp[ui32Index] & SGX_MMU_PTE_VALID) + PVR_DPF(PVR_DBG_ERROR, + "MMU_MapPage: " + "Page is already valid for alloc at " + "VAddr:0x%08lX PDIdx:%u PTIdx:%u", + DevVAddr.uiAddr, + DevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + + SGX_MMU_PT_SHIFT), ui32Index); + + PVR_ASSERT((pui32Tmp[ui32Index] & SGX_MMU_PTE_VALID) == 0); + + ppsPTInfoList[0]->ui32ValidPTECount++; + + pui32Tmp[ui32Index] = (DevPAddr.uiAddr & SGX_MMU_PTE_ADDR_MASK) + | SGX_MMU_PTE_VALID | ui32MMUFlags; +} + +void MMU_MapScatter(struct MMU_HEAP *pMMUHeap, struct IMG_DEV_VIRTADDR DevVAddr, + struct IMG_SYS_PHYADDR *psSysAddr, size_t uSize, + u32 ui32MemFlags, void *hUniqueTag) +{ +#if defined(PDUMP) + struct IMG_DEV_VIRTADDR MapBaseDevVAddr; +#endif + u32 uCount, i; + struct IMG_DEV_PHYADDR DevPAddr; + + PVR_ASSERT(pMMUHeap != NULL); + +#if defined(PDUMP) + MapBaseDevVAddr = DevVAddr; +#else + PVR_UNREFERENCED_PARAMETER(hUniqueTag); +#endif + + for (i = 0, uCount = 0; uCount < uSize; + i++, uCount += SGX_MMU_PAGE_SIZE) { + struct IMG_SYS_PHYADDR sSysAddr; + + sSysAddr = psSysAddr[i]; + + DevPAddr = + SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sSysAddr); + + MMU_MapPage(pMMUHeap, DevVAddr, DevPAddr, ui32MemFlags); + DevVAddr.uiAddr += SGX_MMU_PAGE_SIZE; + + PVR_DPF(PVR_DBG_MESSAGE, "MMU_MapScatter: " + "devVAddr=%08X, SysAddr=%08X, size=0x%x/0x%x", + DevVAddr.uiAddr, sSysAddr.uiAddr, uCount, uSize); + } + +#if defined(PDUMP) + MMU_PDumpPageTables(pMMUHeap, MapBaseDevVAddr, uSize, IMG_FALSE, + hUniqueTag); +#endif +} + +void MMU_MapPages(struct MMU_HEAP *pMMUHeap, struct IMG_DEV_VIRTADDR DevVAddr, + struct IMG_SYS_PHYADDR SysPAddr, size_t uSize, + u32 ui32MemFlags, void *hUniqueTag) +{ + struct IMG_DEV_PHYADDR DevPAddr; +#if defined(PDUMP) + struct IMG_DEV_VIRTADDR MapBaseDevVAddr; +#endif + u32 uCount; + u32 ui32VAdvance = SGX_MMU_PAGE_SIZE; + u32 ui32PAdvance = SGX_MMU_PAGE_SIZE; + + PVR_ASSERT(pMMUHeap != NULL); + + PVR_DPF(PVR_DBG_MESSAGE, "MMU_MapPages: " + "mmu=%08X, devVAddr=%08X, SysPAddr=%08X, size=0x%x", + pMMUHeap, DevVAddr.uiAddr, SysPAddr.uiAddr, uSize); + +#if defined(PDUMP) + MapBaseDevVAddr = DevVAddr; +#else + PVR_UNREFERENCED_PARAMETER(hUniqueTag); +#endif + + DevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, SysPAddr); + + if (ui32MemFlags & PVRSRV_MEM_DUMMY) + ui32PAdvance = 0; + + for (uCount = 0; uCount < uSize; uCount += ui32VAdvance) { + MMU_MapPage(pMMUHeap, DevVAddr, DevPAddr, ui32MemFlags); + DevVAddr.uiAddr += ui32VAdvance; + DevPAddr.uiAddr += ui32PAdvance; + } + +#if defined(PDUMP) + MMU_PDumpPageTables(pMMUHeap, MapBaseDevVAddr, uSize, IMG_FALSE, + hUniqueTag); +#endif +} + +void MMU_MapShadow(struct MMU_HEAP *pMMUHeap, + struct IMG_DEV_VIRTADDR MapBaseDevVAddr, + size_t uByteSize, void *CpuVAddr, void *hOSMemHandle, + struct IMG_DEV_VIRTADDR *pDevVAddr, u32 ui32MemFlags, + void *hUniqueTag) +{ + u32 i; + u32 uOffset = 0; + struct IMG_DEV_VIRTADDR MapDevVAddr; + u32 ui32VAdvance = SGX_MMU_PAGE_SIZE; + u32 ui32PAdvance = SGX_MMU_PAGE_SIZE; + +#if !defined(PDUMP) + PVR_UNREFERENCED_PARAMETER(hUniqueTag); +#endif + + PVR_DPF(PVR_DBG_MESSAGE, + "MMU_MapShadow: %08X, 0x%x, %08X", + MapBaseDevVAddr.uiAddr, uByteSize, CpuVAddr); + + PVR_ASSERT(((u32) CpuVAddr & (SGX_MMU_PAGE_SIZE - 1)) == 0); + PVR_ASSERT(((u32) uByteSize & (SGX_MMU_PAGE_SIZE - 1)) == 0); + pDevVAddr->uiAddr = MapBaseDevVAddr.uiAddr; + + if (ui32MemFlags & PVRSRV_MEM_DUMMY) + ui32PAdvance = 0; + + MapDevVAddr = MapBaseDevVAddr; + for (i = 0; i < uByteSize; i += ui32VAdvance) { + struct IMG_CPU_PHYADDR CpuPAddr; + struct IMG_DEV_PHYADDR DevPAddr; + + if (CpuVAddr) + CpuPAddr = + OSMapLinToCPUPhys((void *)((u32)CpuVAddr + + uOffset)); + else + CpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, uOffset); + DevPAddr = + SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, CpuPAddr); + + PVR_DPF(PVR_DBG_MESSAGE, "0x%x: CpuVAddr=%08X, " + "CpuPAddr=%08X, DevVAddr=%08X, DevPAddr=%08X", + uOffset, (u32)CpuVAddr + uOffset, CpuPAddr.uiAddr, + MapDevVAddr.uiAddr, DevPAddr.uiAddr); + + MMU_MapPage(pMMUHeap, MapDevVAddr, DevPAddr, ui32MemFlags); + + MapDevVAddr.uiAddr += ui32VAdvance; + uOffset += ui32PAdvance; + } + +#if defined(PDUMP) + MMU_PDumpPageTables(pMMUHeap, MapBaseDevVAddr, uByteSize, IMG_FALSE, + hUniqueTag); +#endif +} + +void MMU_UnmapPages(struct MMU_HEAP *psMMUHeap, + struct IMG_DEV_VIRTADDR sDevVAddr, u32 ui32PageCount, + void *hUniqueTag) +{ + u32 uPageSize = HOST_PAGESIZE(); + struct IMG_DEV_VIRTADDR sTmpDevVAddr; + u32 i; + u32 ui32PDIndex; + u32 ui32PTIndex; + u32 *pui32Tmp; + +#if !defined(PDUMP) + PVR_UNREFERENCED_PARAMETER(hUniqueTag); +#endif + + sTmpDevVAddr = sDevVAddr; + + for (i = 0; i < ui32PageCount; i++) { + struct MMU_PT_INFO **ppsPTInfoList; + + ui32PDIndex = sTmpDevVAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + + SGX_MMU_PT_SHIFT); + + ppsPTInfoList = &psMMUHeap->psMMUContext-> + apsPTInfoList[ui32PDIndex]; + + ui32PTIndex = (sTmpDevVAddr.uiAddr & SGX_MMU_PT_MASK) >> + SGX_MMU_PAGE_SHIFT; + + if (!ppsPTInfoList[0]) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_UnmapPages: " + "ERROR Invalid PT for alloc at VAddr:0x%08lX " + "(VaddrIni:0x%08lX AllocPage:%u) PDIdx:%u " + "PTIdx:%u", + sTmpDevVAddr.uiAddr, sDevVAddr.uiAddr, i, + ui32PDIndex, ui32PTIndex); + + sTmpDevVAddr.uiAddr += uPageSize; + + continue; + } + + pui32Tmp = (u32 *)ppsPTInfoList[0]->PTPageCpuVAddr; + + if (pui32Tmp[ui32PTIndex] & SGX_MMU_PTE_VALID) + ppsPTInfoList[0]->ui32ValidPTECount--; + else + PVR_DPF(PVR_DBG_ERROR, + "MMU_UnmapPages: Page is already invalid " + "for alloc at VAddr:0x%08lX " + "(VAddrIni:0x%08lX AllocPage:%u) " + "PDIdx:%u PTIdx:%u", + sTmpDevVAddr.uiAddr, sDevVAddr.uiAddr, i, + ui32PDIndex, ui32PTIndex); + + PVR_ASSERT((s32) ppsPTInfoList[0]->ui32ValidPTECount >= 0); + + pui32Tmp[ui32PTIndex] = 0; + + sTmpDevVAddr.uiAddr += uPageSize; + } + + MMU_InvalidatePageTableCache(psMMUHeap->psMMUContext->psDevInfo); + +#if defined(PDUMP) + MMU_PDumpPageTables(psMMUHeap, sDevVAddr, uPageSize * ui32PageCount, + IMG_TRUE, hUniqueTag); +#endif +} + +struct IMG_DEV_PHYADDR MMU_GetPhysPageAddr(struct MMU_HEAP *pMMUHeap, + struct IMG_DEV_VIRTADDR sDevVPageAddr) +{ + u32 *pui32PageTable; + u32 ui32Index; + struct IMG_DEV_PHYADDR sDevPAddr; + struct MMU_PT_INFO **ppsPTInfoList; + + ui32Index = sDevVPageAddr.uiAddr >> (SGX_MMU_PAGE_SHIFT + + SGX_MMU_PT_SHIFT); + + ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32Index]; + if (!ppsPTInfoList[0]) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_GetPhysPageAddr: Not mapped in at 0x%08x", + sDevVPageAddr.uiAddr); + sDevPAddr.uiAddr = 0; + return sDevPAddr; + } + + ui32Index = + (sDevVPageAddr.uiAddr & SGX_MMU_PT_MASK) >> SGX_MMU_PAGE_SHIFT; + + pui32PageTable = (u32 *) ppsPTInfoList[0]->PTPageCpuVAddr; + + sDevPAddr.uiAddr = pui32PageTable[ui32Index]; + + sDevPAddr.uiAddr &= SGX_MMU_PTE_ADDR_MASK; + + return sDevPAddr; +} + +struct IMG_DEV_PHYADDR MMU_GetPDDevPAddr(struct MMU_CONTEXT *pMMUContext) +{ + return pMMUContext->sPDDevPAddr; +} + +enum PVRSRV_ERROR SGXGetPhysPageAddrKM(void *hDevMemHeap, + struct IMG_DEV_VIRTADDR sDevVAddr, + struct IMG_DEV_PHYADDR *pDevPAddr, + struct IMG_CPU_PHYADDR *pCpuPAddr) +{ + struct MMU_HEAP *pMMUHeap; + struct IMG_DEV_PHYADDR DevPAddr; + + pMMUHeap = (struct MMU_HEAP *)BM_GetMMUHeap(hDevMemHeap); + + DevPAddr = MMU_GetPhysPageAddr(pMMUHeap, sDevVAddr); + pCpuPAddr->uiAddr = DevPAddr.uiAddr; + pDevPAddr->uiAddr = DevPAddr.uiAddr; + + return (pDevPAddr->uiAddr != 0) ? + PVRSRV_OK : PVRSRV_ERROR_INVALID_PARAMS; +} + +enum PVRSRV_ERROR SGXGetMMUPDAddrKM(void *hDevCookie, + void *hDevMemContext, + struct IMG_DEV_PHYADDR *psPDDevPAddr) +{ + if (!hDevCookie || !hDevMemContext || !psPDDevPAddr) + return PVRSRV_ERROR_INVALID_PARAMS; + + *psPDDevPAddr = + ((struct BM_CONTEXT *)hDevMemContext)->psMMUContext->sPDDevPAddr; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR MMU_BIFResetPDAlloc(struct PVRSRV_SGXDEV_INFO *psDevInfo) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct RA_ARENA *psLocalDevMemArena; + void *hOSMemHandle = NULL; + u8 *pui8MemBlock = NULL; + struct IMG_SYS_PHYADDR sMemBlockSysPAddr; + struct IMG_CPU_PHYADDR sMemBlockCpuPAddr; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "MMU_BIFResetPDAlloc: ERROR call to SysAcquireData failed"); + return eError; + } + + psLocalDevMemArena = psSysData->apsLocalDevMemArena[0]; + + if (psLocalDevMemArena == NULL) { + + eError = + OSAllocPages(PVRSRV_HAP_WRITECOMBINE | + PVRSRV_HAP_KERNEL_ONLY, 3 * SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE, (void **)&pui8MemBlock, + &hOSMemHandle); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "MMU_BIFResetPDAlloc: " + "ERROR call to OSAllocPages failed"); + return eError; + } + sMemBlockCpuPAddr = OSMapLinToCPUPhys(pui8MemBlock); + } else { + if (RA_Alloc(psLocalDevMemArena, 3 * SGX_MMU_PAGE_SIZE, + NULL, 0, SGX_MMU_PAGE_SIZE, + &(sMemBlockSysPAddr.uiAddr)) != IMG_TRUE) { + PVR_DPF(PVR_DBG_ERROR, "MMU_BIFResetPDAlloc: " + "ERROR call to RA_Alloc failed"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + sMemBlockCpuPAddr = SysSysPAddrToCpuPAddr(sMemBlockSysPAddr); + pui8MemBlock = (void __force *)OSMapPhysToLin(sMemBlockCpuPAddr, + SGX_MMU_PAGE_SIZE * 3, + PVRSRV_HAP_WRITECOMBINE | + PVRSRV_HAP_KERNEL_ONLY, + &hOSMemHandle); + if (!pui8MemBlock) { + PVR_DPF(PVR_DBG_ERROR, "MMU_BIFResetPDAlloc: " + "ERROR failed to map page tables"); + return PVRSRV_ERROR_BAD_MAPPING; + } + } + + psDevInfo->hBIFResetPDOSMemHandle = hOSMemHandle; + psDevInfo->sBIFResetPDDevPAddr = + SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sMemBlockCpuPAddr); + psDevInfo->sBIFResetPTDevPAddr.uiAddr = + psDevInfo->sBIFResetPDDevPAddr.uiAddr + SGX_MMU_PAGE_SIZE; + psDevInfo->sBIFResetPageDevPAddr.uiAddr = + psDevInfo->sBIFResetPTDevPAddr.uiAddr + SGX_MMU_PAGE_SIZE; + psDevInfo->pui32BIFResetPD = (u32 *) pui8MemBlock; + psDevInfo->pui32BIFResetPT = + (u32 *) (pui8MemBlock + SGX_MMU_PAGE_SIZE); + + OSMemSet(psDevInfo->pui32BIFResetPD, 0, SGX_MMU_PAGE_SIZE); + OSMemSet(psDevInfo->pui32BIFResetPT, 0, SGX_MMU_PAGE_SIZE); + + OSMemSet(pui8MemBlock + (2 * SGX_MMU_PAGE_SIZE), 0xDB, + SGX_MMU_PAGE_SIZE); + + return PVRSRV_OK; +} + +void MMU_BIFResetPDFree(struct PVRSRV_SGXDEV_INFO *psDevInfo) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct RA_ARENA *psLocalDevMemArena; + struct IMG_SYS_PHYADDR sPDSysPAddr; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "MMU_BIFResetPDFree: " + "ERROR call to SysAcquireData failed"); + return; + } + + psLocalDevMemArena = psSysData->apsLocalDevMemArena[0]; + + if (psLocalDevMemArena == NULL) { + OSFreePages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, + 3 * SGX_MMU_PAGE_SIZE, + psDevInfo->pui32BIFResetPD, + psDevInfo->hBIFResetPDOSMemHandle); + } else { + OSUnMapPhysToLin((void __force __iomem *) + psDevInfo->pui32BIFResetPD, + 3 * SGX_MMU_PAGE_SIZE, + PVRSRV_HAP_WRITECOMBINE | + PVRSRV_HAP_KERNEL_ONLY, + psDevInfo->hBIFResetPDOSMemHandle); + + sPDSysPAddr = + SysDevPAddrToSysPAddr(PVRSRV_DEVICE_TYPE_SGX, + psDevInfo->sBIFResetPDDevPAddr); + RA_Free(psLocalDevMemArena, sPDSysPAddr.uiAddr, IMG_FALSE); + } +} + +u32 mmu_get_page_dir(struct MMU_CONTEXT *psMMUContext) +{ + return psMMUContext->sPDDevPAddr.uiAddr; +} diff --git a/drivers/gpu/pvr/mmu.h b/drivers/gpu/pvr/mmu.h new file mode 100644 index 00000000000..003f0c56000 --- /dev/null +++ b/drivers/gpu/pvr/mmu.h @@ -0,0 +1,86 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _MMU_H_ +#define _MMU_H_ + +#include "sgxinfokm.h" + +enum PVRSRV_ERROR MMU_Initialise(struct PVRSRV_DEVICE_NODE *psDeviceNode, + struct MMU_CONTEXT **ppsMMUContext, + struct IMG_DEV_PHYADDR *psPDDevPAddr); + +void MMU_Finalise(struct MMU_CONTEXT *psMMUContext); + +void MMU_InsertHeap(struct MMU_CONTEXT *psMMUContext, + struct MMU_HEAP *psMMUHeap); + +struct MMU_HEAP *MMU_Create(struct MMU_CONTEXT *psMMUContext, + struct DEV_ARENA_DESCRIPTOR *psDevArena, + struct RA_ARENA **ppsVMArena); + +void MMU_Delete(struct MMU_HEAP *pMMU); + +IMG_BOOL MMU_Alloc(struct MMU_HEAP *pMMU, size_t uSize, u32 uFlags, + u32 uDevVAddrAlignment, struct IMG_DEV_VIRTADDR *pDevVAddr); + +void MMU_Free(struct MMU_HEAP *pMMU, struct IMG_DEV_VIRTADDR DevVAddr, + u32 ui32Size); + +void MMU_Enable(struct MMU_HEAP *pMMU); + +void MMU_Disable(struct MMU_HEAP *pMMU); + +void MMU_MapPages(struct MMU_HEAP *pMMU, struct IMG_DEV_VIRTADDR devVAddr, + struct IMG_SYS_PHYADDR SysPAddr, size_t uSize, u32 ui32MemFlags, + void *hUniqueTag); + +void MMU_MapShadow(struct MMU_HEAP *pMMU, + struct IMG_DEV_VIRTADDR MapBaseDevVAddr, size_t uSize, + void *CpuVAddr, void *hOSMemHandle, + struct IMG_DEV_VIRTADDR *pDevVAddr, u32 ui32MemFlags, + void *hUniqueTag); + +void MMU_UnmapPages(struct MMU_HEAP *pMMU, struct IMG_DEV_VIRTADDR dev_vaddr, + u32 ui32PageCount, void *hUniqueTag); + +void MMU_MapScatter(struct MMU_HEAP *pMMU, struct IMG_DEV_VIRTADDR DevVAddr, + struct IMG_SYS_PHYADDR *psSysAddr, size_t uSize, + u32 ui32MemFlags, void *hUniqueTag); + +struct IMG_DEV_PHYADDR MMU_GetPhysPageAddr(struct MMU_HEAP *pMMUHeap, + struct IMG_DEV_VIRTADDR sDevVPageAddr); + +struct IMG_DEV_PHYADDR MMU_GetPDDevPAddr(struct MMU_CONTEXT *pMMUContext); + +void MMU_InvalidateDirectoryCache(struct PVRSRV_SGXDEV_INFO *psDevInfo); + +enum PVRSRV_ERROR MMU_BIFResetPDAlloc(struct PVRSRV_SGXDEV_INFO *psDevInfo); + +void MMU_BIFResetPDFree(struct PVRSRV_SGXDEV_INFO *psDevInfo); + +u32 mmu_get_page_dir(struct MMU_CONTEXT *pMMUContext); +#endif diff --git a/drivers/gpu/pvr/module.c b/drivers/gpu/pvr/module.c new file mode 100644 index 00000000000..d94efe6a1fe --- /dev/null +++ b/drivers/gpu/pvr/module.c @@ -0,0 +1,294 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/miscdevice.h> + +#include <linux/platform_device.h> + +#include "img_defs.h" +#include "services.h" +#include "kerneldisplay.h" +#include "kernelbuffer.h" +#include "syscommon.h" +#include "pvrmmap.h" +#include "mutils.h" +#include "mm.h" +#include "mmap.h" +#include "pvr_debug.h" +#include "srvkm.h" +#include "perproc.h" +#include "handle.h" +#include "pvr_bridge_km.h" +#include "sgx_bridge_km.h" +#include "proc.h" +#include "pvrmodule.h" +#include "private_data.h" +#include "pvr_events.h" + +#define DRVNAME "pvrsrvkm" + +#ifdef CONFIG_PVR_DEBUG_EXTRA +static int debug = DBGPRIV_WARNING; +#include <linux/moduleparam.h> +module_param(debug, int, 0); +#endif + +static int pvr_open(struct inode unref__ * inode, struct file *filp) +{ + struct PVRSRV_FILE_PRIVATE_DATA *priv; + void *block_alloc; + int ret = -ENOMEM; + enum PVRSRV_ERROR err; + u32 pid; + + pvr_lock(); + + if (pvr_is_disabled()) { + ret = -ENODEV; + goto err_unlock; + } + + pid = OSGetCurrentProcessIDKM(); + + if (PVRSRVProcessConnect(pid) != PVRSRV_OK) + goto err_unlock; + + err = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(*priv), + (void **)&priv, &block_alloc); + + if (err != PVRSRV_OK) + goto err_unlock; + + priv->ui32OpenPID = pid; + priv->hBlockAlloc = block_alloc; + filp->private_data = priv; + + INIT_LIST_HEAD(&priv->event_list); + init_waitqueue_head(&priv->event_wait); + priv->event_space = 4096; /* set aside 4k for event buffer */ + + ret = 0; +err_unlock: + pvr_unlock(); + + return ret; +} + +static int pvr_release(struct inode unref__ * inode, struct file *filp) +{ + struct PVRSRV_FILE_PRIVATE_DATA *priv; + + pvr_lock(); + + priv = filp->private_data; + + pvr_release_events(priv); + + PVRSRVProcessDisconnect(priv->ui32OpenPID); + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(*priv), + priv, priv->hBlockAlloc); + + pvr_unlock(); + + return 0; +} + +static const struct file_operations pvr_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = PVRSRV_BridgeDispatchKM, + .open = pvr_open, + .release = pvr_release, + .mmap = PVRMMap, + .poll = pvr_poll, + .read = pvr_read, +}; + +static void pvr_shutdown(struct platform_device *pdev) +{ + PVR_TRACE("pvr_shutdown(pdev=%p)", pdev); + + (void)PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3); +} + +static int pvr_suspend(struct platform_device *pdev, pm_message_t state) +{ + PVR_TRACE("pvr_suspend(pdev=%p)", pdev); + + if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3) != PVRSRV_OK) + return -EINVAL; + return 0; +} + +static int pvr_resume(struct platform_device *pdev) +{ + PVR_TRACE("pvr_resume(pdev=%p)", pdev); + + if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) != PVRSRV_OK) + return -EINVAL; + return 0; +} + +static struct miscdevice pvr_miscdevice = { + .minor = MISC_DYNAMIC_MINOR, + .name = DRVNAME, + .fops = &pvr_fops, +}; + +static int __devinit pvr_probe(struct platform_device *pdev) +{ + struct SYS_DATA *sysdata; + int ret; + + PVR_TRACE("pvr_probe(pdev=%p)", pdev); + + if (SysAcquireData(&sysdata) != PVRSRV_OK && + SysInitialise(pdev) != PVRSRV_OK) { + ret = -ENODEV; + goto err_exit; + } + + ret = misc_register(&pvr_miscdevice); + if (ret < 0) + goto err_exit; + + return 0; + +err_exit: + dev_err(&pdev->dev, "probe failed (%d)\n", ret); + + return ret; +} + +static int __devexit pvr_remove(struct platform_device *pdev) +{ + struct SYS_DATA *sysdata; + int ret; + + PVR_TRACE("pvr_remove(pdev=%p)", pdev); + + ret = misc_deregister(&pvr_miscdevice); + if (ret < 0) { + dev_err(&pdev->dev, "remove failed (%d)\n", ret); + return ret; + } + + if (SysAcquireData(&sysdata) == PVRSRV_OK) + SysDeinitialise(sysdata); + + return 0; +} + + +static struct platform_driver pvr_driver = { + .driver = { + .name = DRVNAME, + }, + .probe = pvr_probe, + .remove = __devexit_p(pvr_remove), + .suspend = pvr_suspend, + .resume = pvr_resume, + .shutdown = pvr_shutdown, +}; + +static int __init pvr_init(void) +{ + int error; + + pvr_dbg_init(); + + PVR_TRACE("pvr_init"); + +#ifdef CONFIG_PVR_DEBUG_EXTRA + PVRDebugSetLevel(debug); +#endif + + error = CreateProcEntries(); + if (error < 0) + goto err1; + + error = -ENOMEM; + if (LinuxMMInit() != PVRSRV_OK) + goto err2; + + if (LinuxBridgeInit() != PVRSRV_OK) + goto err3; + + PVRMMapInit(); + + error = platform_driver_register(&pvr_driver); + if (error < 0) + goto err4; + + pvr_init_events(); + + return 0; + +err4: + PVRMMapCleanup(); + LinuxBridgeDeInit(); +err3: + LinuxMMCleanup(); +err2: + RemoveProcEntries(); +err1: + pr_err("%s: failed (%d)\n", __func__, error); + + return error; +} + +static void __exit pvr_cleanup(void) +{ + PVR_TRACE("pvr_cleanup"); + + pvr_exit_events(); + + platform_driver_unregister(&pvr_driver); + + PVRMMapCleanup(); + LinuxMMCleanup(); + LinuxBridgeDeInit(); + RemoveProcEntries(); + + PVR_TRACE("pvr_cleanup: unloading"); + + pvr_dbg_cleanup(); +} + +module_init(pvr_init); +module_exit(pvr_cleanup); + +MODULE_SUPPORTED_DEVICE(DRVNAME); +MODULE_ALIAS("platform:" DRVNAME); + diff --git a/drivers/gpu/pvr/mutils.h b/drivers/gpu/pvr/mutils.h new file mode 100644 index 00000000000..47279ec6b5d --- /dev/null +++ b/drivers/gpu/pvr/mutils.h @@ -0,0 +1,37 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __IMG_LINUX_MUTILS_H__ +#define __IMG_LINUX_MUTILS_H__ + +#define PGPROT_WC(pv) pgprot_writecombine(pv) +#define PGPROT_UC(pv) pgprot_noncached(pv) + +#define IOREMAP(pa, bytes) ioremap_cached(pa, bytes) +#define IOREMAP_WC(pa, bytes) ioremap_wc(pa, bytes) +#define IOREMAP_UC(pa, bytes) ioremap_nocache(pa, bytes) + +#endif diff --git a/drivers/gpu/pvr/ocpdefs.h b/drivers/gpu/pvr/ocpdefs.h new file mode 100644 index 00000000000..12c3b365e01 --- /dev/null +++ b/drivers/gpu/pvr/ocpdefs.h @@ -0,0 +1,294 @@ +/**************************************************************************** + Name : ocpdefs.h + Author : PowerVR + Copyright : 2009 by Imagination Technologies Limited. + All rights reserved. No part of this software, either + material or conceptual may be copied or distributed, + transmitted, transcribed, stored in a retrieval system or + translated into any human or computer language in any form + by any means, electronic, mechanical, manual or otherwise, + or disclosed to third parties without the express written + permission of Imagination Technologies Limited, + Home Park Estate, Kings Langley, Hertfordshire, + WD4 8LZ, U.K. + Description : + + Program Type : + + Modifications : + +****************************************************************************/ + +#ifndef _OCPDEFS_H_ +#define _OCPDEFS_H_ + +#include "sysconfig.h" + +#define SYS_OMAP3430_OCP_REGS_SYS_PHYS_BASE \ + (SYS_OMAP3430_SGX_REGS_SYS_PHYS_BASE + EUR_CR_OCP_REVISION) +#define SYS_OMAP3430_OCP_REGS_SIZE 0x110 + +/* Register EUR_CR_OCP_REVISION */ +#define EUR_CR_OCP_REVISION 0xFE00 +#define EUR_CR_OCP_REVISION_REV_MASK 0xFFFFFFFFUL +#define EUR_CR_OCP_REVISION_REV_SHIFT 0 +#define EUR_CR_OCP_REVISION_REV_SIGNED 0 + +/* Register EUR_CR_OCP_HWINFO */ +#define EUR_CR_OCP_HWINFO 0xFE04 +#define EUR_CR_OCP_HWINFO_SYS_BUS_WIDTH_MASK 0x00000003UL +#define EUR_CR_OCP_HWINFO_SYS_BUS_WIDTH_SHIFT 0 +#define EUR_CR_OCP_HWINFO_SYS_BUS_WIDTH_SIGNED 0 + +#define EUR_CR_OCP_HWINFO_MEM_BUS_WIDTH_MASK 0x00000004UL +#define EUR_CR_OCP_HWINFO_MEM_BUS_WIDTH_SHIFT 2 +#define EUR_CR_OCP_HWINFO_MEM_BUS_WIDTH_SIGNED 0 + +/* Register EUR_CR_OCP_SYSCONFIG */ +#define EUR_CR_OCP_SYSCONFIG 0xFE10 +#define EUR_CR_OCP_SYSCONFIG_IDLE_MODE_MASK 0x0000000CUL +#define EUR_CR_OCP_SYSCONFIG_IDLE_MODE_SHIFT 2 +#define EUR_CR_OCP_SYSCONFIG_IDLE_MODE_SIGNED 0 + +#define EUR_CR_OCP_SYSCONFIG_STANDBY_MODE_MASK 0x00000030UL +#define EUR_CR_OCP_SYSCONFIG_STANDBY_MODE_SHIFT 4 +#define EUR_CR_OCP_SYSCONFIG_STANDBY_MODE_SIGNED 0 + +/* Register EUR_CR_OCP_IRQSTATUS_RAW_0 */ +#define EUR_CR_OCP_IRQSTATUS_RAW_0 0xFE24 +#define EUR_CR_OCP_IRQSTATUS_RAW_0_INIT_MASK 0x00000001UL +#define EUR_CR_OCP_IRQSTATUS_RAW_0_INIT_SHIFT 0 +#define EUR_CR_OCP_IRQSTATUS_RAW_0_INIT_SIGNED 0 + +/* Register EUR_CR_OCP_IRQSTATUS_RAW_1 */ +#define EUR_CR_OCP_IRQSTATUS_RAW_1 0xFE28 +#define EUR_CR_OCP_IRQSTATUS_RAW_1_TARGET_MASK 0x00000001UL +#define EUR_CR_OCP_IRQSTATUS_RAW_1_TARGET_SHIFT 0 +#define EUR_CR_OCP_IRQSTATUS_RAW_1_TARGET_SIGNED 0 + +/* Register EUR_CR_OCP_IRQSTATUS_RAW_2 */ +#define EUR_CR_OCP_IRQSTATUS_RAW_2 0xFE2C +#define EUR_CR_OCP_IRQSTATUS_RAW_2_SGXCORE_MASK 0x00000001UL +#define EUR_CR_OCP_IRQSTATUS_RAW_2_SGXCORE_SHIFT 0 +#define EUR_CR_OCP_IRQSTATUS_RAW_2_SGXCORE_SIGNED 0 + +/* Register EUR_CR_OCP_IRQSTATUS_0 */ +#define EUR_CR_OCP_IRQSTATUS_0 0xFE30 +#define EUR_CR_OCP_IRQSTATUS_0_INIT_MASK 0x00000001UL +#define EUR_CR_OCP_IRQSTATUS_0_INIT_SHIFT 0 +#define EUR_CR_OCP_IRQSTATUS_0_INIT_SIGNED 0 + +/* Register EUR_CR_OCP_IRQSTATUS_1 */ +#define EUR_CR_OCP_IRQSTATUS_1 0xFE34 +#define EUR_CR_OCP_IRQSTATUS_1_TARGET_MASK 0x00000001UL +#define EUR_CR_OCP_IRQSTATUS_1_TARGET_SHIFT 0 +#define EUR_CR_OCP_IRQSTATUS_1_TARGET_SIGNED 0 + +/* Register EUR_CR_OCP_IRQSTATUS_2 */ +#define EUR_CR_OCP_IRQSTATUS_2 0xFE38 +#define EUR_CR_OCP_IRQSTATUS_2_SGXCORE_MASK 0x00000001UL +#define EUR_CR_OCP_IRQSTATUS_2_SGXCORE_SHIFT 0 +#define EUR_CR_OCP_IRQSTATUS_2_SGXCORE_SIGNED 0 + +/* Register EUR_CR_OCP_IRQENABLE_SET_0 */ +#define EUR_CR_OCP_IRQENABLE_SET_0 0xFE3C +#define EUR_CR_OCP_IRQENABLE_SET_0_INIT_MASK 0x00000001UL +#define EUR_CR_OCP_IRQENABLE_SET_0_INIT_SHIFT 0 +#define EUR_CR_OCP_IRQENABLE_SET_0_INIT_SIGNED 0 + +/* Register EUR_CR_OCP_IRQENABLE_SET_1 */ +#define EUR_CR_OCP_IRQENABLE_SET_1 0xFE40 +#define EUR_CR_OCP_IRQENABLE_SET_1_TARGET_MASK 0x00000001UL +#define EUR_CR_OCP_IRQENABLE_SET_1_TARGET_SHIFT 0 +#define EUR_CR_OCP_IRQENABLE_SET_1_TARGET_SIGNED 0 + +/* Register EUR_CR_OCP_IRQENABLE_SET_2 */ +#define EUR_CR_OCP_IRQENABLE_SET_2 0xFE44 +#define EUR_CR_OCP_IRQENABLE_SET_2_SGXCORE_MASK 0x00000001UL +#define EUR_CR_OCP_IRQENABLE_SET_2_SGXCORE_SHIFT 0 +#define EUR_CR_OCP_IRQENABLE_SET_2_SGXCORE_SIGNED 0 + +/* Register EUR_CR_OCP_IRQENABLE_CLR_0 */ +#define EUR_CR_OCP_IRQENABLE_CLR_0 0xFE48 +#define EUR_CR_OCP_IRQENABLE_CLR_0_INIT_MASK 0x00000001UL +#define EUR_CR_OCP_IRQENABLE_CLR_0_INIT_SHIFT 0 +#define EUR_CR_OCP_IRQENABLE_CLR_0_INIT_SIGNED 0 + +/* Register EUR_CR_OCP_IRQENABLE_CLR_1 */ +#define EUR_CR_OCP_IRQENABLE_CLR_1 0xFE4C +#define EUR_CR_OCP_IRQENABLE_CLR_1_TARGET_MASK 0x00000001UL +#define EUR_CR_OCP_IRQENABLE_CLR_1_TARGET_SHIFT 0 +#define EUR_CR_OCP_IRQENABLE_CLR_1_TARGET_SIGNED 0 + +/* Register EUR_CR_OCP_IRQENABLE_CLR_2 */ +#define EUR_CR_OCP_IRQENABLE_CLR_2 0xFE50 +#define EUR_CR_OCP_IRQENABLE_CLR_2_SGXCORE_MASK 0x00000001UL +#define EUR_CR_OCP_IRQENABLE_CLR_2_SGXCORE_SHIFT 0 +#define EUR_CR_OCP_IRQENABLE_CLR_2_SGXCORE_SIGNED 0 + +/* Register EUR_CR_OCP_PAGE_CONFIG */ +#define EUR_CR_OCP_PAGE_CONFIG 0xFF00 +#define EUR_CR_OCP_PAGE_CONFIG_MEM_PAGE_SIZE_MASK 0x00000001UL +#define EUR_CR_OCP_PAGE_CONFIG_MEM_PAGE_SIZE_SHIFT 0 +#define EUR_CR_OCP_PAGE_CONFIG_MEM_PAGE_SIZE_SIGNED 0 + +#define EUR_CR_OCP_PAGE_CONFIG_MEM_PAGE_CHECK_ENABLE_MASK 0x00000004UL +#define EUR_CR_OCP_PAGE_CONFIG_MEM_PAGE_CHECK_ENABLE_SHIFT 2 +#define EUR_CR_OCP_PAGE_CONFIG_MEM_PAGE_CHECK_ENABLE_SIGNED 0 + +#define EUR_CR_OCP_PAGE_CONFIG_SIZE_MASK 0x00000018UL +#define EUR_CR_OCP_PAGE_CONFIG_SIZE_SHIFT 3 +#define EUR_CR_OCP_PAGE_CONFIG_SIZE_SIGNED 0 + +/* Register EUR_CR_OCP_INTERRUPT_EVENT */ +#define EUR_CR_OCP_INTERRUPT_EVENT 0xFF04 +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_UNEXPECTED_MASK 0x00000001UL +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_UNEXPECTED_SHIFT 0 +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_UNEXPECTED_SIGNED 0 + +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_UNUSED_TAG_MASK 0x00000002UL +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_UNUSED_TAG_SHIFT 1 +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_UNUSED_TAG_SIGNED 0 + +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_ERROR_MASK 0x00000004UL +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_ERROR_SHIFT 2 +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_ERROR_SIGNED 0 + +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_PAGE_CROSS_ERROR_MASK 0x00000008UL +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_PAGE_CROSS_ERROR_SHIFT 3 +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_PAGE_CROSS_ERROR_SIGNED 0 + +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_READ_TAG_FIFO_OVR_MASK 0x00000010UL +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_READ_TAG_FIFO_OVR_SHIFT 4 +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_READ_TAG_FIFO_OVR_SIGNED 0 + +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_MEM_REQ_FIFO_OVR_MASK 0x00000020UL +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_MEM_REQ_FIFO_OVR_SHIFT 5 +#define EUR_CR_OCP_INTERRUPT_EVENT_INIT_MEM_REQ_FIFO_OVR_SIGNED 0 + +#define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_RESP_FIFO_FULL_MASK 0x00000100UL +#define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_RESP_FIFO_FULL_SHIFT 8 +#define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_RESP_FIFO_FULL_SIGNED 0 + +#define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_CMD_FIFO_FULL_MASK 0x00000200UL +#define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_CMD_FIFO_FULL_SHIFT 9 +#define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_CMD_FIFO_FULL_SIGNED 0 + +#define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_INVALID_OCP_CMD_MASK 0x00000400UL +#define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_INVALID_OCP_CMD_SHIFT 10 +#define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_INVALID_OCP_CMD_SIGNED 0 + +/* Register EUR_CR_OCP_DEBUG_CONFIG */ +#define EUR_CR_OCP_DEBUG_CONFIG 0xFF08 +#define EUR_CR_OCP_DEBUG_CONFIG_FORCE_TARGET_IDLE_MASK 0x00000003UL +#define EUR_CR_OCP_DEBUG_CONFIG_FORCE_TARGET_IDLE_SHIFT 0 +#define EUR_CR_OCP_DEBUG_CONFIG_FORCE_TARGET_IDLE_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_CONFIG_FORCE_INIT_IDLE_MASK 0x0000000CUL +#define EUR_CR_OCP_DEBUG_CONFIG_FORCE_INIT_IDLE_SHIFT 2 +#define EUR_CR_OCP_DEBUG_CONFIG_FORCE_INIT_IDLE_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_CONFIG_FORCE_PASS_DATA_MASK 0x00000010UL +#define EUR_CR_OCP_DEBUG_CONFIG_FORCE_PASS_DATA_SHIFT 4 +#define EUR_CR_OCP_DEBUG_CONFIG_FORCE_PASS_DATA_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_CONFIG_SELECT_INIT_IDLE_MASK 0x00000020UL +#define EUR_CR_OCP_DEBUG_CONFIG_SELECT_INIT_IDLE_SHIFT 5 +#define EUR_CR_OCP_DEBUG_CONFIG_SELECT_INIT_IDLE_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_MASK 0x80000000UL +#define EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_SHIFT 31 +#define EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_SIGNED 0 + +/* Register EUR_CR_OCP_DEBUG_STATUS */ +#define EUR_CR_OCP_DEBUG_STATUS 0xFF0C +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_MCONNECT_MASK 0x00000003UL +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_MCONNECT_SHIFT 0 +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_MCONNECT_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SCONNECT_MASK 0x00000004UL +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SCONNECT_SHIFT 2 +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SCONNECT_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SIDLEREQ_MASK 0x00000008UL +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SIDLEREQ_SHIFT 3 +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SIDLEREQ_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SDISCACK_MASK 0x00000030UL +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SDISCACK_SHIFT 4 +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SDISCACK_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SIDLEACK_MASK 0x000000C0UL +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SIDLEACK_SHIFT 6 +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_SIDLEACK_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MCONNECT0_MASK 0x00000300UL +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MCONNECT0_SHIFT 8 +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MCONNECT0_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_INIT_SCONNECT0_MASK 0x00000400UL +#define EUR_CR_OCP_DEBUG_STATUS_INIT_SCONNECT0_SHIFT 10 +#define EUR_CR_OCP_DEBUG_STATUS_INIT_SCONNECT0_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_INIT_SCONNECT1_MASK 0x00000800UL +#define EUR_CR_OCP_DEBUG_STATUS_INIT_SCONNECT1_SHIFT 11 +#define EUR_CR_OCP_DEBUG_STATUS_INIT_SCONNECT1_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_INIT_SCONNECT2_MASK 0x00001000UL +#define EUR_CR_OCP_DEBUG_STATUS_INIT_SCONNECT2_SHIFT 12 +#define EUR_CR_OCP_DEBUG_STATUS_INIT_SCONNECT2_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MDISCACK_MASK 0x00006000UL +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MDISCACK_SHIFT 13 +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MDISCACK_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MDISCREQ_MASK 0x00008000UL +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MDISCREQ_SHIFT 15 +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MDISCREQ_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MWAIT_MASK 0x00010000UL +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MWAIT_SHIFT 16 +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MWAIT_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MSTANDBY_MASK 0x00020000UL +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MSTANDBY_SHIFT 17 +#define EUR_CR_OCP_DEBUG_STATUS_INIT_MSTANDBY_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_CMD_OUT_MASK 0x001C0000UL +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_CMD_OUT_SHIFT 18 +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_CMD_OUT_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_WHICH_TARGET_REGISTER_MASK 0x03E00000UL +#define EUR_CR_OCP_DEBUG_STATUS_WHICH_TARGET_REGISTER_SHIFT 21 +#define EUR_CR_OCP_DEBUG_STATUS_WHICH_TARGET_REGISTER_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_RESP_ERROR_MASK 0x04000000UL +#define EUR_CR_OCP_DEBUG_STATUS_RESP_ERROR_SHIFT 26 +#define EUR_CR_OCP_DEBUG_STATUS_RESP_ERROR_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_CMD_FIFO_FULL_MASK 0x08000000UL +#define EUR_CR_OCP_DEBUG_STATUS_CMD_FIFO_FULL_SHIFT 27 +#define EUR_CR_OCP_DEBUG_STATUS_CMD_FIFO_FULL_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_RESP_FIFO_FULL_MASK 0x10000000UL +#define EUR_CR_OCP_DEBUG_STATUS_RESP_FIFO_FULL_SHIFT 28 +#define EUR_CR_OCP_DEBUG_STATUS_RESP_FIFO_FULL_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_IDLE_MASK 0x20000000UL +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_IDLE_SHIFT 29 +#define EUR_CR_OCP_DEBUG_STATUS_TARGET_IDLE_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_CMD_RESP_DEBUG_STATE_MASK 0x40000000UL +#define EUR_CR_OCP_DEBUG_STATUS_CMD_RESP_DEBUG_STATE_SHIFT 30 +#define EUR_CR_OCP_DEBUG_STATUS_CMD_RESP_DEBUG_STATE_SIGNED 0 + +#define EUR_CR_OCP_DEBUG_STATUS_CMD_DEBUG_STATE_MASK 0x80000000UL +#define EUR_CR_OCP_DEBUG_STATUS_CMD_DEBUG_STATE_SHIFT 31 +#define EUR_CR_OCP_DEBUG_STATUS_CMD_DEBUG_STATE_SIGNED 0 + + +#endif /* _OCPDEFS_H_ */ + +/***************************************************************************** + End of file (ocpdefs.h) +*****************************************************************************/ diff --git a/drivers/gpu/pvr/oemfuncs.h b/drivers/gpu/pvr/oemfuncs.h new file mode 100644 index 00000000000..a957a21cf5f --- /dev/null +++ b/drivers/gpu/pvr/oemfuncs.h @@ -0,0 +1,41 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__OEMFUNCS_H__) +#define __OEMFUNCS_H__ + +#include <linux/fs.h> + +struct PVRSRV_DC_OEM_JTABLE { + long (*pfnOEMBridgeDispatch)(struct file *, unsigned, unsigned long); + void *pvDummy1; + void *pvDummy2; + void *pvDummy3; +}; + +#define OEM_GET_EXT_FUNCS (1<<1) + +#endif diff --git a/drivers/gpu/pvr/omaplfb.h b/drivers/gpu/pvr/omaplfb.h new file mode 100644 index 00000000000..34e7a6d8f16 --- /dev/null +++ b/drivers/gpu/pvr/omaplfb.h @@ -0,0 +1,140 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __OMAPLFB_H__ +#define __OMAPLFB_H__ + +#define OMAPLCD_IRQ 25 + +#define OMAPLCD_SYSCONFIG 0x0410 +#define OMAPLCD_CONFIG 0x0444 +#define OMAPLCD_DEFAULT_COLOR0 0x044C +#define OMAPLCD_TIMING_H 0x0464 +#define OMAPLCD_TIMING_V 0x0468 +#define OMAPLCD_POL_FREQ 0x046C +#define OMAPLCD_DIVISOR 0x0470 +#define OMAPLCD_SIZE_DIG 0x0478 +#define OMAPLCD_SIZE_LCD 0x047C +#define OMAPLCD_GFX_POSITION 0x0488 +#define OMAPLCD_GFX_SIZE 0x048C +#define OMAPLCD_GFX_ATTRIBUTES 0x04a0 +#define OMAPLCD_GFX_FIFO_THRESHOLD 0x04a4 +#define OMAPLCD_GFX_WINDOW_SKIP 0x04b4 + +#define OMAPLCD_IRQSTATUS 0x0418 +#define OMAPLCD_IRQENABLE 0x041c +#define OMAPLCD_CONTROL 0x0440 +#define OMAPLCD_GFX_BA0 0x0480 +#define OMAPLCD_GFX_BA1 0x0484 +#define OMAPLCD_GFX_ROW_INC 0x04ac +#define OMAPLCD_GFX_PIX_INC 0x04b0 +#define OMAPLCD_VID1_BA0 0x04bc +#define OMAPLCD_VID1_BA1 0x04c0 +#define OMAPLCD_VID1_ROW_INC 0x04d8 +#define OMAPLCD_VID1_PIX_INC 0x04dc + +#define OMAP_CONTROL_GODIGITAL (1 << 6) +#define OMAP_CONTROL_GOLCD (1 << 5) +#define OMAP_CONTROL_DIGITALENABLE (1 << 1) +#define OMAP_CONTROL_LCDENABLE (1 << 0) + +#define OMAPLCD_INTMASK_VSYNC (1 << 1) +#define OMAPLCD_INTMASK_OFF 0 + +struct OMAPLFB_BUFFER { + struct IMG_SYS_PHYADDR sSysAddr; + void __iomem *sCPUVAddr; + u32 ui32BufferSize; + struct PVRSRV_SYNC_DATA *psSyncData; + struct OMAPLFB_BUFFER *psNext; +}; + +struct OMAPLFB_SWAPCHAIN { + + u32 ui32BufferCount; + struct OMAPLFB_BUFFER *psBuffer; + struct PVRSRV_DC_DISP2SRV_KMJTABLE *psPVRJTable; + IMG_BOOL bBlanked; +}; + +struct OMAPLFB_FBINFO { + struct IMG_SYS_PHYADDR sSysAddr; + void __iomem *sCPUVAddr; + u32 ui32FBSize; + u32 ui32BufferSize; + u32 ui32RoundedBufferSize; + u32 ui32Width; + u32 ui32Height; + u32 ui32ByteStride; + + enum PVRSRV_PIXEL_FORMAT ePixelFormat; +}; + +struct OMAPLFB_DEVINFO { + u32 ui32DeviceID; + struct DISPLAY_INFO sDisplayInfo; + struct OMAPLFB_BUFFER sSystemBuffer; + struct DISPLAY_FORMAT sDisplayFormat; + struct DISPLAY_DIMS sDisplayDim; + struct PVRSRV_DC_DISP2SRV_KMJTABLE sPVRJTable; + struct PVRSRV_DC_SRV2DISP_KMJTABLE sDCJTable; + struct OMAPLFB_FBINFO sFBInfo; + u32 ui32RefCount; + struct OMAPLFB_SWAPCHAIN *psSwapChain; + struct IMG_DEV_VIRTADDR sDisplayDevVAddr; + struct fb_info *psLINFBInfo; + struct notifier_block sLINNotifBlock; +}; + +#define OMAPLFB_PAGE_SIZE 4096 +#define OMAPLFB_PAGE_MASK (OMAPLFB_PAGE_SIZE - 1) +#define OMAPLFB_PAGE_TRUNC (~OMAPLFB_PAGE_MASK) + +#define OMAPLFB_PAGE_ROUNDUP(x) (((x) + OMAPLFB_PAGE_MASK) & OMAPLFB_PAGE_TRUNC) + +#ifdef CONFIG_PVR_DEBUG_EXTRA +#define DEBUG_PRINTK(x) printk x +#else +#define DEBUG_PRINTK(x) +#endif + +#define DISPLAY_DEVICE_NAME "PowerVR OMAP Linux Display Driver" +#define DRVNAME "omaplfb" +#define DEVNAME DRVNAME +#define DRIVER_PREFIX DRVNAME + +enum PVRSRV_ERROR OMAPLFBInit(void); +enum PVRSRV_ERROR OMAPLFBDeinit(void); + +void OMAPLFBDriverSuspend(void); +void OMAPLFBDriverResume(void); + +void *OMAPLFBAllocKernelMem(u32 ui32Size); +void OMAPLFBFreeKernelMem(void *pvMem); +enum PVRSRV_ERROR OMAPLFBGetLibFuncAddr(char *szFunctionName, + IMG_BOOL (**ppfnFuncTable)(struct PVRSRV_DC_DISP2SRV_KMJTABLE *)); + +#endif diff --git a/drivers/gpu/pvr/omaplfb_displayclass.c b/drivers/gpu/pvr/omaplfb_displayclass.c new file mode 100644 index 00000000000..73588cc0f3e --- /dev/null +++ b/drivers/gpu/pvr/omaplfb_displayclass.c @@ -0,0 +1,820 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/console.h> +#include <linux/fb.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/notifier.h> + +#include <asm/div64.h> +#include <video/sgx-util.h> + +#include "img_defs.h" +#include "servicesext.h" +#include "kerneldisplay.h" +#include "omaplfb.h" + +static void *gpvAnchor; + +static int fb_idx; + +#define OMAPLFB_COMMAND_COUNT 1 + +static IMG_BOOL (*pfnGetPVRJTable)(struct PVRSRV_DC_DISP2SRV_KMJTABLE *); + +static struct OMAPLFB_DEVINFO *GetAnchorPtr(void) +{ + return (struct OMAPLFB_DEVINFO *)gpvAnchor; +} + +static void SetAnchorPtr(struct OMAPLFB_DEVINFO *psDevInfo) +{ + gpvAnchor = (void *) psDevInfo; +} + +static int FrameBufferEvents(struct notifier_block *psNotif, + unsigned long event, void *data) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + struct OMAPLFB_SWAPCHAIN *psSwapChain; + struct fb_event *psFBEvent = (struct fb_event *)data; + + if (event != FB_EVENT_BLANK) + return 0; + + psDevInfo = GetAnchorPtr(); + psSwapChain = psDevInfo->psSwapChain; + psSwapChain->bBlanked = (*(int *)psFBEvent->data != 0); + + return 0; +} + +static enum PVRSRV_ERROR EnableLFBEventNotification(struct OMAPLFB_DEVINFO + *psDevInfo) +{ + int res; + struct OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain; + + memset(&psDevInfo->sLINNotifBlock, 0, + sizeof(psDevInfo->sLINNotifBlock)); + + psDevInfo->sLINNotifBlock.notifier_call = FrameBufferEvents; + + psSwapChain->bBlanked = IMG_FALSE; + + res = fb_register_client(&psDevInfo->sLINNotifBlock); + if (res != 0) { + printk(KERN_WARNING DRIVER_PREFIX + ": fb_register_client failed (%d)", res); + + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR DisableLFBEventNotification(struct OMAPLFB_DEVINFO + *psDevInfo) +{ + int res; + + res = fb_unregister_client(&psDevInfo->sLINNotifBlock); + if (res != 0) { + printk(KERN_WARNING DRIVER_PREFIX + ": fb_unregister_client failed (%d)", res); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR OpenDCDevice(u32 ui32DeviceID, void **phDevice, + struct PVRSRV_SYNC_DATA *psSystemBufferSyncData) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + + PVR_UNREFERENCED_PARAMETER(ui32DeviceID); + + psDevInfo = GetAnchorPtr(); + + psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData; + + *phDevice = (void *) psDevInfo; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR CloseDCDevice(void *hDevice) +{ + PVR_UNREFERENCED_PARAMETER(hDevice); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR EnumDCFormats(void *hDevice, u32 *pui32NumFormats, + struct DISPLAY_FORMAT *psFormat) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + + if (!hDevice || !pui32NumFormats) + return PVRSRV_ERROR_INVALID_PARAMS; + + psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice; + + *pui32NumFormats = 1; + + if (psFormat) + psFormat[0] = psDevInfo->sDisplayFormat; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR EnumDCDims(void *hDevice, + struct DISPLAY_FORMAT *psFormat, + u32 *pui32NumDims, struct DISPLAY_DIMS *psDim) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + + if (!hDevice || !psFormat || !pui32NumDims) + return PVRSRV_ERROR_INVALID_PARAMS; + + psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice; + + *pui32NumDims = 1; + + if (psDim) + psDim[0] = psDevInfo->sDisplayDim; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR GetDCSystemBuffer(void *hDevice, void **phBuffer) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + + if (!hDevice || !phBuffer) + return PVRSRV_ERROR_INVALID_PARAMS; + + psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice; + + *phBuffer = (void *) &psDevInfo->sSystemBuffer; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR GetDCInfo(void *hDevice, struct DISPLAY_INFO *psDCInfo) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + + if (!hDevice || !psDCInfo) + return PVRSRV_ERROR_INVALID_PARAMS; + + psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice; + + *psDCInfo = psDevInfo->sDisplayInfo; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR GetDCBufferAddr(void *hDevice, void *hBuffer, + struct IMG_SYS_PHYADDR **ppsSysAddr, + u32 *pui32ByteSize, + void __iomem **ppvCpuVAddr, + void **phOSMapInfo, + IMG_BOOL *pbIsContiguous) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + struct OMAPLFB_BUFFER *psSystemBuffer; + + if (!hDevice) + return PVRSRV_ERROR_INVALID_PARAMS; + psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice; + + if (!hBuffer) + return PVRSRV_ERROR_INVALID_PARAMS; + psSystemBuffer = (struct OMAPLFB_BUFFER *)hBuffer; + + if (!ppsSysAddr) + return PVRSRV_ERROR_INVALID_PARAMS; + + *ppsSysAddr = &psSystemBuffer->sSysAddr; + + if (!pui32ByteSize) + return PVRSRV_ERROR_INVALID_PARAMS; + + *pui32ByteSize = psDevInfo->sFBInfo.ui32BufferSize; + + if (ppvCpuVAddr) + *ppvCpuVAddr = psSystemBuffer->sCPUVAddr; + + if (phOSMapInfo) + *phOSMapInfo = (void *) 0; + + if (pbIsContiguous) + *pbIsContiguous = IMG_TRUE; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR CreateDCSwapChain(void *hDevice, u32 ui32Flags, + struct DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib, + struct DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib, + u32 ui32BufferCount, + struct PVRSRV_SYNC_DATA **ppsSyncData, + u32 ui32OEMFlags, void **phSwapChain, + u32 *pui32SwapChainID) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + struct OMAPLFB_SWAPCHAIN *psSwapChain; + struct OMAPLFB_BUFFER *psBuffer; + u32 i; + enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC; + + PVR_UNREFERENCED_PARAMETER(ui32OEMFlags); + PVR_UNREFERENCED_PARAMETER(pui32SwapChainID); + + if (!hDevice || !psDstSurfAttrib || !psSrcSurfAttrib || + !ppsSyncData || !phSwapChain) + return PVRSRV_ERROR_INVALID_PARAMS; + + psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice; + + if (psDevInfo->sDisplayInfo.ui32MaxSwapChains == 0) + return PVRSRV_ERROR_NOT_SUPPORTED; + + if (psDevInfo->psSwapChain != NULL) + return PVRSRV_ERROR_FLIP_CHAIN_EXISTS; + + if (ui32BufferCount > psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers) + return PVRSRV_ERROR_TOOMANYBUFFERS; + + if ((psDevInfo->sFBInfo.ui32RoundedBufferSize * ui32BufferCount) > + psDevInfo->sFBInfo.ui32FBSize) + return PVRSRV_ERROR_TOOMANYBUFFERS; + + if (psDstSurfAttrib->pixelformat != + psDevInfo->sDisplayFormat.pixelformat || + psDstSurfAttrib->sDims.ui32ByteStride != + psDevInfo->sDisplayDim.ui32ByteStride || + psDstSurfAttrib->sDims.ui32Width != + psDevInfo->sDisplayDim.ui32Width || + psDstSurfAttrib->sDims.ui32Height != + psDevInfo->sDisplayDim.ui32Height) + return PVRSRV_ERROR_INVALID_PARAMS; + + if (psDstSurfAttrib->pixelformat != psSrcSurfAttrib->pixelformat || + psDstSurfAttrib->sDims.ui32ByteStride != + psSrcSurfAttrib->sDims.ui32ByteStride || + psDstSurfAttrib->sDims.ui32Width != + psSrcSurfAttrib->sDims.ui32Width || + psDstSurfAttrib->sDims.ui32Height != + psSrcSurfAttrib->sDims.ui32Height) + return PVRSRV_ERROR_INVALID_PARAMS; + + PVR_UNREFERENCED_PARAMETER(ui32Flags); + + psSwapChain = (struct OMAPLFB_SWAPCHAIN *) + OMAPLFBAllocKernelMem(sizeof(struct OMAPLFB_SWAPCHAIN)); + if (!psSwapChain) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + psBuffer = (struct OMAPLFB_BUFFER *) + OMAPLFBAllocKernelMem(sizeof(struct OMAPLFB_BUFFER) * + ui32BufferCount); + if (!psBuffer) { + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorFreeSwapChain; + } + + psSwapChain->ui32BufferCount = ui32BufferCount; + psSwapChain->psBuffer = psBuffer; + psSwapChain->psPVRJTable = &psDevInfo->sPVRJTable; + + for (i = 0; i < ui32BufferCount - 1; i++) + psBuffer[i].psNext = &psBuffer[i + 1]; + + psBuffer[i].psNext = &psBuffer[0]; + + for (i = 0; i < ui32BufferCount; i++) { + u32 ui32BufferOffset = i * + psDevInfo->sFBInfo.ui32RoundedBufferSize; + + psBuffer[i].psSyncData = ppsSyncData[i]; + + psBuffer[i].sSysAddr.uiAddr = + psDevInfo->sFBInfo.sSysAddr.uiAddr + ui32BufferOffset; + psBuffer[i].sCPUVAddr = + psDevInfo->sFBInfo.sCPUVAddr + ui32BufferOffset; + } + + psDevInfo->psSwapChain = psSwapChain; + + eError = EnableLFBEventNotification(psDevInfo); + if (eError != PVRSRV_OK) { + printk(DRIVER_PREFIX + ": Couldn't enable framebuffer event notification\n"); + goto ErrorFreeBuffer; + } + + *phSwapChain = (void *) psSwapChain; + + return PVRSRV_OK; + +ErrorFreeBuffer: + OMAPLFBFreeKernelMem(psBuffer); +ErrorFreeSwapChain: + OMAPLFBFreeKernelMem(psSwapChain); + + return eError; +} + +static enum PVRSRV_ERROR DestroyDCSwapChain(void *hDevice, void *hSwapChain) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + struct OMAPLFB_SWAPCHAIN *psSwapChain; + enum PVRSRV_ERROR eError; + + if (!hDevice || !hSwapChain) + return PVRSRV_ERROR_INVALID_PARAMS; + + psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice; + psSwapChain = (struct OMAPLFB_SWAPCHAIN *)hSwapChain; + if (psSwapChain != psDevInfo->psSwapChain) + return PVRSRV_ERROR_INVALID_PARAMS; + + eError = DisableLFBEventNotification(psDevInfo); + if (eError != PVRSRV_OK) + printk(KERN_WARNING DRIVER_PREFIX + ": Couldn't disable framebuffer event notification\n"); + + psDevInfo->psSwapChain = NULL; + + OMAPLFBFreeKernelMem(psSwapChain->psBuffer); + OMAPLFBFreeKernelMem(psSwapChain); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR SetDCDstRect(void *hDevice, + void *hSwapChain, struct IMG_RECT *psRect) +{ + PVR_UNREFERENCED_PARAMETER(hDevice); + PVR_UNREFERENCED_PARAMETER(hSwapChain); + PVR_UNREFERENCED_PARAMETER(psRect); + + return PVRSRV_ERROR_NOT_SUPPORTED; +} + +static enum PVRSRV_ERROR SetDCSrcRect(void *hDevice, + void *hSwapChain, struct IMG_RECT *psRect) +{ + PVR_UNREFERENCED_PARAMETER(hDevice); + PVR_UNREFERENCED_PARAMETER(hSwapChain); + PVR_UNREFERENCED_PARAMETER(psRect); + + return PVRSRV_ERROR_NOT_SUPPORTED; +} + +static enum PVRSRV_ERROR SetDCDstColourKey(void *hDevice, void *hSwapChain, + u32 ui32CKColour) +{ + PVR_UNREFERENCED_PARAMETER(hDevice); + PVR_UNREFERENCED_PARAMETER(hSwapChain); + PVR_UNREFERENCED_PARAMETER(ui32CKColour); + + return PVRSRV_ERROR_NOT_SUPPORTED; +} + +static enum PVRSRV_ERROR SetDCSrcColourKey(void *hDevice, void *hSwapChain, + u32 ui32CKColour) +{ + PVR_UNREFERENCED_PARAMETER(hDevice); + PVR_UNREFERENCED_PARAMETER(hSwapChain); + PVR_UNREFERENCED_PARAMETER(ui32CKColour); + + return PVRSRV_ERROR_NOT_SUPPORTED; +} + +static enum PVRSRV_ERROR GetDCBuffers(void *hDevice, void *hSwapChain, + u32 *pui32BufferCount, void **phBuffer) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + struct OMAPLFB_SWAPCHAIN *psSwapChain; + u32 i; + + if (!hDevice || !hSwapChain || !pui32BufferCount || !phBuffer) + return PVRSRV_ERROR_INVALID_PARAMS; + + psDevInfo = (struct OMAPLFB_DEVINFO *)hDevice; + psSwapChain = (struct OMAPLFB_SWAPCHAIN *)hSwapChain; + if (psSwapChain != psDevInfo->psSwapChain) + return PVRSRV_ERROR_INVALID_PARAMS; + + *pui32BufferCount = psSwapChain->ui32BufferCount; + + for (i = 0; i < psSwapChain->ui32BufferCount; i++) + phBuffer[i] = (void *) &psSwapChain->psBuffer[i]; + + return PVRSRV_OK; +} + +static IMG_BOOL ProcessFlip(void *hCmdCookie, u32 ui32DataSize, void *pvData) +{ + struct DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; + struct OMAPLFB_DEVINFO *psDevInfo; + struct OMAPLFB_BUFFER *psBuffer; + struct OMAPLFB_SWAPCHAIN *psSwapChain; + + if (!hCmdCookie || !pvData) + return IMG_FALSE; + + psFlipCmd = (struct DISPLAYCLASS_FLIP_COMMAND *)pvData; + + if (psFlipCmd == NULL + || sizeof(struct DISPLAYCLASS_FLIP_COMMAND) != ui32DataSize) + return IMG_FALSE; + + psDevInfo = (struct OMAPLFB_DEVINFO *)psFlipCmd->hExtDevice; + + psBuffer = (struct OMAPLFB_BUFFER *)psFlipCmd->hExtBuffer; + psSwapChain = (struct OMAPLFB_SWAPCHAIN *)psFlipCmd->hExtSwapChain; + + psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE); + + return IMG_TRUE; +} + +static void CalcSwapChainSize(struct OMAPLFB_DEVINFO *psDevInfo) +{ + if (psDevInfo->sFBInfo.ui32RoundedBufferSize) + psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = + psDevInfo->sFBInfo.ui32FBSize / + psDevInfo->sFBInfo.ui32RoundedBufferSize; + else + psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = 0; + + if (psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers == 0) { + psDevInfo->sDisplayInfo.ui32MaxSwapChains = 0; + psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 0; + } else { + psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1; + psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 3; + } + + psDevInfo->sDisplayInfo.ui32MinSwapInterval = 0; + + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Maximum number of swap chain buffers: %u\n", + psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers)); +} + +static void SetDevinfo(struct OMAPLFB_DEVINFO *psDevInfo) +{ + struct OMAPLFB_FBINFO *psPVRFBInfo = &psDevInfo->sFBInfo; + struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo; + unsigned long FBSize; + + FBSize = (psLINFBInfo->screen_size) != 0 ? + psLINFBInfo->screen_size : psLINFBInfo->fix.smem_len; + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Framebuffer physical address: 0x%lx\n", + psLINFBInfo->fix.smem_start)); + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Framebuffer virtual address: 0x%lx\n", + (unsigned long)psLINFBInfo->screen_base)); + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Framebuffer size: %lu\n", FBSize)); + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Framebuffer virtual width: %u\n", + psLINFBInfo->var.xres_virtual)); + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Framebuffer virtual height: %u\n", + psLINFBInfo->var.yres_virtual)); + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Framebuffer width: %u\n", psLINFBInfo->var.xres)); + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Framebuffer height: %u\n", psLINFBInfo->var.yres)); + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Framebuffer stride: %u\n", + psLINFBInfo->fix.line_length)); + + psPVRFBInfo->sSysAddr.uiAddr = psLINFBInfo->fix.smem_start; + psPVRFBInfo->sCPUVAddr = psLINFBInfo->screen_base; + + psPVRFBInfo->ui32Width = psLINFBInfo->var.xres_virtual; + psPVRFBInfo->ui32ByteStride = psLINFBInfo->fix.line_length; + psPVRFBInfo->ui32FBSize = FBSize; + + /* Try double buffering */ + psPVRFBInfo->ui32Height = psLINFBInfo->var.yres_virtual >> 1; + psPVRFBInfo->ui32BufferSize = psPVRFBInfo->ui32ByteStride * + psPVRFBInfo->ui32Height; + psPVRFBInfo->ui32RoundedBufferSize = + sgx_buffer_align(psPVRFBInfo->ui32ByteStride, + psPVRFBInfo->ui32BufferSize); + + /* If the buffers aren't aligned assume single buffering */ + if (psPVRFBInfo->ui32BufferSize != psPVRFBInfo->ui32RoundedBufferSize) { + psPVRFBInfo->ui32Height = psLINFBInfo->var.yres_virtual; + psPVRFBInfo->ui32BufferSize = psPVRFBInfo->ui32ByteStride * + psPVRFBInfo->ui32Height; + psPVRFBInfo->ui32RoundedBufferSize = + sgx_buffer_align(psPVRFBInfo->ui32ByteStride, + psPVRFBInfo->ui32BufferSize); + } + + CalcSwapChainSize(psDevInfo); + + if (psLINFBInfo->var.bits_per_pixel == 16) { + if ((psLINFBInfo->var.red.length == 5) && + (psLINFBInfo->var.green.length == 6) && + (psLINFBInfo->var.blue.length == 5) && + (psLINFBInfo->var.red.offset == 11) && + (psLINFBInfo->var.green.offset == 5) && + (psLINFBInfo->var.blue.offset == 0) && + (psLINFBInfo->var.red.msb_right == 0)) + psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_RGB565; + else + printk("Unknown FB format\n"); + } else if (psLINFBInfo->var.bits_per_pixel == 32) { + if ((psLINFBInfo->var.transp.length == 8) && + (psLINFBInfo->var.red.length == 8) && + (psLINFBInfo->var.green.length == 8) && + (psLINFBInfo->var.blue.length == 8) && + (psLINFBInfo->var.transp.offset == 24) && + (psLINFBInfo->var.red.offset == 16) && + (psLINFBInfo->var.green.offset == 8) && + (psLINFBInfo->var.blue.offset == 0) && + (psLINFBInfo->var.red.msb_right == 0)) + psPVRFBInfo->ePixelFormat = + PVRSRV_PIXEL_FORMAT_ARGB8888; + else if ((psLINFBInfo->var.transp.length == 0) && + (psLINFBInfo->var.red.length == 8) && + (psLINFBInfo->var.green.length == 8) && + (psLINFBInfo->var.blue.length == 8) && + (psLINFBInfo->var.transp.offset == 0) && + (psLINFBInfo->var.red.offset == 16) && + (psLINFBInfo->var.green.offset == 8) && + (psLINFBInfo->var.blue.offset == 0) && + (psLINFBInfo->var.red.msb_right == 0)) + psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_RGB888; + else + printk(KERN_ERR "Unknown FB format\n"); + } else { + printk(KERN_ERR "Unknown FB format\n"); + } + + psDevInfo->sDisplayFormat.pixelformat = psDevInfo->sFBInfo.ePixelFormat; + psDevInfo->sDisplayDim.ui32Width = psDevInfo->sFBInfo.ui32Width; + psDevInfo->sDisplayDim.ui32Height = psDevInfo->sFBInfo.ui32Height; + psDevInfo->sDisplayDim.ui32ByteStride = + psDevInfo->sFBInfo.ui32ByteStride; + psDevInfo->sSystemBuffer.sSysAddr = psDevInfo->sFBInfo.sSysAddr; + psDevInfo->sSystemBuffer.sCPUVAddr = psDevInfo->sFBInfo.sCPUVAddr; + psDevInfo->sSystemBuffer.ui32BufferSize = + psDevInfo->sFBInfo.ui32RoundedBufferSize; +} + +static struct FB_EVENTS { + struct notifier_block notif; + struct OMAPLFB_DEVINFO *psDevInfo; +} gFBEventsData; + +static int FBEvents(struct notifier_block *psNotif, + unsigned long event, void *data) +{ + if (event == FB_EVENT_MODE_CHANGE) { + struct FB_EVENTS *psEvents = + container_of(psNotif, struct FB_EVENTS, notif); + SetDevinfo(psEvents->psDevInfo); + } + return 0; +} + +static enum PVRSRV_ERROR InitDev(struct OMAPLFB_DEVINFO *psDevInfo) +{ + struct fb_info *psLINFBInfo; + struct module *psLINFBOwner; + struct OMAPLFB_FBINFO *psPVRFBInfo = &psDevInfo->sFBInfo; + enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC; + + console_lock(); + + if (fb_idx < 0 || fb_idx >= num_registered_fb) { + eError = PVRSRV_ERROR_INVALID_DEVICE; + goto errRelSem; + } + + psLINFBInfo = registered_fb[fb_idx]; + + psLINFBOwner = psLINFBInfo->fbops->owner; + if (!try_module_get(psLINFBOwner)) { + printk(KERN_INFO DRIVER_PREFIX + ": Couldn't get framebuffer module\n"); + + goto errRelSem; + } + + if (psLINFBInfo->fbops->fb_open != NULL) { + int res; + + res = psLINFBInfo->fbops->fb_open(psLINFBInfo, 0); + if (res != 0) { + printk(KERN_INFO DRIVER_PREFIX + ": Couldn't open framebuffer: %d\n", res); + + goto errModPut; + } + } + + psDevInfo->psLINFBInfo = psLINFBInfo; + + SetDevinfo(psDevInfo); + + gFBEventsData.notif.notifier_call = FBEvents; + gFBEventsData.psDevInfo = psDevInfo; + fb_register_client(&gFBEventsData.notif); + + psDevInfo->sFBInfo.sSysAddr.uiAddr = psPVRFBInfo->sSysAddr.uiAddr; + psDevInfo->sFBInfo.sCPUVAddr = psPVRFBInfo->sCPUVAddr; + + eError = PVRSRV_OK; + goto errRelSem; + +errModPut: + module_put(psLINFBOwner); +errRelSem: + console_unlock(); + return eError; +} + +static void DeInitDev(struct OMAPLFB_DEVINFO *psDevInfo) +{ + struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo; + struct module *psLINFBOwner; + + console_lock(); + + fb_unregister_client(&gFBEventsData.notif); + + psLINFBOwner = psLINFBInfo->fbops->owner; + + if (psLINFBInfo->fbops->fb_release != NULL) + (void)psLINFBInfo->fbops->fb_release(psLINFBInfo, 0); + + module_put(psLINFBOwner); + + console_unlock(); +} + +enum PVRSRV_ERROR OMAPLFBInit(void) +{ + struct OMAPLFB_DEVINFO *psDevInfo; + + psDevInfo = GetAnchorPtr(); + + if (psDevInfo == NULL) { + IMG_BOOL (*pfnCmdProcList[OMAPLFB_COMMAND_COUNT]) + (void *, u32, void *); + u32 aui32SyncCountList[OMAPLFB_COMMAND_COUNT][2]; + + psDevInfo = (struct OMAPLFB_DEVINFO *) + OMAPLFBAllocKernelMem(sizeof(struct OMAPLFB_DEVINFO)); + + if (!psDevInfo) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + memset(psDevInfo, 0, sizeof(struct OMAPLFB_DEVINFO)); + + SetAnchorPtr((void *) psDevInfo); + + psDevInfo->ui32RefCount = 0; + + if (InitDev(psDevInfo) != PVRSRV_OK) + return PVRSRV_ERROR_INIT_FAILURE; + + if (OMAPLFBGetLibFuncAddr("PVRGetDisplayClassJTable", + &pfnGetPVRJTable) != PVRSRV_OK) + return PVRSRV_ERROR_INIT_FAILURE; + + if (!(*pfnGetPVRJTable) (&psDevInfo->sPVRJTable)) + return PVRSRV_ERROR_INIT_FAILURE; + + psDevInfo->psSwapChain = NULL; + + CalcSwapChainSize(psDevInfo); + + strncpy(psDevInfo->sDisplayInfo.szDisplayName, + DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE); + + psDevInfo->sDCJTable.ui32TableSize = + sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE); + psDevInfo->sDCJTable.owner = THIS_MODULE; + psDevInfo->sDCJTable.pfnOpenDCDevice = OpenDCDevice; + psDevInfo->sDCJTable.pfnCloseDCDevice = CloseDCDevice; + psDevInfo->sDCJTable.pfnEnumDCFormats = EnumDCFormats; + psDevInfo->sDCJTable.pfnEnumDCDims = EnumDCDims; + psDevInfo->sDCJTable.pfnGetDCSystemBuffer = GetDCSystemBuffer; + psDevInfo->sDCJTable.pfnGetDCInfo = GetDCInfo; + psDevInfo->sDCJTable.pfnGetBufferAddr = GetDCBufferAddr; + psDevInfo->sDCJTable.pfnCreateDCSwapChain = CreateDCSwapChain; + psDevInfo->sDCJTable.pfnDestroyDCSwapChain = DestroyDCSwapChain; + psDevInfo->sDCJTable.pfnSetDCDstRect = SetDCDstRect; + psDevInfo->sDCJTable.pfnSetDCSrcRect = SetDCSrcRect; + psDevInfo->sDCJTable.pfnSetDCDstColourKey = SetDCDstColourKey; + psDevInfo->sDCJTable.pfnSetDCSrcColourKey = SetDCSrcColourKey; + psDevInfo->sDCJTable.pfnGetDCBuffers = GetDCBuffers; + psDevInfo->sDCJTable.pfnSetDCState = NULL; + + if (psDevInfo->sPVRJTable. + pfnPVRSRVRegisterDCDevice(&psDevInfo->sDCJTable, + &psDevInfo->ui32DeviceID) != + PVRSRV_OK) + return PVRSRV_ERROR_DEVICE_REGISTER_FAILED; + + pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip; + + aui32SyncCountList[DC_FLIP_COMMAND][0] = 0; + aui32SyncCountList[DC_FLIP_COMMAND][1] = 2; + + if (psDevInfo->sPVRJTable. + pfnPVRSRVRegisterCmdProcList(psDevInfo->ui32DeviceID, + &pfnCmdProcList[0], + aui32SyncCountList, + OMAPLFB_COMMAND_COUNT) != + PVRSRV_OK) { + printk(KERN_WARNING DRIVER_PREFIX + ": Can't register callback\n"); + return PVRSRV_ERROR_CANT_REGISTER_CALLBACK; + } + + } + + psDevInfo->ui32RefCount++; + + return PVRSRV_OK; + +} + +enum PVRSRV_ERROR OMAPLFBDeinit(void) +{ + struct OMAPLFB_DEVINFO *psDevInfo, *psDevFirst; + + psDevFirst = GetAnchorPtr(); + psDevInfo = psDevFirst; + + if (psDevInfo == NULL) + return PVRSRV_ERROR_GENERIC; + + psDevInfo->ui32RefCount--; + + if (psDevInfo->ui32RefCount == 0) { + struct PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable = + &psDevInfo->sPVRJTable; + if (psDevInfo->sPVRJTable. + pfnPVRSRVRemoveCmdProcList(psDevInfo->ui32DeviceID, + OMAPLFB_COMMAND_COUNT) != + PVRSRV_OK) + return PVRSRV_ERROR_GENERIC; + + if (psJTable-> + pfnPVRSRVRemoveDCDevice(psDevInfo->ui32DeviceID) != + PVRSRV_OK) + return PVRSRV_ERROR_GENERIC; + + DeInitDev(psDevInfo); + + OMAPLFBFreeKernelMem(psDevInfo); + } + + SetAnchorPtr(NULL); + + return PVRSRV_OK; +} + diff --git a/drivers/gpu/pvr/omaplfb_linux.c b/drivers/gpu/pvr/omaplfb_linux.c new file mode 100644 index 00000000000..bba3bbd345f --- /dev/null +++ b/drivers/gpu/pvr/omaplfb_linux.c @@ -0,0 +1,168 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/version.h> +#include <linux/module.h> + +#include <linux/pci.h> +#include <linux/uaccess.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/interrupt.h> + +#include <linux/platform_device.h> + +#include <linux/io.h> + +#include "img_defs.h" +#include "servicesext.h" +#include "kerneldisplay.h" +#include "omaplfb.h" +#include "pvrmodule.h" + +#include <video/omapdss.h> + +MODULE_SUPPORTED_DEVICE(DEVNAME); + +#define unref__ __attribute__ ((unused)) + +void *OMAPLFBAllocKernelMem(u32 ui32Size) +{ + return kmalloc(ui32Size, GFP_KERNEL); +} + +void OMAPLFBFreeKernelMem(void *pvMem) +{ + kfree(pvMem); +} + +enum PVRSRV_ERROR OMAPLFBGetLibFuncAddr(char *szFunctionName, + IMG_BOOL (**ppfnFuncTable)(struct PVRSRV_DC_DISP2SRV_KMJTABLE *)) +{ + if (strcmp("PVRGetDisplayClassJTable", szFunctionName) != 0) + return PVRSRV_ERROR_INVALID_PARAMS; + + *ppfnFuncTable = PVRGetDisplayClassJTable; + + return PVRSRV_OK; +} + +static int OMAPLFBDriverSuspend_Entry(struct platform_device unref__ * pDevice, + pm_message_t unref__ state) +{ + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": OMAPLFBDriverSuspend_Entry\n")); + return 0; +} + +static int OMAPLFBDriverResume_Entry(struct platform_device unref__ * pDevice) +{ + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": OMAPLFBDriverResume_Entry\n")); + return 0; +} + +static void OMAPLFBDriverShutdown_Entry(struct platform_device unref__ * + pDevice) +{ + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": OMAPLFBDriverShutdown_Entry\n")); +} + +static void OMAPLFBDeviceRelease_Entry(struct device unref__ * pDevice) +{ + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": OMAPLFBDriverRelease_Entry\n")); +} + +static struct platform_driver omaplfb_driver = { + .driver = { + .name = DRVNAME, + }, + .suspend = OMAPLFBDriverSuspend_Entry, + .resume = OMAPLFBDriverResume_Entry, + .shutdown = OMAPLFBDriverShutdown_Entry, +}; + +static struct platform_device omaplfb_device = { + .name = DEVNAME, + .id = -1, + .dev = { + .release = OMAPLFBDeviceRelease_Entry + } +}; + +static int __init OMAPLFB_Init(void) +{ + int error; + + if (OMAPLFBInit() != PVRSRV_OK) { + printk(KERN_WARNING DRIVER_PREFIX + ": OMAPLFB_Init: OMAPLFBInit failed\n"); + return -ENODEV; + } + error = platform_driver_register(&omaplfb_driver); + if (error) { + printk(KERN_WARNING DRIVER_PREFIX + ": OMAPLFB_Init: Unable to register platform driver (%d)\n", + error); + + goto ExitDeinit; + } + + error = platform_device_register(&omaplfb_device); + if (error) { + printk(KERN_WARNING DRIVER_PREFIX + ": OMAPLFB_Init: Unable to register platform device (%d)\n", + error); + + goto ExitDriverUnregister; + } + + return 0; + +ExitDriverUnregister: + platform_driver_unregister(&omaplfb_driver); + +ExitDeinit: + if (OMAPLFBDeinit() != PVRSRV_OK) + printk(KERN_WARNING DRIVER_PREFIX + ": OMAPLFB_Init: OMAPLFBDeinit failed\n"); + + return -ENODEV; +} + +static void __exit OMAPLFB_Cleanup(void) +{ + platform_device_unregister(&omaplfb_device); + platform_driver_unregister(&omaplfb_driver); + + if (OMAPLFBDeinit() != PVRSRV_OK) + printk(KERN_WARNING DRIVER_PREFIX + ": OMAPLFB_Cleanup: OMAPLFBDeinit failed\n"); +} + +module_init(OMAPLFB_Init); +module_exit(OMAPLFB_Cleanup); diff --git a/drivers/gpu/pvr/osfunc.c b/drivers/gpu/pvr/osfunc.c new file mode 100644 index 00000000000..c3c36acf9a4 --- /dev/null +++ b/drivers/gpu/pvr/osfunc.c @@ -0,0 +1,1498 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/version.h> +#include <linux/io.h> +#include <asm/page.h> +#include <asm/system.h> +#include <linux/mm.h> +#include <linux/pagemap.h> +#include <linux/hugetlb.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/hardirq.h> +#include <linux/timer.h> +#include <linux/capability.h> +#include <linux/uaccess.h> +#include <linux/spinlock.h> + +#include "img_types.h" +#include "services_headers.h" +#include "mm.h" +#include "pvrmmap.h" +#include "mmap.h" +#include "env_data.h" +#include "proc.h" +#include "event.h" + +#define EVENT_OBJECT_TIMEOUT_MS (100) + +#define HOST_ALLOC_MEM_USING_KMALLOC ((void *)0) +#define HOST_ALLOC_MEM_USING_VMALLOC ((void *)1) + +#define LINUX_KMALLOC_LIMIT PAGE_SIZE /* 4k */ + +#if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +enum PVRSRV_ERROR OSAllocMem(u32 ui32Flags, u32 ui32Size, + void **ppvCpuVAddr, void **phBlockAlloc) +#else +enum PVRSRV_ERROR _OSAllocMem(u32 ui32Flags, u32 ui32Size, + void **ppvCpuVAddr, void **phBlockAlloc, + char *pszFilename, u32 ui32Line) +#endif +{ + u32 ui32Threshold; + + PVR_UNREFERENCED_PARAMETER(ui32Flags); + + /* determine whether to go straight to vmalloc */ + ui32Threshold = LINUX_KMALLOC_LIMIT; + + if (ui32Size > ui32Threshold) { +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + *ppvCpuVAddr = _VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED, + pszFilename, ui32Line); +#else + *ppvCpuVAddr = VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED); +#endif + if (!*ppvCpuVAddr) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + if (phBlockAlloc) + *phBlockAlloc = HOST_ALLOC_MEM_USING_VMALLOC; + } else { + /* default - try kmalloc first */ + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + *ppvCpuVAddr = _KMallocWrapper(ui32Size, pszFilename, ui32Line); +#else + *ppvCpuVAddr = KMallocWrapper(ui32Size); +#endif + + if (!*ppvCpuVAddr) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + if (phBlockAlloc) + *phBlockAlloc = HOST_ALLOC_MEM_USING_KMALLOC; + + } + + return PVRSRV_OK; +} + +#if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +void OSFreeMem(u32 ui32Flags, u32 ui32Size, void *pvCpuVAddr, void *hBlockAlloc) +#else +void _OSFreeMem(u32 ui32Flags, u32 ui32Size, void *pvCpuVAddr, + void *hBlockAlloc, char *pszFilename, u32 ui32Line) +#endif +{ + PVR_UNREFERENCED_PARAMETER(ui32Flags); + + if (ui32Size > LINUX_KMALLOC_LIMIT) { +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + _VFreeWrapper(pvCpuVAddr, pszFilename, ui32Line); +#else + VFreeWrapper(pvCpuVAddr); +#endif + } else { +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + _KFreeWrapper(pvCpuVAddr, pszFilename, ui32Line); +#else + KFreeWrapper(pvCpuVAddr); +#endif + } +} + +enum PVRSRV_ERROR OSAllocPages(u32 ui32AllocFlags, u32 ui32Size, + u32 ui32PageSize, void **ppvCpuVAddr, + void **phOSMemHandle) +{ + struct LinuxMemArea *psLinuxMemArea; + + PVR_UNREFERENCED_PARAMETER(ui32PageSize); + + switch (ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK) { + case PVRSRV_HAP_KERNEL_ONLY: + { + psLinuxMemArea = + NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags); + if (!psLinuxMemArea) + return PVRSRV_ERROR_OUT_OF_MEMORY; + break; + } + case PVRSRV_HAP_SINGLE_PROCESS: + { + psLinuxMemArea = + NewAllocPagesLinuxMemArea(ui32Size, ui32AllocFlags); + if (!psLinuxMemArea) + return PVRSRV_ERROR_OUT_OF_MEMORY; + PVRMMapRegisterArea(psLinuxMemArea); + break; + } + + case PVRSRV_HAP_MULTI_PROCESS: + { + psLinuxMemArea = + NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags); + if (!psLinuxMemArea) + return PVRSRV_ERROR_OUT_OF_MEMORY; + PVRMMapRegisterArea(psLinuxMemArea); + break; + } + default: + PVR_DPF(PVR_DBG_ERROR, "OSAllocPages: invalid flags 0x%x\n", + ui32AllocFlags); + *ppvCpuVAddr = NULL; + *phOSMemHandle = (void *) 0; + return PVRSRV_ERROR_INVALID_PARAMS; + } + + if (ui32AllocFlags & (PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_UNCACHED)) + inv_cache_mem_area(psLinuxMemArea); + + *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea); + *phOSMemHandle = psLinuxMemArea; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSFreePages(u32 ui32AllocFlags, u32 ui32Bytes, + void *pvCpuVAddr, void *hOSMemHandle) +{ + struct LinuxMemArea *psLinuxMemArea; + PVR_UNREFERENCED_PARAMETER(ui32Bytes); + PVR_UNREFERENCED_PARAMETER(pvCpuVAddr); + + psLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle; + + switch (ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK) { + case PVRSRV_HAP_KERNEL_ONLY: + break; + case PVRSRV_HAP_SINGLE_PROCESS: + case PVRSRV_HAP_MULTI_PROCESS: + if (PVRMMapRemoveRegisteredArea(psLinuxMemArea) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "OSFreePages(ui32AllocFlags=0x%08X, ui32Bytes=%ld, " + "pvCpuVAddr=%p, hOSMemHandle=%p) FAILED!", + ui32AllocFlags, ui32Bytes, pvCpuVAddr, + hOSMemHandle); + return PVRSRV_ERROR_GENERIC; + } + break; + default: + PVR_DPF(PVR_DBG_ERROR, "%s: invalid flags 0x%x\n", + __func__, ui32AllocFlags); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + LinuxMemAreaDeepFree(psLinuxMemArea); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSGetSubMemHandle(void *hOSMemHandle, u32 ui32ByteOffset, + u32 ui32Bytes, u32 ui32Flags, + void **phOSMemHandleRet) +{ + struct LinuxMemArea *psParentLinuxMemArea, *psLinuxMemArea; + enum PVRSRV_ERROR eError; + + psParentLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle; + + psLinuxMemArea = + NewSubLinuxMemArea(psParentLinuxMemArea, ui32ByteOffset, ui32Bytes); + if (!psLinuxMemArea) { + *phOSMemHandleRet = NULL; + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + *phOSMemHandleRet = psLinuxMemArea; + + if (ui32Flags & PVRSRV_HAP_KERNEL_ONLY) + return PVRSRV_OK; + + eError = PVRMMapRegisterArea(psLinuxMemArea); + if (eError != PVRSRV_OK) + goto failed_register_area; + + return PVRSRV_OK; + +failed_register_area: + *phOSMemHandleRet = NULL; + LinuxMemAreaDeepFree(psLinuxMemArea); + return eError; +} + +enum PVRSRV_ERROR OSReleaseSubMemHandle(void *hOSMemHandle, u32 ui32Flags) +{ + struct LinuxMemArea *psLinuxMemArea; + enum PVRSRV_ERROR eError; + + psLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle; + PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC); + + if ((ui32Flags & PVRSRV_HAP_KERNEL_ONLY) == 0) { + eError = PVRMMapRemoveRegisteredArea(psLinuxMemArea); + if (eError != PVRSRV_OK) + return eError; + } + LinuxMemAreaDeepFree(psLinuxMemArea); + + return PVRSRV_OK; +} + +struct IMG_CPU_PHYADDR OSMemHandleToCpuPAddr(void *hOSMemHandle, + u32 ui32ByteOffset) +{ + PVR_ASSERT(hOSMemHandle); + + return LinuxMemAreaToCpuPAddr(hOSMemHandle, ui32ByteOffset); +} + +void OSMemCopy(void *pvDst, void *pvSrc, u32 ui32Size) +{ + memcpy(pvDst, pvSrc, ui32Size); +} + +void OSMemSet(void *pvDest, u8 ui8Value, u32 ui32Size) +{ + memset(pvDest, (int)ui8Value, (size_t) ui32Size); +} + +char *OSStringCopy(char *pszDest, const char *pszSrc) +{ + return strcpy(pszDest, pszSrc); +} + +s32 OSSNPrintf(char *pStr, u32 ui32Size, const char *pszFormat, ...) +{ + va_list argList; + s32 iCount; + + va_start(argList, pszFormat); + iCount = vsnprintf(pStr, (size_t) ui32Size, pszFormat, argList); + va_end(argList); + + return iCount; +} + +enum PVRSRV_ERROR OSInitEnvData(void **ppvEnvSpecificData) +{ + struct ENV_DATA *psEnvData; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct ENV_DATA), + (void *)&psEnvData, NULL) != PVRSRV_OK) + return PVRSRV_ERROR_GENERIC; + + memset(psEnvData, 0, sizeof(*psEnvData)); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + PVRSRV_MAX_BRIDGE_IN_SIZE + PVRSRV_MAX_BRIDGE_OUT_SIZE, + &psEnvData->pvBridgeData, NULL) != PVRSRV_OK) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct ENV_DATA), + psEnvData, NULL); + return PVRSRV_ERROR_GENERIC; + } + + psEnvData->bMISRInstalled = IMG_FALSE; + psEnvData->bLISRInstalled = IMG_FALSE; + + *ppvEnvSpecificData = psEnvData; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSDeInitEnvData(void *pvEnvSpecificData) +{ + struct ENV_DATA *psEnvData = (struct ENV_DATA *)pvEnvSpecificData; + + PVR_ASSERT(!psEnvData->bMISRInstalled); + PVR_ASSERT(!psEnvData->bLISRInstalled); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + PVRSRV_MAX_BRIDGE_IN_SIZE + PVRSRV_MAX_BRIDGE_OUT_SIZE, + psEnvData->pvBridgeData, NULL); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct ENV_DATA), + pvEnvSpecificData, NULL); + + return PVRSRV_OK; +} + +void OSReleaseThreadQuanta(void) +{ + schedule(); +} + +u32 OSClockus(void) +{ + u32 time, j = jiffies; + + time = j * (1000000 / HZ); + + return time; +} + +void OSWaitus(u32 ui32Timeus) +{ + udelay(ui32Timeus); +} + +u32 OSGetCurrentProcessIDKM(void) +{ + if (in_interrupt()) + return KERNEL_ID; + + return (u32) task_tgid_nr(current); +} + +u32 OSGetPageSize(void) +{ + return PAGE_SIZE; +} + +static irqreturn_t DeviceISRWrapper(int irq, void *dev_id) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + IMG_BOOL bStatus = IMG_FALSE; + PVR_UNREFERENCED_PARAMETER(irq); + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)dev_id; + if (!psDeviceNode) { + PVR_DPF(PVR_DBG_ERROR, "DeviceISRWrapper: invalid params\n"); + goto out; + } + + bStatus = PVRSRVDeviceLISR(psDeviceNode); + + if (bStatus) { + struct SYS_DATA *psSysData = psDeviceNode->psSysData; + struct ENV_DATA *psEnvData = + (struct ENV_DATA *)psSysData->pvEnvSpecificData; + + queue_work(psEnvData->psMISRWorkqueue, &psEnvData->sMISRWork); + } + +out: + return bStatus ? IRQ_HANDLED : IRQ_NONE; +} + +enum PVRSRV_ERROR OSInstallDeviceLISR(void *pvSysData, + u32 ui32Irq, + char *pszISRName, void *pvDeviceNode) +{ + struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData; + struct ENV_DATA *psEnvData = + (struct ENV_DATA *)psSysData->pvEnvSpecificData; + + if (psEnvData->bLISRInstalled) { + PVR_DPF(PVR_DBG_ERROR, "OSInstallDeviceLISR: " + "An ISR has already been installed: IRQ %d cookie %x", + psEnvData->ui32IRQ, psEnvData->pvISRCookie); + return PVRSRV_ERROR_GENERIC; + } + + PVR_TRACE("Installing device LISR %s on IRQ %d with cookie %x", + pszISRName, ui32Irq, pvDeviceNode); + + if (request_irq(ui32Irq, DeviceISRWrapper, + IRQF_SHARED, pszISRName, pvDeviceNode)) { + PVR_DPF(PVR_DBG_ERROR, "OSInstallDeviceLISR: " + "Couldn't install device LISR on IRQ %d", + ui32Irq); + + return PVRSRV_ERROR_GENERIC; + } + + psEnvData->ui32IRQ = ui32Irq; + psEnvData->pvISRCookie = pvDeviceNode; + psEnvData->bLISRInstalled = IMG_TRUE; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSUninstallDeviceLISR(void *pvSysData) +{ + struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData; + struct ENV_DATA *psEnvData = + (struct ENV_DATA *)psSysData->pvEnvSpecificData; + + if (!psEnvData->bLISRInstalled) { + PVR_DPF(PVR_DBG_ERROR, + "OSUninstallDeviceLISR: No LISR has been installed"); + return PVRSRV_ERROR_GENERIC; + } + + PVR_TRACE("Uninstalling device LISR on IRQ %d with cookie %x", + psEnvData->ui32IRQ, psEnvData->pvISRCookie); + + free_irq(psEnvData->ui32IRQ, psEnvData->pvISRCookie); + + psEnvData->bLISRInstalled = IMG_FALSE; + + return PVRSRV_OK; +} + +static void MISRWrapper(struct work_struct *work) +{ + struct ENV_DATA *psEnvData = container_of(work, struct ENV_DATA, + sMISRWork); + struct SYS_DATA *psSysData = (struct SYS_DATA *)psEnvData->pvSysData; + PVRSRVMISR(psSysData); +} + +enum PVRSRV_ERROR OSInstallMISR(void *pvSysData) +{ + struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData; + struct ENV_DATA *psEnvData = + (struct ENV_DATA *)psSysData->pvEnvSpecificData; + + if (psEnvData->bMISRInstalled) { + PVR_DPF(PVR_DBG_ERROR, + "OSInstallMISR: An MISR has already been installed"); + return PVRSRV_ERROR_GENERIC; + } + + PVR_TRACE("Installing MISR with cookie %x", pvSysData); + + psEnvData->pvSysData = pvSysData; + psEnvData->psMISRWorkqueue = create_singlethread_workqueue("sgx_misr"); + INIT_WORK(&psEnvData->sMISRWork, MISRWrapper); + + psEnvData->bMISRInstalled = IMG_TRUE; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSUninstallMISR(void *pvSysData) +{ + struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData; + struct ENV_DATA *psEnvData = + (struct ENV_DATA *)psSysData->pvEnvSpecificData; + + if (!psEnvData->bMISRInstalled) { + PVR_DPF(PVR_DBG_ERROR, + "OSUninstallMISR: No MISR has been installed"); + return PVRSRV_ERROR_GENERIC; + } + + PVR_TRACE("Uninstalling MISR"); + + flush_workqueue(psEnvData->psMISRWorkqueue); + destroy_workqueue(psEnvData->psMISRWorkqueue); + + psEnvData->bMISRInstalled = IMG_FALSE; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSScheduleMISR(void *pvSysData) +{ + struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData; + struct ENV_DATA *psEnvData = + (struct ENV_DATA *)psSysData->pvEnvSpecificData; + + if (psEnvData->bMISRInstalled) + queue_work(psEnvData->psMISRWorkqueue, &psEnvData->sMISRWork); + + return PVRSRV_OK; +} + + +struct IMG_CPU_PHYADDR OSMapLinToCPUPhys(void *pvLinAddr) +{ + struct IMG_CPU_PHYADDR CpuPAddr; + + CpuPAddr.uiAddr = (u32) VMallocToPhys(pvLinAddr); + + return CpuPAddr; +} + +void __iomem *OSMapPhysToLin(struct IMG_CPU_PHYADDR BasePAddr, u32 ui32Bytes, + u32 ui32MappingFlags, void **phOSMemHandle) +{ + if (phOSMemHandle) + *phOSMemHandle = (void *) 0; + + if (ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY) { + void __iomem *pvIORemapCookie; + pvIORemapCookie = + IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags); + if (pvIORemapCookie == NULL) + return NULL; + return pvIORemapCookie; + } else { + PVR_DPF(PVR_DBG_ERROR, "OSMapPhysToLin " + "should only be used with PVRSRV_HAP_KERNEL_ONLY " + "(Use OSReservePhys otherwise)"); + return NULL; + } + +} + +IMG_BOOL +OSUnMapPhysToLin(void __iomem *pvLinAddr, u32 ui32Bytes, + u32 ui32MappingFlags, void *hPageAlloc) +{ + PVR_TRACE("%s: unmapping %d bytes from 0x%08x", __func__, + ui32Bytes, pvLinAddr); + + PVR_UNREFERENCED_PARAMETER(hPageAlloc); + PVR_UNREFERENCED_PARAMETER(ui32Bytes); + + if (ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY) { + IOUnmapWrapper(pvLinAddr); + return IMG_TRUE; + } else { + PVR_DPF(PVR_DBG_ERROR, "OSUnMapPhysToLin " + "should only be used with PVRSRV_HAP_KERNEL_ONLY " + " (Use OSUnReservePhys otherwise)"); + return IMG_FALSE; + } + +} + +static enum PVRSRV_ERROR RegisterExternalMem(struct IMG_SYS_PHYADDR *pBasePAddr, + void *pvCPUVAddr, u32 ui32Bytes, IMG_BOOL bPhysContig, + u32 ui32MappingFlags, void **phOSMemHandle) +{ + struct LinuxMemArea *psLinuxMemArea; + + switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) { + case PVRSRV_HAP_KERNEL_ONLY: + { + psLinuxMemArea = + NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr, + ui32Bytes, bPhysContig, + ui32MappingFlags); + + if (!psLinuxMemArea) + return PVRSRV_ERROR_GENERIC; + break; + } + case PVRSRV_HAP_SINGLE_PROCESS: + { + psLinuxMemArea = + NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr, + ui32Bytes, bPhysContig, + ui32MappingFlags); + + if (!psLinuxMemArea) + return PVRSRV_ERROR_GENERIC; + PVRMMapRegisterArea(psLinuxMemArea); + break; + } + case PVRSRV_HAP_MULTI_PROCESS: + { + psLinuxMemArea = + NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr, + ui32Bytes, bPhysContig, + ui32MappingFlags); + + if (!psLinuxMemArea) + return PVRSRV_ERROR_GENERIC; + PVRMMapRegisterArea(psLinuxMemArea); + break; + } + default: + PVR_DPF(PVR_DBG_ERROR, "OSRegisterMem : invalid flags 0x%x\n", + ui32MappingFlags); + *phOSMemHandle = (void *) 0; + return PVRSRV_ERROR_GENERIC; + } + + *phOSMemHandle = (void *) psLinuxMemArea; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSRegisterMem(struct IMG_CPU_PHYADDR BasePAddr, + void *pvCPUVAddr, u32 ui32Bytes, + u32 ui32MappingFlags, void **phOSMemHandle) +{ + struct IMG_SYS_PHYADDR SysPAddr = SysCpuPAddrToSysPAddr(BasePAddr); + + return RegisterExternalMem(&SysPAddr, pvCPUVAddr, ui32Bytes, IMG_TRUE, + ui32MappingFlags, phOSMemHandle); +} + +enum PVRSRV_ERROR OSRegisterDiscontigMem(struct IMG_SYS_PHYADDR *pBasePAddr, + void *pvCPUVAddr, u32 ui32Bytes, + u32 ui32MappingFlags, + void **phOSMemHandle) +{ + return RegisterExternalMem(pBasePAddr, pvCPUVAddr, ui32Bytes, + IMG_FALSE, ui32MappingFlags, phOSMemHandle); +} + +enum PVRSRV_ERROR OSUnRegisterMem(void *pvCpuVAddr, u32 ui32Bytes, + u32 ui32MappingFlags, void *hOSMemHandle) +{ + struct LinuxMemArea *psLinuxMemArea = (struct LinuxMemArea *) + hOSMemHandle; + + PVR_UNREFERENCED_PARAMETER(pvCpuVAddr); + PVR_UNREFERENCED_PARAMETER(ui32Bytes); + + switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) { + case PVRSRV_HAP_KERNEL_ONLY: + break; + case PVRSRV_HAP_SINGLE_PROCESS: + case PVRSRV_HAP_MULTI_PROCESS: + { + if (PVRMMapRemoveRegisteredArea(psLinuxMemArea) != + PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "%s(%p, %d, 0x%08X, %p) FAILED!", + __func__, pvCpuVAddr, ui32Bytes, + ui32MappingFlags, hOSMemHandle); + BUG(); + return PVRSRV_ERROR_GENERIC; + } + break; + } + default: + { + PVR_DPF(PVR_DBG_ERROR, + "OSUnRegisterMem : invalid flags 0x%x", + ui32MappingFlags); + return PVRSRV_ERROR_INVALID_PARAMS; + } + } + + LinuxMemAreaDeepFree(psLinuxMemArea); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSUnRegisterDiscontigMem(void *pvCpuVAddr, u32 ui32Bytes, + u32 ui32Flags, void *hOSMemHandle) +{ + return OSUnRegisterMem(pvCpuVAddr, ui32Bytes, ui32Flags, hOSMemHandle); +} + +enum PVRSRV_ERROR OSReservePhys(struct IMG_CPU_PHYADDR BasePAddr, + u32 ui32Bytes, u32 ui32MappingFlags, void **ppvCpuVAddr, + void **phOSMemHandle) +{ + struct LinuxMemArea *psLinuxMemArea; + + switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) { + case PVRSRV_HAP_KERNEL_ONLY: + { + psLinuxMemArea = + NewIORemapLinuxMemArea(BasePAddr, ui32Bytes, + ui32MappingFlags); + if (!psLinuxMemArea) + return PVRSRV_ERROR_GENERIC; + break; + } + case PVRSRV_HAP_SINGLE_PROCESS: + { + psLinuxMemArea = + NewIOLinuxMemArea(BasePAddr, ui32Bytes, + ui32MappingFlags); + if (!psLinuxMemArea) + return PVRSRV_ERROR_GENERIC; + PVRMMapRegisterArea(psLinuxMemArea); + break; + } + case PVRSRV_HAP_MULTI_PROCESS: + { + psLinuxMemArea = + NewIORemapLinuxMemArea(BasePAddr, ui32Bytes, + ui32MappingFlags); + if (!psLinuxMemArea) + return PVRSRV_ERROR_GENERIC; + PVRMMapRegisterArea(psLinuxMemArea); + break; + } + default: + PVR_DPF(PVR_DBG_ERROR, "OSMapPhysToLin : invalid flags 0x%x\n", + ui32MappingFlags); + *ppvCpuVAddr = NULL; + *phOSMemHandle = (void *) 0; + return PVRSRV_ERROR_GENERIC; + } + + *phOSMemHandle = (void *) psLinuxMemArea; + *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSUnReservePhys(void *pvCpuVAddr, + u32 ui32Bytes, u32 ui32MappingFlags, void *hOSMemHandle) +{ + struct LinuxMemArea *psLinuxMemArea; + PVR_UNREFERENCED_PARAMETER(pvCpuVAddr); + PVR_UNREFERENCED_PARAMETER(ui32Bytes); + + psLinuxMemArea = (struct LinuxMemArea *)hOSMemHandle; + + switch (ui32MappingFlags & PVRSRV_HAP_MAPTYPE_MASK) { + case PVRSRV_HAP_KERNEL_ONLY: + break; + case PVRSRV_HAP_SINGLE_PROCESS: + case PVRSRV_HAP_MULTI_PROCESS: + { + if (PVRMMapRemoveRegisteredArea(psLinuxMemArea) != + PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "%s(%p, %d, 0x%08X, %p) FAILED!", + __func__, pvCpuVAddr, ui32Bytes, + ui32MappingFlags, hOSMemHandle); + return PVRSRV_ERROR_GENERIC; + } + break; + } + default: + { + PVR_DPF(PVR_DBG_ERROR, + "OSUnMapPhysToLin : invalid flags 0x%x", + ui32MappingFlags); + return PVRSRV_ERROR_INVALID_PARAMS; + } + } + + LinuxMemAreaDeepFree(psLinuxMemArea); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSBaseAllocContigMemory(u32 ui32Size, void **pvLinAddr, + struct IMG_CPU_PHYADDR *psPhysAddr) +{ +#if !defined(NO_HARDWARE) + PVR_UNREFERENCED_PARAMETER(ui32Size); + PVR_UNREFERENCED_PARAMETER(pvLinAddr); + PVR_UNREFERENCED_PARAMETER(psPhysAddr); + PVR_DPF(PVR_DBG_ERROR, "%s: Not available", __func__); + + return PVRSRV_ERROR_OUT_OF_MEMORY; +#else + void *pvKernLinAddr; + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + pvKernLinAddr = _KMallocWrapper(ui32Size, __FILE__, __LINE__); +#else + pvKernLinAddr = KMallocWrapper(ui32Size); +#endif + if (!pvKernLinAddr) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + *pvLinAddr = pvKernLinAddr; + + psPhysAddr->uiAddr = virt_to_phys(pvKernLinAddr); + + return PVRSRV_OK; +#endif +} + +enum PVRSRV_ERROR OSBaseFreeContigMemory(u32 ui32Size, void *pvLinAddr, + struct IMG_CPU_PHYADDR psPhysAddr) +{ +#if !defined(NO_HARDWARE) + PVR_UNREFERENCED_PARAMETER(ui32Size); + PVR_UNREFERENCED_PARAMETER(pvLinAddr); + PVR_UNREFERENCED_PARAMETER(psPhysAddr.uiAddr); + + PVR_DPF(PVR_DBG_WARNING, "%s: Not available", __func__); +#else + PVR_UNREFERENCED_PARAMETER(ui32Size); + PVR_UNREFERENCED_PARAMETER(psPhysAddr.uiAddr); + + KFreeWrapper(pvLinAddr); +#endif + return PVRSRV_OK; +} + +u32 OSReadHWReg(void __iomem *pvLinRegBaseAddr, u32 ui32Offset) +{ +#if !defined(NO_HARDWARE) + return (u32)readl(pvLinRegBaseAddr + ui32Offset); +#else + return *(u32 *)((u8 *) pvLinRegBaseAddr + ui32Offset); +#endif +} + +void OSWriteHWReg(void __iomem *pvLinRegBaseAddr, u32 ui32Offset, u32 ui32Value) +{ +#if !defined(NO_HARDWARE) + writel(ui32Value, pvLinRegBaseAddr + ui32Offset); +#else + *(u32 *)((u8 *)pvLinRegBaseAddr + ui32Offset) = ui32Value; +#endif +} + +#define OS_MAX_TIMERS 8 + +struct TIMER_CALLBACK_DATA { + IMG_BOOL bInUse; + void (*pfnTimerFunc)(void *); + void *pvData; + struct timer_list sTimer; + u32 ui32Delay; + IMG_BOOL bActive; +}; + +static struct TIMER_CALLBACK_DATA sTimers[OS_MAX_TIMERS]; +static DEFINE_SPINLOCK(sTimerStructLock); +static void OSTimerCallbackWrapper(unsigned long ui32Data) +{ + struct TIMER_CALLBACK_DATA *psTimerCBData = + (struct TIMER_CALLBACK_DATA *)ui32Data; + + if (!psTimerCBData->bActive) + return; + + psTimerCBData->pfnTimerFunc(psTimerCBData->pvData); + + mod_timer(&psTimerCBData->sTimer, psTimerCBData->ui32Delay + jiffies); +} + +void *OSAddTimer(void (*pfnTimerFunc)(void *), void *pvData, u32 ui32MsTimeout) +{ + struct TIMER_CALLBACK_DATA *psTimerCBData; + u32 ui32i; + unsigned long ulLockFlags; + + if (!pfnTimerFunc) { + PVR_DPF(PVR_DBG_ERROR, "OSAddTimer: passed invalid callback"); + return NULL; + } + + spin_lock_irqsave(&sTimerStructLock, ulLockFlags); + for (ui32i = 0; ui32i < OS_MAX_TIMERS; ui32i++) { + psTimerCBData = &sTimers[ui32i]; + if (!psTimerCBData->bInUse) { + psTimerCBData->bInUse = IMG_TRUE; + break; + } + } + spin_unlock_irqrestore(&sTimerStructLock, ulLockFlags); + + if (ui32i >= OS_MAX_TIMERS) { + PVR_DPF(PVR_DBG_ERROR, "OSAddTimer: all timers are in use"); + return NULL; + } + + psTimerCBData->pfnTimerFunc = pfnTimerFunc; + psTimerCBData->pvData = pvData; + psTimerCBData->bActive = IMG_FALSE; + + psTimerCBData->ui32Delay = ((HZ * ui32MsTimeout) < 1000) + ? 1 : ((HZ * ui32MsTimeout) / 1000); + + init_timer(&psTimerCBData->sTimer); + + psTimerCBData->sTimer.function = OSTimerCallbackWrapper; + psTimerCBData->sTimer.data = (u32) psTimerCBData; + psTimerCBData->sTimer.expires = psTimerCBData->ui32Delay + jiffies; + + return (void *)(ui32i + 1); +} + +static inline struct TIMER_CALLBACK_DATA *GetTimerStructure(void *hTimer) +{ + u32 ui32i = ((u32) hTimer) - 1; + PVR_ASSERT(ui32i < OS_MAX_TIMERS); + return &sTimers[ui32i]; +} + +enum PVRSRV_ERROR OSRemoveTimer(void *hTimer) +{ + struct TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer); + + PVR_ASSERT(psTimerCBData->bInUse); + PVR_ASSERT(!psTimerCBData->bActive); + + /* free timer callback data struct */ + psTimerCBData->bInUse = IMG_FALSE; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSEnableTimer(void *hTimer) +{ + struct TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer); + + PVR_ASSERT(psTimerCBData->bInUse); + PVR_ASSERT(!psTimerCBData->bActive); + + psTimerCBData->bActive = IMG_TRUE; + + add_timer(&psTimerCBData->sTimer); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSDisableTimer(void *hTimer) +{ + struct TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer); + + PVR_ASSERT(psTimerCBData->bInUse); + PVR_ASSERT(psTimerCBData->bActive); + + psTimerCBData->bActive = IMG_FALSE; + + del_timer_sync(&psTimerCBData->sTimer); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSEventObjectCreate(const char *pszName, + struct PVRSRV_EVENTOBJECT *psEventObject) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (psEventObject) { + if (pszName) { + strncpy(psEventObject->szName, pszName, + EVENTOBJNAME_MAXLENGTH); + } else { + static u16 ui16NameIndex; + snprintf(psEventObject->szName, EVENTOBJNAME_MAXLENGTH, + "PVRSRV_EVENTOBJECT_%d", ui16NameIndex++); + } + + if (LinuxEventObjectListCreate(&psEventObject->hOSEventKM) != + PVRSRV_OK) + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + + } else { + PVR_DPF(PVR_DBG_ERROR, "OSEventObjectCreate: " + "psEventObject is not a valid pointer"); + eError = PVRSRV_ERROR_GENERIC; + } + + return eError; + +} + +enum PVRSRV_ERROR OSEventObjectDestroy(struct PVRSRV_EVENTOBJECT *psEventObject) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (psEventObject) { + if (psEventObject->hOSEventKM) { + LinuxEventObjectListDestroy(psEventObject->hOSEventKM); + } else { + PVR_DPF(PVR_DBG_ERROR, "OSEventObjectDestroy: " + "hOSEventKM is not a valid pointer"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + } + } else { + PVR_DPF(PVR_DBG_ERROR, "OSEventObjectDestroy: " + "psEventObject is not a valid pointer"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + } + + return eError; +} + +enum PVRSRV_ERROR OSEventObjectWait(void *hOSEventKM) +{ + enum PVRSRV_ERROR eError; + + if (hOSEventKM) { + eError = + LinuxEventObjectWait(hOSEventKM, EVENT_OBJECT_TIMEOUT_MS); + } else { + PVR_DPF(PVR_DBG_ERROR, + "OSEventObjectWait: hOSEventKM is not a valid handle"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + } + + return eError; +} + +enum PVRSRV_ERROR OSEventObjectOpen(struct PVRSRV_EVENTOBJECT *psEventObject, + void **phOSEvent) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (psEventObject) { + if (LinuxEventObjectAdd(psEventObject->hOSEventKM, phOSEvent) != + PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "LinuxEventObjectAdd: failed"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + } + + } else { + PVR_DPF(PVR_DBG_ERROR, "OSEventObjectCreate: " + "psEventObject is not a valid pointer"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + } + + return eError; +} + +enum PVRSRV_ERROR OSEventObjectClose(struct PVRSRV_EVENTOBJECT *psEventObject, + void *hOSEventKM) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (psEventObject) { + if (LinuxEventObjectDelete + (psEventObject->hOSEventKM, hOSEventKM) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "LinuxEventObjectDelete: failed"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + } + + } else { + PVR_DPF(PVR_DBG_ERROR, "OSEventObjectDestroy: " + "psEventObject is not a valid pointer"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + } + + return eError; + +} + +enum PVRSRV_ERROR OSEventObjectSignal(void *hOSEventKM) +{ + enum PVRSRV_ERROR eError; + + if (hOSEventKM) { + eError = LinuxEventObjectSignal(hOSEventKM); + } else { + PVR_DPF(PVR_DBG_ERROR, "OSEventObjectSignal: " + "hOSEventKM is not a valid handle"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + } + + return eError; +} + +IMG_BOOL OSProcHasPrivSrvInit(void) +{ + return (capable(CAP_SYS_MODULE) != 0) ? IMG_TRUE : IMG_FALSE; +} + +enum PVRSRV_ERROR OSCopyToUser(void *pvProcess, void __user *pvDest, + const void *pvSrc, u32 ui32Bytes) +{ + PVR_UNREFERENCED_PARAMETER(pvProcess); + + if (copy_to_user(pvDest, pvSrc, ui32Bytes) == 0) + return PVRSRV_OK; + else + return PVRSRV_ERROR_GENERIC; +} + +enum PVRSRV_ERROR OSCopyFromUser(void *pvProcess, void *pvDest, + const void __user *pvSrc, u32 ui32Bytes) +{ + PVR_UNREFERENCED_PARAMETER(pvProcess); + + if (copy_from_user(pvDest, pvSrc, ui32Bytes) == 0) + return PVRSRV_OK; + else + return PVRSRV_ERROR_GENERIC; +} + +IMG_BOOL OSAccessOK(enum IMG_VERIFY_TEST eVerification, + const void __user *pvUserPtr, u32 ui32Bytes) +{ + int linuxType; + + if (eVerification == PVR_VERIFY_READ) { + linuxType = VERIFY_READ; + } else { + PVR_ASSERT(eVerification == PVR_VERIFY_WRITE); + linuxType = VERIFY_WRITE; + } + + return access_ok(linuxType, pvUserPtr, ui32Bytes); +} + +enum eWrapMemType { + WRAP_TYPE_CLEANUP, + WRAP_TYPE_GET_USER_PAGES, + WRAP_TYPE_FIND_VMA_PAGES, + WRAP_TYPE_FIND_VMA_PFN +}; + +struct sWrapMemInfo { + enum eWrapMemType eType; + int iNumPages; + struct page **ppsPages; + struct IMG_SYS_PHYADDR *psPhysAddr; + int iPageOffset; + int iContiguous; +#if defined(CONFIG_PVR_DEBUG_EXTRA) + u32 ulStartAddr; + u32 ulBeyondEndAddr; + struct vm_area_struct *psVMArea; +#endif +}; + +static void CheckPagesContiguous(struct sWrapMemInfo *psInfo) +{ + int i; + u32 ui32AddrChk; + + BUG_ON(psInfo == NULL); + + psInfo->iContiguous = 1; + + for (i = 0, ui32AddrChk = psInfo->psPhysAddr[0].uiAddr; + i < psInfo->iNumPages; i++, ui32AddrChk += PAGE_SIZE) + if (psInfo->psPhysAddr[i].uiAddr != ui32AddrChk) { + psInfo->iContiguous = 0; + break; + } +} + +static struct page *CPUVAddrToPage(struct vm_area_struct *psVMArea, + u32 ulCPUVAddr) +{ + pgd_t *psPGD; + pud_t *psPUD; + pmd_t *psPMD; + pte_t *psPTE; + struct mm_struct *psMM = psVMArea->vm_mm; + u32 ulPFN; + spinlock_t *psPTLock; + struct page *psPage; + + psPGD = pgd_offset(psMM, ulCPUVAddr); + if (pgd_none(*psPGD) || pgd_bad(*psPGD)) + return NULL; + + psPUD = pud_offset(psPGD, ulCPUVAddr); + if (pud_none(*psPUD) || pud_bad(*psPUD)) + return NULL; + + psPMD = pmd_offset(psPUD, ulCPUVAddr); + if (pmd_none(*psPMD) || pmd_bad(*psPMD)) + return NULL; + + psPage = NULL; + + psPTE = (pte_t *)pte_offset_map_lock(psMM, psPMD, ulCPUVAddr, + &psPTLock); + if ((pte_none(*psPTE) != 0) || (pte_present(*psPTE) == 0) || + (pte_write(*psPTE) == 0)) + goto exit_unlock; + + ulPFN = pte_pfn(*psPTE); + if (!pfn_valid(ulPFN)) + goto exit_unlock; + + psPage = pfn_to_page(ulPFN); + + get_page(psPage); + +exit_unlock: + pte_unmap_unlock(psPTE, psPTLock); + + return psPage; +} + +enum PVRSRV_ERROR OSReleasePhysPageAddr(void *hOSWrapMem) +{ + struct sWrapMemInfo *psInfo = (struct sWrapMemInfo *)hOSWrapMem; + int i; + + BUG_ON(psInfo == NULL); + + switch (psInfo->eType) { + case WRAP_TYPE_CLEANUP: + break; + case WRAP_TYPE_FIND_VMA_PFN: + break; + case WRAP_TYPE_GET_USER_PAGES: + { + for (i = 0; i < psInfo->iNumPages; i++) { + struct page *psPage = psInfo->ppsPages[i]; + + if (!PageReserved(psPage)) + SetPageDirty(psPage); + page_cache_release(psPage); + } + break; + } + case WRAP_TYPE_FIND_VMA_PAGES: + { + for (i = 0; i < psInfo->iNumPages; i++) + put_page_testzero(psInfo->ppsPages[i]); + break; + } + default: + { + PVR_DPF(PVR_DBG_ERROR, + "OSReleasePhysPageAddr: Unknown wrap type (%d)", + psInfo->eType); + return PVRSRV_ERROR_GENERIC; + } + } + + if (psInfo->ppsPages != NULL) + kfree(psInfo->ppsPages); + + if (psInfo->psPhysAddr != NULL) + kfree(psInfo->psPhysAddr); + + kfree(psInfo); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSAcquirePhysPageAddr(void *pvCPUVAddr, u32 ui32Bytes, + struct IMG_SYS_PHYADDR *psSysPAddr, + void **phOSWrapMem) +{ + u32 ulStartAddrOrig = (u32) pvCPUVAddr; + u32 ulAddrRangeOrig = (u32) ui32Bytes; + u32 ulBeyondEndAddrOrig = ulStartAddrOrig + ulAddrRangeOrig; + u32 ulStartAddr; + u32 ulAddrRange; + u32 ulBeyondEndAddr; + u32 ulAddr; + int iNumPagesMapped; + int i; + struct vm_area_struct *psVMArea; + struct sWrapMemInfo *psInfo; + + ulStartAddr = ulStartAddrOrig & PAGE_MASK; + ulBeyondEndAddr = PAGE_ALIGN(ulBeyondEndAddrOrig); + ulAddrRange = ulBeyondEndAddr - ulStartAddr; + + psInfo = kmalloc(sizeof(*psInfo), GFP_KERNEL); + if (psInfo == NULL) { + PVR_DPF(PVR_DBG_ERROR, "OSAcquirePhysPageAddr: " + "Couldn't allocate information structure"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + memset(psInfo, 0, sizeof(*psInfo)); + +#if defined(CONFIG_PVR_DEBUG_EXTRA) + psInfo->ulStartAddr = ulStartAddrOrig; + psInfo->ulBeyondEndAddr = ulBeyondEndAddrOrig; +#endif + + psInfo->iNumPages = (int)(ulAddrRange >> PAGE_SHIFT); + psInfo->iPageOffset = (int)(ulStartAddrOrig & ~PAGE_MASK); + + psInfo->psPhysAddr = + kmalloc((size_t) psInfo->iNumPages * sizeof(*psInfo->psPhysAddr), + GFP_KERNEL); + if (psInfo->psPhysAddr == NULL) { + PVR_DPF(PVR_DBG_ERROR, "OSAcquirePhysPageAddr: " + "Couldn't allocate page array"); + goto error_free; + } + + psInfo->ppsPages = + kmalloc((size_t) psInfo->iNumPages * sizeof(*psInfo->ppsPages), + GFP_KERNEL); + if (psInfo->ppsPages == NULL) { + PVR_DPF(PVR_DBG_ERROR, "OSAcquirePhysPageAddr: " + "Couldn't allocate page array"); + goto error_free; + } + + down_read(¤t->mm->mmap_sem); + + iNumPagesMapped = get_user_pages(current, current->mm, ulStartAddr, + psInfo->iNumPages, 1, 0, + psInfo->ppsPages, NULL); + up_read(¤t->mm->mmap_sem); + + + if (iNumPagesMapped >= 0) { + if (iNumPagesMapped != psInfo->iNumPages) { + PVR_TRACE("OSAcquirePhysPageAddr: " + "Couldn't map all the pages needed " + "(wanted: %d, got %d)", + psInfo->iNumPages, iNumPagesMapped); + + for (i = 0; i < iNumPagesMapped; i++) + page_cache_release(psInfo->ppsPages[i]); + + goto error_free; + } + + for (i = 0; i < psInfo->iNumPages; i++) { + struct IMG_CPU_PHYADDR CPUPhysAddr; + + CPUPhysAddr.uiAddr = + page_to_pfn(psInfo->ppsPages[i]) << PAGE_SHIFT; + psInfo->psPhysAddr[i] = + SysCpuPAddrToSysPAddr(CPUPhysAddr); + psSysPAddr[i] = psInfo->psPhysAddr[i]; + + } + + psInfo->eType = WRAP_TYPE_GET_USER_PAGES; + + goto exit_check; + } + + PVR_TRACE("OSAcquirePhysPageAddr: " + "get_user_pages failed (%d), trying something else", + iNumPagesMapped); + + down_read(¤t->mm->mmap_sem); + + psVMArea = find_vma(current->mm, ulStartAddrOrig); + if (psVMArea == NULL) { + PVR_DPF(PVR_DBG_ERROR, "OSAcquirePhysPageAddr: " + "Couldn't find memory region " + "containing start address %lx", + ulStartAddrOrig); + + goto error_release_mmap_sem; + } +#if defined(CONFIG_PVR_DEBUG_EXTRA) + psInfo->psVMArea = psVMArea; +#endif + + if (ulStartAddrOrig < psVMArea->vm_start) { + PVR_DPF(PVR_DBG_ERROR, "OSAcquirePhysPageAddr: " + "Start address %lx is outside of the " + "region returned by find_vma", + ulStartAddrOrig); + goto error_release_mmap_sem; + } + + if (ulBeyondEndAddrOrig > psVMArea->vm_end) { + PVR_DPF(PVR_DBG_ERROR, "OSAcquirePhysPageAddr: " + "End address %lx is outside of the region " + "returned by find_vma", + ulBeyondEndAddrOrig); + goto error_release_mmap_sem; + } + + if ((psVMArea->vm_flags & (VM_IO | VM_RESERVED)) != + (VM_IO | VM_RESERVED)) { + PVR_DPF(PVR_DBG_ERROR, "OSAcquirePhysPageAddr: " + "Memory region does not represent memory " + "mapped I/O (VMA flags: 0x%lx)", + psVMArea->vm_flags); + goto error_release_mmap_sem; + } + + if ((psVMArea->vm_flags & (VM_READ | VM_WRITE)) != + (VM_READ | VM_WRITE)) { + PVR_DPF(PVR_DBG_ERROR, "OSAcquirePhysPageAddr: " + "No read/write access to memory region " + "(VMA flags: 0x%lx)", + psVMArea->vm_flags); + goto error_release_mmap_sem; + } + + for (ulAddr = ulStartAddrOrig, i = 0; ulAddr < ulBeyondEndAddrOrig; + ulAddr += PAGE_SIZE, i++) { + struct page *psPage; + + BUG_ON(i >= psInfo->iNumPages); + + psPage = CPUVAddrToPage(psVMArea, ulAddr); + if (psPage == NULL) { + int j; + + PVR_TRACE("OSAcquirePhysPageAddr: " + "Couldn't lookup page structure " + "for address 0x%lx, trying something else", + ulAddr); + + for (j = 0; j < i; j++) + put_page_testzero(psInfo->ppsPages[j]); + break; + } + + psInfo->ppsPages[i] = psPage; + } + + BUG_ON(i > psInfo->iNumPages); + if (i == psInfo->iNumPages) { + for (i = 0; i < psInfo->iNumPages; i++) { + struct page *psPage = psInfo->ppsPages[i]; + struct IMG_CPU_PHYADDR CPUPhysAddr; + + CPUPhysAddr.uiAddr = page_to_pfn(psPage) << PAGE_SHIFT; + + psInfo->psPhysAddr[i] = + SysCpuPAddrToSysPAddr(CPUPhysAddr); + psSysPAddr[i] = psInfo->psPhysAddr[i]; + } + + psInfo->eType = WRAP_TYPE_FIND_VMA_PAGES; + } else { + + if ((psVMArea->vm_flags & VM_PFNMAP) == 0) { + PVR_DPF(PVR_DBG_WARNING, "OSAcquirePhysPageAddr: " + "Region isn't a raw PFN mapping. " + "Giving up."); + goto error_release_mmap_sem; + } + + for (ulAddr = ulStartAddrOrig, i = 0; + ulAddr < ulBeyondEndAddrOrig; ulAddr += PAGE_SIZE, i++) { + struct IMG_CPU_PHYADDR CPUPhysAddr; + + CPUPhysAddr.uiAddr = ((ulAddr - psVMArea->vm_start) + + (psVMArea->vm_pgoff << PAGE_SHIFT)) & PAGE_MASK; + + psInfo->psPhysAddr[i] = + SysCpuPAddrToSysPAddr(CPUPhysAddr); + psSysPAddr[i] = psInfo->psPhysAddr[i]; + } + BUG_ON(i != psInfo->iNumPages); + + psInfo->eType = WRAP_TYPE_FIND_VMA_PFN; + + PVR_DPF(PVR_DBG_WARNING, "OSAcquirePhysPageAddr: " + "Region can't be locked down"); + } + + up_read(¤t->mm->mmap_sem); + +exit_check: + CheckPagesContiguous(psInfo); + + *phOSWrapMem = (void *) psInfo; + + return PVRSRV_OK; + +error_release_mmap_sem: + up_read(¤t->mm->mmap_sem); + +error_free: + psInfo->eType = WRAP_TYPE_CLEANUP; + OSReleasePhysPageAddr((void *)psInfo); + return PVRSRV_ERROR_GENERIC; +} diff --git a/drivers/gpu/pvr/osfunc.h b/drivers/gpu/pvr/osfunc.h new file mode 100644 index 00000000000..2d79af9788f --- /dev/null +++ b/drivers/gpu/pvr/osfunc.h @@ -0,0 +1,216 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + + +#ifndef __OSFUNC_H__ +#define __OSFUNC_H__ + +#if defined(__KERNEL__) +#include <linux/hardirq.h> +#include <linux/string.h> +#endif + +#define PVRSRV_PAGEABLE_SELECT PVRSRV_OS_PAGEABLE_HEAP + +#define KERNEL_ID 0xffffffffL +#define POWER_MANAGER_ID 0xfffffffeL +#define ISR_ID 0xfffffffdL +#define TIMER_ID 0xfffffffcL + +#define HOST_PAGESIZE OSGetPageSize +#define HOST_PAGEMASK (~(HOST_PAGESIZE()-1)) + +#define HOST_PAGEALIGN(addr) (((addr) + HOST_PAGESIZE() - 1) & \ + HOST_PAGEMASK) + +#define PVRSRV_OS_HEAP_MASK 0xf +#define PVRSRV_OS_PAGEABLE_HEAP 0x1 +#define PVRSRV_OS_NON_PAGEABLE_HEAP 0x2 + +u32 OSClockus(void); +u32 OSGetPageSize(void); +enum PVRSRV_ERROR OSInstallDeviceLISR(void *pvSysData, u32 ui32Irq, + char *pszISRName, void *pvDeviceNode); +enum PVRSRV_ERROR OSUninstallDeviceLISR(void *pvSysData); +enum PVRSRV_ERROR OSInstallSystemLISR(void *pvSysData, u32 ui32Irq); +enum PVRSRV_ERROR OSUninstallSystemLISR(void *pvSysData); +enum PVRSRV_ERROR OSInstallMISR(void *pvSysData); +enum PVRSRV_ERROR OSUninstallMISR(void *pvSysData); +enum PVRSRV_ERROR OSInitPerf(void *pvSysData); +enum PVRSRV_ERROR OSCleanupPerf(void *pvSysData); +struct IMG_CPU_PHYADDR OSMapLinToCPUPhys(void *pvLinAddr); +void OSMemCopy(void *pvDst, void *pvSrc, u32 ui32Size); +void __iomem *OSMapPhysToLin(struct IMG_CPU_PHYADDR BasePAddr, + u32 ui32Bytes, u32 ui32MappingFlags, void **phOSMemHandle); +IMG_BOOL OSUnMapPhysToLin(void __iomem *pvLinAddr, u32 ui32Bytes, + u32 ui32MappingFlags, void *hPageAlloc); + +enum PVRSRV_ERROR OSReservePhys(struct IMG_CPU_PHYADDR BasePAddr, u32 ui32Bytes, + u32 ui32Flags, void **ppvCpuVAddr, void **phOSMemHandle); +enum PVRSRV_ERROR OSUnReservePhys(void *pvCpuVAddr, u32 ui32Bytes, + u32 ui32Flags, void *hOSMemHandle); + +enum PVRSRV_ERROR OSRegisterDiscontigMem(struct IMG_SYS_PHYADDR *pBasePAddr, + void *pvCpuVAddr, u32 ui32Bytes, u32 ui32Flags, + void **phOSMemHandle); +enum PVRSRV_ERROR OSUnRegisterDiscontigMem(void *pvCpuVAddr, u32 ui32Bytes, + u32 ui32Flags, void *hOSMemHandle); + +static inline enum PVRSRV_ERROR OSReserveDiscontigPhys( + struct IMG_SYS_PHYADDR *pBasePAddr, u32 ui32Bytes, + u32 ui32Flags, void **ppvCpuVAddr, void **phOSMemHandle) +{ + *ppvCpuVAddr = NULL; + return OSRegisterDiscontigMem(pBasePAddr, *ppvCpuVAddr, ui32Bytes, + ui32Flags, phOSMemHandle); +} + +static inline enum PVRSRV_ERROR OSUnReserveDiscontigPhys(void *pvCpuVAddr, + u32 ui32Bytes, u32 ui32Flags, void *hOSMemHandle) +{ + OSUnRegisterDiscontigMem(pvCpuVAddr, ui32Bytes, ui32Flags, + hOSMemHandle); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSRegisterMem(struct IMG_CPU_PHYADDR BasePAddr, + void *pvCpuVAddr, u32 ui32Bytes, u32 ui32Flags, + void **phOSMemHandle); +enum PVRSRV_ERROR OSUnRegisterMem(void *pvCpuVAddr, u32 ui32Bytes, + u32 ui32Flags, void *hOSMemHandle); + +enum PVRSRV_ERROR OSGetSubMemHandle(void *hOSMemHandle, u32 ui32ByteOffset, + u32 ui32Bytes, u32 ui32Flags, void **phOSMemHandleRet); +enum PVRSRV_ERROR OSReleaseSubMemHandle(void *hOSMemHandle, u32 ui32Flags); + +u32 OSGetCurrentProcessIDKM(void); +u32 OSGetCurrentThreadID(void); +void OSMemSet(void *pvDest, u8 ui8Value, u32 ui32Size); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +enum PVRSRV_ERROR _OSAllocMem(u32 ui32Flags, u32 ui32Size, void **ppvLinAddr, + void **phBlockAlloc, char *pszFilename, u32 ui32Line); +#define OSAllocMem(ui32Flags, ui32Size, ppvLinAddr, phBlockAlloc) \ + _OSAllocMem(ui32Flags, ui32Size, ppvLinAddr, phBlockAlloc, \ + __FILE__, __LINE__) +void _OSFreeMem(u32 ui32Flags, u32 ui32Size, void *pvLinAddr, + void *hBlockAlloc, char *pszFilename, u32 ui32Line); +#define OSFreeMem(ui32Flags, ui32Size, pvLinAddr, phBlockAlloc) \ + _OSFreeMem(ui32Flags, ui32Size, pvLinAddr, phBlockAlloc, \ + __FILE__, __LINE__) +#else +enum PVRSRV_ERROR OSAllocMem(u32 ui32Flags, u32 ui32Size, void **ppvLinAddr, + void **phBlockAlloc); +void OSFreeMem(u32 ui32Flags, u32 ui32Size, void *pvLinAddr, void *hBlockAlloc); +#endif +enum PVRSRV_ERROR OSAllocPages(u32 ui32Flags, u32 ui32Size, u32 ui32PageSize, + void **ppvLinAddr, void **phPageAlloc); +enum PVRSRV_ERROR OSFreePages(u32 ui32Flags, u32 ui32Size, void *pvLinAddr, + void *hPageAlloc); +struct IMG_CPU_PHYADDR OSMemHandleToCpuPAddr(void *hOSMemHandle, + u32 ui32ByteOffset); +enum PVRSRV_ERROR OSInitEnvData(void **ppvEnvSpecificData); +enum PVRSRV_ERROR OSDeInitEnvData(void *pvEnvSpecificData); +char *OSStringCopy(char *pszDest, const char *pszSrc); +s32 OSSNPrintf(char *pStr, u32 ui32Size, const char *pszFormat, ...); +#define OSStringLength(pszString) strlen(pszString) + +enum PVRSRV_ERROR OSEventObjectCreate(const char *pszName, + struct PVRSRV_EVENTOBJECT *psEventObject); +enum PVRSRV_ERROR OSEventObjectDestroy( + struct PVRSRV_EVENTOBJECT *psEventObject); +enum PVRSRV_ERROR OSEventObjectSignal(void *hOSEventKM); +enum PVRSRV_ERROR OSEventObjectWait(void *hOSEventKM); +enum PVRSRV_ERROR OSEventObjectOpen(struct PVRSRV_EVENTOBJECT *psEventObject, + void **phOSEvent); +enum PVRSRV_ERROR OSEventObjectClose(struct PVRSRV_EVENTOBJECT *psEventObject, + void *hOSEventKM); + +enum PVRSRV_ERROR OSBaseAllocContigMemory(u32 ui32Size, void **pLinAddr, + struct IMG_CPU_PHYADDR *pPhysAddr); +enum PVRSRV_ERROR OSBaseFreeContigMemory(u32 ui32Size, void *LinAddr, + struct IMG_CPU_PHYADDR PhysAddr); + +void *MapUserFromKernel(void *pvLinAddrKM, u32 ui32Size, void **phMemBlock); +void *OSMapHWRegsIntoUserSpace(void *hDevCookie, + struct IMG_SYS_PHYADDR sRegAddr, u32 ulSize, void **ppvProcess); +void OSUnmapHWRegsFromUserSpace(void *hDevCookie, void *pvUserAddr, + void *pvProcess); + +void UnmapUserFromKernel(void *pvLinAddrUM, u32 ui32Size, void *hMemBlock); + +enum PVRSRV_ERROR OSMapPhysToUserSpace(void *hDevCookie, + struct IMG_SYS_PHYADDR sCPUPhysAddr, u32 uiSizeInBytes, + u32 ui32CacheFlags, void **ppvUserAddr, u32 *puiActualSize, + void *hMappingHandle); + +enum PVRSRV_ERROR OSUnmapPhysToUserSpace(void *hDevCookie, void *pvUserAddr, + void *pvProcess); + +void OSWaitus(u32 ui32Timeus); +void OSReleaseThreadQuanta(void); + +u32 OSReadHWReg(void __iomem *pvLinRegBaseAddr, u32 ui32Offset); +void OSWriteHWReg(void __iomem *pvLinRegBaseAddr, u32 ui32Offset, + u32 ui32Value); + +void *OSAddTimer(void (*pfnTimerFunc)(void *), void *pvData, u32 ui32MsTimeout); +enum PVRSRV_ERROR OSRemoveTimer(void *hTimer); +enum PVRSRV_ERROR OSEnableTimer(void *hTimer); +enum PVRSRV_ERROR OSDisableTimer(void *hTimer); + +enum PVRSRV_ERROR OSGetSysMemSize(u32 *pui32Bytes); + +enum HOST_PCI_INIT_FLAGS { + HOST_PCI_INIT_FLAG_BUS_MASTER = 0x00000001, + HOST_PCI_INIT_FLAG_MSI = 0x00000002, + HOST_PCI_INIT_FLAG_FORCE_I32 = 0x7fffffff +}; + +enum PVRSRV_ERROR OSScheduleMISR(void *pvSysData); + +IMG_BOOL OSProcHasPrivSrvInit(void); + +enum IMG_VERIFY_TEST { + PVR_VERIFY_WRITE = 0, + PVR_VERIFY_READ +}; + +IMG_BOOL OSAccessOK(enum IMG_VERIFY_TEST eVerification, + const void __user *pvUserPtr, u32 ui32Bytes); + +enum PVRSRV_ERROR OSCopyToUser(void *pvProcess, void __user *pvDest, + const void *pvSrc, u32 ui32Bytes); +enum PVRSRV_ERROR OSCopyFromUser(void *pvProcess, void *pvDest, + const void __user *pvSrc, u32 ui32Bytes); + +enum PVRSRV_ERROR OSAcquirePhysPageAddr(void *pvCPUVAddr, u32 ui32Bytes, + struct IMG_SYS_PHYADDR *psSysPAddr, + void **phOSWrapMem); +enum PVRSRV_ERROR OSReleasePhysPageAddr(void *hOSWrapMem); + +#endif diff --git a/drivers/gpu/pvr/osperproc.c b/drivers/gpu/pvr/osperproc.c new file mode 100644 index 00000000000..dffd3172d27 --- /dev/null +++ b/drivers/gpu/pvr/osperproc.c @@ -0,0 +1,84 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "services_headers.h" +#include "osperproc.h" + +#include "env_perproc.h" +#include "proc.h" + +enum PVRSRV_ERROR OSPerProcessPrivateDataInit(void **phOsPrivateData) +{ + enum PVRSRV_ERROR eError; + void *hBlockAlloc; + struct PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc; + + eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_ENV_PER_PROCESS_DATA), + phOsPrivateData, &hBlockAlloc); + + if (eError != PVRSRV_OK) { + *phOsPrivateData = NULL; + + PVR_DPF(PVR_DBG_ERROR, "%s: OSAllocMem failed (%d)", __func__, + eError); + return eError; + } + + psEnvPerProc = (struct PVRSRV_ENV_PER_PROCESS_DATA *)*phOsPrivateData; + OSMemSet(psEnvPerProc, 0, sizeof(*psEnvPerProc)); + + psEnvPerProc->hBlockAlloc = hBlockAlloc; + + LinuxMMapPerProcessConnect(psEnvPerProc); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSPerProcessPrivateDataDeInit(void *hOsPrivateData) +{ + struct PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc; + + if (hOsPrivateData == NULL) + return PVRSRV_OK; + + psEnvPerProc = (struct PVRSRV_ENV_PER_PROCESS_DATA *)hOsPrivateData; + + LinuxMMapPerProcessDisconnect(psEnvPerProc); + + RemovePerProcessProcDir(psEnvPerProc); + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_ENV_PER_PROCESS_DATA), + hOsPrivateData, psEnvPerProc->hBlockAlloc); + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSPerProcessSetHandleOptions(struct PVRSRV_HANDLE_BASE + *psHandleBase) +{ + return LinuxMMapPerProcessHandleOptions(psHandleBase); +} diff --git a/drivers/gpu/pvr/osperproc.h b/drivers/gpu/pvr/osperproc.h new file mode 100644 index 00000000000..891ab66b782 --- /dev/null +++ b/drivers/gpu/pvr/osperproc.h @@ -0,0 +1,36 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __OSPERPROC_H__ +#define __OSPERPROC_H__ + +enum PVRSRV_ERROR OSPerProcessPrivateDataInit(void **phOsPrivateData); +enum PVRSRV_ERROR OSPerProcessPrivateDataDeInit(void *hOsPrivateData); + +enum PVRSRV_ERROR OSPerProcessSetHandleOptions( + struct PVRSRV_HANDLE_BASE *psHandleBase); + +#endif diff --git a/drivers/gpu/pvr/pb.c b/drivers/gpu/pvr/pb.c new file mode 100644 index 00000000000..ffd8f69eecf --- /dev/null +++ b/drivers/gpu/pvr/pb.c @@ -0,0 +1,419 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <stddef.h> + +#include "services_headers.h" +#include "sgxapi_km.h" +#include "sgxinfo.h" +#include "sgxinfokm.h" +#include "pvr_bridge_km.h" +#include "sgx_bridge_km.h" +#include "pdump_km.h" +#include "sgxutils.h" + +static struct RESMAN_ITEM *psResItemCreateSharedPB; +static struct PVRSRV_PER_PROCESS_DATA *psPerProcCreateSharedPB; + +static enum PVRSRV_ERROR SGXCleanupSharedPBDescCallback(void *pvParam, + u32 ui32Param); +static enum PVRSRV_ERROR SGXCleanupSharedPBDescCreateLockCallback(void *pvParam, + u32 ui32Param); + +enum PVRSRV_ERROR SGXFindSharedPBDescKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevCookie, IMG_BOOL bLockOnFailure, + u32 ui32TotalPBSize, void **phSharedPBDesc, + struct PVRSRV_KERNEL_MEM_INFO **ppsSharedPBDescKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO **ppsHWPBDescKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO **ppsBlockKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO ***pppsSharedPBDescSubKernelMemInfos, + u32 *ui32SharedPBDescSubKernelMemInfosCount) +{ + struct PVRSRV_STUB_PBDESC *psStubPBDesc; + struct PVRSRV_KERNEL_MEM_INFO **ppsSharedPBDescSubKernelMemInfos = NULL; + struct PVRSRV_SGXDEV_INFO *psSGXDevInfo; + enum PVRSRV_ERROR eError; + + psSGXDevInfo = ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice; + + psStubPBDesc = psSGXDevInfo->psStubPBDescListKM; + if (psStubPBDesc != NULL) { + u32 i; + struct RESMAN_ITEM *psResItem; + + if (psStubPBDesc->ui32TotalPBSize != ui32TotalPBSize) { + PVR_DPF(PVR_DBG_WARNING, "SGXFindSharedPBDescKM: " + "Shared PB requested with different size " + "(0x%x) from existing shared PB (0x%x) - " + "requested size ignored", + ui32TotalPBSize, + psStubPBDesc->ui32TotalPBSize); + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO *) * + psStubPBDesc->ui32SubKernelMemInfosCount, + (void **) &ppsSharedPBDescSubKernelMemInfos, + NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXFindSharedPBDescKM: OSAllocMem failed"); + + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ExitNotFound; + } + + psResItem = ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_SHARED_PB_DESC, + psStubPBDesc, 0, + &SGXCleanupSharedPBDescCallback); + + if (psResItem == NULL) { + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO *)* + psStubPBDesc->ui32SubKernelMemInfosCount, + ppsSharedPBDescSubKernelMemInfos, NULL); + + PVR_DPF(PVR_DBG_ERROR, "SGXFindSharedPBDescKM: " + "ResManRegisterRes failed"); + eError = PVRSRV_ERROR_GENERIC; + goto ExitNotFound; + } + + *ppsSharedPBDescKernelMemInfo = + psStubPBDesc->psSharedPBDescKernelMemInfo; + *ppsHWPBDescKernelMemInfo = + psStubPBDesc->psHWPBDescKernelMemInfo; + *ppsBlockKernelMemInfo = + psStubPBDesc->psBlockKernelMemInfo; + + *ui32SharedPBDescSubKernelMemInfosCount = + psStubPBDesc->ui32SubKernelMemInfosCount; + + *pppsSharedPBDescSubKernelMemInfos = + ppsSharedPBDescSubKernelMemInfos; + + for (i = 0; + i < psStubPBDesc->ui32SubKernelMemInfosCount; + i++) { + ppsSharedPBDescSubKernelMemInfos[i] = + psStubPBDesc->ppsSubKernelMemInfos[i]; + } + + psStubPBDesc->ui32RefCount++; + *phSharedPBDesc = (void *) psResItem; + return PVRSRV_OK; + } + + eError = PVRSRV_OK; + if (bLockOnFailure) { + if (psResItemCreateSharedPB == NULL) { + psResItemCreateSharedPB = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_SHARED_PB_DESC_CREATE_LOCK, + psPerProc, 0, + &SGXCleanupSharedPBDescCreateLockCallback); + + if (psResItemCreateSharedPB == NULL) { + PVR_DPF(PVR_DBG_ERROR, "SGXFindSharedPBDescKM: " + "ResManRegisterRes failed"); + + eError = PVRSRV_ERROR_GENERIC; + goto ExitNotFound; + } + PVR_ASSERT(psPerProcCreateSharedPB == NULL); + psPerProcCreateSharedPB = psPerProc; + } else { + eError = PVRSRV_ERROR_PROCESSING_BLOCKED; + } + } +ExitNotFound: + *phSharedPBDesc = NULL; + + return eError; +} + +static enum PVRSRV_ERROR SGXCleanupSharedPBDescKM( + struct PVRSRV_STUB_PBDESC *psStubPBDescIn) +{ + struct PVRSRV_STUB_PBDESC **ppsStubPBDesc; + u32 i; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psSGXDevInfo; + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)psStubPBDescIn->hDevCookie; + psSGXDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + + for (ppsStubPBDesc = (struct PVRSRV_STUB_PBDESC **) + &psSGXDevInfo->psStubPBDescListKM; + *ppsStubPBDesc != NULL; + ppsStubPBDesc = &(*ppsStubPBDesc)->psNext) { + struct PVRSRV_STUB_PBDESC *psStubPBDesc = *ppsStubPBDesc; + + if (psStubPBDesc == psStubPBDescIn) { + psStubPBDesc->ui32RefCount--; + PVR_ASSERT((s32) psStubPBDesc->ui32RefCount >= 0); + + if (psStubPBDesc->ui32RefCount == 0) { + *ppsStubPBDesc = psStubPBDesc->psNext; + + for (i = 0; + i < psStubPBDesc->ui32SubKernelMemInfosCount; + i++) + PVRSRVFreeDeviceMemKM(psStubPBDesc-> + hDevCookie, + psStubPBDesc->ppsSubKernelMemInfos[i]); + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO *)* + psStubPBDesc-> + ui32SubKernelMemInfosCount, + psStubPBDesc->ppsSubKernelMemInfos, + NULL); + + PVRSRVFreeSharedSysMemoryKM(psStubPBDesc-> + psBlockKernelMemInfo); + + PVRSRVFreeDeviceMemKM(psStubPBDesc->hDevCookie, + psStubPBDesc-> + psHWPBDescKernelMemInfo); + + PVRSRVFreeSharedSysMemoryKM(psStubPBDesc-> + psSharedPBDescKernelMemInfo); + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_STUB_PBDESC), + psStubPBDesc, NULL); + + SGXCleanupRequest(psDeviceNode, NULL, + PVRSRV_USSE_EDM_RESMAN_CLEANUP_SHAREDPBDESC); + } + return PVRSRV_OK; + } + } + + return PVRSRV_ERROR_INVALID_PARAMS; +} + +static enum PVRSRV_ERROR SGXCleanupSharedPBDescCallback(void *pvParam, + u32 ui32Param) +{ + struct PVRSRV_STUB_PBDESC *psStubPBDesc = + (struct PVRSRV_STUB_PBDESC *)pvParam; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + return SGXCleanupSharedPBDescKM(psStubPBDesc); +} + +static enum PVRSRV_ERROR SGXCleanupSharedPBDescCreateLockCallback(void *pvParam, + u32 ui32Param) +{ +#ifdef CONFIG_PVR_DEBUG_EXTRA + struct PVRSRV_PER_PROCESS_DATA *psPerProc = + (struct PVRSRV_PER_PROCESS_DATA *)pvParam; + PVR_ASSERT(psPerProc == psPerProcCreateSharedPB); +#else + PVR_UNREFERENCED_PARAMETER(pvParam); +#endif + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + psPerProcCreateSharedPB = NULL; + psResItemCreateSharedPB = NULL; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXUnrefSharedPBDescKM(void *hSharedPBDesc) +{ + PVR_ASSERT(hSharedPBDesc != NULL); + + ResManFreeResByPtr(hSharedPBDesc); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXAddSharedPBDescKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevCookie, + struct PVRSRV_KERNEL_MEM_INFO *psSharedPBDescKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO *psHWPBDescKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO *psBlockKernelMemInfo, + u32 ui32TotalPBSize, void **phSharedPBDesc, + struct PVRSRV_KERNEL_MEM_INFO **ppsSharedPBDescSubKernelMemInfos, + u32 ui32SharedPBDescSubKernelMemInfosCount) +{ + struct PVRSRV_STUB_PBDESC *psStubPBDesc = NULL; + enum PVRSRV_ERROR eRet = PVRSRV_ERROR_GENERIC; + u32 i; + struct PVRSRV_SGXDEV_INFO *psSGXDevInfo; + struct RESMAN_ITEM *psResItem; + + if (psPerProcCreateSharedPB != psPerProc) { + goto NoAdd; + } else { + PVR_ASSERT(psResItemCreateSharedPB != NULL); + + ResManFreeResByPtr(psResItemCreateSharedPB); + + PVR_ASSERT(psResItemCreateSharedPB == NULL); + PVR_ASSERT(psPerProcCreateSharedPB == NULL); + } + + psSGXDevInfo = (struct PVRSRV_SGXDEV_INFO *) + ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice; + + psStubPBDesc = psSGXDevInfo->psStubPBDescListKM; + if (psStubPBDesc != NULL) { + if (psStubPBDesc->ui32TotalPBSize != ui32TotalPBSize) { + PVR_DPF(PVR_DBG_WARNING, "SGXAddSharedPBDescKM: " + "Shared PB requested with different size " + "(0x%x) from existing shared PB (0x%x) - " + "requested size ignored", + ui32TotalPBSize, + psStubPBDesc->ui32TotalPBSize); + + } + + psResItem = ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_SHARED_PB_DESC, + psStubPBDesc, 0, + &SGXCleanupSharedPBDescCallback); + if (psResItem == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "SGXAddSharedPBDescKM: " + "Failed to register existing shared " + "PBDesc with the resource manager"); + goto NoAddKeepPB; + } + + psStubPBDesc->ui32RefCount++; + + *phSharedPBDesc = (void *) psResItem; + eRet = PVRSRV_OK; + goto NoAddKeepPB; + } + + if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_STUB_PBDESC), + (void **)&psStubPBDesc, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXAddSharedPBDescKM: Failed to alloc " + "StubPBDesc"); + eRet = PVRSRV_ERROR_OUT_OF_MEMORY; + goto NoAdd; + } + + psStubPBDesc->ppsSubKernelMemInfos = NULL; + + if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO *) * + ui32SharedPBDescSubKernelMemInfosCount, + (void **)&psStubPBDesc->ppsSubKernelMemInfos, NULL) != + PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXAddSharedPBDescKM: " + "Failed to alloc " + "StubPBDesc->ppsSubKernelMemInfos"); + eRet = PVRSRV_ERROR_OUT_OF_MEMORY; + goto NoAdd; + } + + if (PVRSRVDissociateMemFromResmanKM(psSharedPBDescKernelMemInfo) + != PVRSRV_OK) + goto NoAdd; + + if (PVRSRVDissociateMemFromResmanKM(psHWPBDescKernelMemInfo) + != PVRSRV_OK) + goto NoAdd; + + if (PVRSRVDissociateMemFromResmanKM(psBlockKernelMemInfo) + != PVRSRV_OK) + goto NoAdd; + + psStubPBDesc->ui32RefCount = 1; + psStubPBDesc->ui32TotalPBSize = ui32TotalPBSize; + psStubPBDesc->psSharedPBDescKernelMemInfo = psSharedPBDescKernelMemInfo; + psStubPBDesc->psHWPBDescKernelMemInfo = psHWPBDescKernelMemInfo; + psStubPBDesc->psBlockKernelMemInfo = psBlockKernelMemInfo; + + psStubPBDesc->ui32SubKernelMemInfosCount = + ui32SharedPBDescSubKernelMemInfosCount; + for (i = 0; i < ui32SharedPBDescSubKernelMemInfosCount; i++) { + psStubPBDesc->ppsSubKernelMemInfos[i] = + ppsSharedPBDescSubKernelMemInfos[i]; + if (PVRSRVDissociateMemFromResmanKM + (ppsSharedPBDescSubKernelMemInfos[i]) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXAddSharedPBDescKM: " + "Failed to dissociate shared PBDesc " + "from process"); + goto NoAdd; + } + } + + psResItem = ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_SHARED_PB_DESC, + psStubPBDesc, + 0, &SGXCleanupSharedPBDescCallback); + if (psResItem == NULL) { + PVR_DPF(PVR_DBG_ERROR, "SGXAddSharedPBDescKM: " + "Failed to register shared PBDesc " + " with the resource manager"); + goto NoAdd; + } + psStubPBDesc->hDevCookie = hDevCookie; + + psStubPBDesc->psNext = psSGXDevInfo->psStubPBDescListKM; + psSGXDevInfo->psStubPBDescListKM = psStubPBDesc; + + *phSharedPBDesc = (void *) psResItem; + + return PVRSRV_OK; + +NoAdd: + if (psStubPBDesc) { + if (psStubPBDesc->ppsSubKernelMemInfos) { + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_KERNEL_MEM_INFO *) * + ui32SharedPBDescSubKernelMemInfosCount, + psStubPBDesc->ppsSubKernelMemInfos, NULL); + } + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_STUB_PBDESC), psStubPBDesc, + NULL); + } + +NoAddKeepPB: + for (i = 0; i < ui32SharedPBDescSubKernelMemInfosCount; i++) + PVRSRVFreeDeviceMemKM(hDevCookie, + ppsSharedPBDescSubKernelMemInfos[i]); + + PVRSRVFreeSharedSysMemoryKM(psSharedPBDescKernelMemInfo); + PVRSRVFreeDeviceMemKM(hDevCookie, psHWPBDescKernelMemInfo); + + PVRSRVFreeSharedSysMemoryKM(psBlockKernelMemInfo); + + return eRet; +} diff --git a/drivers/gpu/pvr/pdump.c b/drivers/gpu/pvr/pdump.c new file mode 100644 index 00000000000..0dec52f187f --- /dev/null +++ b/drivers/gpu/pvr/pdump.c @@ -0,0 +1,1271 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if defined(PDUMP) +#include <asm/atomic.h> +#include <stdarg.h> +#include "sgxdefs.h" +#include "services_headers.h" + +#include "pvrversion.h" +#include "pvr_debug.h" + +#include "dbgdrvif.h" +#include "sgxmmu.h" +#include "mm.h" +#include "pdump_km.h" + +#include <linux/tty.h> + +static IMG_BOOL PDumpWriteString2(char *pszString, u32 ui32Flags); +static IMG_BOOL PDumpWriteILock(struct DBG_STREAM *psStream, u8 *pui8Data, + u32 ui32Count, u32 ui32Flags); +static void DbgSetFrame(struct DBG_STREAM *psStream, u32 ui32Frame); +static u32 DbgGetFrame(struct DBG_STREAM *psStream); +static void DbgSetMarker(struct DBG_STREAM *psStream, u32 ui32Marker); +static u32 DbgWrite(struct DBG_STREAM *psStream, u8 *pui8Data, + u32 ui32BCount, u32 ui32Flags); + +#define PDUMP_DATAMASTER_PIXEL 1 + +#define MIN(a, b) (a > b ? b : a) + +#define MAX_FILE_SIZE 0x40000000 + +static atomic_t gsPDumpSuspended = ATOMIC_INIT(0); + +static struct DBGKM_SERVICE_TABLE *gpfnDbgDrv; + +#define PDUMP_STREAM_PARAM2 0 +#define PDUMP_STREAM_SCRIPT2 1 +#define PDUMP_STREAM_DRIVERINFO 2 +#define PDUMP_NUM_STREAMS 3 + +static char *pszStreamName[PDUMP_NUM_STREAMS] = { "ParamStream2", + "ScriptStream2", + "DriverInfoStream" +}; + +#define __PDBG_PDUMP_STATE_GET_MSG_STRING(ERROR) \ + char *pszMsg = gsDBGPdumpState.pszMsg; \ + if ((!pszMsg) || PDumpSuspended()) \ + return ERROR + +#define __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(ERROR) \ + char *pszScript = gsDBGPdumpState.pszScript; \ + if ((!pszScript) || PDumpSuspended()) \ + return ERROR + +#define __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(ERROR) \ + char *pszScript = gsDBGPdumpState.pszScript; \ + char *pszFile = gsDBGPdumpState.pszFile; \ + if ((!pszScript) || (!pszFile) || PDumpSuspended()) \ + return ERROR + +struct PDBG_PDUMP_STATE { + struct DBG_STREAM *psStream[PDUMP_NUM_STREAMS]; + u32 ui32ParamFileNum; + + char *pszMsg; + char *pszScript; + char *pszFile; + +}; + +static struct PDBG_PDUMP_STATE gsDBGPdumpState = { + {NULL}, 0, NULL, NULL, NULL +}; + +#define SZ_MSG_SIZE_MAX (PVRSRV_PDUMP_MAX_COMMENT_SIZE - 1) +#define SZ_SCRIPT_SIZE_MAX (PVRSRV_PDUMP_MAX_COMMENT_SIZE - 1) +#define SZ_FILENAME_SIZE_MAX (PVRSRV_PDUMP_MAX_COMMENT_SIZE - 1) + +static inline IMG_BOOL PDumpSuspended(void) +{ + return atomic_read(&gsPDumpSuspended) != 0; +} + +void PDumpInit(void) +{ + u32 i = 0; + + if (!gpfnDbgDrv) { + DBGDrvGetServiceTable((void **) &gpfnDbgDrv); + + if (gpfnDbgDrv == NULL) + return; + + if (!gsDBGPdumpState.pszFile) + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + SZ_FILENAME_SIZE_MAX, + (void **)&gsDBGPdumpState.pszFile, + NULL) != PVRSRV_OK) + goto init_failed; + + if (!gsDBGPdumpState.pszMsg) + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + SZ_MSG_SIZE_MAX, + (void **)&gsDBGPdumpState.pszMsg, + NULL) != PVRSRV_OK) + goto init_failed; + + if (!gsDBGPdumpState.pszScript) + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + SZ_SCRIPT_SIZE_MAX, + (void **)&gsDBGPdumpState.pszScript, + NULL) != PVRSRV_OK) + goto init_failed; + + for (i = 0; i < PDUMP_NUM_STREAMS; i++) { + gsDBGPdumpState.psStream[i] = + gpfnDbgDrv->pfnCreateStream(pszStreamName[i], + DEBUG_CAPMODE_FRAMED, + DEBUG_OUTMODE_STREAMENABLE, + 0, 10); + + gpfnDbgDrv->pfnSetCaptureMode(gsDBGPdumpState. + psStream[i], + DEBUG_CAPMODE_FRAMED, + 0xFFFFFFFF, 0xFFFFFFFF, + 1); + gpfnDbgDrv->pfnSetFrame(gsDBGPdumpState.psStream[i], 0); + } + + PDUMPCOMMENT("Driver Product Name: %s", VS_PRODUCT_NAME); + PDUMPCOMMENT("Driver Product Version: %s (%s)", + PVRVERSION_STRING, PVRVERSION_FILE); + PDUMPCOMMENT("Start of Init Phase"); + } + + return; + +init_failed: + + if (gsDBGPdumpState.pszFile) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_FILENAME_SIZE_MAX, + (void *)gsDBGPdumpState.pszFile, NULL); + gsDBGPdumpState.pszFile = NULL; + } + + if (gsDBGPdumpState.pszScript) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_SCRIPT_SIZE_MAX, + (void *)gsDBGPdumpState.pszScript, NULL); + gsDBGPdumpState.pszScript = NULL; + } + + if (gsDBGPdumpState.pszMsg) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_MSG_SIZE_MAX, + (void *)gsDBGPdumpState.pszMsg, NULL); + gsDBGPdumpState.pszMsg = NULL; + } + + gpfnDbgDrv = NULL; +} + +void PDumpDeInit(void) +{ + u32 i = 0; + + for (i = 0; i < PDUMP_NUM_STREAMS; i++) + gpfnDbgDrv->pfnDestroyStream(gsDBGPdumpState.psStream[i]); + + if (gsDBGPdumpState.pszFile) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_FILENAME_SIZE_MAX, + (void *)gsDBGPdumpState.pszFile, NULL); + gsDBGPdumpState.pszFile = NULL; + } + + if (gsDBGPdumpState.pszScript) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_SCRIPT_SIZE_MAX, + (void *)gsDBGPdumpState.pszScript, NULL); + gsDBGPdumpState.pszScript = NULL; + } + + if (gsDBGPdumpState.pszMsg) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, SZ_MSG_SIZE_MAX, + (void *)gsDBGPdumpState.pszMsg, NULL); + gsDBGPdumpState.pszMsg = NULL; + } + + gpfnDbgDrv = NULL; +} + +enum PVRSRV_ERROR PDumpStartInitPhaseKM(void) +{ + u32 i; + + if (gpfnDbgDrv) { + PDUMPCOMMENT("Start Init Phase"); + for (i = 0; i < PDUMP_NUM_STREAMS; i++) + gpfnDbgDrv->pfnStartInitPhase(gsDBGPdumpState. + psStream[i]); + } + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpStopInitPhaseKM(void) +{ + u32 i; + + if (gpfnDbgDrv) { + PDUMPCOMMENT("Stop Init Phase"); + + for (i = 0; i < PDUMP_NUM_STREAMS; i++) + gpfnDbgDrv->pfnStopInitPhase(gsDBGPdumpState. + psStream[i]); + } + return PVRSRV_OK; +} + +void PDumpComment(char *pszFormat, ...) +{ + va_list ap; + + __PDBG_PDUMP_STATE_GET_MSG_STRING(); + + va_start(ap, pszFormat); + vsnprintf(pszMsg, SZ_MSG_SIZE_MAX, pszFormat, ap); + va_end(ap); + + PDumpCommentKM(pszMsg, PDUMP_FLAGS_CONTINUOUS); +} + +void PDumpCommentWithFlags(u32 ui32Flags, char *pszFormat, ...) +{ + va_list ap; + + __PDBG_PDUMP_STATE_GET_MSG_STRING(); + + va_start(ap, pszFormat); + vsnprintf(pszMsg, SZ_MSG_SIZE_MAX, pszFormat, ap); + va_end(ap); + + PDumpCommentKM(pszMsg, ui32Flags); +} + +IMG_BOOL PDumpIsLastCaptureFrameKM(void) +{ + return gpfnDbgDrv->pfnIsLastCaptureFrame( + gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2]); +} + +IMG_BOOL PDumpIsCaptureFrameKM(void) +{ + if (PDumpSuspended()) + return IMG_FALSE; + return gpfnDbgDrv->pfnIsCaptureFrame(gsDBGPdumpState. + psStream[PDUMP_STREAM_SCRIPT2], + IMG_FALSE); +} + +enum PVRSRV_ERROR PDumpRegWithFlagsKM(u32 ui32Reg, u32 ui32Data, u32 ui32Flags) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(PVRSRV_ERROR_GENERIC); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "WRW :SGXREG:0x%8.8X 0x%8.8X\r\n", ui32Reg, ui32Data); + PDumpWriteString2(pszScript, ui32Flags); + + return PVRSRV_OK; +} + +void PDumpReg(u32 ui32Reg, u32 ui32Data) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "WRW :SGXREG:0x%8.8X 0x%8.8X\r\n", ui32Reg, ui32Data); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); +} + +enum PVRSRV_ERROR PDumpRegPolWithFlagsKM(u32 ui32RegAddr, u32 ui32RegValue, + u32 ui32Mask, u32 ui32Flags) +{ +#define POLL_DELAY 1000 +#define POLL_COUNT_LONG (2000000000 / POLL_DELAY) +#define POLL_COUNT_SHORT (1000000 / POLL_DELAY) + + u32 ui32PollCount; + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(PVRSRV_ERROR_GENERIC); + + if (((ui32RegAddr == EUR_CR_EVENT_STATUS) && + (ui32RegValue & ui32Mask & + EUR_CR_EVENT_STATUS_TA_FINISHED_MASK)) || + ((ui32RegAddr == EUR_CR_EVENT_STATUS) && + (ui32RegValue & ui32Mask & + EUR_CR_EVENT_STATUS_PIXELBE_END_RENDER_MASK)) || + ((ui32RegAddr == EUR_CR_EVENT_STATUS) && + (ui32RegValue & ui32Mask & + EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_MASK))) + ui32PollCount = POLL_COUNT_LONG; + else + ui32PollCount = POLL_COUNT_SHORT; + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "POL :SGXREG:0x%8.8X 0x%8.8X 0x%8.8X %d %u %d\r\n", + ui32RegAddr, ui32RegValue, ui32Mask, 0, ui32PollCount, + POLL_DELAY); + PDumpWriteString2(pszScript, ui32Flags); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpRegPolKM(u32 ui32RegAddr, u32 ui32RegValue, u32 ui32Mask) +{ + return PDumpRegPolWithFlagsKM(ui32RegAddr, ui32RegValue, ui32Mask, + PDUMP_FLAGS_CONTINUOUS); +} + +void PDumpMallocPages(enum PVRSRV_DEVICE_TYPE eDeviceType, u32 ui32DevVAddr, + void *pvLinAddr, void *hOSMemHandle, u32 ui32NumBytes, + u32 ui32PageSize, void *hUniqueTag) +{ + u32 ui32Offset; + u32 ui32NumPages; + struct IMG_CPU_PHYADDR sCpuPAddr; + struct IMG_DEV_PHYADDR sDevPAddr; + u32 ui32Page; + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + PVR_UNREFERENCED_PARAMETER(pvLinAddr); + + PVR_ASSERT(((u32) ui32DevVAddr & (ui32PageSize - 1)) == 0); + PVR_ASSERT(hOSMemHandle); + PVR_ASSERT(((u32) ui32NumBytes & (ui32PageSize - 1)) == 0); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "-- MALLOC :SGXMEM:VA_%8.8X 0x%8.8X %u\r\n", ui32DevVAddr, + ui32NumBytes, ui32PageSize); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + + ui32Offset = 0; + ui32NumPages = ui32NumBytes / ui32PageSize; + while (ui32NumPages--) { + sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); + PVR_ASSERT((sCpuPAddr.uiAddr & (ui32PageSize - 1)) == 0); + ui32Offset += ui32PageSize; + sDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); + ui32Page = sDevPAddr.uiAddr / ui32PageSize; + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "MALLOC :SGXMEM:PA_%8.8X%8.8X %u %u 0x%8.8X\r\n", + (u32)hUniqueTag, ui32Page * ui32PageSize, + ui32PageSize, ui32PageSize, ui32Page * ui32PageSize); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + } +} + +void PDumpMallocPageTable(enum PVRSRV_DEVICE_TYPE eDeviceType, + void *pvLinAddr, u32 ui32PTSize, void *hUniqueTag) +{ + u8 *pui8LinAddr; + u32 ui32NumPages; + struct IMG_CPU_PHYADDR sCpuPAddr; + struct IMG_DEV_PHYADDR sDevPAddr; + u32 ui32Page; + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + PVR_ASSERT(((u32) pvLinAddr & (ui32PTSize - 1)) == 0); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "-- MALLOC :SGXMEM:PAGE_TABLE 0x%8.8X %lu\r\n", ui32PTSize, + SGX_MMU_PAGE_SIZE); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + + pui8LinAddr = (u8 *) pvLinAddr; + + ui32NumPages = 1; + + while (ui32NumPages--) { + sCpuPAddr = OSMapLinToCPUPhys(pui8LinAddr); + sDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); + ui32Page = sDevPAddr.uiAddr >> SGX_MMU_PAGE_SHIFT; + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "MALLOC :SGXMEM:PA_%8.8X%8.8lX 0x%lX %lu 0x%8.8lX\r\n", + (u32)hUniqueTag, ui32Page * SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE, SGX_MMU_PAGE_SIZE, + ui32Page * SGX_MMU_PAGE_SIZE); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + pui8LinAddr += SGX_MMU_PAGE_SIZE; + } +} + +void PDumpFreePages(struct BM_HEAP *psBMHeap, struct IMG_DEV_VIRTADDR sDevVAddr, + u32 ui32NumBytes, u32 ui32PageSize, void *hUniqueTag, + IMG_BOOL bInterleaved) +{ + u32 ui32NumPages, ui32PageCounter; + struct IMG_DEV_PHYADDR sDevPAddr; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + PVR_ASSERT(((u32) sDevVAddr.uiAddr & (ui32PageSize - 1)) == 0); + PVR_ASSERT(((u32) ui32NumBytes & (ui32PageSize - 1)) == 0); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "-- FREE :SGXMEM:VA_%8.8X\r\n", + sDevVAddr.uiAddr); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + + ui32NumPages = ui32NumBytes / ui32PageSize; + psDeviceNode = psBMHeap->pBMContext->psDeviceNode; + for (ui32PageCounter = 0; ui32PageCounter < ui32NumPages; + ui32PageCounter++) { + if (!bInterleaved || (ui32PageCounter % 2) == 0) { + sDevPAddr = + psDeviceNode->pfnMMUGetPhysPageAddr(psBMHeap-> + pMMUHeap, + sDevVAddr); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "FREE :SGXMEM:PA_%8.8X%8.8X\r\n", + (u32)hUniqueTag, sDevPAddr.uiAddr); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + } else { + + } + + sDevVAddr.uiAddr += ui32PageSize; + } +} + +void PDumpFreePageTable(enum PVRSRV_DEVICE_TYPE eDeviceType, + void *pvLinAddr, u32 ui32PTSize, void *hUniqueTag) +{ + u8 *pui8LinAddr; + u32 ui32NumPages; + struct IMG_CPU_PHYADDR sCpuPAddr; + struct IMG_DEV_PHYADDR sDevPAddr; + u32 ui32Page; + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + PVR_ASSERT(((u32) pvLinAddr & (ui32PTSize - 1)) == 0); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "-- FREE :SGXMEM:PAGE_TABLE\r\n"); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + + pui8LinAddr = (u8 *) pvLinAddr; + + ui32NumPages = 1; + + while (ui32NumPages--) { + sCpuPAddr = OSMapLinToCPUPhys(pui8LinAddr); + sDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); + ui32Page = sDevPAddr.uiAddr >> SGX_MMU_PAGE_SHIFT; + pui8LinAddr += SGX_MMU_PAGE_SIZE; + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "FREE :SGXMEM:PA_%8.8X%8.8lX\r\n", (u32)hUniqueTag, + ui32Page * SGX_MMU_PAGE_SIZE); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + } +} + +void PDumpPDReg(u32 ui32Reg, u32 ui32Data, void *hUniqueTag) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, + "WRW :SGXREG:0x%8.8X :SGXMEM:PA_%8.8X%8.8lX:0x%8.8lX\r\n", + ui32Reg, (u32)hUniqueTag, ui32Data & ~(SGX_MMU_PAGE_SIZE - 1), + ui32Data & (SGX_MMU_PAGE_SIZE - 1)); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); +} + +void PDumpPDRegWithFlags(u32 ui32Reg, u32 ui32Data, u32 ui32Flags, + void *hUniqueTag) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, + "WRW :SGXREG:0x%8.8X :SGXMEM:PA_%8.8X%8.8lX:0x%8.8lX\r\n", + ui32Reg, (u32) hUniqueTag, ui32Data & ~(SGX_MMU_PAGE_SIZE - 1), + ui32Data & (SGX_MMU_PAGE_SIZE - 1)); + PDumpWriteString2(pszScript, ui32Flags); +} + +enum PVRSRV_ERROR PDumpMemPolKM(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, + u32 ui32Offset, u32 ui32Value, u32 ui32Mask, + enum PDUMP_POLL_OPERATOR eOperator, + IMG_BOOL bLastFrame, IMG_BOOL bOverwrite, + void *hUniqueTag) +{ +#define MEMPOLL_DELAY (1000) +#define MEMPOLL_COUNT (2000000000 / MEMPOLL_DELAY) + + u32 ui32PageOffset; + struct IMG_DEV_PHYADDR sDevPAddr; + struct IMG_DEV_VIRTADDR sDevVPageAddr; + struct IMG_CPU_PHYADDR CpuPAddr; + u32 ui32Flags; + __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(PVRSRV_ERROR_GENERIC); + + PVR_ASSERT((ui32Offset + sizeof(u32)) <= + psMemInfo->ui32AllocSize); + + if (gsDBGPdumpState.ui32ParamFileNum == 0) + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%.prm"); + else + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%%u.prm", + gsDBGPdumpState.ui32ParamFileNum); + + ui32Flags = 0; + + if (bLastFrame) + ui32Flags |= PDUMP_FLAGS_LASTFRAME; + + if (bOverwrite) + ui32Flags |= PDUMP_FLAGS_RESETLFBUFFER; + + CpuPAddr = + OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset); + ui32PageOffset = CpuPAddr.uiAddr & (PAGE_SIZE - 1); + + sDevVPageAddr.uiAddr = + psMemInfo->sDevVAddr.uiAddr + ui32Offset - ui32PageOffset; + + BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); + + sDevPAddr.uiAddr += ui32PageOffset; + + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, "POL :SGXMEM:" + "PA_%8.8X%8.8lX:0x%8.8lX 0x%8.8X 0x%8.8X %d %d %d\r\n", + (u32)hUniqueTag, sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), + sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), + ui32Value, ui32Mask, eOperator, MEMPOLL_COUNT, MEMPOLL_DELAY); + PDumpWriteString2(pszScript, ui32Flags); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpMemKM(void *pvAltLinAddr, + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, + u32 ui32Offset, u32 ui32Bytes, u32 ui32Flags, + void *hUniqueTag) +{ + u32 ui32PageByteOffset; + u8 *pui8DataLinAddr = NULL; + struct IMG_DEV_VIRTADDR sDevVPageAddr; + struct IMG_DEV_VIRTADDR sDevVAddr; + struct IMG_DEV_PHYADDR sDevPAddr; + struct IMG_CPU_PHYADDR CpuPAddr; + u32 ui32ParamOutPos; + u32 ui32CurrentOffset; + u32 ui32BytesRemaining; + + __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(PVRSRV_ERROR_GENERIC); + + PVR_ASSERT((ui32Offset + ui32Bytes) <= psMemInfo->ui32AllocSize); + + if (ui32Bytes == 0) + return PVRSRV_OK; + + if (pvAltLinAddr) { + pui8DataLinAddr = pvAltLinAddr; + } else { + if (psMemInfo->pvLinAddrKM) + pui8DataLinAddr = + (u8 *) psMemInfo->pvLinAddrKM + ui32Offset; + + } + + PVR_ASSERT(pui8DataLinAddr); + + ui32ParamOutPos = + gpfnDbgDrv->pfnGetStreamOffset(gsDBGPdumpState. + psStream[PDUMP_STREAM_PARAM2]); + + if (!PDumpWriteILock(gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2], + pui8DataLinAddr, ui32Bytes, ui32Flags)) + return PVRSRV_ERROR_GENERIC; + + if (gsDBGPdumpState.ui32ParamFileNum == 0) { + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%.prm"); + } else { + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%%u.prm", + gsDBGPdumpState.ui32ParamFileNum); + } + + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, + "-- LDB :SGXMEM:VA_%8.8X:0x%8.8X 0x%8.8X 0x%8.8X %s\r\n", + psMemInfo->sDevVAddr.uiAddr, + ui32Offset, ui32Bytes, ui32ParamOutPos, pszFile); + PDumpWriteString2(pszScript, ui32Flags); + + CpuPAddr = + OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset); + ui32PageByteOffset = CpuPAddr.uiAddr & (PAGE_SIZE - 1); + + sDevVAddr = psMemInfo->sDevVAddr; + sDevVAddr.uiAddr += ui32Offset; + + ui32BytesRemaining = ui32Bytes; + ui32CurrentOffset = ui32Offset; + + while (ui32BytesRemaining > 0) { + u32 ui32BlockBytes = MIN(ui32BytesRemaining, PAGE_SIZE); + CpuPAddr = + OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, + ui32CurrentOffset); + + sDevVPageAddr.uiAddr = + psMemInfo->sDevVAddr.uiAddr + ui32CurrentOffset - + ui32PageByteOffset; + + BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); + + sDevPAddr.uiAddr += ui32PageByteOffset; + + if (ui32PageByteOffset) { + ui32BlockBytes = + MIN(ui32BytesRemaining, + PAGE_ALIGN(CpuPAddr.uiAddr) - CpuPAddr.uiAddr); + + ui32PageByteOffset = 0; + } + + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, "LDB :SGXMEM:" + "PA_%8.8X%8.8lX:0x%8.8lX 0x%8.8X 0x%8.8X %s\r\n", + (u32) hUniqueTag, + sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), + sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), + ui32BlockBytes, ui32ParamOutPos, pszFile); + PDumpWriteString2(pszScript, ui32Flags); + + ui32BytesRemaining -= ui32BlockBytes; + ui32CurrentOffset += ui32BlockBytes; + ui32ParamOutPos += ui32BlockBytes; + } + PVR_ASSERT(ui32BytesRemaining == 0); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpMem2KM(enum PVRSRV_DEVICE_TYPE eDeviceType, + void *pvLinAddr, u32 ui32Bytes, u32 ui32Flags, + IMG_BOOL bInitialisePages, void *hUniqueTag1, + void *hUniqueTag2) +{ + u32 ui32NumPages; + u32 ui32PageOffset; + u32 ui32BlockBytes; + u8 *pui8LinAddr; + struct IMG_DEV_PHYADDR sDevPAddr; + struct IMG_CPU_PHYADDR sCpuPAddr; + u32 ui32Offset; + u32 ui32ParamOutPos; + + __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(PVRSRV_ERROR_GENERIC); + + if (ui32Flags) + ; + + if (!pvLinAddr) + return PVRSRV_ERROR_GENERIC; + + ui32ParamOutPos = + gpfnDbgDrv->pfnGetStreamOffset(gsDBGPdumpState. + psStream[PDUMP_STREAM_PARAM2]); + + if (bInitialisePages) { + + if (!PDumpWriteILock + (gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2], pvLinAddr, + ui32Bytes, PDUMP_FLAGS_CONTINUOUS)) + return PVRSRV_ERROR_GENERIC; + + if (gsDBGPdumpState.ui32ParamFileNum == 0) + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%.prm"); + else + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%%u.prm", + gsDBGPdumpState.ui32ParamFileNum); + } + + ui32PageOffset = (u32) pvLinAddr & (HOST_PAGESIZE() - 1); + ui32NumPages = + (ui32PageOffset + ui32Bytes + HOST_PAGESIZE() - 1) / + HOST_PAGESIZE(); + pui8LinAddr = (u8 *) pvLinAddr; + + while (ui32NumPages--) { + sCpuPAddr = OSMapLinToCPUPhys(pui8LinAddr); + sDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); + + if (ui32PageOffset + ui32Bytes > HOST_PAGESIZE()) + ui32BlockBytes = HOST_PAGESIZE() - ui32PageOffset; + else + ui32BlockBytes = ui32Bytes; + + if (bInitialisePages) { + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, "LDB :SGXMEM:" + "PA_%8.8X%8.8lX:0x%8.8lX 0x%8.8X " + "0x%8.8X %s\r\n", + (u32) hUniqueTag1, + sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), + sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), + ui32BlockBytes, ui32ParamOutPos, pszFile); + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + } else { + for (ui32Offset = 0; ui32Offset < ui32BlockBytes; + ui32Offset += sizeof(u32)) { + u32 ui32PTE = + *((u32 *) (pui8LinAddr + + ui32Offset)); + + if ((ui32PTE & SGX_MMU_PDE_ADDR_MASK) != 0) { + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, +"WRW :SGXMEM:PA_%8.8X%8.8lX:0x%8.8lX :SGXMEM:PA_%8.8X%8.8lX:0x%8.8lX\r\n", + (u32)hUniqueTag1, + (sDevPAddr.uiAddr + + ui32Offset) & + ~(SGX_MMU_PAGE_SIZE - 1), + (sDevPAddr.uiAddr + + ui32Offset) & + (SGX_MMU_PAGE_SIZE - 1), + (u32)hUniqueTag2, + ui32PTE & + SGX_MMU_PDE_ADDR_MASK, + ui32PTE & + ~SGX_MMU_PDE_ADDR_MASK); + } else { + PVR_ASSERT(! + (ui32PTE & + SGX_MMU_PTE_VALID)); + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "WRW :SGXMEM:PA_%8.8X%8.8lX:0x%8.8lX 0x%8.8X%8.8X\r\n", + (u32) hUniqueTag1, + (sDevPAddr.uiAddr + + ui32Offset) & + ~(SGX_MMU_PAGE_SIZE - 1), + (sDevPAddr.uiAddr + + ui32Offset) & + (SGX_MMU_PAGE_SIZE - 1), + ui32PTE, (u32)hUniqueTag2); + } + PDumpWriteString2(pszScript, + PDUMP_FLAGS_CONTINUOUS); + } + } + + ui32PageOffset = 0; + ui32Bytes -= ui32BlockBytes; + pui8LinAddr += ui32BlockBytes; + ui32ParamOutPos += ui32BlockBytes; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpPDDevPAddrKM(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, + u32 ui32Offset, + struct IMG_DEV_PHYADDR sPDDevPAddr, + void *hUniqueTag1, void *hUniqueTag2) +{ + u32 ui32ParamOutPos; + struct IMG_CPU_PHYADDR CpuPAddr; + u32 ui32PageByteOffset; + struct IMG_DEV_VIRTADDR sDevVAddr; + struct IMG_DEV_VIRTADDR sDevVPageAddr; + struct IMG_DEV_PHYADDR sDevPAddr; + + __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(PVRSRV_ERROR_GENERIC); + + ui32ParamOutPos = + gpfnDbgDrv->pfnGetStreamOffset(gsDBGPdumpState. + psStream[PDUMP_STREAM_PARAM2]); + + if (!PDumpWriteILock(gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2], + (u8 *)&sPDDevPAddr, sizeof(struct IMG_DEV_PHYADDR), + PDUMP_FLAGS_CONTINUOUS)) + return PVRSRV_ERROR_GENERIC; + + if (gsDBGPdumpState.ui32ParamFileNum == 0) + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%.prm"); + else + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "%%0%%%u.prm", + gsDBGPdumpState.ui32ParamFileNum); + + CpuPAddr = + OSMemHandleToCpuPAddr(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset); + ui32PageByteOffset = CpuPAddr.uiAddr & (PAGE_SIZE - 1); + + sDevVAddr = psMemInfo->sDevVAddr; + sDevVAddr.uiAddr += ui32Offset; + + sDevVPageAddr.uiAddr = sDevVAddr.uiAddr - ui32PageByteOffset; + BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); + sDevPAddr.uiAddr += ui32PageByteOffset; + + if ((sPDDevPAddr.uiAddr & SGX_MMU_PDE_ADDR_MASK) != 0) { + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, +"WRW :SGXMEM:PA_%8.8X%8.8lX:0x%8.8lX :SGXMEM:PA_%8.8X%8.8lX:0x%8.8lX\r\n", + (u32) hUniqueTag1, + sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), + sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), + (u32)hUniqueTag2, + sPDDevPAddr.uiAddr & SGX_MMU_PDE_ADDR_MASK, + sPDDevPAddr.uiAddr & ~SGX_MMU_PDE_ADDR_MASK); + } else { + PVR_ASSERT(!(sDevPAddr.uiAddr & SGX_MMU_PTE_VALID)); + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, + "WRW :SGXMEM:PA_%8.8X%8.8lX:0x%8.8lX 0x%8.8X\r\n", + (u32)hUniqueTag1, + sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), + sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), + sPDDevPAddr.uiAddr); + } + PDumpWriteString2(pszScript, PDUMP_FLAGS_CONTINUOUS); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpSetFrameKM(u32 ui32Frame) +{ + u32 ui32Stream; + + for (ui32Stream = 0; ui32Stream < PDUMP_NUM_STREAMS; ui32Stream++) + if (gsDBGPdumpState.psStream[ui32Stream]) + DbgSetFrame(gsDBGPdumpState.psStream[ui32Stream], + ui32Frame); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR PDumpGetFrameKM(u32 *pui32Frame) +{ + *pui32Frame = + DbgGetFrame(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2]); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpCommentKM(char *pszComment, u32 ui32Flags) +{ + u32 ui32Count = 0; + enum PVRSRV_ERROR eError; + __PDBG_PDUMP_STATE_GET_MSG_STRING(PVRSRV_ERROR_GENERIC); + + if (ui32Flags & PDUMP_FLAGS_CONTINUOUS) + eError = PVRSRV_ERROR_GENERIC; + else + eError = PVRSRV_ERROR_CMD_NOT_PROCESSED; + + if (!PDumpWriteString2("-- ", ui32Flags)) + return eError; + + snprintf(pszMsg, SZ_MSG_SIZE_MAX, "%s", pszComment); + + while ((pszMsg[ui32Count] != 0) && (ui32Count < SZ_MSG_SIZE_MAX)) + ui32Count++; + + if ((pszMsg[ui32Count - 1] != '\n') && (ui32Count < SZ_MSG_SIZE_MAX)) { + pszMsg[ui32Count] = '\n'; + ui32Count++; + pszMsg[ui32Count] = '\0'; + } + if ((pszMsg[ui32Count - 2] != '\r') && (ui32Count < SZ_MSG_SIZE_MAX)) { + pszMsg[ui32Count - 1] = '\r'; + pszMsg[ui32Count] = '\n'; + ui32Count++; + pszMsg[ui32Count] = '\0'; + } + + PDumpWriteString2(pszMsg, ui32Flags); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpDriverInfoKM(char *pszString, u32 ui32Flags) +{ + u32 ui32Count = 0; + __PDBG_PDUMP_STATE_GET_MSG_STRING(PVRSRV_ERROR_GENERIC); + + snprintf(pszMsg, SZ_MSG_SIZE_MAX, "%s", pszString); + + while ((pszMsg[ui32Count] != 0) && (ui32Count < SZ_MSG_SIZE_MAX)) + ui32Count++; + + if ((pszMsg[ui32Count - 1] != '\n') && (ui32Count < SZ_MSG_SIZE_MAX)) { + pszMsg[ui32Count] = '\n'; + ui32Count++; + pszMsg[ui32Count] = '\0'; + } + if ((pszMsg[ui32Count - 2] != '\r') && (ui32Count < SZ_MSG_SIZE_MAX)) { + pszMsg[ui32Count - 1] = '\r'; + pszMsg[ui32Count] = '\n'; + ui32Count++; + pszMsg[ui32Count] = '\0'; + } + + if (!PDumpWriteILock(gsDBGPdumpState.psStream[PDUMP_STREAM_DRIVERINFO], + (u8 *) pszMsg, ui32Count, ui32Flags)) { + if (ui32Flags & PDUMP_FLAGS_CONTINUOUS) + return PVRSRV_ERROR_GENERIC; + else + return PVRSRV_ERROR_CMD_NOT_PROCESSED; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpBitmapKM(char *pszFileName, u32 ui32FileOffset, + u32 ui32Width, u32 ui32Height, u32 ui32StrideInBytes, + struct IMG_DEV_VIRTADDR sDevBaseAddr, + u32 ui32Size, enum PDUMP_PIXEL_FORMAT ePixelFormat, + enum PDUMP_MEM_FORMAT eMemFormat, u32 ui32PDumpFlags) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(PVRSRV_ERROR_GENERIC); + PDUMPCOMMENTWITHFLAGS(ui32PDumpFlags, + "\r\n-- Dump bitmap of render\r\n"); + + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, + "SII %s %s.bin :SGXMEM:v:0x%08X 0x%08X " + "0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\r\n", + pszFileName, pszFileName, sDevBaseAddr.uiAddr, ui32Size, + ui32FileOffset, ePixelFormat, ui32Width, ui32Height, + ui32StrideInBytes, eMemFormat); + + PDumpWriteString2(pszScript, ui32PDumpFlags); + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpReadRegKM(char *pszFileName, u32 ui32FileOffset, + u32 ui32Address, u32 ui32Size, u32 ui32PDumpFlags) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(PVRSRV_ERROR_GENERIC); + + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, + "SAB :SGXREG:0x%08X 0x%08X %s\r\n", + ui32Address, ui32FileOffset, pszFileName); + + PDumpWriteString2(pszScript, ui32PDumpFlags); + + return PVRSRV_OK; +} + +static IMG_BOOL PDumpWriteString2(char *pszString, u32 ui32Flags) +{ + return PDumpWriteILock(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2], + (u8 *)pszString, strlen(pszString), ui32Flags); +} + +static IMG_BOOL PDumpWriteILock(struct DBG_STREAM *psStream, u8 *pui8Data, + u32 ui32Count, u32 ui32Flags) +{ + u32 ui32Written = 0; + u32 ui32Off = 0; + + if (!psStream || PDumpSuspended() || (ui32Flags & PDUMP_FLAGS_NEVER)) + return IMG_TRUE; + + if (psStream == gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2]) { + u32 ui32ParamOutPos = + gpfnDbgDrv->pfnGetStreamOffset(gsDBGPdumpState. + psStream + [PDUMP_STREAM_PARAM2]); + + if (ui32ParamOutPos + ui32Count > MAX_FILE_SIZE) + if ((gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2] + && + PDumpWriteString2 + ("\r\n-- Splitting pdump output file\r\n\r\n", + ui32Flags))) { + DbgSetMarker(gsDBGPdumpState. + psStream[PDUMP_STREAM_PARAM2], + ui32ParamOutPos); + gsDBGPdumpState.ui32ParamFileNum++; + } + } + + while (((u32) ui32Count > 0) && (ui32Written != 0xFFFFFFFF)) { + ui32Written = + DbgWrite(psStream, &pui8Data[ui32Off], ui32Count, + ui32Flags); + + if (ui32Written == 0) + OSReleaseThreadQuanta(); + + if (ui32Written != 0xFFFFFFFF) { + ui32Off += ui32Written; + ui32Count -= ui32Written; + } + } + + if (ui32Written == 0xFFFFFFFF) + return IMG_FALSE; + + return IMG_TRUE; +} + +static void DbgSetFrame(struct DBG_STREAM *psStream, u32 ui32Frame) +{ + gpfnDbgDrv->pfnSetFrame(psStream, ui32Frame); +} + +static u32 DbgGetFrame(struct DBG_STREAM *psStream) +{ + return gpfnDbgDrv->pfnGetFrame(psStream); +} + +static void DbgSetMarker(struct DBG_STREAM *psStream, u32 ui32Marker) +{ + gpfnDbgDrv->pfnSetMarker(psStream, ui32Marker); +} + +static u32 DbgWrite(struct DBG_STREAM *psStream, u8 *pui8Data, + u32 ui32BCount, u32 ui32Flags) +{ + u32 ui32BytesWritten; + + if (ui32Flags & PDUMP_FLAGS_CONTINUOUS) { + if ((psStream->ui32CapMode & DEBUG_CAPMODE_FRAMED) && + (psStream->ui32Start == 0xFFFFFFFF) && + (psStream->ui32End == 0xFFFFFFFF) && + psStream->bInitPhaseComplete) + ui32BytesWritten = ui32BCount; + else + ui32BytesWritten = + gpfnDbgDrv->pfnDBGDrivWrite2(psStream, pui8Data, + ui32BCount, 1); + } else if (ui32Flags & PDUMP_FLAGS_LASTFRAME) { + u32 ui32DbgFlags; + + ui32DbgFlags = 0; + if (ui32Flags & PDUMP_FLAGS_RESETLFBUFFER) + ui32DbgFlags |= WRITELF_FLAGS_RESETBUF; + + ui32BytesWritten = + gpfnDbgDrv->pfnWriteLF(psStream, pui8Data, + ui32BCount, 1, ui32DbgFlags); + } else { + ui32BytesWritten = + gpfnDbgDrv->pfnWriteBINCM(psStream, pui8Data, + ui32BCount, 1); + } + + return ui32BytesWritten; +} + +IMG_BOOL PDumpTestNextFrame(u32 ui32CurrentFrame) +{ + IMG_BOOL bFrameDumped; + + bFrameDumped = IMG_FALSE; + PDumpSetFrameKM(ui32CurrentFrame + 1); + bFrameDumped = PDumpIsCaptureFrameKM(); + PDumpSetFrameKM(ui32CurrentFrame); + + return bFrameDumped; +} + +void PDump3DSignatureRegisters(u32 ui32DumpFrameNum, IMG_BOOL bLastFrame, + u32 *pui32Registers, u32 ui32NumRegisters) +{ + u32 ui32FileOffset, ui32Flags; + u32 i; + + __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(); + + ui32Flags = bLastFrame ? PDUMP_FLAGS_LASTFRAME : 0; + ui32FileOffset = 0; + + PDUMPCOMMENTWITHFLAGS(ui32Flags, + "\r\n-- Dump 3D signature registers\r\n"); + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "out%u_3d.sig", + ui32DumpFrameNum); + + for (i = 0; i < ui32NumRegisters; i++) { + PDumpReadRegKM(pszFile, ui32FileOffset, pui32Registers[i], + sizeof(u32), ui32Flags); + ui32FileOffset += sizeof(u32); + } +} + +static void PDumpCountRead(char *pszFileName, u32 ui32Address, u32 ui32Size, + u32 *pui32FileOffset, IMG_BOOL bLastFrame) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, + "SAB :SGXREG:0x%08X 0x%08X %s\r\n", ui32Address, + *pui32FileOffset, pszFileName); + PDumpWriteString2(pszScript, bLastFrame ? PDUMP_FLAGS_LASTFRAME : 0); + + *pui32FileOffset += ui32Size; +} + +void PDumpCounterRegisters(u32 ui32DumpFrameNum, IMG_BOOL bLastFrame, + u32 *pui32Registers, u32 ui32NumRegisters) +{ + u32 ui32FileOffset; + u32 i; + + __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(); + + PDUMPCOMMENTWITHFLAGS(bLastFrame ? PDUMP_FLAGS_LASTFRAME : 0, + "\r\n-- Dump counter registers\r\n"); + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "out%u.perf", + ui32DumpFrameNum); + ui32FileOffset = 0; + + for (i = 0; i < ui32NumRegisters; i++) + PDumpCountRead(pszFile, pui32Registers[i], sizeof(u32), + &ui32FileOffset, bLastFrame); +} + +void PDumpTASignatureRegisters(u32 ui32DumpFrameNum, u32 ui32TAKickCount, + IMG_BOOL bLastFrame, u32 *pui32Registers, + u32 ui32NumRegisters) +{ + u32 ui32FileOffset, ui32Flags; + u32 i; + + __PDBG_PDUMP_STATE_GET_SCRIPT_AND_FILE_STRING(); + + ui32Flags = bLastFrame ? PDUMP_FLAGS_LASTFRAME : 0; + PDUMPCOMMENTWITHFLAGS(ui32Flags, + "\r\n-- Dump TA signature registers\r\n"); + snprintf(pszFile, SZ_FILENAME_SIZE_MAX, "out%u_ta.sig", + ui32DumpFrameNum); + + ui32FileOffset = ui32TAKickCount * ui32NumRegisters * sizeof(u32); + + for (i = 0; i < ui32NumRegisters; i++) { + PDumpReadRegKM(pszFile, ui32FileOffset, pui32Registers[i], + sizeof(u32), ui32Flags); + ui32FileOffset += sizeof(u32); + } +} + +void PDumpRegRead(const u32 ui32RegOffset, u32 ui32Flags) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "RDW :SGXREG:0x%X\r\n", + ui32RegOffset); + PDumpWriteString2(pszScript, ui32Flags); +} + +void PDumpCycleCountRegRead(const u32 ui32RegOffset, IMG_BOOL bLastFrame) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + snprintf(pszScript, SZ_SCRIPT_SIZE_MAX, "RDW :SGXREG:0x%X\r\n", + ui32RegOffset); + PDumpWriteString2(pszScript, bLastFrame ? PDUMP_FLAGS_LASTFRAME : 0); +} + +void PDumpHWPerfCBKM(char *pszFileName, u32 ui32FileOffset, + struct IMG_DEV_VIRTADDR sDevBaseAddr, u32 ui32Size, + u32 ui32PDumpFlags) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + PDUMPCOMMENTWITHFLAGS(ui32PDumpFlags, + "\r\n-- Dump Hardware Performance Circular Buffer\r\n"); + + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, + "SAB :SGXMEM:v:0x%08X 0x%08X 0x%08X %s.bin\r\n", + sDevBaseAddr.uiAddr, ui32Size, ui32FileOffset, pszFileName); + + PDumpWriteString2(pszScript, ui32PDumpFlags); +} + +void PDumpCBP(struct PVRSRV_KERNEL_MEM_INFO *psROffMemInfo, + u32 ui32ROffOffset, u32 ui32WPosVal, u32 ui32PacketSize, + u32 ui32BufferSize, u32 ui32Flags, void *hUniqueTag) +{ + u32 ui32PageOffset; + struct IMG_DEV_VIRTADDR sDevVAddr; + struct IMG_DEV_PHYADDR sDevPAddr; + struct IMG_DEV_VIRTADDR sDevVPageAddr; + struct IMG_CPU_PHYADDR CpuPAddr; + + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + PVR_ASSERT((ui32ROffOffset + sizeof(u32)) <= + psROffMemInfo->ui32AllocSize); + + sDevVAddr = psROffMemInfo->sDevVAddr; + + sDevVAddr.uiAddr += ui32ROffOffset; + + CpuPAddr = + OSMemHandleToCpuPAddr(psROffMemInfo->sMemBlk.hOSMemHandle, + ui32ROffOffset); + ui32PageOffset = CpuPAddr.uiAddr & (PAGE_SIZE - 1); + + sDevVPageAddr.uiAddr = sDevVAddr.uiAddr - ui32PageOffset; + + BM_GetPhysPageAddr(psROffMemInfo, sDevVPageAddr, &sDevPAddr); + + sDevPAddr.uiAddr += ui32PageOffset; + + snprintf(pszScript, + SZ_SCRIPT_SIZE_MAX, + "CBP :SGXMEM:PA_%8.8X%8.8lX:0x%8.8lX 0x%8.8X 0x%8.8X 0x%8.8X\r\n", + (u32) hUniqueTag, + sDevPAddr.uiAddr & ~(SGX_MMU_PAGE_SIZE - 1), + sDevPAddr.uiAddr & (SGX_MMU_PAGE_SIZE - 1), + ui32WPosVal, ui32PacketSize, ui32BufferSize); + PDumpWriteString2(pszScript, ui32Flags); +} + +void PDumpIDLWithFlags(u32 ui32Clocks, u32 ui32Flags) +{ + __PDBG_PDUMP_STATE_GET_SCRIPT_STRING(); + + sprintf(pszScript, "IDL %u\r\n", ui32Clocks); + PDumpWriteString2(pszScript, ui32Flags); +} + +void PDumpIDL(u32 ui32Clocks) +{ + PDumpIDLWithFlags(ui32Clocks, PDUMP_FLAGS_CONTINUOUS); +} + +void PDumpSuspendKM(void) +{ + atomic_inc(&gsPDumpSuspended); +} + +void PDumpResumeKM(void) +{ + atomic_dec(&gsPDumpSuspended); +} + +#endif diff --git a/drivers/gpu/pvr/pdump_common.c b/drivers/gpu/pvr/pdump_common.c new file mode 100644 index 00000000000..4f0e6f2f116 --- /dev/null +++ b/drivers/gpu/pvr/pdump_common.c @@ -0,0 +1,237 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if defined(PDUMP) +#include "services_headers.h" +#include "pdump_km.h" + +#if !defined(PDUMP_TEMP_BUFFER_SIZE) +#define PDUMP_TEMP_BUFFER_SIZE (64 * 1024L) +#endif + +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define PTR_PLUS(t, p, x) ((t *)(((char *)(p)) + (x))) +#define VPTR_PLUS(p, x) PTR_PLUS(void, p, x) +#define VPTR_INC(p, x) (p = VPTR_PLUS(p, x)) +#define MAX_PDUMP_MMU_CONTEXTS 10 +static void *gpvTempBuffer; +static void *ghTempBufferBlockAlloc; +static u16 gui16MMUContextUsage; + +static void *GetTempBuffer(void) +{ + if (gpvTempBuffer == NULL) { + enum PVRSRV_ERROR eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + PDUMP_TEMP_BUFFER_SIZE, + &gpvTempBuffer, + &ghTempBufferBlockAlloc); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, + "GetTempBuffer: OSAllocMem failed: %d", + eError); + } + + return gpvTempBuffer; +} + +static void FreeTempBuffer(void) +{ + if (gpvTempBuffer != NULL) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, PDUMP_TEMP_BUFFER_SIZE, + gpvTempBuffer, ghTempBufferBlockAlloc); + gpvTempBuffer = NULL; + } +} + +void PDumpInitCommon(void) +{ + (void)GetTempBuffer(); + PDumpInit(); +} + +void PDumpDeInitCommon(void) +{ + FreeTempBuffer(); + PDumpDeInit(); +} + +enum PVRSRV_ERROR PDumpMemUM(struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *pvAltLinAddrUM, void *pvLinAddrUM, + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, + u32 ui32Offset, u32 ui32Bytes, u32 ui32Flags, + void *hUniqueTag) +{ + void *pvAddrUM; + void *pvAddrKM; + u32 ui32BytesDumped; + u32 ui32CurrentOffset; + + if (psMemInfo->pvLinAddrKM != NULL && pvAltLinAddrUM == NULL) + return PDumpMemKM(NULL, psMemInfo, ui32Offset, ui32Bytes, + ui32Flags, hUniqueTag); + + pvAddrUM = (pvAltLinAddrUM != NULL) ? pvAltLinAddrUM : + ((pvLinAddrUM != NULL) ? VPTR_PLUS(pvLinAddrUM, + ui32Offset) : NULL); + + pvAddrKM = GetTempBuffer(); + + PVR_ASSERT(pvAddrUM != NULL && pvAddrKM != NULL); + if (pvAddrUM == NULL || pvAddrKM == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PDumpMemUM: Nothing to dump"); + return PVRSRV_ERROR_GENERIC; + } + + if (ui32Bytes > PDUMP_TEMP_BUFFER_SIZE) + PDumpCommentWithFlags(ui32Flags, + "Dumping 0x%8.8lx bytes of memory, in blocks of 0x%8.8lx bytes", + ui32Bytes, (u32) PDUMP_TEMP_BUFFER_SIZE); + + ui32CurrentOffset = ui32Offset; + for (ui32BytesDumped = 0; ui32BytesDumped < ui32Bytes;) { + enum PVRSRV_ERROR eError; + u32 ui32BytesToDump = + MIN(PDUMP_TEMP_BUFFER_SIZE, ui32Bytes - ui32BytesDumped); + + eError = OSCopyFromUser(psPerProc, + pvAddrKM, pvAddrUM, ui32BytesToDump); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PDumpMemUM: OSCopyFromUser failed (%d), eError"); + return PVRSRV_ERROR_GENERIC; + } + + eError = PDumpMemKM(pvAddrKM, psMemInfo, ui32CurrentOffset, + ui32BytesToDump, ui32Flags, hUniqueTag); + + if (eError != PVRSRV_OK) { + if (ui32BytesDumped != 0) + PVR_DPF(PVR_DBG_ERROR, + "PDumpMemUM: PDumpMemKM failed (%d)", + eError); + PVR_ASSERT(ui32BytesDumped == 0); + return eError; + } + + VPTR_INC(pvAddrUM, ui32BytesToDump); + ui32CurrentOffset += ui32BytesToDump; + ui32BytesDumped += ui32BytesToDump; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR _PdumpAllocMMUContext(u32 *pui32MMUContextID) +{ + u32 i; + + for (i = 0; i < MAX_PDUMP_MMU_CONTEXTS; i++) + if ((gui16MMUContextUsage & (1UL << i)) == 0) { + gui16MMUContextUsage |= 1UL << i; + *pui32MMUContextID = i; + return PVRSRV_OK; + } + + PVR_DPF(PVR_DBG_ERROR, + "_PdumpAllocMMUContext: no free MMU context ids"); + + return PVRSRV_ERROR_GENERIC; +} + +static enum PVRSRV_ERROR _PdumpFreeMMUContext(u32 ui32MMUContextID) +{ + if (ui32MMUContextID < MAX_PDUMP_MMU_CONTEXTS) { + + gui16MMUContextUsage &= ~(1UL << ui32MMUContextID); + return PVRSRV_OK; + } + + PVR_DPF(PVR_DBG_ERROR, + "_PdumpFreeMMUContext: MMU context ids invalid"); + + return PVRSRV_ERROR_GENERIC; +} + +enum PVRSRV_ERROR PDumpSetMMUContext(enum PVRSRV_DEVICE_TYPE eDeviceType, + char *pszMemSpace, u32 *pui32MMUContextID, + u32 ui32MMUType, void *hUniqueTag1, + void *pvPDCPUAddr) +{ + u8 *pui8LinAddr = (u8 *) pvPDCPUAddr; + struct IMG_CPU_PHYADDR sCpuPAddr; + struct IMG_DEV_PHYADDR sDevPAddr; + u32 ui32MMUContextID; + enum PVRSRV_ERROR eError; + + eError = _PdumpAllocMMUContext(&ui32MMUContextID); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PDumpSetMMUContext: _PdumpAllocMMUContext failed: %d", + eError); + return eError; + } + + sCpuPAddr = OSMapLinToCPUPhys(pui8LinAddr); + sDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); + + sDevPAddr.uiAddr &= ~PVRSRV_4K_PAGE_SIZE; + + PDumpComment("Set MMU Context\r\n"); + + PDumpComment("MMU :%s:v%d %d :%s:PA_%8.8lX%8.8lX\r\n", + pszMemSpace, ui32MMUContextID, ui32MMUType, pszMemSpace, + hUniqueTag1, sDevPAddr.uiAddr); + + *pui32MMUContextID = ui32MMUContextID; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PDumpClearMMUContext(enum PVRSRV_DEVICE_TYPE eDeviceType, + char *pszMemSpace, + u32 ui32MMUContextID, u32 ui32MMUType) +{ + enum PVRSRV_ERROR eError; + + PVR_UNREFERENCED_PARAMETER(eDeviceType); + + PDumpComment("Clear MMU Context\r\n"); + + PDumpComment("MMU :%s:v%d %d\r\n", + pszMemSpace, ui32MMUContextID, ui32MMUType); + + eError = _PdumpFreeMMUContext(ui32MMUContextID); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PDumpClearMMUContext: _PdumpFreeMMUContext failed: %d", + eError); + return eError; + } + + return PVRSRV_OK; +} + +#endif diff --git a/drivers/gpu/pvr/pdump_km.h b/drivers/gpu/pvr/pdump_km.h new file mode 100644 index 00000000000..958c3332f80 --- /dev/null +++ b/drivers/gpu/pvr/pdump_km.h @@ -0,0 +1,268 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _PDUMP_KM_H_ +#define _PDUMP_KM_H_ + + +#define PDUMP_FLAGS_NEVER 0x08000000 +#define PDUMP_FLAGS_TOOUT2MEM 0x10000000 +#define PDUMP_FLAGS_LASTFRAME 0x20000000 +#define PDUMP_FLAGS_RESETLFBUFFER 0x40000000 +#define PDUMP_FLAGS_CONTINUOUS 0x80000000 + +#define PDUMP_PD_UNIQUETAG ((void *)0) +#define PDUMP_PT_UNIQUETAG ((void *)0) + +#ifndef PDUMP +#define MAKEUNIQUETAG(hMemInfo) (0) +#endif + +#ifdef PDUMP + +#define MAKEUNIQUETAG(hMemInfo) \ + (((struct BM_BUF *)(((struct PVRSRV_KERNEL_MEM_INFO *) \ + hMemInfo)->sMemBlk.hBuffer))->pMapping) + +#define PDUMP_REG_FUNC_NAME PDumpReg + +enum PVRSRV_ERROR PDumpMemPolKM(struct PVRSRV_KERNEL_MEM_INFO + *psMemInfo, u32 ui32Offset, + u32 ui32Value, u32 ui32Mask, + enum PDUMP_POLL_OPERATOR eOperator, + IMG_BOOL bLastFrame, + IMG_BOOL bOverwrite, + void *hUniqueTag); + +enum PVRSRV_ERROR PDumpMemUM(struct PVRSRV_PER_PROCESS_DATA + *psProcData, void *pvAltLinAddr, + void *pvLinAddr, + struct PVRSRV_KERNEL_MEM_INFO + *psMemInfo, u32 ui32Offset, + u32 ui32Bytes, u32 ui32Flags, + void *hUniqueTag); + +enum PVRSRV_ERROR PDumpMemKM(void *pvAltLinAddr, + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, u32 ui32Offset, + u32 ui32Bytes, u32 ui32Flags, void *hUniqueTag); + +enum PVRSRV_ERROR PDumpMemPagesKM(enum PVRSRV_DEVICE_TYPE eDeviceType, + struct IMG_DEV_PHYADDR *pPages, u32 ui32NumPages, + struct IMG_DEV_VIRTADDR sDevAddr, u32 ui32Start, + u32 ui32Length, u32 ui32Flags, void *hUniqueTag); + +enum PVRSRV_ERROR PDumpMem2KM(enum PVRSRV_DEVICE_TYPE eDeviceType, + void *pvLinAddr, + u32 ui32Bytes, + u32 ui32Flags, + IMG_BOOL bInitialisePages, + void *hUniqueTag1, void *hUniqueTag2); +void PDumpInitCommon(void); +void PDumpDeInitCommon(void); +void PDumpInit(void); +void PDumpDeInit(void); +enum PVRSRV_ERROR PDumpStartInitPhaseKM(void); +enum PVRSRV_ERROR PDumpStopInitPhaseKM(void); +enum PVRSRV_ERROR PDumpSetFrameKM(u32 ui32Frame); +enum PVRSRV_ERROR PDumpCommentKM(char *pszComment, u32 ui32Flags); +enum PVRSRV_ERROR PDumpDriverInfoKM(char *pszString, u32 ui32Flags); +enum PVRSRV_ERROR PDumpRegWithFlagsKM(u32 ui32RegAddr, u32 ui32RegValue, + u32 ui32Flags); + +enum PVRSRV_ERROR PDumpBitmapKM(char *pszFileName, u32 ui32FileOffset, + u32 ui32Width, u32 ui32Height, u32 ui32StrideInBytes, + struct IMG_DEV_VIRTADDR sDevBaseAddr, u32 ui32Size, + enum PDUMP_PIXEL_FORMAT ePixelFormat, + enum PDUMP_MEM_FORMAT eMemFormat, u32 ui32PDumpFlags); +void PDumpHWPerfCBKM(char *pszFileName, u32 ui32FileOffset, + struct IMG_DEV_VIRTADDR sDevBaseAddr, + u32 ui32Size, u32 ui32PDumpFlags); +enum PVRSRV_ERROR PDumpReadRegKM(char *pszFileName, u32 ui32FileOffset, + u32 ui32Address, u32 ui32Size, u32 ui32PDumpFlags); +void PDUMP_REG_FUNC_NAME(u32 dwReg, u32 dwData); + +void PDumpMsvdxRegRead(const char *const pRegRegion, const u32 dwRegOffset); + +void PDumpMsvdxRegWrite(const char *const pRegRegion, const u32 dwRegOffset, + const u32 dwData); + +enum PVRSRV_ERROR PDumpMsvdxRegPol(const char *const pRegRegion, + const u32 ui32Offset, const u32 ui32CheckFuncIdExt, + const u32 ui32RequValue, const u32 ui32Enable, + const u32 ui32PollCount, const u32 ui32TimeOut); + +enum PVRSRV_ERROR PDumpMsvdxWriteRef(const char *const pRegRegion, + const u32 ui32VLROffset, const u32 ui32Physical); + +void PDumpComment(char *pszFormat, ...); + +void PDumpCommentWithFlags(u32 ui32Flags, char *pszFormat, ...); +enum PVRSRV_ERROR PDumpRegPolKM(u32 ui32RegAddr, u32 ui32RegValue, + u32 ui32Mask); +enum PVRSRV_ERROR PDumpRegPolWithFlagsKM(u32 ui32RegAddr, u32 ui32RegValue, + u32 ui32Mask, u32 ui32Flags); + +IMG_BOOL PDumpIsLastCaptureFrameKM(void); +IMG_BOOL PDumpIsCaptureFrameKM(void); + +void PDumpMallocPages(enum PVRSRV_DEVICE_TYPE eDeviceType, + u32 ui32DevVAddr, void *pvLinAddr, void *hOSMemHandle, + u32 ui32NumBytes, u32 ui32PageSize, void *hUniqueTag); +void PDumpMallocPagesPhys(enum PVRSRV_DEVICE_TYPE eDeviceType, + u32 ui32DevVAddr, u32 *pui32PhysPages, u32 ui32NumPages, + void *hUniqueTag); +void PDumpMallocPageTable(enum PVRSRV_DEVICE_TYPE eDeviceType, + void *pvLinAddr, u32 ui32NumBytes, void *hUniqueTag); +enum PVRSRV_ERROR PDumpSetMMUContext(enum PVRSRV_DEVICE_TYPE eDeviceType, + char *pszMemSpace, u32 *pui32MMUContextID, + u32 ui32MMUType, void *hUniqueTag1, + void *pvPDCPUAddr); +enum PVRSRV_ERROR PDumpClearMMUContext(enum PVRSRV_DEVICE_TYPE eDeviceType, + char *pszMemSpace, + u32 ui32MMUContextID, u32 ui32MMUType); +void PDumpFreePages(struct BM_HEAP *psBMHeap, + struct IMG_DEV_VIRTADDR sDevVAddr, u32 ui32NumBytes, + u32 ui32PageSize, void *hUniqueTag, IMG_BOOL bInterleaved); +void PDumpFreePageTable(enum PVRSRV_DEVICE_TYPE eDeviceType, + void *pvLinAddr, u32 ui32NumBytes, void *hUniqueTag); +void PDumpPDReg(u32 ui32Reg, u32 ui32dwData, void *hUniqueTag); +void PDumpPDRegWithFlags(u32 ui32Reg, u32 ui32Data, u32 ui32Flags, + void *hUniqueTag); + +enum PVRSRV_ERROR PDumpPDDevPAddrKM(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo, + u32 ui32Offset, struct IMG_DEV_PHYADDR sPDDevPAddr, + void *hUniqueTag1, void *hUniqueTag2); + +IMG_BOOL PDumpTestNextFrame(u32 ui32CurrentFrame); + +void PDumpTASignatureRegisters(u32 ui32DumpFrameNum, + u32 ui32TAKickCount, IMG_BOOL bLastFrame, + u32 *pui32Registers, u32 ui32NumRegisters); + +void PDump3DSignatureRegisters(u32 ui32DumpFrameNum, IMG_BOOL bLastFrame, + u32 *pui32Registers, u32 ui32NumRegisters); + +void PDumpRegRead(const u32 dwRegOffset, u32 ui32Flags); + +void PDumpCycleCountRegRead(const u32 dwRegOffset, IMG_BOOL bLastFrame); + +void PDumpCounterRegisters(u32 ui32DumpFrameNum, IMG_BOOL bLastFrame, + u32 *pui32Registers, u32 ui32NumRegisters); + +void PDumpCBP(struct PVRSRV_KERNEL_MEM_INFO *psROffMemInfo, + u32 ui32ROffOffset, + u32 ui32WPosVal, + u32 ui32PacketSize, + u32 ui32BufferSize, u32 ui32Flags, void *hUniqueTag); + +void PDumpIDLWithFlags(u32 ui32Clocks, u32 ui32Flags); +void PDumpIDL(u32 ui32Clocks); + +void PDumpSuspendKM(void); +void PDumpResumeKM(void); + +#define PDUMPMEMPOL PDumpMemPolKM +#define PDUMPMEM PDumpMemKM +#define PDUMPMEM2 PDumpMem2KM +#define PDUMPMEMUM PDumpMemUM +#define PDUMPINIT PDumpInitCommon +#define PDUMPDEINIT PDumpDeInitCommon +#define PDUMPISLASTFRAME PDumpIsLastCaptureFrameKM +#define PDUMPTESTFRAME PDumpIsCaptureFrameKM +#define PDUMPTESTNEXTFRAME PDumpTestNextFrame +#define PDUMPREGWITHFLAGS PDumpRegWithFlagsKM +#define PDUMPREG PDUMP_REG_FUNC_NAME +#define PDUMPCOMMENT PDumpComment +#define PDUMPCOMMENTWITHFLAGS PDumpCommentWithFlags +#define PDUMPREGPOL PDumpRegPolKM +#define PDUMPREGPOLWITHFLAGS PDumpRegPolWithFlagsKM +#define PDUMPMALLOCPAGES PDumpMallocPages +#define PDUMPMALLOCPAGETABLE PDumpMallocPageTable +#define PDUMPSETMMUCONTEXT PDumpSetMMUContext +#define PDUMPCLEARMMUCONTEXT PDumpClearMMUContext +#define PDUMPFREEPAGES PDumpFreePages +#define PDUMPFREEPAGETABLE PDumpFreePageTable +#define PDUMPPDREG PDumpPDReg +#define PDUMPPDREGWITHFLAGS PDumpPDRegWithFlags +#define PDUMPCBP PDumpCBP +#define PDUMPMALLOCPAGESPHYS PDumpMallocPagesPhys +#define PDUMPENDINITPHASE PDumpStopInitPhaseKM +#define PDUMPMSVDXREGWRITE PDumpMsvdxRegWrite +#define PDUMPMSVDXREGREAD PDumpMsvdxRegRead +#define PDUMPMSVDXPOL PDumpMsvdxRegPol +#define PDUMPMSVDXWRITEREF PDumpMsvdxWriteRef +#define PDUMPBITMAPKM PDumpBitmapKM +#define PDUMPDRIVERINFO PDumpDriverInfoKM +#define PDUMPIDLWITHFLAGS PDumpIDLWithFlags +#define PDUMPIDL PDumpIDL +#define PDUMPSUSPEND PDumpSuspendKM +#define PDUMPRESUME PDumpResumeKM + +#else +#define PDUMPMEMPOL(args...) +#define PDUMPMEM(args...) +#define PDUMPMEM2(args...) +#define PDUMPMEMUM(args...) +#define PDUMPINIT(args...) +#define PDUMPDEINIT(args...) +#define PDUMPISLASTFRAME(args...) +#define PDUMPTESTFRAME(args...) +#define PDUMPTESTNEXTFRAME(args...) +#define PDUMPREGWITHFLAGS(args...) +#define PDUMPREG(args...) +#define PDUMPCOMMENT(args...) +#define PDUMPREGPOL(args...) +#define PDUMPREGPOLWITHFLAGS(args...) +#define PDUMPMALLOCPAGES(args...) +#define PDUMPMALLOCPAGETABLE(args...) +#define PDUMPSETMMUCONTEXT(args...) +#define PDUMPCLEARMMUCONTEXT(args...) +#define PDUMPFREEPAGES(args...) +#define PDUMPFREEPAGETABLE(args...) +#define PDUMPPDREG(args...) +#define PDUMPPDREGWITHFLAGS(args...) +#define PDUMPSYNC(args...) +#define PDUMPCOPYTOMEM(args...) +#define PDUMPWRITE(args...) +#define PDUMPCBP(args...) +#define PDUMPCOMMENTWITHFLAGS(args...) +#define PDUMPMALLOCPAGESPHYS(args...) +#define PDUMPENDINITPHASE(args...) +#define PDUMPMSVDXREG(args...) +#define PDUMPMSVDXREGWRITE(args...) +#define PDUMPMSVDXREGREAD(args...) +#define PDUMPMSVDXPOLEQ(args...) +#define PDUMPMSVDXPOL(args...) +#define PDUMPBITMAPKM(args...) +#define PDUMPDRIVERINFO(args...) +#define PDUMPIDLWITHFLAGS(args...) +#define PDUMPIDL(args...) +#define PDUMPSUSPEND(args...) +#define PDUMPRESUME(args...) +#define PDUMPMSVDXWRITEREF(args...) +#endif + +#endif diff --git a/drivers/gpu/pvr/pdumpdefs.h b/drivers/gpu/pvr/pdumpdefs.h new file mode 100644 index 00000000000..dec488bbdd4 --- /dev/null +++ b/drivers/gpu/pvr/pdumpdefs.h @@ -0,0 +1,92 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__PDUMPDEFS_H__) +#define __PDUMPDEFS_H__ + +enum PDUMP_PIXEL_FORMAT { + PVRSRV_PDUMP_PIXEL_FORMAT_RGB8 = 1, + PVRSRV_PDUMP_PIXEL_FORMAT_RGB332 = 2, + PVRSRV_PDUMP_PIXEL_FORMAT_KRGB555 = 3, + PVRSRV_PDUMP_PIXEL_FORMAT_RGB565 = 4, + PVRSRV_PDUMP_PIXEL_FORMAT_ARGB4444 = 5, + PVRSRV_PDUMP_PIXEL_FORMAT_ARGB1555 = 6, + PVRSRV_PDUMP_PIXEL_FORMAT_RGB888 = 7, + PVRSRV_PDUMP_PIXEL_FORMAT_ARGB8888 = 8, + PVRSRV_PDUMP_PIXEL_FORMAT_YUV8 = 9, + PVRSRV_PDUMP_PIXEL_FORMAT_AYUV4444 = 10, + PVRSRV_PDUMP_PIXEL_FORMAT_VY0UY1_8888 = 11, + PVRSRV_PDUMP_PIXEL_FORMAT_UY0VY1_8888 = 12, + PVRSRV_PDUMP_PIXEL_FORMAT_Y0UY1V_8888 = 13, + PVRSRV_PDUMP_PIXEL_FORMAT_Y0VY1U_8888 = 14, + PVRSRV_PDUMP_PIXEL_FORMAT_YUV888 = 15, + PVRSRV_PDUMP_PIXEL_FORMAT_UYVY10101010 = 16, + PVRSRV_PDUMP_PIXEL_FORMAT_VYAUYA8888 = 17, + PVRSRV_PDUMP_PIXEL_FORMAT_AYUV8888 = 18, + PVRSRV_PDUMP_PIXEL_FORMAT_AYUV2101010 = 19, + PVRSRV_PDUMP_PIXEL_FORMAT_YUV101010 = 20, + PVRSRV_PDUMP_PIXEL_FORMAT_PL12Y8 = 21, + PVRSRV_PDUMP_PIXEL_FORMAT_YUV_IMC2 = 22, + PVRSRV_PDUMP_PIXEL_FORMAT_YUV_YV12 = 23, + PVRSRV_PDUMP_PIXEL_FORMAT_YUV_PL8 = 24, + PVRSRV_PDUMP_PIXEL_FORMAT_YUV_PL12 = 25, + PVRSRV_PDUMP_PIXEL_FORMAT_422PL12YUV8 = 26, + PVRSRV_PDUMP_PIXEL_FORMAT_420PL12YUV8 = 27, + PVRSRV_PDUMP_PIXEL_FORMAT_PL12Y10 = 28, + PVRSRV_PDUMP_PIXEL_FORMAT_422PL12YUV10 = 29, + PVRSRV_PDUMP_PIXEL_FORMAT_420PL12YUV10 = 30, + PVRSRV_PDUMP_PIXEL_FORMAT_ABGR8888 = 31, + PVRSRV_PDUMP_PIXEL_FORMAT_BGRA8888 = 32, + PVRSRV_PDUMP_PIXEL_FORMAT_ARGB8332 = 33, + PVRSRV_PDUMP_PIXEL_FORMAT_RGB555 = 34, + PVRSRV_PDUMP_PIXEL_FORMAT_F16 = 35, + PVRSRV_PDUMP_PIXEL_FORMAT_F32 = 36, + PVRSRV_PDUMP_PIXEL_FORMAT_L16 = 37, + PVRSRV_PDUMP_PIXEL_FORMAT_L32 = 38, + + PVRSRV_PDUMP_PIXEL_FORMAT_FORCE_I32 = 0x7fffffff +}; + +enum PDUMP_MEM_FORMAT { + PVRSRV_PDUMP_MEM_FORMAT_STRIDE = 0, + PVRSRV_PDUMP_MEM_FORMAT_RESERVED = 1, + PVRSRV_PDUMP_MEM_FORMAT_TILED = 8, + PVRSRV_PDUMP_MEM_FORMAT_TWIDDLED = 9, + PVRSRV_PDUMP_MEM_FORMAT_HYBRID = 10, + + PVRSRV_PDUMP_MEM_FORMAT_FORCE_I32 = 0x7fffffff +}; + +enum PDUMP_POLL_OPERATOR { + PDUMP_POLL_OPERATOR_EQUAL = 0, + PDUMP_POLL_OPERATOR_LESS = 1, + PDUMP_POLL_OPERATOR_LESSEQUAL = 2, + PDUMP_POLL_OPERATOR_GREATER = 3, + PDUMP_POLL_OPERATOR_GREATEREQUAL = 4, + PDUMP_POLL_OPERATOR_NOTEQUAL = 5, +}; + +#endif diff --git a/drivers/gpu/pvr/perproc.c b/drivers/gpu/pvr/perproc.c new file mode 100644 index 00000000000..d0d4f4cc806 --- /dev/null +++ b/drivers/gpu/pvr/perproc.c @@ -0,0 +1,266 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "services_headers.h" +#include "resman.h" +#include "handle.h" +#include "perproc.h" +#include "osperproc.h" + +#define HASH_TAB_INIT_SIZE 32 + +static struct HASH_TABLE *psHashTab; + +static enum PVRSRV_ERROR FreePerProcessData( + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + enum PVRSRV_ERROR eError; + u32 uiPerProc; + + PVR_ASSERT(psPerProc != NULL); + + if (psPerProc == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "FreePerProcessData: invalid parameter"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + uiPerProc = HASH_Remove(psHashTab, (u32)psPerProc->ui32PID); + if (uiPerProc == 0) { + PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: " + "Couldn't find process in per-process data hash table"); + + PVR_ASSERT(psPerProc->ui32PID == 0); + } else { + PVR_ASSERT((struct PVRSRV_PER_PROCESS_DATA *) + uiPerProc == psPerProc); + PVR_ASSERT(((struct PVRSRV_PER_PROCESS_DATA *)uiPerProc)-> + ui32PID == psPerProc->ui32PID); + } + + if (psPerProc->psHandleBase != NULL) { + eError = PVRSRVFreeHandleBase(psPerProc->psHandleBase); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: " + "Couldn't free handle base for process (%d)", + eError); + return eError; + } + } + + if (psPerProc->hPerProcData != NULL) { + eError = + PVRSRVReleaseHandle(KERNEL_HANDLE_BASE, + psPerProc->hPerProcData, + PVRSRV_HANDLE_TYPE_PERPROC_DATA); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: " + "Couldn't release per-process data handle (%d)", + eError); + return eError; + } + } + + eError = OSPerProcessPrivateDataDeInit(psPerProc->hOsPrivateData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: " + "OSPerProcessPrivateDataDeInit failed (%d)", + eError); + return eError; + } + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), psPerProc, + psPerProc->hBlockAlloc); + + return PVRSRV_OK; +} + +struct PVRSRV_PER_PROCESS_DATA *PVRSRVPerProcessData(u32 ui32PID) +{ + struct PVRSRV_PER_PROCESS_DATA *psPerProc; + + PVR_ASSERT(psHashTab != NULL); + + psPerProc = + (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, + (u32) ui32PID); + return psPerProc; +} + +enum PVRSRV_ERROR PVRSRVPerProcessDataConnect(u32 ui32PID) +{ + struct PVRSRV_PER_PROCESS_DATA *psPerProc; + void *hBlockAlloc; + enum PVRSRV_ERROR eError = PVRSRV_OK; + + PVR_ASSERT(psHashTab != NULL); + + psPerProc = (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, + (u32)ui32PID); + if (psPerProc == NULL) { + eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(*psPerProc), (void **)&psPerProc, + &hBlockAlloc); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " + "Couldn't allocate per-process data (%d)", + eError); + return eError; + } + OSMemSet(psPerProc, 0, sizeof(*psPerProc)); + psPerProc->hBlockAlloc = hBlockAlloc; + + if (!HASH_Insert(psHashTab, (u32) ui32PID, (u32)psPerProc)) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " + "Couldn't insert per-process data into hash table"); + eError = PVRSRV_ERROR_GENERIC; + goto failure; + } + + psPerProc->ui32PID = ui32PID; + psPerProc->ui32RefCount = 0; + + eError = + OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " + "OSPerProcessPrivateDataInit failed (%d)", + eError); + goto failure; + } + + eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE, + &psPerProc->hPerProcData, + psPerProc, + PVRSRV_HANDLE_TYPE_PERPROC_DATA, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " + "Couldn't allocate handle for per-process data (%d)", + eError); + goto failure; + } + + eError = PVRSRVAllocHandleBase(&psPerProc->psHandleBase); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " + "Couldn't allocate handle base for process (%d)", + eError); + goto failure; + } + + eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " + "Couldn't set handle options (%d)", + eError); + goto failure; + } + + eError = + PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " + "Couldn't register with the resource manager"); + goto failure; + } + } + + psPerProc->ui32RefCount++; + PVR_DPF(PVR_DBG_MESSAGE, + "PVRSRVPerProcessDataConnect: Process 0x%x has ref-count %d", + ui32PID, psPerProc->ui32RefCount); + + return eError; + +failure: + (void)FreePerProcessData(psPerProc); + return eError; +} + +void PVRSRVPerProcessDataDisconnect(u32 ui32PID) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_PER_PROCESS_DATA *psPerProc; + + PVR_ASSERT(psHashTab != NULL); + + psPerProc = (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, + (u32)ui32PID); + if (psPerProc == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataDealloc: " + "Couldn't locate per-process data for PID %u", + ui32PID); + } else { + psPerProc->ui32RefCount--; + if (psPerProc->ui32RefCount == 0) { + PVR_DPF(PVR_DBG_MESSAGE, + "PVRSRVPerProcessDataDisconnect: " + "Last close from process 0x%x received", + ui32PID); + + PVRSRVResManDisconnect(psPerProc->hResManContext, + IMG_FALSE); + + eError = FreePerProcessData(psPerProc); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVPerProcessDataDisconnect: " + "Error freeing per-process data"); + } + } + + eError = PVRSRVPurgeHandles(KERNEL_HANDLE_BASE); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataDisconnect: " + "Purge of global handle pool failed (%d)", + eError); +} + +enum PVRSRV_ERROR PVRSRVPerProcessDataInit(void) +{ + PVR_ASSERT(psHashTab == NULL); + + psHashTab = HASH_Create(HASH_TAB_INIT_SIZE); + if (psHashTab == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataInit: " + "Couldn't create per-process data hash table"); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVPerProcessDataDeInit(void) +{ + if (psHashTab != NULL) { + HASH_Delete(psHashTab); + psHashTab = NULL; + } + + return PVRSRV_OK; +} diff --git a/drivers/gpu/pvr/perproc.h b/drivers/gpu/pvr/perproc.h new file mode 100644 index 00000000000..a89b0e4e51e --- /dev/null +++ b/drivers/gpu/pvr/perproc.h @@ -0,0 +1,79 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __PERPROC_H__ +#define __PERPROC_H__ + +#include "img_types.h" +#include "resman.h" + +#include "handle.h" + +struct PVRSRV_PER_PROCESS_DATA { + u32 ui32PID; + void *hBlockAlloc; + struct RESMAN_CONTEXT *hResManContext; + void *hPerProcData; + struct PVRSRV_HANDLE_BASE *psHandleBase; + + IMG_BOOL bHandlesBatched; + u32 ui32RefCount; + + IMG_BOOL bInitProcess; + + void *hOsPrivateData; +}; + +struct PVRSRV_PER_PROCESS_DATA *PVRSRVPerProcessData(u32 ui32PID); + +enum PVRSRV_ERROR PVRSRVPerProcessDataConnect(u32 ui32PID); +void PVRSRVPerProcessDataDisconnect(u32 ui32PID); + +enum PVRSRV_ERROR PVRSRVPerProcessDataInit(void); +enum PVRSRV_ERROR PVRSRVPerProcessDataDeInit(void); + +static inline struct PVRSRV_PER_PROCESS_DATA *PVRSRVFindPerProcessData(void) +{ + return PVRSRVPerProcessData(OSGetCurrentProcessIDKM()); +} + +static inline void *PVRSRVProcessPrivateData(struct PVRSRV_PER_PROCESS_DATA + *psPerProc) +{ + return (psPerProc != NULL) ? psPerProc->hOsPrivateData : NULL; +} + +static inline void *PVRSRVPerProcessPrivateData(u32 ui32PID) +{ + return PVRSRVProcessPrivateData(PVRSRVPerProcessData(ui32PID)); +} + +static inline void *PVRSRVFindPerProcessPrivateData(void) +{ + return PVRSRVProcessPrivateData(PVRSRVFindPerProcessData()); +} + +#endif diff --git a/drivers/gpu/pvr/power.c b/drivers/gpu/pvr/power.c new file mode 100644 index 00000000000..a33e0de81c4 --- /dev/null +++ b/drivers/gpu/pvr/power.c @@ -0,0 +1,559 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ +#include "services_headers.h" +#include "pdump_km.h" +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/sched.h> +#include <linux/wait.h> + +static IMG_BOOL gbInitServerRunning; +static IMG_BOOL gbInitServerRan; +static IMG_BOOL gbInitSuccessful; +static DEFINE_MUTEX(hPowerAndFreqLock); + +enum PVRSRV_ERROR PVRSRVSetInitServerState(enum PVRSRV_INIT_SERVER_STATE + eInitServerState, IMG_BOOL bState) +{ + + switch (eInitServerState) { + case PVRSRV_INIT_SERVER_RUNNING: + gbInitServerRunning = bState; + break; + case PVRSRV_INIT_SERVER_RAN: + gbInitServerRan = bState; + break; + case PVRSRV_INIT_SERVER_SUCCESSFUL: + gbInitSuccessful = bState; + break; + default: + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetInitServerState : Unknown state %lx", + eInitServerState); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +IMG_BOOL PVRSRVGetInitServerState( + enum PVRSRV_INIT_SERVER_STATE eInitServerState) +{ + IMG_BOOL bReturnVal; + + switch (eInitServerState) { + case PVRSRV_INIT_SERVER_RUNNING: + bReturnVal = gbInitServerRunning; + break; + case PVRSRV_INIT_SERVER_RAN: + bReturnVal = gbInitServerRan; + break; + case PVRSRV_INIT_SERVER_SUCCESSFUL: + bReturnVal = gbInitSuccessful; + break; + default: + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetInitServerState : Unknown state %lx", + eInitServerState); + bReturnVal = IMG_FALSE; + } + + return bReturnVal; +} + +static IMG_BOOL _IsSystemStatePowered(enum PVR_POWER_STATE eSystemPowerState) +{ + return (IMG_BOOL)(eSystemPowerState < PVRSRV_POWER_STATE_D2); +} + +static enum PVRSRV_ERROR PVRSRVDevicePrePowerStateKM(IMG_BOOL bAllDevices, + u32 ui32DeviceIndex, + enum PVR_POWER_STATE eNewPowerState) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct PVRSRV_POWER_DEV *psPowerDevice; + enum PVR_POWER_STATE eNewDevicePowerState; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + psPowerDevice = psSysData->psPowerDeviceList; + while (psPowerDevice) { + if (bAllDevices || + (ui32DeviceIndex == psPowerDevice->ui32DeviceIndex)) { + eNewDevicePowerState = + (eNewPowerState == PVRSRV_POWER_Unspecified) ? + psPowerDevice->eDefaultPowerState : + eNewPowerState; + + if (psPowerDevice->eCurrentPowerState != + eNewDevicePowerState) { + if (psPowerDevice->pfnPrePower != NULL) { + eError = + psPowerDevice-> + pfnPrePower(psPowerDevice-> + hDevCookie, + eNewDevicePowerState, + psPowerDevice-> + eCurrentPowerState); + if (eError != PVRSRV_OK) { + pr_err + ("pfnPrePower failed (%u)\n", + eError); + return eError; + } + } + + eError = SysDevicePrePowerState( + psPowerDevice->ui32DeviceIndex, + eNewDevicePowerState, + psPowerDevice->eCurrentPowerState); + if (eError != PVRSRV_OK) { + pr_err("SysDevicePrePowerState failed " + "(%u)\n", eError); + return eError; + } + } + } + + psPowerDevice = psPowerDevice->psNext; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR PVRSRVDevicePostPowerStateKM(IMG_BOOL bAllDevices, + u32 ui32DeviceIndex, + enum PVR_POWER_STATE eNewPowerState) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct PVRSRV_POWER_DEV *psPowerDevice; + enum PVR_POWER_STATE eNewDevicePowerState; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + psPowerDevice = psSysData->psPowerDeviceList; + while (psPowerDevice) { + if (bAllDevices || + (ui32DeviceIndex == psPowerDevice->ui32DeviceIndex)) { + eNewDevicePowerState = (eNewPowerState == + PVRSRV_POWER_Unspecified) ? psPowerDevice-> + eDefaultPowerState : eNewPowerState; + + if (psPowerDevice->eCurrentPowerState != + eNewDevicePowerState) { + eError = SysDevicePostPowerState( + psPowerDevice->ui32DeviceIndex, + eNewDevicePowerState, + psPowerDevice->eCurrentPowerState); + if (eError != PVRSRV_OK) { + pr_err("SysDevicePostPowerState " + "failed (%u)\n", eError); + return eError; + } + + if (psPowerDevice->pfnPostPower != NULL) { + eError = + psPowerDevice-> + pfnPostPower(psPowerDevice-> + hDevCookie, + eNewDevicePowerState, + psPowerDevice-> + eCurrentPowerState); + if (eError != PVRSRV_OK) { + pr_err + ("pfnPostPower failed " + "(%u)\n", eError); + return eError; + } + } + + psPowerDevice->eCurrentPowerState = + eNewDevicePowerState; + } + } + + psPowerDevice = psPowerDevice->psNext; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVSetDevicePowerStateKM(u32 ui32DeviceIndex, + enum PVR_POWER_STATE eNewPowerState) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + +#if defined(PDUMP) + if (eNewPowerState == PVRSRV_POWER_Unspecified) { + eError = + PVRSRVDevicePrePowerStateKM(IMG_FALSE, ui32DeviceIndex, + PVRSRV_POWER_STATE_D0); + if (eError != PVRSRV_OK) + goto Exit; + eError = + PVRSRVDevicePostPowerStateKM(IMG_FALSE, ui32DeviceIndex, + PVRSRV_POWER_STATE_D0); + if (eError != PVRSRV_OK) + goto Exit; + + PDUMPSUSPEND(); + } +#endif + + eError = PVRSRVDevicePrePowerStateKM(IMG_FALSE, ui32DeviceIndex, + eNewPowerState); + if (eError != PVRSRV_OK) { + if (eNewPowerState == PVRSRV_POWER_Unspecified) + PDUMPRESUME(); + goto Exit; + } + + eError = PVRSRVDevicePostPowerStateKM(IMG_FALSE, ui32DeviceIndex, + eNewPowerState); + + if (eNewPowerState == PVRSRV_POWER_Unspecified) + PDUMPRESUME(); + +Exit: + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVSetDevicePowerStateKM : " + "Transition to %d FAILED 0x%x", + eNewPowerState, eError); + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVSystemPrePowerStateKM( + enum PVR_POWER_STATE eNewPowerState) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + enum PVR_POWER_STATE eNewDevicePowerState; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + if (_IsSystemStatePowered(eNewPowerState) != + _IsSystemStatePowered(psSysData->eCurrentPowerState)) { + if (_IsSystemStatePowered(eNewPowerState)) + eNewDevicePowerState = PVRSRV_POWER_Unspecified; + else + eNewDevicePowerState = PVRSRV_POWER_STATE_D3; + + eError = PVRSRVDevicePrePowerStateKM(IMG_TRUE, 0, + eNewDevicePowerState); + if (eError != PVRSRV_OK) + goto ErrorExit; + } + + if (eNewPowerState != psSysData->eCurrentPowerState) { + eError = SysSystemPrePowerState(eNewPowerState); + if (eError != PVRSRV_OK) + goto ErrorExit; + } + + return eError; + +ErrorExit: + + PVR_DPF(PVR_DBG_ERROR, "PVRSRVSystemPrePowerStateKM: " + "Transition from %d to %d FAILED 0x%x", + psSysData->eCurrentPowerState, eNewPowerState, eError); + + psSysData->eFailedPowerState = eNewPowerState; + + return eError; +} + +enum PVRSRV_ERROR PVRSRVSystemPostPowerStateKM( + enum PVR_POWER_STATE eNewPowerState) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + enum PVR_POWER_STATE eNewDevicePowerState; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + goto Exit; + + if (eNewPowerState != psSysData->eCurrentPowerState) { + eError = SysSystemPostPowerState(eNewPowerState); + if (eError != PVRSRV_OK) + goto Exit; + } + + if (_IsSystemStatePowered(eNewPowerState) != + _IsSystemStatePowered(psSysData->eCurrentPowerState)) { + if (_IsSystemStatePowered(eNewPowerState)) + eNewDevicePowerState = PVRSRV_POWER_Unspecified; + else + eNewDevicePowerState = PVRSRV_POWER_STATE_D3; + + eError = + PVRSRVDevicePostPowerStateKM(IMG_TRUE, 0, + eNewDevicePowerState); + if (eError != PVRSRV_OK) + goto Exit; + } + + PVR_DPF(PVR_DBG_WARNING, "PVRSRVSystemPostPowerStateKM: " + "System Power Transition from %d to %d OK", + psSysData->eCurrentPowerState, eNewPowerState); + + psSysData->eCurrentPowerState = eNewPowerState; + +Exit: + + if (_IsSystemStatePowered(eNewPowerState) && + PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL)) + PVRSRVCommandCompleteCallbacks(); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVSetPowerStateKM(enum PVR_POWER_STATE eNewPowerState) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + eError = PVRSRVSystemPrePowerStateKM(eNewPowerState); + if (eError != PVRSRV_OK) + goto ErrorExit; + + eError = PVRSRVSystemPostPowerStateKM(eNewPowerState); + if (eError != PVRSRV_OK) + goto ErrorExit; + + psSysData->eFailedPowerState = PVRSRV_POWER_Unspecified; + + return PVRSRV_OK; + +ErrorExit: + + PVR_DPF(PVR_DBG_ERROR, "PVRSRVSetPowerStateKM: " + "Transition from %d to %d FAILED 0x%x", + psSysData->eCurrentPowerState, eNewPowerState, eError); + + psSysData->eFailedPowerState = eNewPowerState; + + return eError; +} + +enum PVRSRV_ERROR PVRSRVRegisterPowerDevice(u32 ui32DeviceIndex, + enum PVRSRV_ERROR (*pfnPrePower)(void *, enum PVR_POWER_STATE, + enum PVR_POWER_STATE), + enum PVRSRV_ERROR (*pfnPostPower)(void *, enum PVR_POWER_STATE, + enum PVR_POWER_STATE), + enum PVRSRV_ERROR (*pfnPreClockSpeedChange)(void *, IMG_BOOL, + enum PVR_POWER_STATE), + enum PVRSRV_ERROR (*pfnPostClockSpeedChange)(void *, IMG_BOOL, + enum PVR_POWER_STATE), + void *hDevCookie, enum PVR_POWER_STATE eCurrentPowerState, + enum PVR_POWER_STATE eDefaultPowerState) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct PVRSRV_POWER_DEV *psPowerDevice; + + if (pfnPrePower == NULL && pfnPostPower == NULL) + return PVRSRVRemovePowerDevice(ui32DeviceIndex); + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_POWER_DEV), + (void **) &psPowerDevice, NULL); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterPowerDevice: " + "Failed to alloc struct PVRSRV_POWER_DEV"); + return eError; + } + + psPowerDevice->pfnPrePower = pfnPrePower; + psPowerDevice->pfnPostPower = pfnPostPower; + psPowerDevice->pfnPreClockSpeedChange = pfnPreClockSpeedChange; + psPowerDevice->pfnPostClockSpeedChange = pfnPostClockSpeedChange; + psPowerDevice->hDevCookie = hDevCookie; + psPowerDevice->ui32DeviceIndex = ui32DeviceIndex; + psPowerDevice->eCurrentPowerState = eCurrentPowerState; + psPowerDevice->eDefaultPowerState = eDefaultPowerState; + + psPowerDevice->psNext = psSysData->psPowerDeviceList; + psSysData->psPowerDeviceList = psPowerDevice; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVRemovePowerDevice(u32 ui32DeviceIndex) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct PVRSRV_POWER_DEV *psCurrent, *psPrevious; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + psCurrent = psSysData->psPowerDeviceList; + psPrevious = NULL; + + while (psCurrent) + if (psCurrent->ui32DeviceIndex == ui32DeviceIndex) { + if (psPrevious) + psPrevious->psNext = psCurrent->psNext; + else + psSysData->psPowerDeviceList = + psCurrent->psNext; + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_POWER_DEV), psCurrent, + NULL); + break; + } else { + psPrevious = psCurrent; + psCurrent = psCurrent->psNext; + } + return PVRSRV_OK; +} + +IMG_BOOL PVRSRVIsDevicePowered(u32 ui32DeviceIndex) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct PVRSRV_POWER_DEV *psPowerDevice; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return IMG_FALSE; + + psPowerDevice = psSysData->psPowerDeviceList; + while (psPowerDevice) { + if (psPowerDevice->ui32DeviceIndex == ui32DeviceIndex) + return (IMG_BOOL)(psPowerDevice->eCurrentPowerState == + PVRSRV_POWER_STATE_D0); + psPowerDevice = psPowerDevice->psNext; + } + + return IMG_FALSE; +} + +enum PVRSRV_ERROR PVRSRVDevicePreClockSpeedChange(u32 ui32DeviceIndex, + IMG_BOOL bIdleDevice, + void *pvInfo) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + struct SYS_DATA *psSysData; + struct PVRSRV_POWER_DEV *psPowerDevice; + + PVR_UNREFERENCED_PARAMETER(pvInfo); + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + psPowerDevice = psSysData->psPowerDeviceList; + while (psPowerDevice) { + if (ui32DeviceIndex == psPowerDevice->ui32DeviceIndex) + if (psPowerDevice->pfnPreClockSpeedChange) { + eError = + psPowerDevice-> + pfnPreClockSpeedChange(psPowerDevice-> + hDevCookie, + bIdleDevice, + psPowerDevice-> + eCurrentPowerState); + if (eError != PVRSRV_OK) { + pr_err + ("pfnPreClockSpeedChange failed\n"); + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDevicePreClockSpeedChange : " + "Device %lu failed, error:0x%lx", + ui32DeviceIndex, eError); + break; + } + } + psPowerDevice = psPowerDevice->psNext; + } + + return eError; +} + +void PVRSRVDevicePostClockSpeedChange(u32 ui32DeviceIndex, IMG_BOOL bIdleDevice, + void *pvInfo) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct PVRSRV_POWER_DEV *psPowerDevice; + + PVR_UNREFERENCED_PARAMETER(pvInfo); + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return; + + psPowerDevice = psSysData->psPowerDeviceList; + while (psPowerDevice) { + if (ui32DeviceIndex == psPowerDevice->ui32DeviceIndex) + if (psPowerDevice->pfnPostClockSpeedChange) { + eError = + psPowerDevice-> + pfnPostClockSpeedChange(psPowerDevice-> + hDevCookie, + bIdleDevice, + psPowerDevice-> + eCurrentPowerState); + if (eError != PVRSRV_OK) { + pr_err + ("pfnPostClockSpeedChange " + "failed\n"); + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDevicePostClockSpeedChange : " + "Device %lu failed, error:0x%lx", + ui32DeviceIndex, eError); + } + } + psPowerDevice = psPowerDevice->psNext; + } +} diff --git a/drivers/gpu/pvr/power.h b/drivers/gpu/pvr/power.h new file mode 100644 index 00000000000..a5d00e2a1a9 --- /dev/null +++ b/drivers/gpu/pvr/power.h @@ -0,0 +1,97 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef POWER_H +#define POWER_H + +struct PVRSRV_POWER_DEV { + enum PVRSRV_ERROR (*pfnPrePower)(void *, enum PVR_POWER_STATE, + enum PVR_POWER_STATE); + enum PVRSRV_ERROR (*pfnPostPower)(void *, enum PVR_POWER_STATE, + enum PVR_POWER_STATE); + enum PVRSRV_ERROR (*pfnPreClockSpeedChange)(void *, IMG_BOOL, + enum PVR_POWER_STATE); + enum PVRSRV_ERROR (*pfnPostClockSpeedChange)(void *, IMG_BOOL, + enum PVR_POWER_STATE); + void *hDevCookie; + u32 ui32DeviceIndex; + enum PVR_POWER_STATE eDefaultPowerState; + enum PVR_POWER_STATE eCurrentPowerState; + struct PVRSRV_POWER_DEV *psNext; + +}; + +enum PVRSRV_INIT_SERVER_STATE { + PVRSRV_INIT_SERVER_Unspecified = -1, + PVRSRV_INIT_SERVER_RUNNING = 0, + PVRSRV_INIT_SERVER_RAN = 1, + PVRSRV_INIT_SERVER_SUCCESSFUL = 2, + PVRSRV_INIT_SERVER_NUM = 3, + PVRSRV_INIT_SERVER_FORCE_I32 = 0x7fffffff +}; + +IMG_BOOL PVRSRVGetInitServerState(enum PVRSRV_INIT_SERVER_STATE + eInitServerState); + +enum PVRSRV_ERROR PVRSRVSetInitServerState(enum PVRSRV_INIT_SERVER_STATE + eInitServerState, + IMG_BOOL bState); + +enum PVRSRV_ERROR PVRSRVSetDevicePowerStateKM(u32 ui32DeviceIndex, + enum PVR_POWER_STATE eNewPowerState); + +enum PVRSRV_ERROR PVRSRVSystemPrePowerStateKM( + enum PVR_POWER_STATE eNewPowerState); +enum PVRSRV_ERROR PVRSRVSystemPostPowerStateKM( + enum PVR_POWER_STATE eNewPowerState); + +enum PVRSRV_ERROR PVRSRVSetPowerStateKM(enum PVR_POWER_STATE ePVRState); + +enum PVRSRV_ERROR PVRSRVRegisterPowerDevice(u32 ui32DeviceIndex, + enum PVRSRV_ERROR (*pfnPrePower)(void *, enum PVR_POWER_STATE, + enum PVR_POWER_STATE), + enum PVRSRV_ERROR (*pfnPostPower)(void *, enum PVR_POWER_STATE, + enum PVR_POWER_STATE), + enum PVRSRV_ERROR (*pfnPreClockSpeedChange)(void *, IMG_BOOL, + enum PVR_POWER_STATE), + enum PVRSRV_ERROR (*pfnPostClockSpeedChange)(void *, IMG_BOOL, + enum PVR_POWER_STATE), + void *hDevCookie, enum PVR_POWER_STATE eCurrentPowerState, + enum PVR_POWER_STATE eDefaultPowerState); + +enum PVRSRV_ERROR PVRSRVRemovePowerDevice(u32 ui32DeviceIndex); + +IMG_BOOL PVRSRVIsDevicePowered(u32 ui32DeviceIndex); + +enum PVRSRV_ERROR PVRSRVDevicePreClockSpeedChange(u32 ui32DeviceIndex, + IMG_BOOL bIdleDevice, + void *pvInfo); + +void PVRSRVDevicePostClockSpeedChange(u32 ui32DeviceIndex, + IMG_BOOL bIdleDevice, + void *pvInfo); + +#endif diff --git a/drivers/gpu/pvr/private_data.h b/drivers/gpu/pvr/private_data.h new file mode 100644 index 00000000000..b91b838e7fd --- /dev/null +++ b/drivers/gpu/pvr/private_data.h @@ -0,0 +1,42 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __INCLUDED_PRIVATE_DATA_H_ +#define __INCLUDED_PRIVATE_DATA_H_ + +#include <linux/wait.h> +#include <linux/list.h> + +struct PVRSRV_FILE_PRIVATE_DATA { + u32 ui32OpenPID; + void *hBlockAlloc; + + wait_queue_head_t event_wait; + struct list_head event_list; + int event_space; +}; + +#endif diff --git a/drivers/gpu/pvr/proc.c b/drivers/gpu/pvr/proc.c new file mode 100644 index 00000000000..613d3decab6 --- /dev/null +++ b/drivers/gpu/pvr/proc.c @@ -0,0 +1,421 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> + +#include "services_headers.h" + +#include "queue.h" +#include "resman.h" +#include "pvrmmap.h" +#include "pvr_debug.h" +#include "pvrversion.h" +#include "proc.h" +#include "perproc.h" +#include "env_perproc.h" + +/* The proc entry for our /proc/pvr directory */ + +static struct proc_dir_entry *dir; + +static off_t procDumpSysNodes(char *buf, size_t size, off_t off); +static off_t procDumpVersion(char *buf, size_t size, off_t off); + +static const char PVRProcDirRoot[] = "pvr"; + +off_t printAppend(char *buffer, size_t size, off_t off, const char *format, ...) +{ + int n; + int space = size - off; + va_list ap; + + PVR_ASSERT(space >= 0); + + va_start(ap, format); + n = vsnprintf(buffer + off, space, format, ap); + va_end(ap); + + if (n >= space || n < 0) { + + buffer[size - 1] = 0; + return size - 1; + } else { + return off + n; +} +} + +static int pvr_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + off_t (*pprn)(char *, size_t, off_t) = data; + + off_t len = pprn(page, count, off); + + if (len == END_OF_FILE) { + len = 0; + *eof = 1; + } else if (!len) { + *start = (char *)0; + } else { + *start = (char *)1; + } + + return len; +} + +static int CreateProcEntryInDir(struct proc_dir_entry *pdir, const char *name, + read_proc_t rhandler, write_proc_t whandler, + void *data) +{ + struct proc_dir_entry *file; + mode_t mode; + + if (!pdir) { + PVR_DPF(PVR_DBG_ERROR, + "CreateProcEntryInDir: parent directory doesn't exist"); + + return -ENOMEM; + } + + mode = S_IFREG; + + if (rhandler) + mode |= S_IRUGO; + + if (whandler) + mode |= S_IWUSR; + + file = create_proc_entry(name, mode, pdir); + + if (file) { + file->read_proc = rhandler; + file->write_proc = whandler; + file->data = data; + + PVR_DPF(PVR_DBG_MESSAGE, "Created proc entry %s in %s", name, + pdir->name); + + return 0; + } + + PVR_DPF(PVR_DBG_ERROR, + "CreateProcEntry: cannot create proc entry %s in %s", name, + pdir->name); + + return -ENOMEM; +} + +int CreateProcEntry(const char *name, read_proc_t rhandler, + write_proc_t whandler, void *data) +{ + return CreateProcEntryInDir(dir, name, rhandler, whandler, data); +} + +int CreatePerProcessProcEntry(const char *name, read_proc_t rhandler, + write_proc_t whandler, void *data) +{ + struct PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; + u32 ui32PID; + + if (!dir) { + PVR_DPF(PVR_DBG_ERROR, + "CreatePerProcessProcEntries: /proc/%s doesn't exist", + PVRProcDirRoot); + + return -ENOMEM; + } + + ui32PID = OSGetCurrentProcessIDKM(); + + psPerProc = PVRSRVPerProcessPrivateData(ui32PID); + if (!psPerProc) { + PVR_DPF(PVR_DBG_ERROR, + "CreatePerProcessProcEntries: no per process data"); + + return -ENOMEM; + } + + if (!psPerProc->psProcDir) { + char dirname[16]; + int ret; + + ret = snprintf(dirname, sizeof(dirname), "%u", ui32PID); + + if (ret <= 0 || ret >= sizeof(dirname)) { + PVR_DPF(PVR_DBG_ERROR, "CreatePerProcessProcEntries: " + "couldn't generate per process proc " + "directory name \"%u\"", + ui32PID); + + return -ENOMEM; + } else { + psPerProc->psProcDir = proc_mkdir(dirname, dir); + if (!psPerProc->psProcDir) { + PVR_DPF(PVR_DBG_ERROR, + "CreatePerProcessProcEntries: " + "couldn't create per process proc " + "directory /proc/%s/%u", + PVRProcDirRoot, ui32PID); + + return -ENOMEM; + } + } + } + + return CreateProcEntryInDir(psPerProc->psProcDir, name, rhandler, + whandler, data); +} + +int CreateProcReadEntry(const char *name, + off_t (handler)(char *, size_t, off_t)) +{ + struct proc_dir_entry *file; + + if (!dir) { + PVR_DPF(PVR_DBG_ERROR, "CreateProcReadEntry: " + "cannot make proc entry /proc/%s/%s: no parent", + PVRProcDirRoot, name); + + return -ENOMEM; + } + + file = + create_proc_read_entry(name, S_IFREG | S_IRUGO, dir, pvr_read_proc, + (void *)handler); + + if (file) + return 0; + + PVR_DPF(PVR_DBG_ERROR, "CreateProcReadEntry: " + "cannot make proc entry /proc/%s/%s: no memory", + PVRProcDirRoot, name); + + return -ENOMEM; +} + +int CreateProcEntries(void) +{ + dir = proc_mkdir(PVRProcDirRoot, NULL); + + if (!dir) { + PVR_DPF(PVR_DBG_ERROR, + "CreateProcEntries: cannot make /proc/%s directory", + PVRProcDirRoot); + + return -ENOMEM; + } + + if (CreateProcReadEntry("queue", QueuePrintQueues) || + CreateProcReadEntry("version", procDumpVersion) || + CreateProcReadEntry("nodes", procDumpSysNodes)) { + PVR_DPF(PVR_DBG_ERROR, + "CreateProcEntries: couldn't make /proc/%s files", + PVRProcDirRoot); + + return -ENOMEM; + } +#ifdef CONFIG_PVR_DEBUG_EXTRA + if (CreateProcEntry + ("debug_level", PVRDebugProcGetLevel, PVRDebugProcSetLevel, NULL)) { + PVR_DPF(PVR_DBG_ERROR, + "CreateProcEntries: couldn't make /proc/%s/debug_level", + PVRProcDirRoot); + + return -ENOMEM; + } +#endif + + return 0; +} + +void RemoveProcEntry(const char *name) +{ + if (dir) { + remove_proc_entry(name, dir); + PVR_DPF(PVR_DBG_MESSAGE, "Removing /proc/%s/%s", + PVRProcDirRoot, name); + } +} + +void RemovePerProcessProcEntry(const char *name) +{ + struct PVRSRV_ENV_PER_PROCESS_DATA *psPerProc = + PVRSRVFindPerProcessPrivateData(); + + if (!psPerProc) { + PVR_DPF(PVR_DBG_ERROR, "CreatePerProcessProcEntries: " + "can't remove %s, no per process data", + name); + return; + } + + if (psPerProc->psProcDir) { + remove_proc_entry(name, psPerProc->psProcDir); + + PVR_DPF(PVR_DBG_MESSAGE, "Removing proc entry %s from %s", + name, psPerProc->psProcDir->name); + } +} + +void RemovePerProcessProcDir(struct PVRSRV_ENV_PER_PROCESS_DATA *psPerProc) +{ + if (psPerProc->psProcDir) { + while (psPerProc->psProcDir->subdir) { + PVR_DPF(PVR_DBG_WARNING, + "Belatedly removing /proc/%s/%s/%s", + PVRProcDirRoot, psPerProc->psProcDir->name, + psPerProc->psProcDir->subdir->name); + + RemoveProcEntry(psPerProc->psProcDir->subdir->name); + } + RemoveProcEntry(psPerProc->psProcDir->name); + } +} + +void RemoveProcEntries(void) +{ +#ifdef CONFIG_PVR_DEBUG_EXTRA + RemoveProcEntry("debug_level"); +#endif + RemoveProcEntry("queue"); + RemoveProcEntry("nodes"); + RemoveProcEntry("version"); + + while (dir->subdir) { + PVR_DPF(PVR_DBG_WARNING, "Belatedly removing /proc/%s/%s", + PVRProcDirRoot, dir->subdir->name); + + RemoveProcEntry(dir->subdir->name); + } + + remove_proc_entry(PVRProcDirRoot, NULL); +} + +static off_t procDumpVersion(char *buf, size_t size, off_t off) +{ + struct SYS_DATA *psSysData; + + if (off == 0) + return printAppend(buf, size, 0, "Version %s (%s) %s\n", + PVRVERSION_STRING, PVR_BUILD_TYPE, + PVR_BUILD_DIR); + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return PVRSRV_ERROR_GENERIC; + + if (off == 1) { + char *pszSystemVersionString = "None"; + + if (psSysData->pszVersionString) + pszSystemVersionString = psSysData->pszVersionString; + + if (strlen(pszSystemVersionString) + + strlen("System Version String: \n") + 1 > size) + return 0; + return printAppend(buf, size, 0, "System Version String: %s\n", + pszSystemVersionString); + } + + return END_OF_FILE; +} + +static const char *deviceTypeToString(enum PVRSRV_DEVICE_TYPE deviceType) +{ + switch (deviceType) { + default: + { + static char text[10]; + sprintf(text, "?%x", deviceType); + return text; + } + } +} + +static const char *deviceClassToString(enum PVRSRV_DEVICE_CLASS deviceClass) +{ + switch (deviceClass) { + case PVRSRV_DEVICE_CLASS_3D: + { + return "3D"; + } + case PVRSRV_DEVICE_CLASS_DISPLAY: + { + return "display"; + } + case PVRSRV_DEVICE_CLASS_BUFFER: + { + return "buffer"; + } + default: + { + static char text[10]; + + sprintf(text, "?%x", deviceClass); + return text; + } + } +} + +static off_t procDumpSysNodes(char *buf, size_t size, off_t off) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_DEVICE_NODE *psDevNode; + off_t len; + + if (size < 80) + return 0; + + if (off == 0) + return printAppend(buf, size, 0, + "Registered nodes\n" + "Addr Type Class Index Ref pvDev Size Res\n"); + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return PVRSRV_ERROR_GENERIC; + + for (psDevNode = psSysData->psDeviceNodeList; + --off && psDevNode; psDevNode = psDevNode->psNext) + ; + + if (!psDevNode) + return END_OF_FILE; + + len = printAppend(buf, size, 0, + "%p %-8s %-8s %4d %2u %p %3u %p\n", + psDevNode, + deviceTypeToString(psDevNode->sDevId.eDeviceType), + deviceClassToString(psDevNode->sDevId.eDeviceClass), + psDevNode->sDevId.eDeviceClass, + psDevNode->ui32RefCount, + psDevNode->pvDevice, + psDevNode->ui32pvDeviceSize, + psDevNode->hResManContext); + return len; +} diff --git a/drivers/gpu/pvr/proc.h b/drivers/gpu/pvr/proc.h new file mode 100644 index 00000000000..942b2ea9d0b --- /dev/null +++ b/drivers/gpu/pvr/proc.h @@ -0,0 +1,54 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __SERVICES_PROC_H__ +#define __SERVICES_PROC_H__ + +#include <asm/system.h> +#include <linux/proc_fs.h> + +#define END_OF_FILE ((off_t) -1) + +off_t printAppend(char *buffer, size_t size, off_t off, + const char *format, ...) + __attribute__ ((format(printf, 4, 5))); + +int CreateProcEntries(void); +int CreateProcReadEntry(const char *name, + off_t (handler)(char *, size_t, off_t)); +int CreateProcEntry(const char *name, read_proc_t rhandler, + write_proc_t whandler, void *data); + +int CreatePerProcessProcEntry(const char *name, read_proc_t rhandler, + write_proc_t whandler, void *data); + +void RemoveProcEntry(const char *name); + +void RemovePerProcessProcEntry(const char *name); + +void RemoveProcEntries(void); + +#endif diff --git a/drivers/gpu/pvr/pvr_bridge.h b/drivers/gpu/pvr/pvr_bridge.h new file mode 100644 index 00000000000..d41e73d5861 --- /dev/null +++ b/drivers/gpu/pvr/pvr_bridge.h @@ -0,0 +1,1107 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __PVR_BRIDGE_H__ +#define __PVR_BRIDGE_H__ + + +#include "servicesint.h" + + +#include <linux/ioctl.h> + +#define PVRSRV_IOC_GID 'g' +#define PVRSRV_IO(INDEX) \ + _IO(PVRSRV_IOC_GID, INDEX, struct PVRSRV_BRIDGE_PACKAGE) +#define PVRSRV_IOW(INDEX) \ + _IOW(PVRSRV_IOC_GID, INDEX, struct PVRSRV_BRIDGE_PACKAGE) +#define PVRSRV_IOR(INDEX) \ + _IOR(PVRSRV_IOC_GID, INDEX, struct PVRSRV_BRIDGE_PACKAGE) +#define PVRSRV_IOWR(INDEX) \ + _IOWR(PVRSRV_IOC_GID, INDEX, struct PVRSRV_BRIDGE_PACKAGE) + + +#define PVRSRV_BRIDGE_CORE_CMD_FIRST 0 +#define PVRSRV_BRIDGE_ENUM_DEVICES \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+0) +#define PVRSRV_BRIDGE_ACQUIRE_DEVICEINFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+1) +#define PVRSRV_BRIDGE_RELEASE_DEVICEINFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+2) +#define PVRSRV_BRIDGE_CREATE_DEVMEMCONTEXT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+3) +#define PVRSRV_BRIDGE_DESTROY_DEVMEMCONTEXT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+4) +#define PVRSRV_BRIDGE_GET_DEVMEM_HEAPINFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+5) +#define PVRSRV_BRIDGE_ALLOC_DEVICEMEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+6) +#define PVRSRV_BRIDGE_FREE_DEVICEMEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+7) +#define PVRSRV_BRIDGE_GETFREE_DEVICEMEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+8) +#define PVRSRV_BRIDGE_CREATE_COMMANDQUEUE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+9) +#define PVRSRV_BRIDGE_DESTROY_COMMANDQUEUE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+10) +#define PVRSRV_BRIDGE_MHANDLE_TO_MMAP_DATA \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+11) +#define PVRSRV_BRIDGE_CONNECT_SERVICES \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+12) +#define PVRSRV_BRIDGE_DISCONNECT_SERVICES \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+13) +#define PVRSRV_BRIDGE_WRAP_DEVICE_MEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+14) +#define PVRSRV_BRIDGE_GET_DEVICEMEMINFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+15) +#define PVRSRV_BRIDGE_RESERVE_DEV_VIRTMEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+16) +#define PVRSRV_BRIDGE_FREE_DEV_VIRTMEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+17) +#define PVRSRV_BRIDGE_MAP_EXT_MEMORY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+18) +#define PVRSRV_BRIDGE_UNMAP_EXT_MEMORY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+19) +#define PVRSRV_BRIDGE_MAP_DEV_MEMORY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+20) +#define PVRSRV_BRIDGE_UNMAP_DEV_MEMORY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+21) +#define PVRSRV_BRIDGE_MAP_DEVICECLASS_MEMORY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+22) +#define PVRSRV_BRIDGE_UNMAP_DEVICECLASS_MEMORY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+23) +#define PVRSRV_BRIDGE_MAP_MEM_INFO_TO_USER \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+24) +#define PVRSRV_BRIDGE_UNMAP_MEM_INFO_FROM_USER \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+25) +#define PVRSRV_BRIDGE_EXPORT_DEVICEMEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+26) +#define PVRSRV_BRIDGE_RELEASE_MMAP_DATA \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+27) +#define PVRSRV_BRIDGE_CACHE_FLUSH_DRM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_CORE_CMD_FIRST+28) +#define PVRSRV_BRIDGE_CORE_CMD_LAST \ + (PVRSRV_BRIDGE_CORE_CMD_FIRST+28) + +#define PVRSRV_BRIDGE_SIM_CMD_FIRST \ + (PVRSRV_BRIDGE_CORE_CMD_LAST+1) +#define PVRSRV_BRIDGE_PROCESS_SIMISR_EVENT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SIM_CMD_FIRST+0) +#define PVRSRV_BRIDGE_REGISTER_SIM_PROCESS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SIM_CMD_FIRST+1) +#define PVRSRV_BRIDGE_UNREGISTER_SIM_PROCESS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SIM_CMD_FIRST+2) +#define PVRSRV_BRIDGE_SIM_CMD_LAST \ + (PVRSRV_BRIDGE_SIM_CMD_FIRST+2) + +#define PVRSRV_BRIDGE_MAPPING_CMD_FIRST \ + (PVRSRV_BRIDGE_SIM_CMD_LAST+1) +#define PVRSRV_BRIDGE_MAPPHYSTOUSERSPACE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_MAPPING_CMD_FIRST+0) +#define PVRSRV_BRIDGE_UNMAPPHYSTOUSERSPACE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_MAPPING_CMD_FIRST+1) +#define PVRSRV_BRIDGE_GETPHYSTOUSERSPACEMAP \ + PVRSRV_IOWR(PVRSRV_BRIDGE_MAPPING_CMD_FIRST+2) +#define PVRSRV_BRIDGE_MAPPING_CMD_LAST \ + (PVRSRV_BRIDGE_MAPPING_CMD_FIRST+2) + +#define PVRSRV_BRIDGE_STATS_CMD_FIRST \ + (PVRSRV_BRIDGE_MAPPING_CMD_LAST+1) +#define PVRSRV_BRIDGE_GET_FB_STATS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_STATS_CMD_FIRST+0) +#define PVRSRV_BRIDGE_STATS_CMD_LAST \ + (PVRSRV_BRIDGE_STATS_CMD_FIRST+0) + +#define PVRSRV_BRIDGE_MISC_CMD_FIRST \ + (PVRSRV_BRIDGE_STATS_CMD_LAST+1) +#define PVRSRV_BRIDGE_GET_MISC_INFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_MISC_CMD_FIRST+0) +#define PVRSRV_BRIDGE_RELEASE_MISC_INFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_MISC_CMD_FIRST+1) +#define PVRSRV_BRIDGE_MISC_CMD_LAST \ + (PVRSRV_BRIDGE_MISC_CMD_FIRST+1) + +#define PVRSRV_BRIDGE_OVERLAY_CMD_FIRST \ + (PVRSRV_BRIDGE_MISC_CMD_LAST+1) +#define PVRSRV_BRIDGE_OVERLAY_CMD_LAST \ + (PVRSRV_BRIDGE_OVERLAY_CMD_FIRST+1) + +#if defined(PDUMP) +#define PVRSRV_BRIDGE_PDUMP_CMD_FIRST \ + (PVRSRV_BRIDGE_OVERLAY_CMD_FIRST+1) +#define PVRSRV_BRIDGE_PDUMP_INIT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+0) +#define PVRSRV_BRIDGE_PDUMP_MEMPOL \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+1) +#define PVRSRV_BRIDGE_PDUMP_DUMPMEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+2) +#define PVRSRV_BRIDGE_PDUMP_REG \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+3) +#define PVRSRV_BRIDGE_PDUMP_REGPOL \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+4) +#define PVRSRV_BRIDGE_PDUMP_COMMENT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+5) +#define PVRSRV_BRIDGE_PDUMP_SETFRAME \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+6) +#define PVRSRV_BRIDGE_PDUMP_ISCAPTURING \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+7) +#define PVRSRV_BRIDGE_PDUMP_DUMPBITMAP \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+8) +#define PVRSRV_BRIDGE_PDUMP_DUMPREADREG \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+9) +#define PVRSRV_BRIDGE_PDUMP_SYNCPOL \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+10) +#define PVRSRV_BRIDGE_PDUMP_DUMPSYNC \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+11) +#define PVRSRV_BRIDGE_PDUMP_MEMPAGES \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+12) +#define PVRSRV_BRIDGE_PDUMP_DRIVERINFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+13) +#define PVRSRV_BRIDGE_PDUMP_PDREG \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+14) +#define PVRSRV_BRIDGE_PDUMP_DUMPPDDEVPADDR \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+15) +#define PVRSRV_BRIDGE_PDUMP_CYCLE_COUNT_REG_READ \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+16) +#define PVRSRV_BRIDGE_PDUMP_STARTINITPHASE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+17) +#define PVRSRV_BRIDGE_PDUMP_STOPINITPHASE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_PDUMP_CMD_FIRST+18) +#define PVRSRV_BRIDGE_PDUMP_CMD_LAST \ + (PVRSRV_BRIDGE_PDUMP_CMD_FIRST+18) +#else +#define PVRSRV_BRIDGE_PDUMP_CMD_LAST PVRSRV_BRIDGE_OVERLAY_CMD_LAST +#endif + +#define PVRSRV_BRIDGE_OEM_CMD_FIRST \ + (PVRSRV_BRIDGE_PDUMP_CMD_LAST+1) +#define PVRSRV_BRIDGE_GET_OEMJTABLE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_OEM_CMD_FIRST+0) +#define PVRSRV_BRIDGE_OEM_CMD_LAST \ + (PVRSRV_BRIDGE_OEM_CMD_FIRST+0) + +#define PVRSRV_BRIDGE_DEVCLASS_CMD_FIRST \ + (PVRSRV_BRIDGE_OEM_CMD_LAST+1) +#define PVRSRV_BRIDGE_ENUM_CLASS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DEVCLASS_CMD_FIRST+0) +#define PVRSRV_BRIDGE_DEVCLASS_CMD_LAST \ + (PVRSRV_BRIDGE_DEVCLASS_CMD_FIRST+0) + +#define PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST \ + (PVRSRV_BRIDGE_DEVCLASS_CMD_LAST+1) +#define PVRSRV_BRIDGE_OPEN_DISPCLASS_DEVICE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+0) +#define PVRSRV_BRIDGE_CLOSE_DISPCLASS_DEVICE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+1) +#define PVRSRV_BRIDGE_ENUM_DISPCLASS_FORMATS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+2) +#define PVRSRV_BRIDGE_ENUM_DISPCLASS_DIMS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+3) +#define PVRSRV_BRIDGE_GET_DISPCLASS_SYSBUFFER \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+4) +#define PVRSRV_BRIDGE_GET_DISPCLASS_INFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+5) +#define PVRSRV_BRIDGE_CREATE_DISPCLASS_SWAPCHAIN \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+6) +#define PVRSRV_BRIDGE_DESTROY_DISPCLASS_SWAPCHAIN \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+7) +#define PVRSRV_BRIDGE_SET_DISPCLASS_DSTRECT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+8) +#define PVRSRV_BRIDGE_SET_DISPCLASS_SRCRECT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+9) +#define PVRSRV_BRIDGE_SET_DISPCLASS_DSTCOLOURKEY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+10) +#define PVRSRV_BRIDGE_SET_DISPCLASS_SRCCOLOURKEY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+11) +#define PVRSRV_BRIDGE_GET_DISPCLASS_BUFFERS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+12) +#define PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_BUFFER \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+13) +#define PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_SYSTEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+14) +#define PVRSRV_BRIDGE_DISPCLASS_CMD_LAST \ + (PVRSRV_BRIDGE_DISPCLASS_CMD_FIRST+14) + +#define PVRSRV_BRIDGE_BUFCLASS_CMD_FIRST \ + (PVRSRV_BRIDGE_DISPCLASS_CMD_LAST+1) +#define PVRSRV_BRIDGE_OPEN_BUFFERCLASS_DEVICE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_BUFCLASS_CMD_FIRST+0) +#define PVRSRV_BRIDGE_CLOSE_BUFFERCLASS_DEVICE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_BUFCLASS_CMD_FIRST+1) +#define PVRSRV_BRIDGE_GET_BUFFERCLASS_INFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_BUFCLASS_CMD_FIRST+2) +#define PVRSRV_BRIDGE_GET_BUFFERCLASS_BUFFER \ + PVRSRV_IOWR(PVRSRV_BRIDGE_BUFCLASS_CMD_FIRST+3) +#define PVRSRV_BRIDGE_BUFCLASS_CMD_LAST \ + (PVRSRV_BRIDGE_BUFCLASS_CMD_FIRST+3) + +#define PVRSRV_BRIDGE_WRAP_CMD_FIRST \ + (PVRSRV_BRIDGE_BUFCLASS_CMD_LAST+1) +#define PVRSRV_BRIDGE_WRAP_EXT_MEMORY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_WRAP_CMD_FIRST+0) +#define PVRSRV_BRIDGE_UNWRAP_EXT_MEMORY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_WRAP_CMD_FIRST+1) +#define PVRSRV_BRIDGE_WRAP_CMD_LAST \ + (PVRSRV_BRIDGE_WRAP_CMD_FIRST+1) + +#define PVRSRV_BRIDGE_SHAREDMEM_CMD_FIRST \ + (PVRSRV_BRIDGE_WRAP_CMD_LAST+1) +#define PVRSRV_BRIDGE_ALLOC_SHARED_SYS_MEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SHAREDMEM_CMD_FIRST+0) +#define PVRSRV_BRIDGE_FREE_SHARED_SYS_MEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SHAREDMEM_CMD_FIRST+1) +#define PVRSRV_BRIDGE_MAP_MEMINFO_MEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SHAREDMEM_CMD_FIRST+2) +#define PVRSRV_BRIDGE_UNMAP_MEMINFO_MEM \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SHAREDMEM_CMD_FIRST+3) +#define PVRSRV_BRIDGE_SHAREDMEM_CMD_LAST \ + (PVRSRV_BRIDGE_SHAREDMEM_CMD_FIRST+3) + +#define PVRSRV_BRIDGE_SERVICES4_TMP_CMD_FIRST \ + (PVRSRV_BRIDGE_SHAREDMEM_CMD_LAST+1) +#define PVRSRV_BRIDGE_GETMMU_PD_DEVPADDR \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SERVICES4_TMP_CMD_FIRST+0) +#define PVRSRV_BRIDGE_SERVICES4_TMP_CMD_LAST \ + (PVRSRV_BRIDGE_SERVICES4_TMP_CMD_FIRST+0) + +#define PVRSRV_BRIDGE_INITSRV_CMD_FIRST \ + (PVRSRV_BRIDGE_SERVICES4_TMP_CMD_LAST+1) +#define PVRSRV_BRIDGE_INITSRV_CONNECT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_INITSRV_CMD_FIRST+0) +#define PVRSRV_BRIDGE_INITSRV_DISCONNECT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_INITSRV_CMD_FIRST+1) +#define PVRSRV_BRIDGE_INITSRV_CMD_LAST \ + (PVRSRV_BRIDGE_INITSRV_CMD_FIRST+1) + +#define PVRSRV_BRIDGE_EVENT_OBJECT_CMD_FIRST \ + (PVRSRV_BRIDGE_INITSRV_CMD_LAST+1) +#define PVRSRV_BRIDGE_EVENT_OBJECT_WAIT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_EVENT_OBJECT_CMD_FIRST+0) +#define PVRSRV_BRIDGE_EVENT_OBJECT_OPEN \ + PVRSRV_IOWR(PVRSRV_BRIDGE_EVENT_OBJECT_CMD_FIRST+1) +#define PVRSRV_BRIDGE_EVENT_OBJECT_CLOSE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_EVENT_OBJECT_CMD_FIRST+2) +#define PVRSRV_BRIDGE_EVENT_OBJECT_CMD_LAST \ + (PVRSRV_BRIDGE_EVENT_OBJECT_CMD_FIRST+2) + +#define PVRSRV_BRIDGE_SYNC_OPS_CMD_FIRST \ + (PVRSRV_BRIDGE_EVENT_OBJECT_CMD_LAST+1) +#define PVRSRV_BRIDGE_MODIFY_SYNC_OPS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SYNC_OPS_CMD_FIRST+0) +#define PVRSRV_BRIDGE_SYNC_OPS_CMD_LAST \ + (PVRSRV_BRIDGE_SYNC_OPS_CMD_FIRST+0) + +#define PVRSRV_BRIDGE_LAST_NON_DEVICE_CMD \ + (PVRSRV_BRIDGE_SYNC_OPS_CMD_LAST+1) + +#define PVRSRV_KERNEL_MODE_CLIENT 1 + +struct PVRSRV_BRIDGE_RETURN { + enum PVRSRV_ERROR eError; + void *pvData; +}; + +struct PVRSRV_BRIDGE_PACKAGE { + u32 ui32BridgeID; + u32 ui32Size; + void __user *pvParamIn; + u32 ui32InBufferSize; + void __user *pvParamOut; + u32 ui32OutBufferSize; + + void *hKernelServices; +}; + +struct PVRSRV_BRIDGE_IN_ACQUIRE_DEVICEINFO { + u32 ui32BridgeFlags; + u32 uiDevIndex; + enum PVRSRV_DEVICE_TYPE eDeviceType; +}; + +struct PVRSRV_BRIDGE_IN_ENUMCLASS { + u32 ui32BridgeFlags; + enum PVRSRV_DEVICE_CLASS sDeviceClass; +}; + +struct PVRSRV_BRIDGE_IN_CLOSE_DISPCLASS_DEVICE { + u32 ui32BridgeFlags; + void *hDeviceKM; +}; + +struct PVRSRV_BRIDGE_IN_ENUM_DISPCLASS_FORMATS { + u32 ui32BridgeFlags; + void *hDeviceKM; +}; + +struct PVRSRV_BRIDGE_IN_GET_DISPCLASS_SYSBUFFER { + u32 ui32BridgeFlags; + void *hDeviceKM; +}; + +struct PVRSRV_BRIDGE_IN_GET_DISPCLASS_INFO { + u32 ui32BridgeFlags; + void *hDeviceKM; +}; + +struct PVRSRV_BRIDGE_IN_CLOSE_BUFFERCLASS_DEVICE { + u32 ui32BridgeFlags; + void *hDeviceKM; +}; + +struct PVRSRV_BRIDGE_IN_GET_BUFFERCLASS_INFO { + u32 ui32BridgeFlags; + void *hDeviceKM; +}; + +struct PVRSRV_BRIDGE_IN_RELEASE_DEVICEINFO { + u32 ui32BridgeFlags; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_IN_FREE_CLASSDEVICEINFO { + u32 ui32BridgeFlags; + enum PVRSRV_DEVICE_CLASS DeviceClass; + void *pvDevInfo; +}; + +struct PVRSRV_BRIDGE_IN_GET_DEVMEM_HEAPINFO { + u32 ui32BridgeFlags; + void *hDevCookie; + void *hDevMemContext; +}; + +struct PVRSRV_BRIDGE_IN_CREATE_DEVMEMCONTEXT { + u32 ui32BridgeFlags; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_IN_DESTROY_DEVMEMCONTEXT { + u32 ui32BridgeFlags; + void *hDevCookie; + void *hDevMemContext; +}; + +struct PVRSRV_BRIDGE_IN_ALLOCDEVICEMEM { + u32 ui32BridgeFlags; + void *hDevCookie; + void *hDevMemHeap; + u32 ui32Attribs; + u32 ui32Size; + u32 ui32Alignment; +}; + +struct PVRSRV_BRIDGE_IN_MAPMEMINFOTOUSER { + u32 ui32BridgeFlags; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; +}; + +struct PVRSRV_BRIDGE_IN_UNMAPMEMINFOFROMUSER { + u32 ui32BridgeFlags; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + void *pvLinAddr; + void *hMappingInfo; +}; + +#define DRM_PVR2D_CFLUSH_FROM_GPU 1 +#define DRM_PVR2D_CFLUSH_TO_GPU 2 + +struct PVRSRV_BRIDGE_IN_CACHEFLUSHDRMFROMUSER { + u32 ui32BridgeFlags; + void *hDevCookie; + u32 ui32Type; + u32 ui32Virt; + u32 ui32Length; +}; + +struct PVRSRV_BRIDGE_IN_FREEDEVICEMEM { + u32 ui32BridgeFlags; + void *hDevCookie; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + +}; + +struct PVRSRV_BRIDGE_IN_EXPORTDEVICEMEM { + u32 ui32BridgeFlags; + void *hDevCookie; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + +}; + +struct PVRSRV_BRIDGE_IN_GETFREEDEVICEMEM { + u32 ui32BridgeFlags; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_CREATECOMMANDQUEUE { + u32 ui32BridgeFlags; + void *hDevCookie; + u32 ui32QueueSize; +}; + +struct PVRSRV_BRIDGE_IN_DESTROYCOMMANDQUEUE { + u32 ui32BridgeFlags; + void *hDevCookie; + struct PVRSRV_QUEUE_INFO *psQueueInfo; + +}; + +struct PVRSRV_BRIDGE_IN_MHANDLE_TO_MMAP_DATA { + u32 ui32BridgeFlags; + void *hMHandle; +}; + +struct PVRSRV_BRIDGE_IN_RELEASE_MMAP_DATA { + u32 ui32BridgeFlags; + void *hMHandle; +}; + +struct PVRSRV_BRIDGE_IN_RESERVE_DEV_VIRTMEM { + u32 ui32BridgeFlags; + void *hDevMemHeap; + struct IMG_DEV_VIRTADDR *psDevVAddr; + u32 ui32Size; + u32 ui32Alignment; +}; + +struct PVRSRV_BRIDGE_OUT_CONNECT_SERVICES { + enum PVRSRV_ERROR eError; + void *hKernelServices; +}; + +struct PVRSRV_BRIDGE_OUT_RESERVE_DEV_VIRTMEM { + enum PVRSRV_ERROR eError; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; +}; + +struct PVRSRV_BRIDGE_IN_FREE_DEV_VIRTMEM { + u32 ui32BridgeFlags; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; +}; + +struct PVRSRV_BRIDGE_IN_MAP_DEV_MEMORY { + u32 ui32BridgeFlags; + void *hKernelMemInfo; + void *hDstDevMemHeap; +}; + +struct PVRSRV_BRIDGE_OUT_MAP_DEV_MEMORY { + enum PVRSRV_ERROR eError; + struct PVRSRV_KERNEL_MEM_INFO *psDstKernelMemInfo; + struct PVRSRV_KERNEL_SYNC_INFO *psDstKernelSyncInfo; + struct PVRSRV_CLIENT_MEM_INFO sDstClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sDstClientSyncInfo; +}; + +struct PVRSRV_BRIDGE_IN_UNMAP_DEV_MEMORY { + u32 ui32BridgeFlags; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; +}; + +struct PVRSRV_BRIDGE_IN_MAP_EXT_MEMORY { + u32 ui32BridgeFlags; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct IMG_SYS_PHYADDR *psSysPAddr; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_UNMAP_EXT_MEMORY { + u32 ui32BridgeFlags; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_MAP_DEVICECLASS_MEMORY { + u32 ui32BridgeFlags; + void *hDeviceClassBuffer; + void *hDevMemContext; + +}; + +struct PVRSRV_BRIDGE_OUT_MAP_DEVICECLASS_MEMORY { + enum PVRSRV_ERROR eError; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; + void *hMappingInfo; +}; + +struct PVRSRV_BRIDGE_IN_UNMAP_DEVICECLASS_MEMORY { + u32 ui32BridgeFlags; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_MEMPOL { + u32 ui32BridgeFlags; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + u32 ui32Offset; + u32 ui32Value; + u32 ui32Mask; + IMG_BOOL bLastFrame; + IMG_BOOL bOverwrite; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_SYNCPOL { + u32 ui32BridgeFlags; + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; + IMG_BOOL bIsRead; + u32 ui32Value; + u32 ui32Mask; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_DUMPMEM { + u32 ui32BridgeFlags; + void *pvLinAddr; + void *pvAltLinAddr; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + u32 ui32Offset; + u32 ui32Bytes; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_DUMPSYNC { + u32 ui32BridgeFlags; + void *pvAltLinAddr; + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; + u32 ui32Offset; + u32 ui32Bytes; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_DUMPREG { + u32 ui32BridgeFlags; + struct PVRSRV_HWREG sHWReg; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_REGPOL { + u32 ui32BridgeFlags; + struct PVRSRV_HWREG sHWReg; + u32 ui32Mask; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_DUMPPDREG { + u32 ui32BridgeFlags; + struct PVRSRV_HWREG sHWReg; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_MEMPAGES { + u32 ui32BridgeFlags; + void *hKernelMemInfo; + struct IMG_DEV_PHYADDR *pPages; + u32 ui32NumPages; + struct IMG_DEV_VIRTADDR sDevAddr; + u32 ui32Start; + u32 ui32Length; + IMG_BOOL bContinuous; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_COMMENT { + u32 ui32BridgeFlags; + char szComment[PVRSRV_PDUMP_MAX_COMMENT_SIZE]; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_SETFRAME { + u32 ui32BridgeFlags; + u32 ui32Frame; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_BITMAP { + u32 ui32BridgeFlags; + char szFileName[PVRSRV_PDUMP_MAX_FILENAME_SIZE]; + u32 ui32FileOffset; + u32 ui32Width; + u32 ui32Height; + u32 ui32StrideInBytes; + struct IMG_DEV_VIRTADDR sDevBaseAddr; + u32 ui32Size; + enum PDUMP_PIXEL_FORMAT ePixelFormat; + enum PDUMP_MEM_FORMAT eMemFormat; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_READREG { + u32 ui32BridgeFlags; + char szFileName[PVRSRV_PDUMP_MAX_FILENAME_SIZE]; + u32 ui32FileOffset; + u32 ui32Address; + u32 ui32Size; + u32 ui32Flags; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_DRIVERINFO { + u32 ui32BridgeFlags; + char szString[PVRSRV_PDUMP_MAX_COMMENT_SIZE]; + IMG_BOOL bContinuous; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_DUMPPDDEVPADDR { + u32 ui32BridgeFlags; + void *hKernelMemInfo; + u32 ui32Offset; + struct IMG_DEV_PHYADDR sPDDevPAddr; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_CYCLE_COUNT_REG_READ { + u32 ui32BridgeFlags; + u32 ui32RegOffset; + IMG_BOOL bLastFrame; +}; + +struct PVRSRV_BRIDGE_OUT_ENUMDEVICE { + enum PVRSRV_ERROR eError; + u32 ui32NumDevices; + struct PVRSRV_DEVICE_IDENTIFIER asDeviceIdentifier[PVRSRV_MAX_DEVICES]; +}; + +struct PVRSRV_BRIDGE_OUT_ACQUIRE_DEVICEINFO { + + enum PVRSRV_ERROR eError; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_OUT_ENUMCLASS { + enum PVRSRV_ERROR eError; + u32 ui32NumDevices; + u32 ui32DevID[PVRSRV_MAX_DEVICES]; +}; + +struct PVRSRV_BRIDGE_IN_OPEN_DISPCLASS_DEVICE { + u32 ui32BridgeFlags; + u32 ui32DeviceID; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_OUT_OPEN_DISPCLASS_DEVICE { + enum PVRSRV_ERROR eError; + void *hDeviceKM; +}; + +struct PVRSRV_BRIDGE_IN_WRAP_EXT_MEMORY { + u32 ui32BridgeFlags; + void *hDevCookie; + void *hDevMemContext; + void *pvLinAddr; + u32 ui32ByteSize; + u32 ui32PageOffset; + IMG_BOOL bPhysContig; + u32 ui32NumPageTableEntries; + struct IMG_SYS_PHYADDR __user *psSysPAddr; +}; + +struct PVRSRV_BRIDGE_OUT_WRAP_EXT_MEMORY { + enum PVRSRV_ERROR eError; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; +}; + +struct PVRSRV_BRIDGE_IN_UNWRAP_EXT_MEMORY { + u32 ui32BridgeFlags; + void *hKernelMemInfo; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; + +}; + +#define PVRSRV_MAX_DC_DISPLAY_FORMATS 10 +#define PVRSRV_MAX_DC_DISPLAY_DIMENSIONS 10 +#define PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS 4 +#define PVRSRV_MAX_DC_CLIP_RECTS 32 + +struct PVRSRV_BRIDGE_OUT_ENUM_DISPCLASS_FORMATS { + enum PVRSRV_ERROR eError; + u32 ui32Count; + struct DISPLAY_FORMAT asFormat[PVRSRV_MAX_DC_DISPLAY_FORMATS]; +}; + +struct PVRSRV_BRIDGE_IN_ENUM_DISPCLASS_DIMS { + u32 ui32BridgeFlags; + void *hDeviceKM; + struct DISPLAY_FORMAT sFormat; +}; + +struct PVRSRV_BRIDGE_OUT_ENUM_DISPCLASS_DIMS { + enum PVRSRV_ERROR eError; + u32 ui32Count; + struct DISPLAY_DIMS asDim[PVRSRV_MAX_DC_DISPLAY_DIMENSIONS]; +}; + +struct PVRSRV_BRIDGE_OUT_GET_DISPCLASS_INFO { + enum PVRSRV_ERROR eError; + struct DISPLAY_INFO sDisplayInfo; +}; + +struct PVRSRV_BRIDGE_OUT_GET_DISPCLASS_SYSBUFFER { + enum PVRSRV_ERROR eError; + void *hBuffer; +}; + +struct PVRSRV_BRIDGE_IN_CREATE_DISPCLASS_SWAPCHAIN { + u32 ui32BridgeFlags; + void *hDeviceKM; + u32 ui32Flags; + struct DISPLAY_SURF_ATTRIBUTES sDstSurfAttrib; + struct DISPLAY_SURF_ATTRIBUTES sSrcSurfAttrib; + u32 ui32BufferCount; + u32 ui32OEMFlags; + u32 ui32SwapChainID; +}; + +struct PVRSRV_BRIDGE_OUT_CREATE_DISPCLASS_SWAPCHAIN { + enum PVRSRV_ERROR eError; + void *hSwapChain; + u32 ui32SwapChainID; +}; + +struct PVRSRV_BRIDGE_IN_DESTROY_DISPCLASS_SWAPCHAIN { + u32 ui32BridgeFlags; + void *hDeviceKM; + void *hSwapChain; +}; + +struct PVRSRV_BRIDGE_IN_SET_DISPCLASS_RECT { + u32 ui32BridgeFlags; + void *hDeviceKM; + void *hSwapChain; + struct IMG_RECT sRect; +}; + +struct PVRSRV_BRIDGE_IN_SET_DISPCLASS_COLOURKEY { + u32 ui32BridgeFlags; + void *hDeviceKM; + void *hSwapChain; + u32 ui32CKColour; +}; + +struct PVRSRV_BRIDGE_IN_GET_DISPCLASS_BUFFERS { + u32 ui32BridgeFlags; + void *hDeviceKM; + void *hSwapChain; +}; + +struct PVRSRV_BRIDGE_OUT_GET_DISPCLASS_BUFFERS { + enum PVRSRV_ERROR eError; + u32 ui32BufferCount; + void *ahBuffer[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS]; +}; + +struct PVRSRV_BRIDGE_IN_SWAP_DISPCLASS_TO_BUFFER { + u32 ui32BridgeFlags; + void *hDeviceKM; + void *hBuffer; + u32 ui32SwapInterval; + void *hPrivateTag; + u32 ui32ClipRectCount; + struct IMG_RECT sClipRect[PVRSRV_MAX_DC_CLIP_RECTS]; +}; + +struct PVRSRV_BRIDGE_IN_SWAP_DISPCLASS_TO_SYSTEM { + u32 ui32BridgeFlags; + void *hDeviceKM; + void *hSwapChain; +}; + +struct PVRSRV_BRIDGE_IN_OPEN_BUFFERCLASS_DEVICE { + u32 ui32BridgeFlags; + u32 ui32DeviceID; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_OUT_OPEN_BUFFERCLASS_DEVICE { + enum PVRSRV_ERROR eError; + void *hDeviceKM; +}; + +struct PVRSRV_BRIDGE_OUT_GET_BUFFERCLASS_INFO { + enum PVRSRV_ERROR eError; + struct BUFFER_INFO sBufferInfo; +}; + +struct PVRSRV_BRIDGE_IN_GET_BUFFERCLASS_BUFFER { + u32 ui32BridgeFlags; + void *hDeviceKM; + u32 ui32BufferIndex; +}; + +struct PVRSRV_BRIDGE_OUT_GET_BUFFERCLASS_BUFFER { + enum PVRSRV_ERROR eError; + void *hBuffer; +}; + +struct PVRSRV_BRIDGE_OUT_GET_DEVMEM_HEAPINFO { + enum PVRSRV_ERROR eError; + u32 ui32ClientHeapCount; + struct PVRSRV_HEAP_INFO sHeapInfo[PVRSRV_MAX_CLIENT_HEAPS]; +}; + +struct PVRSRV_BRIDGE_OUT_CREATE_DEVMEMCONTEXT { + enum PVRSRV_ERROR eError; + void *hDevMemContext; + u32 ui32ClientHeapCount; + struct PVRSRV_HEAP_INFO sHeapInfo[PVRSRV_MAX_CLIENT_HEAPS]; +}; + +struct PVRSRV_BRIDGE_OUT_CREATE_DEVMEMHEAP { + enum PVRSRV_ERROR eError; + void *hDevMemHeap; +}; + +struct PVRSRV_BRIDGE_OUT_ALLOCDEVICEMEM { + enum PVRSRV_ERROR eError; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; + +}; + +struct PVRSRV_BRIDGE_OUT_EXPORTDEVICEMEM { + enum PVRSRV_ERROR eError; + void *hMemInfo; + +}; + +struct PVRSRV_BRIDGE_OUT_MAPMEMINFOTOUSER { + enum PVRSRV_ERROR eError; + void *pvLinAddr; + void *hMappingInfo; +}; + +struct PVRSRV_BRIDGE_OUT_GETFREEDEVICEMEM { + enum PVRSRV_ERROR eError; + u32 ui32Total; + u32 ui32Free; + u32 ui32LargestBlock; +}; + +#include "pvrmmap.h" +struct PVRSRV_BRIDGE_OUT_MHANDLE_TO_MMAP_DATA { + enum PVRSRV_ERROR eError; + u32 ui32MMapOffset; + u32 ui32ByteOffset; + u32 ui32RealByteSize; + u32 ui32UserVAddr; +}; + +struct PVRSRV_BRIDGE_OUT_RELEASE_MMAP_DATA { + enum PVRSRV_ERROR eError; + IMG_BOOL bMUnmap; + u32 ui32UserVAddr; + u32 ui32RealByteSize; +}; + +struct PVRSRV_BRIDGE_IN_GET_MISC_INFO { + u32 ui32BridgeFlags; + struct PVRSRV_MISC_INFO sMiscInfo; +}; + +struct PVRSRV_BRIDGE_OUT_GET_MISC_INFO { + enum PVRSRV_ERROR eError; + struct PVRSRV_MISC_INFO sMiscInfo; +}; + +struct PVRSRV_BRIDGE_IN_RELEASE_MISC_INFO { + u32 ui32BridgeFlags; + struct PVRSRV_MISC_INFO sMiscInfo; +}; + +struct PVRSRV_BRIDGE_OUT_RELEASE_MISC_INFO { + enum PVRSRV_ERROR eError; + struct PVRSRV_MISC_INFO sMiscInfo; +}; + +struct PVRSRV_BRIDGE_OUT_PDUMP_ISCAPTURING { + enum PVRSRV_ERROR eError; + IMG_BOOL bIsCapturing; +}; + +struct PVRSRV_BRIDGE_IN_GET_FB_STATS { + u32 ui32BridgeFlags; + u32 ui32Total; + u32 ui32Available; +}; + +struct PVRSRV_BRIDGE_IN_MAPPHYSTOUSERSPACE { + u32 ui32BridgeFlags; + void *hDevCookie; + struct IMG_SYS_PHYADDR sSysPhysAddr; + u32 uiSizeInBytes; +}; + +struct PVRSRV_BRIDGE_OUT_MAPPHYSTOUSERSPACE { + void *pvUserAddr; + u32 uiActualSize; + void *pvProcess; +}; + +struct PVRSRV_BRIDGE_IN_UNMAPPHYSTOUSERSPACE { + u32 ui32BridgeFlags; + void *hDevCookie; + void *pvUserAddr; + void *pvProcess; +}; + +struct PVRSRV_BRIDGE_OUT_GETPHYSTOUSERSPACEMAP { + void **ppvTbl; + u32 uiTblSize; +}; + +struct PVRSRV_BRIDGE_IN_REGISTER_SIM_PROCESS { + u32 ui32BridgeFlags; + void *hDevCookie; + void *pvProcess; +}; + +struct PVRSRV_BRIDGE_OUT_REGISTER_SIM_PROCESS { + struct IMG_SYS_PHYADDR sRegsPhysBase; + void *pvRegsBase; + void *pvProcess; + u32 ulNoOfEntries; + void *pvTblLinAddr; +}; + +struct PVRSRV_BRIDGE_IN_UNREGISTER_SIM_PROCESS { + u32 ui32BridgeFlags; + void *hDevCookie; + void *pvProcess; + void *pvRegsBase; +}; + +struct PVRSRV_BRIDGE_IN_PROCESS_SIMISR_EVENT { + u32 ui32BridgeFlags; + void *hDevCookie; + u32 ui32StatusAndMask; + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_INITSRV_DISCONNECT { + u32 ui32BridgeFlags; + IMG_BOOL bInitSuccesful; +}; + +struct PVRSRV_BRIDGE_IN_ALLOC_SHARED_SYS_MEM { + u32 ui32BridgeFlags; + u32 ui32Flags; + u32 ui32Size; +}; + +struct PVRSRV_BRIDGE_OUT_ALLOC_SHARED_SYS_MEM { + enum PVRSRV_ERROR eError; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; +}; + +struct PVRSRV_BRIDGE_IN_FREE_SHARED_SYS_MEM { + u32 ui32BridgeFlags; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; +}; + +struct PVRSRV_BRIDGE_OUT_FREE_SHARED_SYS_MEM { + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_MAP_MEMINFO_MEM { + u32 ui32BridgeFlags; + void *hKernelMemInfo; +}; + +struct PVRSRV_BRIDGE_OUT_MAP_MEMINFO_MEM { + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; + struct PVRSRV_CLIENT_SYNC_INFO sClientSyncInfo; + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_UNMAP_MEMINFO_MEM { + u32 ui32BridgeFlags; + struct PVRSRV_CLIENT_MEM_INFO sClientMemInfo; +}; + +struct PVRSRV_BRIDGE_OUT_UNMAP_MEMINFO_MEM { + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_GETMMU_PD_DEVPADDR { + u32 ui32BridgeFlags; + void *hDevMemContext; +}; + +struct PVRSRV_BRIDGE_OUT_GETMMU_PD_DEVPADDR { + struct IMG_DEV_PHYADDR sPDDevPAddr; + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_EVENT_OBJECT_WAIT { + u32 ui32BridgeFlags; + void *hOSEventKM; +}; + +struct PVRSRV_BRIDGE_IN_EVENT_OBJECT_OPEN { + struct PVRSRV_EVENTOBJECT sEventObject; +}; + +struct PVRSRV_BRIDGE_OUT_EVENT_OBJECT_OPEN { + void *hOSEvent; + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_EVENT_OBJECT_CLOSE { + struct PVRSRV_EVENTOBJECT sEventObject; + void *hOSEventKM; +}; + +struct PVRSRV_BRIDGE_IN_MODIFY_SYNC_OPS { + u32 ui32BridgeFlags; + void *hKernelSyncInfo; + u32 ui32ModifyFlags; + +}; + +struct PVRSRV_BRIDGE_OUT_MODIFY_SYNC_OPS { + enum PVRSRV_ERROR eError; + u32 ui32ReadOpsPending; + u32 ui32ReadOpsComplete; + u32 ui32WriteOpsPending; + u32 ui32WriteOpsComplete; + +}; + +#endif diff --git a/drivers/gpu/pvr/pvr_bridge_k.c b/drivers/gpu/pvr/pvr_bridge_k.c new file mode 100644 index 00000000000..4cbc04167d7 --- /dev/null +++ b/drivers/gpu/pvr/pvr_bridge_k.c @@ -0,0 +1,241 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/sched.h> + +#include "img_defs.h" +#include "services.h" +#include "pvr_bridge.h" +#include "pvr_bridge_km.h" +#include "perproc.h" +#include "syscommon.h" +#include "pvr_debug.h" +#include "proc.h" +#include "private_data.h" + +#include "sgx_bridge.h" + +#include "bridged_pvr_bridge.h" + +/* Global driver lock protecting all HW and SW state tracking objects. */ +DEFINE_MUTEX(gPVRSRVLock); +static int pvr_dev_locked; +static DECLARE_WAIT_QUEUE_HEAD(pvr_dev_wq); +int pvr_disabled; + +/* + * The pvr_dvfs_* interface is needed to suppress a lockdep warning in + * the following situation during a clock rate change: + * On the CLK_PRE_RATE_CHANGE: + * 1. lock A <- __blocking_notifier_call_chain:nh->rwsem + * 2. lock B <- vdd2_pre_post_func:gPVRSRVLock + * 3. unlock A + * + * On the CLK_POST_RATE_CHANGE/CLK_ABORT_RATE_CHANGE: + * 4. lock A + * 5. unlock B + * 6. unlock A + * + * The above has an ABA lock pattern which triggers the warning. This can't + * lead to a dead lock though since at 3. we always release A, before it's + * again acquired at 4. To avoid the warning use a wait queue based approach + * so that we can unlock B before 3. + */ +void pvr_dev_lock(void) +{ + while (cmpxchg(&pvr_dev_locked, 0, 1)) { + DEFINE_WAIT(pvr_dev_wait); + prepare_to_wait(&pvr_dev_wq, &pvr_dev_wait, + TASK_UNINTERRUPTIBLE); + if (pvr_dev_locked) + schedule(); + finish_wait(&pvr_dev_wq, &pvr_dev_wait); + } +} + +void pvr_dev_unlock(void) +{ + BUG_ON(!pvr_dev_locked); + pvr_dev_locked = 0; + wake_up(&pvr_dev_wq); +} + +#if defined(DEBUG_BRIDGE_KM) +static off_t printLinuxBridgeStats(char *buffer, size_t size, off_t off); +#endif + +enum PVRSRV_ERROR LinuxBridgeInit(void) +{ +#if defined(DEBUG_BRIDGE_KM) + { + int iStatus; + iStatus = + CreateProcReadEntry("bridge_stats", printLinuxBridgeStats); + if (iStatus != 0) + return PVRSRV_ERROR_OUT_OF_MEMORY; + } +#endif + return CommonBridgeInit(); +} + +void LinuxBridgeDeInit(void) +{ +#if defined(DEBUG_BRIDGE_KM) + RemoveProcEntry("bridge_stats"); +#endif +} + +#if defined(DEBUG_BRIDGE_KM) +static off_t printLinuxBridgeStats(char *buffer, size_t count, off_t off) +{ + struct PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *psEntry; + off_t Ret; + + pvr_lock(); + + if (!off) { + if (count < 500) { + Ret = 0; + goto unlock_and_return; + } + Ret = printAppend(buffer, count, 0, + "Total ioctl call count = %u\n" + "Total number of bytes copied via copy_from_user = %u\n" + "Total number of bytes copied via copy_to_user = %u\n" + "Total number of bytes copied via copy_*_user = %u\n\n" + "%-45s | %-40s | %10s | %20s | %10s\n", + g_BridgeGlobalStats.ui32IOCTLCount, + g_BridgeGlobalStats.ui32TotalCopyFromUserBytes, + g_BridgeGlobalStats.ui32TotalCopyToUserBytes, + g_BridgeGlobalStats.ui32TotalCopyFromUserBytes + + g_BridgeGlobalStats.ui32TotalCopyToUserBytes, + "Bridge Name", "Wrapper Function", + "Call Count", "copy_from_user Bytes", + "copy_to_user Bytes"); + + goto unlock_and_return; + } + + if (off > BRIDGE_DISPATCH_TABLE_ENTRY_COUNT) { + Ret = END_OF_FILE; + goto unlock_and_return; + } + + if (count < 300) { + Ret = 0; + goto unlock_and_return; + } + + psEntry = &g_BridgeDispatchTable[off - 1]; + Ret = printAppend(buffer, count, 0, + "%-45s %-40s %-10u %-20u %-10u\n", + psEntry->pszIOCName, + psEntry->pszFunctionName, + psEntry->ui32CallCount, + psEntry->ui32CopyFromUserTotalBytes, + psEntry->ui32CopyToUserTotalBytes); + +unlock_and_return: + pvr_unlock(); + + return Ret; +} +#endif + +long PVRSRV_BridgeDispatchKM(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + u32 ui32BridgeID = PVRSRV_GET_BRIDGE_ID(cmd); + struct PVRSRV_BRIDGE_PACKAGE __user *psBridgePackageUM = + (struct PVRSRV_BRIDGE_PACKAGE __user *)arg; + struct PVRSRV_BRIDGE_PACKAGE sBridgePackageKM; + u32 ui32PID = OSGetCurrentProcessIDKM(); + struct PVRSRV_PER_PROCESS_DATA *psPerProc; + int err = -EFAULT; + + pvr_lock(); + + if (pvr_is_disabled()) { + pvr_unlock(); + return -ENODEV; + } + + if (!OSAccessOK(PVR_VERIFY_WRITE, psBridgePackageUM, + sizeof(struct PVRSRV_BRIDGE_PACKAGE))) { + PVR_DPF(PVR_DBG_ERROR, + "%s: Received invalid pointer to function arguments", + __func__); + + goto unlock_and_return; + } + + if (OSCopyFromUser(NULL, &sBridgePackageKM, psBridgePackageUM, + sizeof(struct PVRSRV_BRIDGE_PACKAGE)) != PVRSRV_OK) + goto unlock_and_return; + + if (ui32BridgeID != + PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_CONNECT_SERVICES)) { + enum PVRSRV_ERROR eError; + + eError = PVRSRVLookupHandle(KERNEL_HANDLE_BASE, + (void **)&psPerProc, + sBridgePackageKM.hKernelServices, + PVRSRV_HANDLE_TYPE_PERPROC_DATA); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "%s: Invalid kernel services handle (%d)", + __func__, eError); + goto unlock_and_return; + } + + if (psPerProc->ui32PID != ui32PID) { + PVR_DPF(PVR_DBG_ERROR, + "%s: Process %d tried to access data " + "belonging to process %d", __func__, + ui32PID, psPerProc->ui32PID); + goto unlock_and_return; + } + } else { + psPerProc = PVRSRVPerProcessData(ui32PID); + if (psPerProc == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRV_BridgeDispatchKM: " + "Couldn't create per-process data area"); + goto unlock_and_return; + } + } + + sBridgePackageKM.ui32BridgeID = PVRSRV_GET_BRIDGE_ID( + sBridgePackageKM.ui32BridgeID); + + err = BridgedDispatchKM(filp, psPerProc, &sBridgePackageKM); + if (err != PVRSRV_OK) + goto unlock_and_return; + +unlock_and_return: + pvr_unlock(); + + return err; +} diff --git a/drivers/gpu/pvr/pvr_bridge_km.h b/drivers/gpu/pvr/pvr_bridge_km.h new file mode 100644 index 00000000000..55392f2d574 --- /dev/null +++ b/drivers/gpu/pvr/pvr_bridge_km.h @@ -0,0 +1,222 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __PVR_BRIDGE_KM_H_ +#define __PVR_BRIDGE_KM_H_ + +#include <linux/fs.h> /* for struct file */ +#include <linux/wait.h> +#include <linux/sched.h> + +#include "pvr_bridge.h" +#include "perproc.h" + +extern void pvr_dev_lock(void); +extern void pvr_dev_unlock(void); +extern struct mutex gPVRSRVLock; +extern int pvr_disabled; + +static inline void pvr_lock(void) +{ + mutex_lock(&gPVRSRVLock); +} + +static inline void pvr_unlock(void) +{ + mutex_unlock(&gPVRSRVLock); +} + +static inline int pvr_is_locked(void) +{ + return mutex_is_locked(&gPVRSRVLock); +} + +static inline void pvr_disable(void) +{ + pvr_disabled = 1; +} + +static inline int pvr_is_disabled(void) +{ + return unlikely(pvr_disabled); +} + +enum PVRSRV_ERROR LinuxBridgeInit(void); +void LinuxBridgeDeInit(void); + +enum PVRSRV_ERROR PVRSRVEnumerateDevicesKM(u32 *pui32NumDevices, + struct PVRSRV_DEVICE_IDENTIFIER *psDevIdList); + +enum PVRSRV_ERROR PVRSRVAcquireDeviceDataKM(u32 uiDevIndex, + enum PVRSRV_DEVICE_TYPE eDeviceType, + void **phDevCookie); + +enum PVRSRV_ERROR PVRSRVCreateCommandQueueKM(u32 ui32QueueSize, + struct PVRSRV_QUEUE_INFO **ppsQueueInfo); + +enum PVRSRV_ERROR PVRSRVDestroyCommandQueueKM( + struct PVRSRV_QUEUE_INFO *psQueueInfo); + +enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapsKM(void *hDevCookie, + struct PVRSRV_HEAP_INFO *psHeapInfo); + +enum PVRSRV_ERROR PVRSRVCreateDeviceMemContextKM(void *hDevCookie, + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void **phDevMemContext, u32 *pui32ClientHeapCount, + struct PVRSRV_HEAP_INFO *psHeapInfo, IMG_BOOL *pbCreated, + IMG_BOOL *pbShared); + +enum PVRSRV_ERROR PVRSRVDestroyDeviceMemContextKM(void *hDevCookie, + void *hDevMemContext, IMG_BOOL *pbCreated); + +enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapInfoKM(void *hDevCookie, + void *hDevMemContext, u32 *pui32ClientHeapCount, + struct PVRSRV_HEAP_INFO *psHeapInfo, IMG_BOOL *pbShared); + +enum PVRSRV_ERROR PVRSRVAllocDeviceMemKM(void *hDevCookie, + struct PVRSRV_PER_PROCESS_DATA *psPerProc, void *hDevMemHeap, + u32 ui32Flags, u32 ui32Size, u32 ui32Alignment, + struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo); + +enum PVRSRV_ERROR PVRSRVFreeDeviceMemKM(void *hDevCookie, + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo); + +enum PVRSRV_ERROR PVRSRVDissociateDeviceMemKM(void *hDevCookie, + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo); + +enum PVRSRV_ERROR PVRSRVReserveDeviceVirtualMemKM(void *hDevMemHeap, + struct IMG_DEV_VIRTADDR *psDevVAddr, u32 ui32Size, + u32 ui32Alignment, struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo); + +enum PVRSRV_ERROR PVRSRVFreeDeviceVirtualMemKM( + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo); + +enum PVRSRV_ERROR PVRSRVMapDeviceMemoryKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo, + void *hDstDevMemHeap, + struct PVRSRV_KERNEL_MEM_INFO **ppsDstMemInfo); + +enum PVRSRV_ERROR PVRSRVUnmapDeviceMemoryKM( + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo); + +enum PVRSRV_ERROR PVRSRVWrapExtMemoryKM(void *hDevCookie, + struct PVRSRV_PER_PROCESS_DATA *psPerProc, void *hDevMemContext, + u32 ui32ByteSize, u32 ui32PageOffset, IMG_BOOL bPhysContig, + struct IMG_SYS_PHYADDR *psSysAddr, void *pvLinAddr, + struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo); + +enum PVRSRV_ERROR PVRSRVUnwrapExtMemoryKM(struct PVRSRV_KERNEL_MEM_INFO + *psMemInfo); + +enum PVRSRV_ERROR PVRSRVEnumerateDCKM(enum PVRSRV_DEVICE_CLASS DeviceClass, + u32 *pui32DevCount, u32 *pui32DevID); + +enum PVRSRV_ERROR PVRSRVOpenDCDeviceKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + u32 ui32DeviceID, void *hDevCookie, void **phDeviceKM); + +enum PVRSRV_ERROR PVRSRVCloseDCDeviceKM(void *hDeviceKM, + IMG_BOOL bResManCallback); + +enum PVRSRV_ERROR PVRSRVEnumDCFormatsKM(void *hDeviceKM, u32 *pui32Count, + struct DISPLAY_FORMAT *psFormat); + +enum PVRSRV_ERROR PVRSRVEnumDCDimsKM(void *hDeviceKM, + struct DISPLAY_FORMAT *psFormat, u32 *pui32Count, + struct DISPLAY_DIMS *psDim); + +enum PVRSRV_ERROR PVRSRVGetDCSystemBufferKM(void *hDeviceKM, void **phBuffer); + +enum PVRSRV_ERROR PVRSRVGetDCInfoKM(void *hDeviceKM, + struct DISPLAY_INFO *psDisplayInfo); + +enum PVRSRV_ERROR PVRSRVCreateDCSwapChainKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, void *hDeviceKM, + u32 ui32Flags, struct DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib, + struct DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib, + u32 ui32BufferCount, u32 ui32OEMFlags, void **phSwapChain, + u32 *pui32SwapChainID); + +enum PVRSRV_ERROR PVRSRVDestroyDCSwapChainKM(void *hSwapChain); +enum PVRSRV_ERROR PVRSRVSetDCDstRectKM(void *hDeviceKM, void *hSwapChain, + struct IMG_RECT *psRect); +enum PVRSRV_ERROR PVRSRVSetDCSrcRectKM(void *hDeviceKM, void *hSwapChain, + struct IMG_RECT *psRect); +enum PVRSRV_ERROR PVRSRVSetDCDstColourKeyKM(void *hDeviceKM, void *hSwapChain, + u32 ui32CKColour); +enum PVRSRV_ERROR PVRSRVSetDCSrcColourKeyKM(void *hDeviceKM, void *hSwapChain, + u32 ui32CKColour); +enum PVRSRV_ERROR PVRSRVGetDCBuffersKM(void *hDeviceKM, void *hSwapChain, + u32 *pui32BufferCount, void **phBuffer); +enum PVRSRV_ERROR PVRSRVSwapToDCBufferKM(void *hDeviceKM, void *hBuffer, + u32 ui32SwapInterval, void *hPrivateTag, + u32 ui32ClipRectCount, struct IMG_RECT *psClipRect); +enum PVRSRV_ERROR PVRSRVSwapToDCSystemKM(void *hDeviceKM, void *hSwapChain); + +enum PVRSRV_ERROR PVRSRVOpenBCDeviceKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + u32 ui32DeviceID, void *hDevCookie, void **phDeviceKM); +enum PVRSRV_ERROR PVRSRVCloseBCDeviceKM(void *hDeviceKM, + IMG_BOOL bResManCallback); + +enum PVRSRV_ERROR PVRSRVGetBCInfoKM(void *hDeviceKM, + struct BUFFER_INFO *psBufferInfo); +enum PVRSRV_ERROR PVRSRVGetBCBufferKM(void *hDeviceKM, + u32 ui32BufferIndex, void **phBuffer); + +enum PVRSRV_ERROR PVRSRVMapDeviceClassMemoryKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, void *hDevMemContext, + void *hDeviceClassBuffer, + struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo, void **phOSMapInfo); + +enum PVRSRV_ERROR PVRSRVUnmapDeviceClassMemoryKM( + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo); + +enum PVRSRV_ERROR PVRSRVGetFreeDeviceMemKM(u32 ui32Flags, u32 *pui32Total, + u32 *pui32Free, u32 *pui32LargestBlock); +enum PVRSRV_ERROR PVRSRVAllocSyncInfoKM(void *hDevCookie, void *hDevMemContext, + struct PVRSRV_KERNEL_SYNC_INFO **ppsKernelSyncInfo); +enum PVRSRV_ERROR PVRSRVFreeSyncInfoKM( + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo); + +enum PVRSRV_ERROR PVRSRVGetMiscInfoKM(struct PVRSRV_MISC_INFO *psMiscInfo); + +enum PVRSRV_ERROR PVRSRVGetFBStatsKM(u32 *pui32Total, u32 *pui32Available); + +enum PVRSRV_ERROR PVRSRVAllocSharedSysMemoryKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, u32 ui32Flags, + u32 ui32Size, struct PVRSRV_KERNEL_MEM_INFO **ppsKernelMemInfo); + +enum PVRSRV_ERROR PVRSRVFreeSharedSysMemoryKM( + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo); + +enum PVRSRV_ERROR PVRSRVDissociateMemFromResmanKM( + struct PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo); + +long PVRSRV_BridgeDispatchKM(struct file *, unsigned, unsigned long); + +#endif diff --git a/drivers/gpu/pvr/pvr_debug.c b/drivers/gpu/pvr/pvr_debug.c new file mode 100644 index 00000000000..0ac1322a700 --- /dev/null +++ b/drivers/gpu/pvr/pvr_debug.c @@ -0,0 +1,358 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/kernel.h> +#include <linux/hardirq.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/tty.h> +#include <linux/debugfs.h> +#include <stdarg.h> +#include "img_types.h" +#include "servicesext.h" +#include "pvr_debug.h" +#include "proc.h" +#include "syscommon.h" +#include "sgxinfokm.h" +#include "sgxutils.h" +#include "pvr_bridge_km.h" + +u32 gPVRDebugLevel = DBGPRIV_WARNING; + +#define PVR_MAX_MSG_LEN PVR_MAX_DEBUG_MESSAGE_LEN + +static char gszBufferNonIRQ[PVR_MAX_MSG_LEN + 1]; + +static char gszBufferIRQ[PVR_MAX_MSG_LEN + 1]; +static struct mutex gsDebugMutexNonIRQ; +static DEFINE_SPINLOCK(gsDebugLockIRQ); +#define USE_SPIN_LOCK (in_interrupt() || !preemptible()) +static inline void GetBufferLock(unsigned long *pulLockFlags) +{ + if (USE_SPIN_LOCK) + spin_lock_irqsave(&gsDebugLockIRQ, *pulLockFlags); + else + mutex_lock(&gsDebugMutexNonIRQ); +} + +static inline void ReleaseBufferLock(unsigned long ulLockFlags) +{ + if (USE_SPIN_LOCK) + spin_unlock_irqrestore(&gsDebugLockIRQ, ulLockFlags); + else + mutex_unlock(&gsDebugMutexNonIRQ); +} + +static inline void SelectBuffer(char **ppszBuf, u32 *pui32BufSiz) +{ + if (USE_SPIN_LOCK) { + *ppszBuf = gszBufferIRQ; + *pui32BufSiz = sizeof(gszBufferIRQ); + } else { + *ppszBuf = gszBufferNonIRQ; + *pui32BufSiz = sizeof(gszBufferNonIRQ); + } +} + +static IMG_BOOL VBAppend(char *pszBuf, u32 ui32BufSiz, const char *pszFormat, + va_list VArgs) +{ + u32 ui32Used; + u32 ui32Space; + s32 i32Len; + ui32Used = strlen(pszBuf); + BUG_ON(ui32Used >= ui32BufSiz); + ui32Space = ui32BufSiz - ui32Used; + i32Len = vsnprintf(&pszBuf[ui32Used], ui32Space, pszFormat, VArgs); + pszBuf[ui32BufSiz - 1] = 0; + return i32Len < 0 || i32Len >= ui32Space; +} + +static IMG_BOOL BAppend(char *pszBuf, u32 ui32BufSiz, const char *pszFormat, + ...) +{ + va_list VArgs; + IMG_BOOL bTrunc; + + va_start(VArgs, pszFormat); + + bTrunc = VBAppend(pszBuf, ui32BufSiz, pszFormat, VArgs); + + va_end(VArgs); + + return bTrunc; +} + +void PVRSRVDebugPrintf(u32 ui32DebugLevel, + const char *pszFileName, + u32 ui32Line, const char *pszFormat, ...) +{ + IMG_BOOL bTrace, bDebug; + char *pszLeafName; + + pszLeafName = (char *)strrchr(pszFileName, '\\'); + + if (pszLeafName) + pszFileName = pszLeafName; + + bTrace = gPVRDebugLevel & ui32DebugLevel & DBGPRIV_CALLTRACE; + bDebug = ((gPVRDebugLevel & DBGPRIV_ALLLEVELS) >= ui32DebugLevel); + + if (bTrace || bDebug) { + va_list vaArgs; + unsigned long ulLockFlags = 0; /* suppress gc warning */ + char *pszBuf; + u32 ui32BufSiz; + + SelectBuffer(&pszBuf, &ui32BufSiz); + va_start(vaArgs, pszFormat); + + GetBufferLock(&ulLockFlags); + + if (bDebug) { + switch (ui32DebugLevel) { + case DBGPRIV_FATAL: + strncpy(pszBuf, "PVR_K:(Fatal): ", + (ui32BufSiz - 1)); + break; + case DBGPRIV_ERROR: + strncpy(pszBuf, "PVR_K:(Error): ", + (ui32BufSiz - 1)); + break; + case DBGPRIV_WARNING: + strncpy(pszBuf, "PVR_K:(Warning): ", + (ui32BufSiz - 1)); + break; + case DBGPRIV_MESSAGE: + strncpy(pszBuf, "PVR_K:(Message): ", + (ui32BufSiz - 1)); + break; + case DBGPRIV_VERBOSE: + strncpy(pszBuf, "PVR_K:(Verbose): ", + (ui32BufSiz - 1)); + break; + default: + strncpy(pszBuf, + "PVR_K:(Unknown message level)", + (ui32BufSiz - 1)); + break; + } + } else { + strncpy(pszBuf, "PVR_K: ", (ui32BufSiz - 1)); + } + + if (VBAppend(pszBuf, ui32BufSiz, pszFormat, vaArgs)) { + printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", + pszBuf); + } else { + if (!bTrace) { + if (BAppend + (pszBuf, ui32BufSiz, " [%lu, %s]", ui32Line, + pszFileName)) + printk(KERN_INFO + "PVR_K:(Message Truncated): %s\n", + pszBuf); + else + printk(KERN_INFO "%s\n", pszBuf); + } + } + + ReleaseBufferLock(ulLockFlags); + va_end(vaArgs); + } +} + +void PVRSRVDebugAssertFail(const char *pszFile, u32 uLine) +{ + PVRSRVDebugPrintf(DBGPRIV_FATAL, pszFile, uLine, + "Debug assertion failed!"); + BUG(); +} + +void PVRSRVTrace(const char *pszFormat, ...) +{ + va_list VArgs; + unsigned long ulLockFlags = 0; /* suppress gcc warning */ + char *pszBuf; + u32 ui32BufSiz; + + SelectBuffer(&pszBuf, &ui32BufSiz); + + va_start(VArgs, pszFormat); + GetBufferLock(&ulLockFlags); + strncpy(pszBuf, "PVR: ", (ui32BufSiz - 1)); + if (VBAppend(pszBuf, ui32BufSiz, pszFormat, VArgs)) + printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", pszBuf); + else + printk(KERN_INFO "%s\n", pszBuf); + ReleaseBufferLock(ulLockFlags); + va_end(VArgs); +} + +void PVRDebugSetLevel(u32 uDebugLevel) +{ + printk(KERN_INFO "PVR: Setting Debug Level = 0x%x\n", + (unsigned)uDebugLevel); + + gPVRDebugLevel = uDebugLevel; +} + +int PVRDebugProcSetLevel(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ +#define _PROC_SET_BUFFER_SZ 2 + char data_buffer[_PROC_SET_BUFFER_SZ]; + + if (count != _PROC_SET_BUFFER_SZ) { + return -EINVAL; + } else { + if (copy_from_user(data_buffer, buffer, count)) + return -EINVAL; + if (data_buffer[count - 1] != '\n') + return -EINVAL; + PVRDebugSetLevel(data_buffer[0] - '0'); + } + return count; +} + +int PVRDebugProcGetLevel(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + if (off == 0) { + *start = (char *)1; + return printAppend(page, count, 0, "%u\n", gPVRDebugLevel); + } + *eof = 1; + return 0; +} + +#ifdef CONFIG_DEBUG_FS + +static struct dentry *debugfs_dentry; +static u32 pvr_reset; + +static struct PVRSRV_DEVICE_NODE *get_sgx_node(void) +{ + struct SYS_DATA *sysdata; + struct PVRSRV_DEVICE_NODE *node; + + if (SysAcquireData(&sysdata) != PVRSRV_OK) + return NULL; + + for (node = sysdata->psDeviceNodeList; node; node = node->psNext) + if (node->sDevId.eDeviceType == PVRSRV_DEVICE_TYPE_SGX) + break; + + return node; +} + +static int pvr_dbg_reset(void *data, u64 val) +{ + struct PVRSRV_DEVICE_NODE *node; + enum PVRSRV_ERROR err; + int r = 0; + + if (val != 1) + return 0; + + pvr_lock(); + + if (pvr_is_disabled()) { + r = -ENODEV; + goto exit; + } + + node = get_sgx_node(); + if (!node) { + r = -ENODEV; + goto exit; + } + + err = PVRSRVSetDevicePowerStateKM(node->sDevId.ui32DeviceIndex, + PVRSRV_POWER_STATE_D0); + if (err != PVRSRV_OK) { + r = -EIO; + goto exit; + } + + HWRecoveryResetSGX(node); + + SGXTestActivePowerEvent(node); +exit: + pvr_unlock(); + + return r; +} + +static int pvr_dbg_set(void *data, u64 val) +{ + u32 *var = data; + + if (var == &pvr_reset) + return pvr_dbg_reset(data, val); + + BUG(); +} + +DEFINE_SIMPLE_ATTRIBUTE(pvr_dbg_fops, NULL, pvr_dbg_set, "%llu\n"); + +static int pvr_init_debugfs(void) +{ + debugfs_dentry = debugfs_create_file("reset_sgx", S_IWUGO, NULL, + &pvr_reset, &pvr_dbg_fops); + + return debugfs_dentry ? 0 : -ENODEV; +} + +static void pvr_cleanup_debugfs(void) +{ + debugfs_remove(debugfs_dentry); +} + +#else /* !CONFIG_DEBUG_FS */ + +static int pvr_init_debugfs(void) +{ + return 0; +} + +static void pvr_cleanup_debugfs(void) { } + +#endif + +void pvr_dbg_init(void) +{ + mutex_init(&gsDebugMutexNonIRQ); + pvr_init_debugfs(); +} + +void pvr_dbg_cleanup(void) +{ + pvr_cleanup_debugfs(); +} + diff --git a/drivers/gpu/pvr/pvr_debug.h b/drivers/gpu/pvr/pvr_debug.h new file mode 100644 index 00000000000..c8c7e75b9b1 --- /dev/null +++ b/drivers/gpu/pvr/pvr_debug.h @@ -0,0 +1,110 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __PVR_DEBUG_H__ +#define __PVR_DEBUG_H__ + +#include <linux/fs.h> + +#include "img_types.h" + +#define PVR_MAX_DEBUG_MESSAGE_LEN 512 + +#define DBGPRIV_FATAL 0x01UL +#define DBGPRIV_ERROR 0x02UL +#define DBGPRIV_WARNING 0x04UL +#define DBGPRIV_MESSAGE 0x08UL +#define DBGPRIV_VERBOSE 0x10UL +#define DBGPRIV_CALLTRACE 0x20UL +#define DBGPRIV_ALLOC 0x40UL +#define DBGPRIV_ALLLEVELS (DBGPRIV_FATAL | DBGPRIV_ERROR | \ + DBGPRIV_WARNING | DBGPRIV_MESSAGE | \ + DBGPRIV_VERBOSE) + +#define PVR_DBG_FATAL DBGPRIV_FATAL +#define PVR_DBG_ERROR DBGPRIV_ERROR +#define PVR_DBG_WARNING DBGPRIV_WARNING +#define PVR_DBG_MESSAGE DBGPRIV_MESSAGE +#define PVR_DBG_VERBOSE DBGPRIV_VERBOSE +#define PVR_DBG_CALLTRACE DBGPRIV_CALLTRACE +#define PVR_DBG_ALLOC DBGPRIV_ALLOC + +#if defined(CONFIG_PVR_DEBUG) + +#define PVR_ASSERT(EXPR) \ + do { \ + if (!(EXPR)) \ + PVRSRVDebugAssertFail(__FILE__, __LINE__); \ + } while (0) + +#define PVR_DPF(level, fmt, ...) \ + PVRSRVDebugPrintf(level, __FILE__, __LINE__, fmt, ## __VA_ARGS__) + +#define PVR_TRACE(fmt, ...) \ + PVRSRVTrace(fmt, ##__VA_ARGS__) + +void PVRSRVDebugAssertFail(const char *pszFile, u32 ui32Line); +void PVRSRVDebugPrintf(u32 ui32DebugLevel, const char *pszFileName, + u32 ui32Line, const char *pszFormat, ...); +void PVRSRVTrace(const char *pszFormat, ...); + +int PVRDebugProcSetLevel(struct file *file, const char __user *buffer, + unsigned long count, void *data); +int PVRDebugProcGetLevel(char *page, char **start, off_t off, int count, + int *eof, void *data); +void PVRDebugSetLevel(u32 uDebugLevel); + +void pvr_dbg_init(void); +void pvr_dbg_cleanup(void); + +#define PVR_DBG_BREAK + +#else + +#if defined(TIMING) + +#define PVR_ASSERT(EXPR) do { } while (0) +#define PVR_DPF(level, fmt, ...) do { } while (0) +#define PVR_TRACE(fmt, ...) \ + PVRSRVTrace(fmt, ##__VA_ARGS__) +#define PVR_DBG_BREAK do { } while (0) + +void PVRSRVTrace(const char *pszFormat, ...); + +#else + +#define PVR_ASSERT(EXPR) do { } while (0) +#define PVR_DPF(level, fmt, ...) do { } while (0) +#define PVR_TRACE(fmt, ...) do { } while (0) +#define PVR_DBG_BREAK do { } while (0) + +static inline void pvr_dbg_init(void) {}; +static inline void pvr_dbg_cleanup(void) {}; + +#endif +#endif + +#endif diff --git a/drivers/gpu/pvr/pvr_events.c b/drivers/gpu/pvr/pvr_events.c new file mode 100644 index 00000000000..616fa0aeacb --- /dev/null +++ b/drivers/gpu/pvr/pvr_events.c @@ -0,0 +1,303 @@ + +#include "pvr_events.h" +#include "servicesint.h" +#include "sgx_bridge.h" + +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/time.h> +#include <linux/uaccess.h> +#include <linux/fs.h> +#include <linux/notifier.h> +#include <linux/slab.h> + +#include <video/omapdss.h> + +static spinlock_t event_lock; +static struct list_head sync_wait_list; +static struct list_head flip_wait_list; +static struct notifier_block dss_nb; + +static inline bool is_render_complete(const struct PVRSRV_SYNC_DATA *sync, + u32 write_ops_pending) +{ + return (int)sync->ui32WriteOpsComplete - (int)write_ops_pending >= 0; +} + +static void pvr_signal_sync_event(struct pvr_pending_sync_event *e, + const struct timeval *now) +{ + e->event.tv_sec = now->tv_sec; + e->event.tv_usec = now->tv_usec; + + list_move_tail(&e->base.link, &e->base.file_priv->event_list); + + wake_up_interruptible(&e->base.file_priv->event_wait); +} + +int pvr_sync_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv, + const struct PVRSRV_KERNEL_SYNC_INFO *sync_info, + u64 user_data) +{ + struct pvr_pending_sync_event *e; + struct timeval now; + unsigned long flags; + + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (e == NULL) + return -ENOMEM; + + e->event.base.type = PVR_EVENT_SYNC; + e->event.base.length = sizeof(e->event); + e->event.sync_info = sync_info; + e->event.user_data = user_data; + e->base.event = &e->event.base; + e->base.file_priv = priv; + e->base.destroy = (void (*)(struct pvr_pending_event *))kfree; + e->base.write_ops_pending = sync_info->psSyncData->ui32WriteOpsPending; + + do_gettimeofday(&now); + spin_lock_irqsave(&event_lock, flags); + + if (priv->event_space < sizeof(e->event)) { + spin_unlock_irqrestore(&event_lock, flags); + kfree(e); + return -ENOMEM; + } + + priv->event_space -= sizeof(e->event); + + list_add_tail(&e->base.link, &sync_wait_list); + if (is_render_complete(sync_info->psSyncData, + e->base.write_ops_pending)) + pvr_signal_sync_event(e, &now); + + spin_unlock_irqrestore(&event_lock, flags); + + return 0; +} + +static void pvr_signal_flip_event(struct pvr_pending_flip_event *e, + const struct timeval *now) +{ + e->event.tv_sec = now->tv_sec; + e->event.tv_usec = now->tv_usec; + + list_move_tail(&e->base.link, &e->base.file_priv->event_list); + + wake_up_interruptible(&e->base.file_priv->event_wait); +} + +int pvr_flip_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv, + unsigned int overlay, + enum pvr_sync_wait_seq_type type, u64 user_data) +{ + struct pvr_pending_flip_event *e; + struct timeval now; + unsigned long flags; + + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (e == NULL) + return -ENOMEM; + + switch (type) { + case _PVR_SYNC_WAIT_FLIP: + e->event.base.type = PVR_EVENT_FLIP; + e->dss_event = OMAP_DSS_NOTIFY_GO_OVL; + break; + case _PVR_SYNC_WAIT_UPDATE: + e->event.base.type = PVR_EVENT_UPDATE; + e->dss_event = OMAP_DSS_NOTIFY_UPDATE_OVL; + break; + default: + BUG(); + } + e->event.base.length = sizeof(e->event); + e->base.event = &e->event.base; + e->event.overlay = overlay; + e->event.user_data = user_data; + e->base.file_priv = priv; + e->base.destroy = (void (*)(struct pvr_pending_event *))kfree; + + do_gettimeofday(&now); + spin_lock_irqsave(&event_lock, flags); + + if (priv->event_space < sizeof(e->event)) { + spin_unlock_irqrestore(&event_lock, flags); + kfree(e); + return -ENOMEM; + } + + priv->event_space -= sizeof(e->event); + + list_add_tail(&e->base.link, &flip_wait_list); + + spin_unlock_irqrestore(&event_lock, flags); + + return omap_dss_request_notify(e->dss_event, overlay); +} + +static bool pvr_dequeue_event(struct PVRSRV_FILE_PRIVATE_DATA *priv, + size_t total, size_t max, struct pvr_pending_event **out) +{ + struct pvr_pending_event *e; + unsigned long flags; + bool ret = false; + + spin_lock_irqsave(&event_lock, flags); + + *out = NULL; + if (list_empty(&priv->event_list)) + goto err; + + e = list_first_entry(&priv->event_list, struct pvr_pending_event, link); + if (e->event->length + total > max) + goto err; + + priv->event_space += e->event->length; + list_del(&e->link); + *out = e; + ret = true; + +err: + spin_unlock_irqrestore(&event_lock, flags); + + return ret; +} + +ssize_t pvr_read(struct file *filp, char __user *buf, size_t count, loff_t *off) +{ + struct PVRSRV_FILE_PRIVATE_DATA *priv = filp->private_data; + struct pvr_pending_event *e; + size_t total; + ssize_t ret; + + ret = wait_event_interruptible(priv->event_wait, + !list_empty(&priv->event_list)); + + if (ret < 0) + return ret; + + total = 0; + while (pvr_dequeue_event(priv, total, count, &e)) { + if (copy_to_user(buf + total, e->event, e->event->length)) { + total = -EFAULT; + break; + } + + total += e->event->length; + e->destroy(e); + } + + return total; +} + +unsigned int pvr_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct PVRSRV_FILE_PRIVATE_DATA *priv = filp->private_data; + unsigned int mask = 0; + + poll_wait(filp, &priv->event_wait, wait); + + if (!list_empty(&priv->event_list)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +void pvr_handle_sync_events(void) +{ + struct pvr_pending_sync_event *e; + struct pvr_pending_sync_event *t; + struct timeval now; + unsigned long flags; + + do_gettimeofday(&now); + + spin_lock_irqsave(&event_lock, flags); + + list_for_each_entry_safe(e, t, &sync_wait_list, base.link) { + if (!is_render_complete(e->event.sync_info->psSyncData, + e->base.write_ops_pending)) + continue; + + pvr_signal_sync_event(e, &now); + } + + spin_unlock_irqrestore(&event_lock, flags); +} + +static int dss_notifier_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct pvr_pending_flip_event *e; + struct pvr_pending_flip_event *t; + struct timeval now; + unsigned long flags; + long overlay = (long) data; + + do_gettimeofday(&now); + + spin_lock_irqsave(&event_lock, flags); + + list_for_each_entry_safe(e, t, &flip_wait_list, base.link) { + if (!(e->dss_event & event)) + continue; + if (e->event.overlay != overlay) + continue; + + pvr_signal_flip_event(e, &now); + } + + spin_unlock_irqrestore(&event_lock, flags); + + return 0; +} + +void pvr_release_events(struct PVRSRV_FILE_PRIVATE_DATA *priv) +{ + struct pvr_pending_event *w; + struct pvr_pending_event *z; + struct pvr_pending_sync_event *e; + struct pvr_pending_sync_event *t; + struct pvr_pending_flip_event *e2; + struct pvr_pending_flip_event *t2; + unsigned long flags; + + spin_lock_irqsave(&event_lock, flags); + + /* Remove pending waits */ + list_for_each_entry_safe(e, t, &sync_wait_list, base.link) + if (e->base.file_priv == priv) { + list_del(&e->base.link); + e->base.destroy(&e->base); + } + + list_for_each_entry_safe(e2, t2, &flip_wait_list, base.link) + if (e2->base.file_priv == priv) { + list_del(&e2->base.link); + e2->base.destroy(&e2->base); + } + + /* Remove unconsumed events */ + list_for_each_entry_safe(w, z, &priv->event_list, link) + w->destroy(w); + + spin_unlock_irqrestore(&event_lock, flags); +} + +void pvr_init_events(void) +{ + spin_lock_init(&event_lock); + INIT_LIST_HEAD(&sync_wait_list); + INIT_LIST_HEAD(&flip_wait_list); + + dss_nb.notifier_call = dss_notifier_callback; + omap_dss_register_notifier(&dss_nb); +} + +void pvr_exit_events(void) +{ + omap_dss_unregister_notifier(&dss_nb); +} diff --git a/drivers/gpu/pvr/pvr_events.h b/drivers/gpu/pvr/pvr_events.h new file mode 100644 index 00000000000..11cfc119d28 --- /dev/null +++ b/drivers/gpu/pvr/pvr_events.h @@ -0,0 +1,99 @@ + +#ifndef PVR_EVENTS_H +#define PVR_EVENTS_H + +#include "servicesext.h" +#include "private_data.h" +#include <linux/list.h> +#include <linux/file.h> +#include <linux/poll.h> + +/* + * Header for events written back to userspace on the drm fd. The + * type defines the type of event, the length specifies the total + * length of the event (including the header), and user_data is + * typically a 64 bit value passed with the ioctl that triggered the + * event. A read on the drm fd will always only return complete + * events, that is, if for example the read buffer is 100 bytes, and + * there are two 64 byte events pending, only one will be returned. + */ +struct pvr_event { + __u32 type; + __u32 length; +}; + +#define PVR_EVENT_SYNC 0x01 +#define PVR_EVENT_FLIP 0x02 +#define PVR_EVENT_UPDATE 0x03 /* also uses struct pvr_event_flip */ + +/* + * Every buffer used as a render target has a 'PVRSRV_KERNEL_SYNC_INFO' + * associated with it. This structure simply contains four counters, number of + * pending and completed read and write operations. Counters for pending + * operations are modified (incremented) by the kernel driver while the + * counters for completed operations are directly updated by the SGX micro + * kernel. Once both the read counters and the write counters mutually match, + * one has completed a full frame. + * + * Micro kernel issues interrupts whenever TA or 3D phases are completed. These + * interrupts, however, as such do not tell if any particular frame is + * completed. It is the responsibility of the kerner driver to determine this. + * Hence the core interrupt handler calls 'pvr_handle_sync_events' to check if + * one of the monitored render operations are finished. This is accomplished by + * examining the before-mentioned counters designated by the pending events. + */ +struct pvr_event_sync { + struct pvr_event base; + const struct PVRSRV_KERNEL_SYNC_INFO *sync_info; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; +}; + +struct pvr_event_flip { + struct pvr_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 overlay; +}; + +/* Event queued up for userspace to read */ +struct pvr_pending_event { + struct pvr_event *event; + struct list_head link; + struct PVRSRV_FILE_PRIVATE_DATA *file_priv; + void (*destroy)(struct pvr_pending_event *event); + u32 write_ops_pending; +}; + +struct pvr_pending_sync_event { + struct pvr_pending_event base; + struct pvr_event_sync event; +}; + +struct pvr_pending_flip_event { + struct pvr_pending_event base; + struct pvr_event_flip event; + unsigned int dss_event; +}; + +enum pvr_sync_wait_seq_type; + +void pvr_init_events(void); +void pvr_exit_events(void); + +int pvr_sync_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv, + const struct PVRSRV_KERNEL_SYNC_INFO *sync_info, + u64 user_data); +int pvr_flip_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv, + unsigned int overlay, + enum pvr_sync_wait_seq_type type, u64 user_data); +ssize_t pvr_read(struct file *filp, char __user *buf, size_t count, + loff_t *off); +unsigned int pvr_poll(struct file *filp, struct poll_table_struct *wait); +void pvr_release_events(struct PVRSRV_FILE_PRIVATE_DATA *priv); + +void pvr_handle_sync_events(void); + +#endif /* PVR_EVENTS_H */ diff --git a/drivers/gpu/pvr/pvrconfig.h b/drivers/gpu/pvr/pvrconfig.h new file mode 100644 index 00000000000..5f16f2faa47 --- /dev/null +++ b/drivers/gpu/pvr/pvrconfig.h @@ -0,0 +1,35 @@ +#ifndef _PVRCONFIG_H +#define _PVRCONFIG_H + +#define SGX530 1 + +#ifdef CONFIG_PVR_DEBUG +# define PVR_BUILD_TYPE "debug" +# define DEBUG 1 +#elif defined(CONFIG_PVR_TIMING) +# define PVR_BUILD_TYPE "timing" +# define TIMING 1 +#elif defined(CONFIG_PVR_RELEASE) +# define PVR_BUILD_TYPE "release" +#endif + +#ifdef CONFIG_PVR_NO_HARDWARE +# define NO_HARDWARE 1 +#endif + +#ifdef CONFIG_PVR_DEBUG_EXTRA +# define DEBUG_LINUX_MEMORY_ALLOCATIONS 1 +# define DEBUG_LINUX_MEM_AREAS 1 +# define DEBUG_LINUX_MMAP_AREAS 1 +# define DEBUG_BRIDGE_KM 1 +#endif + +# if (defined CONFIG_PVR_DEBUG_PDUMP) || (defined CONFIG_PVR_DEBUG_PDUMP_MODULE) +# define PDUMP 1 +# endif + +#ifdef CONFIG_PVR_EDM_DEBUG +# define PVRSRV_USSE_EDM_STATUS_DEBUG 1 +#endif + +#endif diff --git a/drivers/gpu/pvr/pvrmmap.h b/drivers/gpu/pvr/pvrmmap.h new file mode 100644 index 00000000000..c84e4d89eff --- /dev/null +++ b/drivers/gpu/pvr/pvrmmap.h @@ -0,0 +1,36 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __PVRMMAP_H__ +#define __PVRMMAP_H__ + +enum PVRSRV_ERROR PVRPMapKMem(void *hModule, void **ppvLinAddr, + void *pvLinAddrKM, void **phMappingInfo, + void *hMHandle); + +IMG_BOOL PVRUnMapKMem(void *hModule, void *hMappingInfo, void *hMHandle); + +#endif diff --git a/drivers/gpu/pvr/pvrmodule.h b/drivers/gpu/pvr/pvrmodule.h new file mode 100644 index 00000000000..5f77d1c1fde --- /dev/null +++ b/drivers/gpu/pvr/pvrmodule.h @@ -0,0 +1,31 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _PVRMODULE_H_ +#define _PVRMODULE_H_ +MODULE_AUTHOR("Imagination Technologies Ltd. <gpl-support@imgtec.com>"); +MODULE_LICENSE("GPL"); +#endif diff --git a/drivers/gpu/pvr/pvrsrv.c b/drivers/gpu/pvr/pvrsrv.c new file mode 100644 index 00000000000..332e0003160 --- /dev/null +++ b/drivers/gpu/pvr/pvrsrv.c @@ -0,0 +1,921 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/io.h> + +#include "services_headers.h" +#include "buffer_manager.h" +#include "pvr_bridge_km.h" +#include "handle.h" +#include "perproc.h" +#include "pdump_km.h" +#include "ra.h" +#include "pvr_events.h" + +#include "pvrversion.h" + +#define HASH_TAB_INIT_SIZE 32 +enum PVRSRV_ERROR AllocateDeviceID(struct SYS_DATA *psSysData, u32 *pui32DevID) +{ + struct SYS_DEVICE_ID *psDeviceWalker; + struct SYS_DEVICE_ID *psDeviceEnd; + + psDeviceWalker = &psSysData->sDeviceID[0]; + psDeviceEnd = psDeviceWalker + psSysData->ui32NumDevices; + + while (psDeviceWalker < psDeviceEnd) { + if (!psDeviceWalker->bInUse) { + psDeviceWalker->bInUse = IMG_TRUE; + *pui32DevID = psDeviceWalker->uiID; + return PVRSRV_OK; + } + psDeviceWalker++; + } + + PVR_DPF(PVR_DBG_ERROR, + "AllocateDeviceID: No free and valid device IDs available!"); + + PVR_ASSERT(psDeviceWalker < psDeviceEnd); + + return PVRSRV_ERROR_GENERIC; +} + +enum PVRSRV_ERROR FreeDeviceID(struct SYS_DATA *psSysData, u32 ui32DevID) +{ + struct SYS_DEVICE_ID *psDeviceWalker; + struct SYS_DEVICE_ID *psDeviceEnd; + + psDeviceWalker = &psSysData->sDeviceID[0]; + psDeviceEnd = psDeviceWalker + psSysData->ui32NumDevices; + + while (psDeviceWalker < psDeviceEnd) { + if ((psDeviceWalker->uiID == ui32DevID) && + (psDeviceWalker->bInUse)) { + psDeviceWalker->bInUse = IMG_FALSE; + return PVRSRV_OK; + } + psDeviceWalker++; + } + + PVR_DPF(PVR_DBG_ERROR, + "FreeDeviceID: no matching dev ID that is in use!"); + + PVR_ASSERT(psDeviceWalker < psDeviceEnd); + + return PVRSRV_ERROR_GENERIC; +} + +enum PVRSRV_ERROR PVRSRVEnumerateDevicesKM(u32 *pui32NumDevices, + struct PVRSRV_DEVICE_IDENTIFIER *psDevIdList) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + u32 i; + + if (!pui32NumDevices || !psDevIdList) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumerateDevicesKM: Invalid params"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumerateDevicesKM: Failed to get SysData"); + return eError; + } + + for (i = 0; i < PVRSRV_MAX_DEVICES; i++) + psDevIdList[i].eDeviceType = PVRSRV_DEVICE_TYPE_UNKNOWN; + + *pui32NumDevices = 0; + + psDeviceNode = psSysData->psDeviceNodeList; + for (i = 0; psDeviceNode != NULL; i++) { + if (psDeviceNode->sDevId.eDeviceType != + PVRSRV_DEVICE_TYPE_EXT) { + *psDevIdList++ = psDeviceNode->sDevId; + (*pui32NumDevices)++; + } + psDeviceNode = psDeviceNode->psNext; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVInit(struct SYS_DATA *psSysData) +{ + enum PVRSRV_ERROR eError; + + eError = ResManInit(); + if (eError != PVRSRV_OK) + goto Error; + + eError = PVRSRVPerProcessDataInit(); + if (eError != PVRSRV_OK) + goto Error; + + eError = PVRSRVHandleInit(); + if (eError != PVRSRV_OK) + goto Error; + + psSysData->eCurrentPowerState = PVRSRV_POWER_STATE_D0; + psSysData->eFailedPowerState = PVRSRV_POWER_Unspecified; + +#if defined(PDUMP) + psSysData->bPowerUpPDumped = IMG_FALSE; +#endif + + if (OSAllocMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_EVENTOBJECT), + (void **) &psSysData->psGlobalEventObject, + NULL) != PVRSRV_OK) + + goto Error; + + if (OSEventObjectCreate("PVRSRV_GLOBAL_EVENTOBJECT", + psSysData->psGlobalEventObject) != PVRSRV_OK) + goto Error; + + return eError; + +Error: + PVRSRVDeInit(psSysData); + return eError; +} + +void PVRSRVDeInit(struct SYS_DATA *psSysData) +{ + enum PVRSRV_ERROR eError; + + PVR_UNREFERENCED_PARAMETER(psSysData); + + if (psSysData == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVDeInit: " + "PVRSRVHandleDeInit failed - invalid param"); + return; + } + + if (psSysData->psGlobalEventObject) { + OSEventObjectDestroy(psSysData->psGlobalEventObject); + OSFreeMem(PVRSRV_PAGEABLE_SELECT, + sizeof(struct PVRSRV_EVENTOBJECT), + psSysData->psGlobalEventObject, NULL); + } + + eError = PVRSRVHandleDeInit(); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDeInit: PVRSRVHandleDeInit failed"); + + eError = PVRSRVPerProcessDataDeInit(); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDeInit: PVRSRVPerProcessDataDeInit failed"); + + ResManDeInit(); +} + +enum PVRSRV_ERROR PVRSRVRegisterDevice(struct SYS_DATA *psSysData, + enum PVRSRV_ERROR(*pfnRegisterDevice) + (struct PVRSRV_DEVICE_NODE *), + u32 ui32SOCInterruptBit, + u32 *pui32DeviceIndex) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + + if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), + (void **) &psDeviceNode, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterDevice : " + "Failed to alloc memory for psDeviceNode"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psDeviceNode, 0, sizeof(struct PVRSRV_DEVICE_NODE)); + + eError = pfnRegisterDevice(psDeviceNode); + if (eError != PVRSRV_OK) { + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), psDeviceNode, + NULL); + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterDevice : " + "Failed to register device"); + return PVRSRV_ERROR_DEVICE_REGISTER_FAILED; + } + + psDeviceNode->ui32RefCount = 1; + psDeviceNode->psSysData = psSysData; + psDeviceNode->ui32SOCInterruptBit = ui32SOCInterruptBit; + + AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex); + + psDeviceNode->psNext = psSysData->psDeviceNodeList; + psSysData->psDeviceNodeList = psDeviceNode; + + *pui32DeviceIndex = psDeviceNode->sDevId.ui32DeviceIndex; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVInitialiseDevice(u32 ui32DevIndex) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + enum PVRSRV_ERROR eError; + + PVR_DPF(PVR_DBG_MESSAGE, "PVRSRVInitialiseDevice"); + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVInitialiseDevice: Failed to get SysData"); + return eError; + } + + psDeviceNode = psSysData->psDeviceNodeList; + + while (psDeviceNode) { + if (psDeviceNode->sDevId.ui32DeviceIndex == ui32DevIndex) + goto FoundDevice; + psDeviceNode = psDeviceNode->psNext; + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVInitialiseDevice: requested device is not present"); + return PVRSRV_ERROR_INIT_FAILURE; + +FoundDevice: + + PVR_ASSERT(psDeviceNode->ui32RefCount > 0); + + eError = PVRSRVResManConnect(NULL, &psDeviceNode->hResManContext); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVInitialiseDevice: " + "Failed PVRSRVResManConnect call"); + return eError; + } + + if (psDeviceNode->pfnInitDevice != NULL) { + eError = psDeviceNode->pfnInitDevice(psDeviceNode); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVInitialiseDevice: " + "Failed InitDevice call"); + return eError; + } + } + + psDeviceNode->sync_table = HASH_Create(HASH_TAB_INIT_SIZE); + if (psDeviceNode->sync_table == NULL) { + PVR_DPF(PVR_DBG_ERROR, "InitDevInfo: " + "Couldn't create syncobject hash table"); + eError = PVRSRV_ERROR_GENERIC; + return eError; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVFinaliseSystem(IMG_BOOL bInitSuccessful) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + enum PVRSRV_ERROR eError; + + PVR_DPF(PVR_DBG_MESSAGE, "PVRSRVFinaliseSystem"); + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVFinaliseSystem: Failed to get SysData"); + return eError; + } + + if (bInitSuccessful) { + eError = SysFinalise(); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVFinaliseSystem: SysFinalise failed (%d)", + eError); + return eError; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + eError = + PVRSRVSetDevicePowerStateKM( + psDeviceNode->sDevId.ui32DeviceIndex, + PVRSRV_POWER_Unspecified); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, "PVRSRVFinaliseSystem: " + "Failed PVRSRVSetDevicePowerStateKM " + "call (device index: %d)", + psDeviceNode->sDevId.ui32DeviceIndex); + psDeviceNode = psDeviceNode->psNext; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + if (psDeviceNode->pfnInitDeviceCompatCheck) { + eError = PVRSRVDevInitCompatCheck(psDeviceNode); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVFinaliseSystem: " + "Failed PVRSRVDevInitCompatCheck " + "call (device index: %d)", + psDeviceNode->sDevId. + ui32DeviceIndex); + return eError; + } + } + psDeviceNode = psDeviceNode->psNext; + + } + + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVDevInitCompatCheck(struct PVRSRV_DEVICE_NODE + *psDeviceNode) +{ + + return psDeviceNode->pfnInitDeviceCompatCheck(psDeviceNode); +} + +enum PVRSRV_ERROR PVRSRVAcquireDeviceDataKM(u32 ui32DevIndex, + enum PVRSRV_DEVICE_TYPE eDeviceType, + void **phDevCookie) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + enum PVRSRV_ERROR eError; + + PVR_DPF(PVR_DBG_MESSAGE, "PVRSRVAcquireDeviceDataKM"); + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVAcquireDeviceDataKM: Failed to get SysData"); + return eError; + } + + psDeviceNode = psSysData->psDeviceNodeList; + + if (eDeviceType != PVRSRV_DEVICE_TYPE_UNKNOWN) { + while (psDeviceNode) { + if (psDeviceNode->sDevId.eDeviceType == eDeviceType) + goto FoundDevice; + psDeviceNode = psDeviceNode->psNext; + } + } else { + while (psDeviceNode) { + if (psDeviceNode->sDevId.ui32DeviceIndex == + ui32DevIndex) { + goto FoundDevice; + } + psDeviceNode = psDeviceNode->psNext; + } + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVAcquireDeviceDataKM: requested device is not present"); + return PVRSRV_ERROR_INIT_FAILURE; + +FoundDevice: + + PVR_ASSERT(psDeviceNode->ui32RefCount > 0); + + if (phDevCookie) + *phDevCookie = (void *) psDeviceNode; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVDeinitialiseDevice(u32 ui32DevIndex) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct PVRSRV_DEVICE_NODE **ppsDevNode; + struct SYS_DATA *psSysData; + enum PVRSRV_ERROR eError; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDeinitialiseDevice: Failed to get SysData"); + return eError; + } + + ppsDevNode = &psSysData->psDeviceNodeList; + while (*ppsDevNode) { + if ((*ppsDevNode)->sDevId.ui32DeviceIndex == ui32DevIndex) { + psDeviceNode = *ppsDevNode; + goto FoundDevice; + } + ppsDevNode = &((*ppsDevNode)->psNext); + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDeinitialiseDevice: requested device %d is not present", + ui32DevIndex); + + return PVRSRV_ERROR_GENERIC; + +FoundDevice: + + eError = PVRSRVSetDevicePowerStateKM(ui32DevIndex, + PVRSRV_POWER_STATE_D3); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVDeinitialiseDevice: " + "Failed PVRSRVSetDevicePowerStateKM call"); + return eError; + } + + HASH_Delete(psDeviceNode->sync_table); + + ResManFreeResByCriteria(psDeviceNode->hResManContext, + RESMAN_CRITERIA_RESTYPE, + RESMAN_TYPE_DEVICEMEM_ALLOCATION, + NULL, 0); + + if (psDeviceNode->pfnDeInitDevice != NULL) { + eError = psDeviceNode->pfnDeInitDevice(psDeviceNode); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVDeinitialiseDevice: " + "Failed DeInitDevice call"); + return eError; + } + } + + PVRSRVResManDisconnect(psDeviceNode->hResManContext, IMG_TRUE); + psDeviceNode->hResManContext = NULL; + + *ppsDevNode = psDeviceNode->psNext; + + FreeDeviceID(psSysData, ui32DevIndex); + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), psDeviceNode, NULL); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PollForValueKM(u32 __iomem *pui32LinMemAddr, + u32 ui32Value, u32 ui32Mask, u32 ui32Waitus, + u32 ui32Tries) +{ + u32 uiMaxTime; + + uiMaxTime = ui32Tries * ui32Waitus; + + LOOP_UNTIL_TIMEOUT(uiMaxTime) { + if ((readl(pui32LinMemAddr) & ui32Mask) == ui32Value) + return PVRSRV_OK; + } + END_LOOP_UNTIL_TIMEOUT(); + + return PVRSRV_ERROR_GENERIC; +} + + +enum PVRSRV_ERROR PVRSRVGetMiscInfoKM(struct PVRSRV_MISC_INFO *psMiscInfo) +{ + struct SYS_DATA *psSysData; + enum PVRSRV_ERROR eError; + + if (!psMiscInfo) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetMiscInfoKM: invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psMiscInfo->ui32StatePresent = 0; + + if (psMiscInfo->ui32StateRequest & ~( + PVRSRV_MISC_INFO_TIMER_PRESENT | + PVRSRV_MISC_INFO_CLOCKGATE_PRESENT | + PVRSRV_MISC_INFO_MEMSTATS_PRESENT | + PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT | + PVRSRV_MISC_INFO_DDKVERSION_PRESENT)) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetMiscInfoKM: invalid state request flags"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetMiscInfoKM: Failed to get SysData"); + return eError; + } + + if (((psMiscInfo->ui32StateRequest & + PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) && + (psSysData->pvSOCTimerRegisterKM != NULL)) { + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT; + psMiscInfo->pvSOCTimerRegisterKM = + psSysData->pvSOCTimerRegisterKM; + psMiscInfo->hSOCTimerRegisterOSMemHandle = + psSysData->hSOCTimerRegisterOSMemHandle; + } else { + psMiscInfo->pvSOCTimerRegisterKM = NULL; + psMiscInfo->hSOCTimerRegisterOSMemHandle = NULL; + } + + if (((psMiscInfo->ui32StateRequest & + PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) && + (psSysData->pvSOCClockGateRegsBase != NULL)) { + psMiscInfo->ui32StatePresent |= + PVRSRV_MISC_INFO_CLOCKGATE_PRESENT; + psMiscInfo->pvSOCClockGateRegs = + psSysData->pvSOCClockGateRegsBase; + psMiscInfo->ui32SOCClockGateRegsSize = + psSysData->ui32SOCClockGateRegsSize; + } + + if (((psMiscInfo->ui32StateRequest & + PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) && + (psMiscInfo->pszMemoryStr != NULL)) { + struct RA_ARENA **ppArena; + struct BM_HEAP *psBMHeap; + struct BM_CONTEXT *psBMContext; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + char *pszStr; + u32 ui32StrLen; + s32 i32Count; + + pszStr = psMiscInfo->pszMemoryStr; + ui32StrLen = psMiscInfo->ui32MemoryStrLen; + + psMiscInfo->ui32StatePresent |= + PVRSRV_MISC_INFO_MEMSTATS_PRESENT; + + ppArena = &psSysData->apsLocalDevMemArena[0]; + while (*ppArena) { + CHECK_SPACE(ui32StrLen); + i32Count = + OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n"); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + RA_GetStats(*ppArena, &pszStr, &ui32StrLen); + + ppArena++; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + CHECK_SPACE(ui32StrLen); + i32Count = + OSSNPrintf(pszStr, 100, "\n\nDevice Type %d:\n", + psDeviceNode->sDevId.eDeviceType); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + if (psDeviceNode->sDevMemoryInfo.pBMKernelContext) { + CHECK_SPACE(ui32StrLen); + i32Count = + OSSNPrintf(pszStr, 100, + "\nKernel Context:\n"); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + psBMHeap = + psDeviceNode->sDevMemoryInfo. + pBMKernelContext->psBMHeap; + while (psBMHeap) { + if (psBMHeap->pImportArena) { + RA_GetStats(psBMHeap-> + pImportArena, + &pszStr, + &ui32StrLen); + } + + if (psBMHeap->pVMArena) { + RA_GetStats(psBMHeap->pVMArena, + &pszStr, + &ui32StrLen); + } + psBMHeap = psBMHeap->psNext; + } + } + + psBMContext = psDeviceNode->sDevMemoryInfo.pBMContext; + while (psBMContext) { + CHECK_SPACE(ui32StrLen); + i32Count = + OSSNPrintf(pszStr, 100, + "\nApplication Context (hDevMemContext) 0x%08X:\n", + (void *)psBMContext); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + psBMHeap = psBMContext->psBMHeap; + while (psBMHeap) { + if (psBMHeap->pImportArena) { + RA_GetStats(psBMHeap-> + pImportArena, + &pszStr, + &ui32StrLen); + } + + if (psBMHeap->pVMArena) { + RA_GetStats(psBMHeap->pVMArena, + &pszStr, + &ui32StrLen); + } + psBMHeap = psBMHeap->psNext; + } + psBMContext = psBMContext->psNext; + } + psDeviceNode = psDeviceNode->psNext; + } + + i32Count = OSSNPrintf(pszStr, 100, "\n\0"); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + } + + if (((psMiscInfo->ui32StateRequest & + PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) && + (psSysData->psGlobalEventObject != NULL)) { + psMiscInfo->ui32StatePresent |= + PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT; + psMiscInfo->sGlobalEventObject = + *psSysData->psGlobalEventObject; + } + + if (((psMiscInfo->ui32StateRequest & + PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL) && + ((psMiscInfo->ui32StateRequest & + PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL) && + (psMiscInfo->pszMemoryStr != NULL)) { + char *pszStr; + u32 ui32StrLen; + u32 ui32LenStrPerNum = 12; + s32 i32Count; + int i; + psMiscInfo->ui32StatePresent |= + PVRSRV_MISC_INFO_DDKVERSION_PRESENT; + + psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ; + psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN; + psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BRANCH; + psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD; + + pszStr = psMiscInfo->pszMemoryStr; + ui32StrLen = psMiscInfo->ui32MemoryStrLen; + + for (i = 0; i < 4; i++) { + if (ui32StrLen < ui32LenStrPerNum) + return PVRSRV_ERROR_INVALID_PARAMS; + + i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%ld", + psMiscInfo->aui32DDKVersion[i]); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + if (i != 3) { + i32Count = OSSNPrintf(pszStr, 2, "."); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + } + } + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVGetFBStatsKM(u32 *pui32Total, u32 *pui32Available) +{ + u32 ui32Total = 0, i = 0; + u32 ui32Available = 0; + + *pui32Total = 0; + *pui32Available = 0; + + while (BM_ContiguousStatistics(i, &ui32Total, &ui32Available) == + IMG_TRUE) { + *pui32Total += ui32Total; + *pui32Available += ui32Available; + + i++; + } + + return PVRSRV_OK; +} + +IMG_BOOL PVRSRVDeviceLISR(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + struct SYS_DATA *psSysData; + IMG_BOOL bStatus = IMG_FALSE; + u32 ui32InterruptSource; + + if (!psDeviceNode) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVDeviceLISR: Invalid params\n"); + goto out; + } + psSysData = psDeviceNode->psSysData; + + ui32InterruptSource = SysGetInterruptSource(psSysData, psDeviceNode); + if (ui32InterruptSource & psDeviceNode->ui32SOCInterruptBit) { + if (psDeviceNode->pfnDeviceISR != NULL) + bStatus = + (*psDeviceNode->pfnDeviceISR) (psDeviceNode-> + pvISRData); + + SysClearInterrupts(psSysData, + psDeviceNode->ui32SOCInterruptBit); + } + +out: + return bStatus; +} + +IMG_BOOL PVRSRVSystemLISR(void *pvSysData) +{ + struct SYS_DATA *psSysData = pvSysData; + IMG_BOOL bStatus = IMG_FALSE; + u32 ui32InterruptSource; + u32 ui32ClearInterrupts = 0; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + + if (!psSysData) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVSystemLISR: Invalid params\n"); + goto out; + } + + ui32InterruptSource = SysGetInterruptSource(psSysData, NULL); + + if (ui32InterruptSource == 0) + goto out; + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode != NULL) { + if (psDeviceNode->pfnDeviceISR != NULL) + if (ui32InterruptSource & psDeviceNode-> + ui32SOCInterruptBit) { + if ((*psDeviceNode->pfnDeviceISR) + (psDeviceNode->pvISRData)) + bStatus = IMG_TRUE; + + ui32ClearInterrupts |= + psDeviceNode->ui32SOCInterruptBit; + } + psDeviceNode = psDeviceNode->psNext; + } + + SysClearInterrupts(psSysData, ui32ClearInterrupts); + +out: + return bStatus; +} + +void PVRSRVMISR(void *pvSysData) +{ + struct SYS_DATA *psSysData = pvSysData; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + + if (!psSysData) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVMISR: Invalid params\n"); + return; + } + + pvr_lock(); + + if (pvr_is_disabled()) { + pvr_unlock(); + return; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode != NULL) { + if (psDeviceNode->pfnDeviceMISR != NULL) + (*psDeviceNode->pfnDeviceMISR)(psDeviceNode-> + pvISRData); + psDeviceNode = psDeviceNode->psNext; + } + + PVRSRVProcessQueues(IMG_FALSE); + + if (psSysData->psGlobalEventObject) { + void *hOSEventKM = + psSysData->psGlobalEventObject->hOSEventKM; + if (hOSEventKM) + OSEventObjectSignal(hOSEventKM); + } + + pvr_handle_sync_events(); + + pvr_unlock(); +} + +enum PVRSRV_ERROR PVRSRVProcessConnect(u32 ui32PID) +{ + return PVRSRVPerProcessDataConnect(ui32PID); +} + +void PVRSRVProcessDisconnect(u32 ui32PID) +{ + PVRSRVPerProcessDataDisconnect(ui32PID); +} + +enum PVRSRV_ERROR PVRSRVSaveRestoreLiveSegments(void *hArena, u8 *pbyBuffer, + u32 *puiBufSize, IMG_BOOL bSave) +{ + u32 uiBytesSaved = 0; + void *pvLocalMemCPUVAddr; + struct RA_SEGMENT_DETAILS sSegDetails; + + if (hArena == NULL) + return PVRSRV_ERROR_INVALID_PARAMS; + + sSegDetails.uiSize = 0; + sSegDetails.sCpuPhyAddr.uiAddr = 0; + sSegDetails.hSegment = NULL; + + while (RA_GetNextLiveSegment(hArena, &sSegDetails)) + if (pbyBuffer == NULL) { + uiBytesSaved += + sizeof(sSegDetails.uiSize) + sSegDetails.uiSize; + } else { + if ((uiBytesSaved + sizeof(sSegDetails.uiSize) + + sSegDetails.uiSize) > *puiBufSize) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + PVR_DPF(PVR_DBG_MESSAGE, + "PVRSRVSaveRestoreLiveSegments: " + "Base %08x size %08x", + sSegDetails.sCpuPhyAddr.uiAddr, + sSegDetails.uiSize); + + pvLocalMemCPUVAddr = (void __force *) + OSMapPhysToLin(sSegDetails.sCpuPhyAddr, + sSegDetails.uiSize, + PVRSRV_HAP_KERNEL_ONLY | + PVRSRV_HAP_UNCACHED, NULL); + if (pvLocalMemCPUVAddr == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSaveRestoreLiveSegments: " + "Failed to map local memory to host"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + if (bSave) { + OSMemCopy(pbyBuffer, &sSegDetails.uiSize, + sizeof(sSegDetails.uiSize)); + pbyBuffer += sizeof(sSegDetails.uiSize); + + OSMemCopy(pbyBuffer, pvLocalMemCPUVAddr, + sSegDetails.uiSize); + pbyBuffer += sSegDetails.uiSize; + } else { + u32 uiSize; + + OSMemCopy(&uiSize, pbyBuffer, + sizeof(sSegDetails.uiSize)); + + if (uiSize != sSegDetails.uiSize) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSaveRestoreLiveSegments:" + " Segment size error"); + } else { + pbyBuffer += sizeof(sSegDetails.uiSize); + + OSMemCopy(pvLocalMemCPUVAddr, pbyBuffer, + sSegDetails.uiSize); + pbyBuffer += sSegDetails.uiSize; + } + } + + uiBytesSaved += + sizeof(sSegDetails.uiSize) + sSegDetails.uiSize; + + OSUnMapPhysToLin((void __force __iomem *) + pvLocalMemCPUVAddr, + sSegDetails.uiSize, + PVRSRV_HAP_KERNEL_ONLY | + PVRSRV_HAP_UNCACHED, NULL); + } + + if (pbyBuffer == NULL) + *puiBufSize = uiBytesSaved; + + return PVRSRV_OK; +} diff --git a/drivers/gpu/pvr/pvrversion.h b/drivers/gpu/pvr/pvrversion.h new file mode 100644 index 00000000000..5dc477929fe --- /dev/null +++ b/drivers/gpu/pvr/pvrversion.h @@ -0,0 +1,37 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _PVRVERSION_H_ +#define _PVRVERSION_H_ + +#define PVRVERSION_MAJ 1 +#define PVRVERSION_MIN 4 +#define PVRVERSION_BRANCH 14 +#define PVRVERSION_BUILD 2514 +#define PVRVERSION_STRING "1.4.14.2514" +#define PVRVERSION_FILE "eurasiacon.pj" + +#endif diff --git a/drivers/gpu/pvr/queue.c b/drivers/gpu/pvr/queue.c new file mode 100644 index 00000000000..b88b22fd6a2 --- /dev/null +++ b/drivers/gpu/pvr/queue.c @@ -0,0 +1,761 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "services_headers.h" + +#include "proc.h" + +static int QueuePrintCommands(struct PVRSRV_QUEUE_INFO *psQueue, char *buffer, + size_t size) +{ + off_t off = 0; + int cmds = 0; + u32 ui32ReadOffset = psQueue->ui32ReadOffset; + u32 ui32WriteOffset = psQueue->ui32WriteOffset; + struct PVRSRV_COMMAND *psCmd; + + while (ui32ReadOffset != ui32WriteOffset) { + psCmd = (struct PVRSRV_COMMAND *)((u32) psQueue->pvLinQueueKM + + ui32ReadOffset); + + off = printAppend(buffer, size, off, + "%p %p %5u %6u %3u %5u %2u %2u %3u \n", + psQueue, psCmd, psCmd->ui32ProcessID, + psCmd->CommandType, psCmd->ui32CmdSize, + psCmd->ui32DevIndex, psCmd->ui32DstSyncCount, + psCmd->ui32SrcSyncCount, psCmd->ui32DataSize); + + ui32ReadOffset += psCmd->ui32CmdSize; + ui32ReadOffset &= psQueue->ui32QueueSize - 1; + cmds++; + } + if (cmds == 0) + off = printAppend(buffer, size, off, "%p <empty>\n", psQueue); + return off; +} + +off_t QueuePrintQueues(char *buffer, size_t size, off_t off) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_QUEUE_INFO *psQueue; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return END_OF_FILE; + + if (!off) + return printAppend(buffer, size, 0, + "Command Queues\nQueue CmdPtr " + "Pid Command Size DevInd DSC SSC #Data ...\n"); + + for (psQueue = psSysData->psQueueList; --off && psQueue; + psQueue = psQueue->psNextKM) + ; + + return psQueue ? + QueuePrintCommands(psQueue, buffer, size) : END_OF_FILE; +} + +#define GET_SPACE_IN_CMDQ(psQueue) \ + (((psQueue->ui32ReadOffset - psQueue->ui32WriteOffset) + \ + (psQueue->ui32QueueSize - 1)) & (psQueue->ui32QueueSize - 1)) + +#define UPDATE_QUEUE_WOFF(psQueue, ui32Size) \ + psQueue->ui32WriteOffset = (psQueue->ui32WriteOffset + ui32Size) & \ + (psQueue->ui32QueueSize - 1); + +#define SYNCOPS_STALE(ui32OpsComplete, ui32OpsPending) \ + (ui32OpsComplete >= ui32OpsPending) + +static u32 NearestPower2(u32 ui32Value) +{ + u32 ui32Temp, ui32Result = 1; + + if (!ui32Value) + return 0; + + ui32Temp = ui32Value - 1; + while (ui32Temp) { + ui32Result <<= 1; + ui32Temp >>= 1; + } + + return ui32Result; +} + +enum PVRSRV_ERROR PVRSRVCreateCommandQueueKM(u32 ui32QueueSize, + struct PVRSRV_QUEUE_INFO **ppsQueueInfo) +{ + struct PVRSRV_QUEUE_INFO *psQueueInfo; + u32 ui32Power2QueueSize = NearestPower2(ui32QueueSize); + struct SYS_DATA *psSysData; + enum PVRSRV_ERROR eError; + void *hMemBlock; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_QUEUE_INFO), + (void **) &psQueueInfo, &hMemBlock) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateCommandQueueKM: " + "Failed to alloc queue struct"); + goto ErrorExit; + } + OSMemSet(psQueueInfo, 0, sizeof(struct PVRSRV_QUEUE_INFO)); + + psQueueInfo->hMemBlock[0] = hMemBlock; + psQueueInfo->ui32ProcessID = OSGetCurrentProcessIDKM(); + + if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + ui32Power2QueueSize + PVRSRV_MAX_CMD_SIZE, + &psQueueInfo->pvLinQueueKM, &hMemBlock) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateCommandQueueKM: " + "Failed to alloc queue buffer"); + goto ErrorExit; + } + + psQueueInfo->hMemBlock[1] = hMemBlock; + psQueueInfo->pvLinQueueUM = psQueueInfo->pvLinQueueKM; + + PVR_ASSERT(psQueueInfo->ui32ReadOffset == 0); + PVR_ASSERT(psQueueInfo->ui32WriteOffset == 0); + + psQueueInfo->ui32QueueSize = ui32Power2QueueSize; + + psQueueInfo->psNextKM = psSysData->psQueueList; + psSysData->psQueueList = psQueueInfo; + + *ppsQueueInfo = psQueueInfo; + + return PVRSRV_OK; + +ErrorExit: + + if (psQueueInfo) { + if (psQueueInfo->pvLinQueueKM) + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + psQueueInfo->ui32QueueSize, + psQueueInfo->pvLinQueueKM, + psQueueInfo->hMemBlock[1]); + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_QUEUE_INFO), + psQueueInfo, psQueueInfo->hMemBlock[0]); + } + + return PVRSRV_ERROR_GENERIC; +} + +enum PVRSRV_ERROR PVRSRVDestroyCommandQueueKM( + struct PVRSRV_QUEUE_INFO *psQueueInfo) +{ + struct PVRSRV_QUEUE_INFO *psQueue; + struct SYS_DATA *psSysData; + enum PVRSRV_ERROR eError; + IMG_BOOL bTimeout = IMG_TRUE; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + psQueue = psSysData->psQueueList; + + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + if (psQueueInfo->ui32ReadOffset == + psQueueInfo->ui32WriteOffset) { + bTimeout = IMG_FALSE; + break; + } + OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT); + } + END_LOOP_UNTIL_TIMEOUT(); + + if (bTimeout) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDestroyCommandQueueKM : Failed to empty queue"); + eError = PVRSRV_ERROR_CANNOT_FLUSH_QUEUE; + goto ErrorExit; + } + + if (psQueue == psQueueInfo) { + psSysData->psQueueList = psQueueInfo->psNextKM; + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + psQueueInfo->ui32QueueSize, + psQueueInfo->pvLinQueueKM, psQueueInfo->hMemBlock[1]); + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_QUEUE_INFO), + psQueueInfo, psQueueInfo->hMemBlock[0]); + } else { + while (psQueue) { + if (psQueue->psNextKM == psQueueInfo) { + psQueue->psNextKM = psQueueInfo->psNextKM; + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + psQueueInfo->ui32QueueSize, + psQueueInfo->pvLinQueueKM, + psQueueInfo->hMemBlock[1]); + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_QUEUE_INFO), + psQueueInfo, + psQueueInfo->hMemBlock[0]); + break; + } + psQueue = psQueue->psNextKM; + } + + if (!psQueue) { + eError = PVRSRV_ERROR_INVALID_PARAMS; + goto ErrorExit; + } + } + +ErrorExit: + + return eError; +} + +enum PVRSRV_ERROR PVRSRVGetQueueSpaceKM(struct PVRSRV_QUEUE_INFO *psQueue, + u32 ui32ParamSize, void **ppvSpace) +{ + IMG_BOOL bTimeout = IMG_TRUE; + + ui32ParamSize = (ui32ParamSize + 3) & 0xFFFFFFFC; + + if (ui32ParamSize > PVRSRV_MAX_CMD_SIZE) { + PVR_DPF(PVR_DBG_WARNING, + "PVRSRVGetQueueSpace: max command size is %d bytes", + PVRSRV_MAX_CMD_SIZE); + return PVRSRV_ERROR_CMD_TOO_BIG; + } + + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + if (GET_SPACE_IN_CMDQ(psQueue) > ui32ParamSize) { + bTimeout = IMG_FALSE; + break; + } + OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT); + } + END_LOOP_UNTIL_TIMEOUT(); + + if (bTimeout == IMG_TRUE) { + *ppvSpace = NULL; + + return PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE; + } else { + *ppvSpace = (void *)(psQueue->ui32WriteOffset + + (u32)psQueue->pvLinQueueUM); + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVInsertCommandKM(struct PVRSRV_QUEUE_INFO *psQueue, + struct PVRSRV_COMMAND **ppsCommand, + u32 ui32DevIndex, u16 CommandType, + u32 ui32DstSyncCount, + struct PVRSRV_KERNEL_SYNC_INFO *apsDstSync[], + u32 ui32SrcSyncCount, + struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[], + u32 ui32DataByteSize) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_COMMAND *psCommand; + u32 ui32CommandSize; + u32 i; + + ui32DataByteSize = (ui32DataByteSize + 3) & 0xFFFFFFFC; + + ui32CommandSize = sizeof(struct PVRSRV_COMMAND) + + ((ui32DstSyncCount + ui32SrcSyncCount) * + sizeof(struct PVRSRV_SYNC_OBJECT)) + ui32DataByteSize; + + eError = PVRSRVGetQueueSpaceKM(psQueue, ui32CommandSize, + (void **) &psCommand); + if (eError != PVRSRV_OK) + return eError; + + psCommand->ui32ProcessID = OSGetCurrentProcessIDKM(); + + psCommand->ui32CmdSize = ui32CommandSize; + psCommand->ui32DevIndex = ui32DevIndex; + psCommand->CommandType = CommandType; + psCommand->ui32DstSyncCount = ui32DstSyncCount; + psCommand->ui32SrcSyncCount = ui32SrcSyncCount; + psCommand->psDstSync = + (struct PVRSRV_SYNC_OBJECT *)(((u8 *) psCommand) + + sizeof(struct PVRSRV_COMMAND)); + + psCommand->psSrcSync = + (struct PVRSRV_SYNC_OBJECT *)(((u8 *) psCommand->psDstSync) + + (ui32DstSyncCount * + sizeof(struct PVRSRV_SYNC_OBJECT))); + + psCommand->pvData = + (struct PVRSRV_SYNC_OBJECT *)(((u8 *) psCommand->psSrcSync) + + (ui32SrcSyncCount * + sizeof(struct PVRSRV_SYNC_OBJECT))); + + psCommand->ui32DataSize = ui32DataByteSize; + + for (i = 0; i < ui32DstSyncCount; i++) { + psCommand->psDstSync[i].psKernelSyncInfoKM = apsDstSync[i]; + psCommand->psDstSync[i].ui32WriteOpsPending = + PVRSRVGetWriteOpsPending(apsDstSync[i], IMG_FALSE); + psCommand->psDstSync[i].ui32ReadOpsPending = + PVRSRVGetReadOpsPending(apsDstSync[i], IMG_FALSE); + } + + for (i = 0; i < ui32SrcSyncCount; i++) { + psCommand->psSrcSync[i].psKernelSyncInfoKM = apsSrcSync[i]; + psCommand->psSrcSync[i].ui32WriteOpsPending = + PVRSRVGetWriteOpsPending(apsSrcSync[i], IMG_TRUE); + psCommand->psSrcSync[i].ui32ReadOpsPending = + PVRSRVGetReadOpsPending(apsSrcSync[i], IMG_TRUE); + } + + *ppsCommand = psCommand; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVSubmitCommandKM(struct PVRSRV_QUEUE_INFO *psQueue, + struct PVRSRV_COMMAND *psCommand) +{ + + if (psCommand->ui32DstSyncCount > 0) { + psCommand->psDstSync = (struct PVRSRV_SYNC_OBJECT *) + (((u8 *)psQueue->pvLinQueueKM) + + psQueue->ui32WriteOffset + + sizeof(struct PVRSRV_COMMAND)); + } + + if (psCommand->ui32SrcSyncCount > 0) { + psCommand->psSrcSync = (struct PVRSRV_SYNC_OBJECT *) + (((u8 *)psQueue->pvLinQueueKM) + + psQueue->ui32WriteOffset + + sizeof(struct PVRSRV_COMMAND) + + (psCommand->ui32DstSyncCount * + sizeof(struct PVRSRV_SYNC_OBJECT))); + } + + psCommand->pvData = (struct PVRSRV_SYNC_OBJECT *) + (((u8 *)psQueue->pvLinQueueKM) + + psQueue->ui32WriteOffset + + sizeof(struct PVRSRV_COMMAND) + + (psCommand->ui32DstSyncCount * + sizeof(struct PVRSRV_SYNC_OBJECT)) + + (psCommand->ui32SrcSyncCount * + sizeof(struct PVRSRV_SYNC_OBJECT))); + + UPDATE_QUEUE_WOFF(psQueue, psCommand->ui32CmdSize); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR PVRSRVProcessCommand(struct SYS_DATA *psSysData, + struct PVRSRV_COMMAND *psCommand, + IMG_BOOL bFlush) +{ + struct PVRSRV_SYNC_OBJECT *psWalkerObj; + struct PVRSRV_SYNC_OBJECT *psEndObj; + u32 i; + struct COMMAND_COMPLETE_DATA *psCmdCompleteData; + enum PVRSRV_ERROR eError = PVRSRV_OK; + u32 ui32WriteOpsComplete; + u32 ui32ReadOpsComplete; + + psWalkerObj = psCommand->psDstSync; + psEndObj = psWalkerObj + psCommand->ui32DstSyncCount; + while (psWalkerObj < psEndObj) { + struct PVRSRV_SYNC_DATA *psSyncData = + psWalkerObj->psKernelSyncInfoKM->psSyncData; + + ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete; + ui32ReadOpsComplete = psSyncData->ui32ReadOpsComplete; + + if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending) + || (ui32ReadOpsComplete != + psWalkerObj->ui32ReadOpsPending)) { + if (!bFlush || + !SYNCOPS_STALE(ui32WriteOpsComplete, + psWalkerObj->ui32WriteOpsPending) || + !SYNCOPS_STALE(ui32ReadOpsComplete, + psWalkerObj->ui32ReadOpsPending)) { + return PVRSRV_ERROR_FAILED_DEPENDENCIES; + } + } + + psWalkerObj++; + } + + psWalkerObj = psCommand->psSrcSync; + psEndObj = psWalkerObj + psCommand->ui32SrcSyncCount; + while (psWalkerObj < psEndObj) { + struct PVRSRV_SYNC_DATA *psSyncData = + psWalkerObj->psKernelSyncInfoKM->psSyncData; + + ui32ReadOpsComplete = psSyncData->ui32ReadOpsComplete; + ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete; + + if ((ui32WriteOpsComplete != + psWalkerObj->ui32WriteOpsPending) || + (ui32ReadOpsComplete != + psWalkerObj->ui32ReadOpsPending)) { + if (!bFlush && + SYNCOPS_STALE(ui32WriteOpsComplete, + psWalkerObj->ui32WriteOpsPending) && + SYNCOPS_STALE(ui32ReadOpsComplete, + psWalkerObj->ui32ReadOpsPending)) { + PVR_DPF(PVR_DBG_WARNING, + "PVRSRVProcessCommand: Stale syncops psSyncData:0x%x " + "ui32WriteOpsComplete:0x%x ui32WriteOpsPending:0x%x", + psSyncData, ui32WriteOpsComplete, + psWalkerObj->ui32WriteOpsPending); + } + + if (!bFlush || + !SYNCOPS_STALE(ui32WriteOpsComplete, + psWalkerObj->ui32WriteOpsPending) || + !SYNCOPS_STALE(ui32ReadOpsComplete, + psWalkerObj->ui32ReadOpsPending)) { + return PVRSRV_ERROR_FAILED_DEPENDENCIES; + } + } + psWalkerObj++; + } + + if (psCommand->ui32DevIndex >= SYS_DEVICE_COUNT) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVProcessCommand: invalid DeviceType 0x%x", + psCommand->ui32DevIndex); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psCmdCompleteData = + psSysData->ppsCmdCompleteData[psCommand->ui32DevIndex][psCommand-> + CommandType]; + if (psCmdCompleteData->bInUse) + + return PVRSRV_ERROR_FAILED_DEPENDENCIES; + + psCmdCompleteData->bInUse = IMG_TRUE; + + psCmdCompleteData->ui32DstSyncCount = psCommand->ui32DstSyncCount; + for (i = 0; i < psCommand->ui32DstSyncCount; i++) + psCmdCompleteData->psDstSync[i] = psCommand->psDstSync[i]; + + psCmdCompleteData->ui32SrcSyncCount = psCommand->ui32SrcSyncCount; + for (i = 0; i < psCommand->ui32SrcSyncCount; i++) + psCmdCompleteData->psSrcSync[i] = psCommand->psSrcSync[i]; + + if (psSysData->ppfnCmdProcList[psCommand->ui32DevIndex] + [psCommand->CommandType]((void *) + psCmdCompleteData, + psCommand->ui32DataSize, + psCommand->pvData) == IMG_FALSE) { + psCmdCompleteData->bInUse = IMG_FALSE; + eError = PVRSRV_ERROR_CMD_NOT_PROCESSED; + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVProcessQueues(IMG_BOOL bFlush) +{ + struct PVRSRV_QUEUE_INFO *psQueue; + struct SYS_DATA *psSysData; + struct PVRSRV_COMMAND *psCommand; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + enum PVRSRV_ERROR eError; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return eError; + + psQueue = psSysData->psQueueList; + + if (!psQueue) { + PVR_DPF(PVR_DBG_MESSAGE, + "No Queues installed - cannot process commands"); + } + + if (bFlush) + PVRSRVSetDCState(DC_STATE_FLUSH_COMMANDS); + + while (psQueue) { + while (psQueue->ui32ReadOffset != psQueue->ui32WriteOffset) { + psCommand = (struct PVRSRV_COMMAND *)((u32) psQueue-> + pvLinQueueKM + psQueue->ui32ReadOffset); + + if (PVRSRVProcessCommand(psSysData, psCommand, bFlush) + == PVRSRV_OK) { + UPDATE_QUEUE_ROFF(psQueue, + psCommand->ui32CmdSize) + if (bFlush) + continue; + } + break; + } + psQueue = psQueue->psNextKM; + } + + if (bFlush) + PVRSRVSetDCState(DC_STATE_NO_FLUSH_COMMANDS); + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode != NULL) { + if (psDeviceNode->bReProcessDeviceCommandComplete && + psDeviceNode->pfnDeviceCommandComplete != NULL) { + (*psDeviceNode-> + pfnDeviceCommandComplete) (psDeviceNode); + } + psDeviceNode = psDeviceNode->psNext; + } + + return PVRSRV_OK; +} + +void PVRSRVCommandCompleteKM(void *hCmdCookie, IMG_BOOL bScheduleMISR) +{ + u32 i; + struct COMMAND_COMPLETE_DATA *psCmdCompleteData = + (struct COMMAND_COMPLETE_DATA *)hCmdCookie; + struct SYS_DATA *psSysData; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return; + + for (i = 0; i < psCmdCompleteData->ui32DstSyncCount; i++) { + psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->psSyncData-> + ui32WriteOpsComplete++; + } + + for (i = 0; i < psCmdCompleteData->ui32SrcSyncCount; i++) { + psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->psSyncData-> + ui32ReadOpsComplete++; + } + + psCmdCompleteData->bInUse = IMG_FALSE; + + PVRSRVCommandCompleteCallbacks(); + + if (bScheduleMISR) + OSScheduleMISR(psSysData); +} + +void PVRSRVCommandCompleteCallbacks(void) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVCommandCompleteCallbacks: " + "SysAcquireData failed"); + return; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode != NULL) { + if (psDeviceNode->pfnDeviceCommandComplete != NULL) + (*psDeviceNode->pfnDeviceCommandComplete)(psDeviceNode); + psDeviceNode = psDeviceNode->psNext; + } +} + +enum PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(u32 ui32DevIndex, + IMG_BOOL (**ppfnCmdProcList)(void *, u32, void *), + u32 ui32MaxSyncsPerCmd[][2], u32 ui32CmdCount) +{ + struct SYS_DATA *psSysData; + enum PVRSRV_ERROR eError; + u32 i; + u32 ui32AllocSize; + IMG_BOOL (**ppfnCmdProc)(void *, u32, void *); + struct COMMAND_COMPLETE_DATA *psCmdCompleteData; + + if (ui32DevIndex >= SYS_DEVICE_COUNT) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterCmdProcListKM: invalid DeviceType 0x%x", + ui32DevIndex); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterCmdProcListKM: SysAcquireData failed"); + return eError; + } + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ui32CmdCount * + sizeof(IMG_BOOL (*)(void *, u32, void *)), + (void **)&psSysData->ppfnCmdProcList[ui32DevIndex], + NULL); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterCmdProcListKM: Failed to alloc queue"); + return eError; + } + + ppfnCmdProc = psSysData->ppfnCmdProcList[ui32DevIndex]; + + for (i = 0; i < ui32CmdCount; i++) + ppfnCmdProc[i] = ppfnCmdProcList[i]; + + ui32AllocSize = ui32CmdCount * sizeof(struct COMMAND_COMPLETE_DATA *); + eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + ui32AllocSize, + (void **) &psSysData-> + ppsCmdCompleteData[ui32DevIndex], NULL); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterCmdProcListKM: Failed to alloc CC data"); + goto ErrorExit; + } + + /* clear the list to ensure that we don't try to access uninitialised + * pointer in the 'error' execution path */ + OSMemSet(psSysData->ppsCmdCompleteData[ui32DevIndex], 0x00, + ui32AllocSize); + + for (i = 0; i < ui32CmdCount; i++) { + ui32AllocSize = sizeof(struct COMMAND_COMPLETE_DATA) + + ((ui32MaxSyncsPerCmd[i][0] + ui32MaxSyncsPerCmd[i][1]) + * sizeof(struct PVRSRV_SYNC_OBJECT)); + + eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + ui32AllocSize, + (void **)&psSysData-> + ppsCmdCompleteData[ui32DevIndex][i], + NULL); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterCmdProcListKM: " + "Failed to alloc cmd %d", + i); + goto ErrorExit; + } + + OSMemSet(psSysData->ppsCmdCompleteData[ui32DevIndex][i], 0x00, + ui32AllocSize); + + psCmdCompleteData = + psSysData->ppsCmdCompleteData[ui32DevIndex][i]; + + psCmdCompleteData->psDstSync = (struct PVRSRV_SYNC_OBJECT *) + (((u32) psCmdCompleteData) + + sizeof(struct COMMAND_COMPLETE_DATA)); + psCmdCompleteData->psSrcSync = (struct PVRSRV_SYNC_OBJECT *) + (((u32) psCmdCompleteData->psDstSync) + + (sizeof(struct PVRSRV_SYNC_OBJECT) * + ui32MaxSyncsPerCmd[i][0])); + psCmdCompleteData->ui32AllocSize = ui32AllocSize; + } + + return PVRSRV_OK; + +ErrorExit: + + if (psSysData->ppsCmdCompleteData[ui32DevIndex] != NULL) { + for (i = 0; i < ui32CmdCount; i++) { + if (psSysData->ppsCmdCompleteData[ui32DevIndex][i] != + NULL) { + psCmdCompleteData = + psSysData-> + ppsCmdCompleteData[ui32DevIndex][i]; + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + psCmdCompleteData->ui32AllocSize, + psCmdCompleteData, NULL); + } + } + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + ui32CmdCount * sizeof(struct COMMAND_COMPLETE_DATA *), + psSysData->ppsCmdCompleteData[ui32DevIndex], + NULL); + } + + if (psSysData->ppfnCmdProcList[ui32DevIndex] != NULL) { + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, 0, + psSysData->ppfnCmdProcList[ui32DevIndex], NULL); + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(u32 ui32DevIndex, u32 ui32CmdCount) +{ + struct SYS_DATA *psSysData; + enum PVRSRV_ERROR eError; + u32 i; + + if (ui32DevIndex >= SYS_DEVICE_COUNT) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveCmdProcListKM: invalid DeviceType 0x%x", + ui32DevIndex); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveCmdProcListKM: SysAcquireData failed"); + return eError; + } + + if (psSysData->ppsCmdCompleteData[ui32DevIndex] == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveCmdProcListKM: Invalid command array"); + return PVRSRV_ERROR_INVALID_PARAMS; + } else { + for (i = 0; i < ui32CmdCount; i++) { + + if (psSysData->ppsCmdCompleteData[ui32DevIndex][i] != + NULL) { + struct COMMAND_COMPLETE_DATA * + psCmdCompleteData = psSysData-> + ppsCmdCompleteData[ui32DevIndex][i]; + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + psCmdCompleteData->ui32AllocSize, + psCmdCompleteData, NULL); + } + } + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + ui32CmdCount * sizeof(struct COMMAND_COMPLETE_DATA *), + psSysData->ppsCmdCompleteData[ui32DevIndex], NULL); + } + + if (psSysData->ppfnCmdProcList[ui32DevIndex] != NULL) { + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + ui32CmdCount * + sizeof(IMG_BOOL (*)(void *, u32, void *)), + psSysData->ppfnCmdProcList[ui32DevIndex], NULL); + } + + return PVRSRV_OK; +} diff --git a/drivers/gpu/pvr/queue.h b/drivers/gpu/pvr/queue.h new file mode 100644 index 00000000000..92d9fe952c4 --- /dev/null +++ b/drivers/gpu/pvr/queue.h @@ -0,0 +1,81 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef QUEUE_H +#define QUEUE_H + +#define UPDATE_QUEUE_ROFF(psQueue, ui32Size) \ + psQueue->ui32ReadOffset = (psQueue->ui32ReadOffset + ui32Size) \ + & (psQueue->ui32QueueSize - 1); + +struct COMMAND_COMPLETE_DATA { + IMG_BOOL bInUse; + + u32 ui32DstSyncCount; + u32 ui32SrcSyncCount; + struct PVRSRV_SYNC_OBJECT *psDstSync; + struct PVRSRV_SYNC_OBJECT *psSrcSync; + u32 ui32AllocSize; +}; + +enum PVRSRV_ERROR PVRSRVProcessQueues(IMG_BOOL bFlush); + +#if defined(__KERNEL__) +#include <linux/types.h> +off_t QueuePrintQueues(char *buffer, size_t size, off_t off); +#endif + +enum PVRSRV_ERROR PVRSRVCreateCommandQueueKM(u32 ui32QueueSize, + struct PVRSRV_QUEUE_INFO **ppsQueueInfo); +enum PVRSRV_ERROR PVRSRVDestroyCommandQueueKM( + struct PVRSRV_QUEUE_INFO *psQueueInfo); + +enum PVRSRV_ERROR PVRSRVInsertCommandKM(struct PVRSRV_QUEUE_INFO *psQueue, + struct PVRSRV_COMMAND **ppsCommand, u32 ui32DevIndex, + u16 CommandType, u32 ui32DstSyncCount, + struct PVRSRV_KERNEL_SYNC_INFO *apsDstSync[], + u32 ui32SrcSyncCount, + struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[], + u32 ui32DataByteSize); + +enum PVRSRV_ERROR PVRSRVGetQueueSpaceKM(struct PVRSRV_QUEUE_INFO *psQueue, + u32 ui32ParamSize, void **ppvSpace); + +enum PVRSRV_ERROR PVRSRVSubmitCommandKM(struct PVRSRV_QUEUE_INFO *psQueue, + struct PVRSRV_COMMAND *psCommand); + +void PVRSRVCommandCompleteKM(void *hCmdCookie, IMG_BOOL bScheduleMISR); + +void PVRSRVCommandCompleteCallbacks(void); + +enum PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(u32 ui32DevIndex, + IMG_BOOL (**ppfnCmdProcList)(void *, u32, void *), + u32 ui32MaxSyncsPerCmd[][2], u32 ui32CmdCount); +enum PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(u32 ui32DevIndex, + u32 ui32CmdCount); + + +#endif diff --git a/drivers/gpu/pvr/ra.c b/drivers/gpu/pvr/ra.c new file mode 100644 index 00000000000..4c71af18839 --- /dev/null +++ b/drivers/gpu/pvr/ra.c @@ -0,0 +1,1164 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "services_headers.h" +#include "hash.h" +#include "ra.h" +#include "buffer_manager.h" +#include "osfunc.h" + +#include <linux/kernel.h> +#include "proc.h" + + +#define MINIMUM_HASH_SIZE 64 + +struct BT { + enum bt_type { + btt_span, + btt_free, + btt_live + } type; + + u32 base; + size_t uSize; + + struct BT *pNextSegment; + struct BT *pPrevSegment; + + struct BT *pNextFree; + struct BT *pPrevFree; + + struct BM_MAPPING *psMapping; +}; +struct BT; + +struct RA_ARENA { + char *name; + u32 uQuantum; + IMG_BOOL(*pImportAlloc)(void *, size_t uSize, size_t *pActualSize, + struct BM_MAPPING **ppsMapping, u32 uFlags, + u32 *pBase); + void (*pImportFree)(void *, u32, struct BM_MAPPING *psMapping); + void (*pBackingStoreFree)(void *, u32, u32, void *); + void *pImportHandle; +#define FREE_TABLE_LIMIT 32 + struct BT *aHeadFree[FREE_TABLE_LIMIT]; + struct BT *pHeadSegment; + struct BT *pTailSegment; + struct HASH_TABLE *pSegmentHash; +#ifdef RA_STATS + struct RA_STATISTICS sStatistics; +#endif +#if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA) +#define PROC_NAME_SIZE 32 + char szProcInfoName[PROC_NAME_SIZE]; + char szProcSegsName[PROC_NAME_SIZE]; + IMG_BOOL bInitProcEntry; +#endif +}; + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA) +static int RA_DumpSegs(char *page, char **start, off_t off, int count, int *eof, + void *data); +static int RA_DumpInfo(char *page, char **start, off_t off, int count, int *eof, + void *data); +#endif + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA) +static char *ReplaceSpaces(char *const pS) +{ + char *pT; + + for (pT = pS; *pT != 0; pT++) + if (*pT == ' ' || *pT == '\t') + *pT = '_'; + + return pS; +} +#endif + +static IMG_BOOL _RequestAllocFail(void *_h, size_t _uSize, size_t *_pActualSize, + struct BM_MAPPING **_ppsMapping, + u32 _uFlags, u32 *_pBase) +{ + PVR_UNREFERENCED_PARAMETER(_h); + PVR_UNREFERENCED_PARAMETER(_uSize); + PVR_UNREFERENCED_PARAMETER(_pActualSize); + PVR_UNREFERENCED_PARAMETER(_ppsMapping); + PVR_UNREFERENCED_PARAMETER(_uFlags); + PVR_UNREFERENCED_PARAMETER(_pBase); + + return IMG_FALSE; +} + +static u32 pvr_log2(size_t n) +{ + u32 l = 0; + n >>= 1; + while (n > 0) { + n >>= 1; + l++; + } + return l; +} + +static enum PVRSRV_ERROR _SegmentListInsertAfter(struct RA_ARENA *pArena, + struct BT *pInsertionPoint, + struct BT *pBT) +{ + PVR_ASSERT(pArena != NULL); + PVR_ASSERT(pInsertionPoint != NULL); + + if ((pInsertionPoint == NULL) || (pArena == NULL)) { + PVR_DPF(PVR_DBG_ERROR, + "_SegmentListInsertAfter: invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + pBT->pNextSegment = pInsertionPoint->pNextSegment; + pBT->pPrevSegment = pInsertionPoint; + if (pInsertionPoint->pNextSegment == NULL) + pArena->pTailSegment = pBT; + else + pInsertionPoint->pNextSegment->pPrevSegment = pBT; + pInsertionPoint->pNextSegment = pBT; + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR _SegmentListInsert(struct RA_ARENA *pArena, + struct BT *pBT) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (pArena->pHeadSegment == NULL) { + pArena->pHeadSegment = pArena->pTailSegment = pBT; + pBT->pNextSegment = pBT->pPrevSegment = NULL; + } else { + struct BT *pBTScan; + if (pBT->base < pArena->pHeadSegment->base) { + pBT->pNextSegment = pArena->pHeadSegment; + pArena->pHeadSegment->pPrevSegment = pBT; + pArena->pHeadSegment = pBT; + pBT->pPrevSegment = NULL; + } else { + pBTScan = pArena->pHeadSegment; + + while ((pBTScan->pNextSegment != NULL) && + (pBT->base >= pBTScan->pNextSegment->base)) + pBTScan = pBTScan->pNextSegment; + + eError = _SegmentListInsertAfter(pArena, pBTScan, pBT); + if (eError != PVRSRV_OK) + return eError; + } + } + return eError; +} + +static void _SegmentListRemove(struct RA_ARENA *pArena, struct BT *pBT) +{ + if (pBT->pPrevSegment == NULL) + pArena->pHeadSegment = pBT->pNextSegment; + else + pBT->pPrevSegment->pNextSegment = pBT->pNextSegment; + + if (pBT->pNextSegment == NULL) + pArena->pTailSegment = pBT->pPrevSegment; + else + pBT->pNextSegment->pPrevSegment = pBT->pPrevSegment; +} + +static struct BT *_SegmentSplit(struct RA_ARENA *pArena, struct BT *pBT, + size_t uSize) +{ + struct BT *pNeighbour; + + PVR_ASSERT(pArena != NULL); + + if (pArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "_SegmentSplit: invalid parameter - pArena"); + return NULL; + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct BT), + (void **) &pNeighbour, NULL) != PVRSRV_OK) + return NULL; + + pNeighbour->pPrevSegment = pBT; + pNeighbour->pNextSegment = pBT->pNextSegment; + if (pBT->pNextSegment == NULL) + pArena->pTailSegment = pNeighbour; + else + pBT->pNextSegment->pPrevSegment = pNeighbour; + pBT->pNextSegment = pNeighbour; + + pNeighbour->type = btt_free; + pNeighbour->uSize = pBT->uSize - uSize; + pNeighbour->base = pBT->base + uSize; + pNeighbour->psMapping = pBT->psMapping; + pBT->uSize = uSize; + return pNeighbour; +} + +static void _FreeListInsert(struct RA_ARENA *pArena, struct BT *pBT) +{ + u32 uIndex; + uIndex = pvr_log2(pBT->uSize); + pBT->type = btt_free; + pBT->pNextFree = pArena->aHeadFree[uIndex]; + pBT->pPrevFree = NULL; + if (pArena->aHeadFree[uIndex] != NULL) + pArena->aHeadFree[uIndex]->pPrevFree = pBT; + pArena->aHeadFree[uIndex] = pBT; +} + +static void _FreeListRemove(struct RA_ARENA *pArena, struct BT *pBT) +{ + u32 uIndex; + uIndex = pvr_log2(pBT->uSize); + if (pBT->pNextFree != NULL) + pBT->pNextFree->pPrevFree = pBT->pPrevFree; + if (pBT->pPrevFree == NULL) + pArena->aHeadFree[uIndex] = pBT->pNextFree; + else + pBT->pPrevFree->pNextFree = pBT->pNextFree; +} + +static struct BT *_BuildSpanMarker(u32 base, size_t uSize) +{ + struct BT *pBT; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct BT), + (void **) &pBT, NULL) != PVRSRV_OK) + return NULL; + + pBT->type = btt_span; + pBT->base = base; + pBT->uSize = uSize; + pBT->psMapping = NULL; + + return pBT; +} + +static struct BT *_BuildBT(u32 base, size_t uSize) +{ + struct BT *pBT; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct BT), + (void **) &pBT, NULL) != PVRSRV_OK) + return NULL; + + pBT->type = btt_free; + pBT->base = base; + pBT->uSize = uSize; + + return pBT; +} + +static struct BT *_InsertResource(struct RA_ARENA *pArena, u32 base, + size_t uSize) +{ + struct BT *pBT; + PVR_ASSERT(pArena != NULL); + if (pArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "_InsertResource: invalid parameter - pArena"); + return NULL; + } + + pBT = _BuildBT(base, uSize); + if (pBT != NULL) { + if (_SegmentListInsert(pArena, pBT) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "_InsertResource: call to _SegmentListInsert failed"); + return NULL; + } + _FreeListInsert(pArena, pBT); +#ifdef RA_STATS + pArena->sStatistics.uTotalResourceCount += uSize; + pArena->sStatistics.uFreeResourceCount += uSize; + pArena->sStatistics.uSpanCount++; +#endif + } + return pBT; +} + +static struct BT *_InsertResourceSpan(struct RA_ARENA *pArena, u32 base, + size_t uSize) +{ + enum PVRSRV_ERROR eError; + struct BT *pSpanStart; + struct BT *pSpanEnd; + struct BT *pBT; + + PVR_ASSERT(pArena != NULL); + if (pArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "_InsertResourceSpan: invalid parameter - pArena"); + return NULL; + } + + PVR_DPF(PVR_DBG_MESSAGE, + "RA_InsertResourceSpan: arena='%s', base=0x%x, size=0x%x", + pArena->name, base, uSize); + + pSpanStart = _BuildSpanMarker(base, uSize); + if (pSpanStart == NULL) + goto fail_start; + pSpanEnd = _BuildSpanMarker(base + uSize, 0); + if (pSpanEnd == NULL) + goto fail_end; + + pBT = _BuildBT(base, uSize); + if (pBT == NULL) + goto fail_bt; + + eError = _SegmentListInsert(pArena, pSpanStart); + if (eError != PVRSRV_OK) + goto fail_SegListInsert; + + eError = _SegmentListInsertAfter(pArena, pSpanStart, pBT); + if (eError != PVRSRV_OK) + goto fail_SegListInsert; + + _FreeListInsert(pArena, pBT); + + eError = _SegmentListInsertAfter(pArena, pBT, pSpanEnd); + if (eError != PVRSRV_OK) + goto fail_SegListInsert; + +#ifdef RA_STATS + pArena->sStatistics.uTotalResourceCount += uSize; +#endif + return pBT; + +fail_SegListInsert: + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pBT, NULL); +fail_bt: + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pSpanEnd, NULL); +fail_end: + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pSpanStart, NULL); +fail_start: + return NULL; +} + +static void _FreeBT(struct RA_ARENA *pArena, struct BT *pBT, + IMG_BOOL bFreeBackingStore) +{ + struct BT *pNeighbour; + u32 uOrigBase; + size_t uOrigSize; + + PVR_ASSERT(pArena != NULL); + PVR_ASSERT(pBT != NULL); + + if ((pArena == NULL) || (pBT == NULL)) { + PVR_DPF(PVR_DBG_ERROR, "_FreeBT: invalid parameter"); + return; + } +#ifdef RA_STATS + pArena->sStatistics.uLiveSegmentCount--; + pArena->sStatistics.uFreeSegmentCount++; + pArena->sStatistics.uFreeResourceCount += pBT->uSize; +#endif + + uOrigBase = pBT->base; + uOrigSize = pBT->uSize; + + pNeighbour = pBT->pPrevSegment; + if (pNeighbour != NULL && pNeighbour->type == btt_free && + pNeighbour->base + pNeighbour->uSize == pBT->base) { + _FreeListRemove(pArena, pNeighbour); + _SegmentListRemove(pArena, pNeighbour); + pBT->base = pNeighbour->base; + pBT->uSize += pNeighbour->uSize; + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), + pNeighbour, NULL); +#ifdef RA_STATS + pArena->sStatistics.uFreeSegmentCount--; +#endif + } + + pNeighbour = pBT->pNextSegment; + if (pNeighbour != NULL && pNeighbour->type == btt_free && + pBT->base + pBT->uSize == pNeighbour->base) { + _FreeListRemove(pArena, pNeighbour); + _SegmentListRemove(pArena, pNeighbour); + pBT->uSize += pNeighbour->uSize; + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), + pNeighbour, NULL); +#ifdef RA_STATS + pArena->sStatistics.uFreeSegmentCount--; +#endif + } + + if (pArena->pBackingStoreFree != NULL && bFreeBackingStore) { + u32 uRoundedStart, uRoundedEnd; + + uRoundedStart = (uOrigBase / pArena->uQuantum) * + pArena->uQuantum; + + if (uRoundedStart < pBT->base) + uRoundedStart += pArena->uQuantum; + + uRoundedEnd = ((uOrigBase + uOrigSize + pArena->uQuantum - + 1) / pArena->uQuantum) * pArena->uQuantum; + + if (uRoundedEnd > (pBT->base + pBT->uSize)) + uRoundedEnd -= pArena->uQuantum; + + if (uRoundedStart < uRoundedEnd) + pArena->pBackingStoreFree(pArena->pImportHandle, + uRoundedStart, uRoundedEnd, + (void *) 0); + } + + if (pBT->pNextSegment != NULL && pBT->pNextSegment->type == btt_span && + pBT->pPrevSegment != NULL && pBT->pPrevSegment->type == btt_span) { + struct BT *next = pBT->pNextSegment; + struct BT *prev = pBT->pPrevSegment; + _SegmentListRemove(pArena, next); + _SegmentListRemove(pArena, prev); + _SegmentListRemove(pArena, pBT); + pArena->pImportFree(pArena->pImportHandle, pBT->base, + pBT->psMapping); +#ifdef RA_STATS + pArena->sStatistics.uSpanCount--; + pArena->sStatistics.uExportCount++; + pArena->sStatistics.uFreeSegmentCount--; + pArena->sStatistics.uFreeResourceCount -= pBT->uSize; + pArena->sStatistics.uTotalResourceCount -= pBT->uSize; +#endif + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), next, + NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), prev, + NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pBT, + NULL); + } else + _FreeListInsert(pArena, pBT); +} + +static int alloc_from_bt(struct RA_ARENA *arena, struct BT *bt, u32 start, + size_t size, u32 align, + struct BM_MAPPING **new_mapping, u32 *new_base) +{ + _FreeListRemove(arena, bt); + PVR_ASSERT(bt->type == btt_free); +#ifdef RA_STATS + arena->sStatistics.uLiveSegmentCount++; + arena->sStatistics.uFreeSegmentCount--; + arena->sStatistics.uFreeResourceCount -= bt->uSize; +#endif + if (start > bt->base) { + struct BT *next_bt; + + next_bt = _SegmentSplit(arena, bt, start - bt->base); + + if (!next_bt) { + PVR_DPF(PVR_DBG_ERROR, "_AttemptAllocAligned: " + "Front split failed"); + + _FreeListInsert(arena, bt); + return -1; + } + + _FreeListInsert(arena, bt); +#ifdef RA_STATS + arena->sStatistics.uFreeSegmentCount++; + arena->sStatistics.uFreeResourceCount += bt->uSize; +#endif + bt = next_bt; + } + + if (bt->uSize > size) { + struct BT *next_bt; + next_bt = _SegmentSplit(arena, bt, size); + + if (!next_bt) { + PVR_DPF(PVR_DBG_ERROR, "_AttemptAllocAligned: " + "Back split failed"); + + _FreeListInsert(arena, bt); + return -1; + } + + _FreeListInsert(arena, next_bt); +#ifdef RA_STATS + arena->sStatistics.uFreeSegmentCount++; + arena->sStatistics.uFreeResourceCount += next_bt->uSize; +#endif + } + + bt->type = btt_live; + + if (!HASH_Insert(arena->pSegmentHash, bt->base, (u32)bt)) { + _FreeBT(arena, bt, IMG_FALSE); + return -1; + } + + if (new_mapping) + *new_mapping = bt->psMapping; + + *new_base = bt->base; + + return 0; +} + +static IMG_BOOL _AttemptAllocAligned(struct RA_ARENA *pArena, size_t uSize, + struct BM_MAPPING **ppsMapping, u32 uFlags, u32 uAlignment, + u32 *base) +{ + u32 uIndex; + PVR_ASSERT(pArena != NULL); + if (pArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "_AttemptAllocAligned: invalid parameter - pArena"); + return IMG_FALSE; + } + + uIndex = pvr_log2(uSize); + + while (uIndex < FREE_TABLE_LIMIT && pArena->aHeadFree[uIndex] == NULL) + uIndex++; + + for (; uIndex < FREE_TABLE_LIMIT; uIndex++) { + struct BT *pBT; + + pBT = pArena->aHeadFree[uIndex]; + if (!pBT) + continue; + + for (; pBT != NULL; pBT = pBT->pNextFree) { + u32 aligned_base; + + if (uAlignment > 1) + aligned_base = (pBT->base + uAlignment - + 1) / uAlignment * uAlignment; + else + aligned_base = pBT->base; + PVR_DPF(PVR_DBG_MESSAGE, + "RA_AttemptAllocAligned: pBT-base=0x%x " + "pBT-size=0x%x alignedbase=0x%x size=0x%x", + pBT->base, pBT->uSize, aligned_base, uSize); + + if (pBT->base + pBT->uSize < aligned_base + uSize) + continue; + + if (pBT->psMapping && pBT->psMapping->ui32Flags != + uFlags) { + PVR_DPF(PVR_DBG_MESSAGE, + "AttemptAllocAligned: mismatch in " + "flags. Import has %x, request was %x", + pBT->psMapping->ui32Flags, uFlags); + continue; + } + + if (alloc_from_bt(pArena, pBT, aligned_base, uSize, + uFlags, ppsMapping, base) < 0) + return IMG_FALSE; + + return IMG_TRUE; + } + } + + return IMG_FALSE; +} + +struct RA_ARENA *RA_Create(char *name, u32 base, size_t uSize, + struct BM_MAPPING *psMapping, size_t uQuantum, + IMG_BOOL(*imp_alloc) (void *, size_t uSize, + size_t *pActualSize, + struct BM_MAPPING **ppsMapping, + u32 _flags, u32 *pBase), + void (*imp_free) (void *, u32, struct BM_MAPPING *), + void(*backingstore_free) (void *, u32, u32, void *), + void *pImportHandle) +{ + struct RA_ARENA *pArena; + struct BT *pBT; + int i; + + PVR_DPF(PVR_DBG_MESSAGE, "RA_Create: " + "name='%s', base=0x%x, uSize=0x%x, alloc=0x%x, free=0x%x", + name, base, uSize, imp_alloc, imp_free); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(*pArena), + (void **) &pArena, NULL) != PVRSRV_OK) + goto arena_fail; + + pArena->name = name; + pArena->pImportAlloc = + (imp_alloc != NULL) ? imp_alloc : _RequestAllocFail; + pArena->pImportFree = imp_free; + pArena->pBackingStoreFree = backingstore_free; + pArena->pImportHandle = pImportHandle; + for (i = 0; i < FREE_TABLE_LIMIT; i++) + pArena->aHeadFree[i] = NULL; + pArena->pHeadSegment = NULL; + pArena->pTailSegment = NULL; + pArena->uQuantum = uQuantum; + +#ifdef RA_STATS + pArena->sStatistics.uSpanCount = 0; + pArena->sStatistics.uLiveSegmentCount = 0; + pArena->sStatistics.uFreeSegmentCount = 0; + pArena->sStatistics.uFreeResourceCount = 0; + pArena->sStatistics.uTotalResourceCount = 0; + pArena->sStatistics.uCumulativeAllocs = 0; + pArena->sStatistics.uCumulativeFrees = 0; + pArena->sStatistics.uImportCount = 0; + pArena->sStatistics.uExportCount = 0; +#endif + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA) + if (strcmp(pArena->name, "") != 0) { + int ret; + int (*pfnCreateProcEntry) (const char *, read_proc_t, + write_proc_t, void *); + + pArena->bInitProcEntry = + !PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL); + + pfnCreateProcEntry = pArena->bInitProcEntry ? CreateProcEntry : + CreatePerProcessProcEntry; + + ret = snprintf(pArena->szProcInfoName, + sizeof(pArena->szProcInfoName), "ra_info_%s", + pArena->name); + if (ret > 0 && ret < sizeof(pArena->szProcInfoName)) { + (void)pfnCreateProcEntry(ReplaceSpaces + (pArena->szProcInfoName), + RA_DumpInfo, NULL, pArena); + } else { + pArena->szProcInfoName[0] = 0; + PVR_DPF(PVR_DBG_ERROR, "RA_Create: " + "couldn't create ra_info proc entry for arena %s", + pArena->name); + } + + ret = snprintf(pArena->szProcSegsName, + sizeof(pArena->szProcSegsName), "ra_segs_%s", + pArena->name); + if (ret > 0 && ret < sizeof(pArena->szProcInfoName)) { + (void)pfnCreateProcEntry(ReplaceSpaces + (pArena->szProcSegsName), + RA_DumpSegs, NULL, pArena); + } else { + pArena->szProcSegsName[0] = 0; + PVR_DPF(PVR_DBG_ERROR, "RA_Create: " + "couldn't create ra_segs proc entry for arena %s", + pArena->name); + } + } +#endif + + pArena->pSegmentHash = HASH_Create(MINIMUM_HASH_SIZE); + if (pArena->pSegmentHash == NULL) + goto hash_fail; + if (uSize > 0) { + uSize = (uSize + uQuantum - 1) / uQuantum * uQuantum; + pBT = _InsertResource(pArena, base, uSize); + if (pBT == NULL) + goto insert_fail; + pBT->psMapping = psMapping; + + } + return pArena; + +insert_fail: + HASH_Delete(pArena->pSegmentHash); +hash_fail: + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RA_ARENA), pArena, + NULL); +arena_fail: + return NULL; +} + +void RA_Delete(struct RA_ARENA *pArena) +{ + u32 uIndex; + + PVR_ASSERT(pArena != NULL); + + if (pArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "RA_Delete: invalid parameter - pArena"); + return; + } + + PVR_DPF(PVR_DBG_MESSAGE, "RA_Delete: name='%s'", pArena->name); + + for (uIndex = 0; uIndex < FREE_TABLE_LIMIT; uIndex++) + pArena->aHeadFree[uIndex] = NULL; + + while (pArena->pHeadSegment != NULL) { + struct BT *pBT = pArena->pHeadSegment; + PVR_ASSERT(pBT->type == btt_free); + _SegmentListRemove(pArena, pBT); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pBT, + NULL); +#ifdef RA_STATS + pArena->sStatistics.uSpanCount--; +#endif + } +#if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA) + { + void (*pfnRemoveProcEntry) (const char *); + + pfnRemoveProcEntry = + pArena-> + bInitProcEntry ? RemoveProcEntry : + RemovePerProcessProcEntry; + + if (pArena->szProcInfoName[0] != 0) + pfnRemoveProcEntry(pArena->szProcInfoName); + + if (pArena->szProcSegsName[0] != 0) + pfnRemoveProcEntry(pArena->szProcSegsName); + } +#endif + HASH_Delete(pArena->pSegmentHash); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RA_ARENA), pArena, + NULL); +} + +IMG_BOOL RA_TestDelete(struct RA_ARENA *pArena) +{ + PVR_ASSERT(pArena != NULL); + + if (pArena != NULL) + while (pArena->pHeadSegment != NULL) { + struct BT *pBT = pArena->pHeadSegment; + if (pBT->type != btt_free) + return IMG_FALSE; + } + + return IMG_TRUE; +} + +IMG_BOOL RA_Add(struct RA_ARENA *pArena, u32 base, size_t uSize) +{ + PVR_ASSERT(pArena != NULL); + + if (pArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, "RA_Add: invalid parameter - pArena"); + return IMG_FALSE; + } + + PVR_DPF(PVR_DBG_MESSAGE, + "RA_Add: name='%s', base=0x%x, size=0x%x", pArena->name, base, + uSize); + + uSize = (uSize + pArena->uQuantum - 1) / + pArena->uQuantum * pArena->uQuantum; + return (IMG_BOOL)(_InsertResource(pArena, base, uSize) != NULL); +} + +IMG_BOOL RA_Alloc(struct RA_ARENA *pArena, size_t uRequestSize, + struct BM_MAPPING **ppsMapping, u32 uFlags, u32 uAlignment, + u32 *base) +{ + IMG_BOOL bResult; + size_t uSize = uRequestSize; + + PVR_ASSERT(pArena != NULL); + + if (pArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "RA_Alloc: invalid parameter - pArena"); + return IMG_FALSE; + } + + PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: " + "arena='%s', size=0x%x(0x%x), alignment=0x%x", + pArena->name, uSize, uRequestSize, uAlignment); + + bResult = _AttemptAllocAligned(pArena, uSize, ppsMapping, uFlags, + uAlignment, base); + if (!bResult) { + struct BM_MAPPING *psImportMapping; + u32 import_base; + size_t uImportSize = uSize; + + if (uAlignment > pArena->uQuantum) + uImportSize += (uAlignment - 1); + + uImportSize = + ((uImportSize + pArena->uQuantum - 1) / + pArena->uQuantum) * pArena->uQuantum; + + bResult = + pArena->pImportAlloc(pArena->pImportHandle, uImportSize, + &uImportSize, &psImportMapping, uFlags, + &import_base); + if (bResult) { + struct BT *pBT; + pBT = _InsertResourceSpan(pArena, import_base, + uImportSize); + + if (pBT == NULL) { + pArena->pImportFree(pArena->pImportHandle, + import_base, + psImportMapping); + PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: " + "name='%s', size=0x%x failed!", + pArena->name, uSize); + + return IMG_FALSE; + } + pBT->psMapping = psImportMapping; +#ifdef RA_STATS + pArena->sStatistics.uFreeSegmentCount++; + pArena->sStatistics.uFreeResourceCount += uImportSize; + pArena->sStatistics.uImportCount++; + pArena->sStatistics.uSpanCount++; +#endif + bResult = _AttemptAllocAligned(pArena, uSize, + ppsMapping, uFlags, uAlignment, + base); + if (!bResult) + PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: " + "name='%s' uAlignment failed!", + pArena->name); + } + } +#ifdef RA_STATS + if (bResult) + pArena->sStatistics.uCumulativeAllocs++; +#endif + + PVR_DPF(PVR_DBG_MESSAGE, + "RA_Alloc: name='%s', size=0x%x, *base=0x%x = %d", + pArena->name, uSize, *base, bResult); + + return bResult; +} + +void RA_Free(struct RA_ARENA *pArena, u32 base, IMG_BOOL bFreeBackingStore) +{ + struct BT *pBT; + + PVR_ASSERT(pArena != NULL); + + if (pArena == NULL) { + PVR_DPF(PVR_DBG_ERROR, "RA_Free: invalid parameter - pArena"); + return; + } + + PVR_DPF(PVR_DBG_MESSAGE, + "RA_Free: name='%s', base=0x%x", pArena->name, base); + + pBT = (struct BT *)HASH_Remove(pArena->pSegmentHash, base); + PVR_ASSERT(pBT != NULL); + + if (pBT) { + PVR_ASSERT(pBT->base == base); + +#ifdef RA_STATS + pArena->sStatistics.uCumulativeFrees++; +#endif + + _FreeBT(pArena, pBT, bFreeBackingStore); + } +} + +IMG_BOOL RA_GetNextLiveSegment(void *hArena, + struct RA_SEGMENT_DETAILS *psSegDetails) +{ + struct BT *pBT; + + if (psSegDetails->hSegment) { + pBT = (struct BT *)psSegDetails->hSegment; + } else { + struct RA_ARENA *pArena = (struct RA_ARENA *)hArena; + pBT = pArena->pHeadSegment; + } + + while (pBT != NULL) { + if (pBT->type == btt_live) { + psSegDetails->uiSize = pBT->uSize; + psSegDetails->sCpuPhyAddr.uiAddr = pBT->base; + psSegDetails->hSegment = (void *) pBT->pNextSegment; + + return IMG_TRUE; + } + + pBT = pBT->pNextSegment; + } + + psSegDetails->uiSize = 0; + psSegDetails->sCpuPhyAddr.uiAddr = 0; + psSegDetails->hSegment = (void *) -1; + + return IMG_FALSE; +} + +#if (defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)) || \ + defined(RA_STATS) +static char *_BTType(int eType) +{ + switch (eType) { + case btt_span: + return "span"; + case btt_free: + return "free"; + case btt_live: + return "live"; + } + return "junk"; +} +#endif + +#if defined(ENABLE_RA_DUMP) +void RA_Dump(struct RA_ARENA *pArena) +{ + struct BT *pBT; + PVR_ASSERT(pArena != NULL); + PVR_DPF(PVR_DBG_MESSAGE, "Arena '%s':", pArena->name); + PVR_DPF(PVR_DBG_MESSAGE, + " alloc=%08X free=%08X handle=%08X quantum=%d", + pArena->pImportAlloc, pArena->pImportFree, + pArena->pImportHandle, pArena->uQuantum); + PVR_DPF(PVR_DBG_MESSAGE, " segment Chain:"); + if (pArena->pHeadSegment != NULL && + pArena->pHeadSegment->pPrevSegment != NULL) + PVR_DPF(PVR_DBG_MESSAGE, + " error: head boundary tag has invalid pPrevSegment"); + if (pArena->pTailSegment != NULL && + pArena->pTailSegment->pNextSegment != NULL) + PVR_DPF(PVR_DBG_MESSAGE, + " error: tail boundary tag has invalid pNextSegment"); + + for (pBT = pArena->pHeadSegment; pBT != NULL; pBT = pBT->pNextSegment) + PVR_DPF(PVR_DBG_MESSAGE, + "\tbase=0x%x size=0x%x type=%s ref=%08X", + (u32) pBT->base, pBT->uSize, _BTType(pBT->type), + pBT->pRef); + +} +#endif + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA) +static int RA_DumpSegs(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + struct BT *pBT = NULL; + int len = 0; + struct RA_ARENA *pArena = (struct RA_ARENA *)data; + + if (count < 80) { + *start = (char *)0; + return 0; + } + *eof = 0; + *start = (char *)1; + if (off == 0) + return printAppend(page, count, 0, + "Arena \"%s\"\nBase Size Type Ref\n", + pArena->name); + for (pBT = pArena->pHeadSegment; --off && pBT; + pBT = pBT->pNextSegment) + ; + if (pBT) + len = printAppend(page, count, 0, "%08x %8x %4s %08x\n", + (unsigned)pBT->base, (unsigned)pBT->uSize, + _BTType(pBT->type), (unsigned)pBT->psMapping); + else + *eof = 1; + return len; +} + +static int RA_DumpInfo(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + struct RA_ARENA *pArena = (struct RA_ARENA *)data; + + if (count < 80) { + *start = (char *)0; + return 0; + } + *eof = 0; + switch (off) { + case 0: + len = printAppend(page, count, 0, "quantum\t\t\t%u\n", + pArena->uQuantum); + break; + case 1: + len = printAppend(page, count, 0, "import_handle\t\t%08X\n", + (unsigned)pArena->pImportHandle); + break; +#ifdef RA_STATS + case 2: + len = printAppend(page, count, 0, "span count\t\t%u\n", + pArena->sStatistics.uSpanCount); + break; + case 3: + len = printAppend(page, count, 0, "live segment count\t%u\n", + pArena->sStatistics.uLiveSegmentCount); + break; + case 4: + len = printAppend(page, count, 0, "free segment count\t%u\n", + pArena->sStatistics.uFreeSegmentCount); + break; + case 5: + len = printAppend(page, count, 0, + "free resource count\t%u (0x%x)\n", + pArena->sStatistics.uFreeResourceCount, + (unsigned)pArena->sStatistics. + uFreeResourceCount); + break; + case 6: + len = printAppend(page, count, 0, "total allocs\t\t%u\n", + pArena->sStatistics.uCumulativeAllocs); + break; + case 7: + len = printAppend(page, count, 0, "total frees\t\t%u\n", + pArena->sStatistics.uCumulativeFrees); + break; + case 8: + len = printAppend(page, count, 0, "import count\t\t%u\n", + pArena->sStatistics.uImportCount); + break; + case 9: + len = printAppend(page, count, 0, "export count\t\t%u\n", + pArena->sStatistics.uExportCount); + break; +#endif + + default: + *eof = 1; + } + *start = (char *)1; + return len; +} +#endif + +#ifdef RA_STATS +enum PVRSRV_ERROR RA_GetStats(struct RA_ARENA *pArena, char **ppszStr, + u32 *pui32StrLen) +{ + char *pszStr = *ppszStr; + u32 ui32StrLen = *pui32StrLen; + s32 i32Count; + struct BT *pBT; + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "\nArena '%s':\n", pArena->name); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, + " allocCB=%08X freeCB=%08X handle=%08X quantum=%d\n", + pArena->pImportAlloc, pArena->pImportFree, + pArena->pImportHandle, pArena->uQuantum); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "span count\t\t%lu\n", + pArena->sStatistics.uSpanCount); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "live segment count\t%lu\n", + pArena->sStatistics.uLiveSegmentCount); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "free segment count\t%lu\n", + pArena->sStatistics.uFreeSegmentCount); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "free resource count\t%lu (0x%x)\n", + pArena->sStatistics.uFreeResourceCount, + (unsigned)pArena->sStatistics.uFreeResourceCount); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "total allocs\t\t%lu\n", + pArena->sStatistics.uCumulativeAllocs); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "total frees\t\t%lu\n", + pArena->sStatistics.uCumulativeFrees); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "import count\t\t%lu\n", + pArena->sStatistics.uImportCount); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "export count\t\t%lu\n", + pArena->sStatistics.uExportCount); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, " segment Chain:\n"); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + if (pArena->pHeadSegment != NULL && + pArena->pHeadSegment->pPrevSegment != NULL) { + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, + " error: head boundary tag has invalid pPrevSegment\n"); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + } + + if (pArena->pTailSegment != NULL && + pArena->pTailSegment->pNextSegment != NULL) { + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, + " error: tail boundary tag has invalid pNextSegment\n"); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + } + + for (pBT = pArena->pHeadSegment; pBT != NULL; + pBT = pBT->pNextSegment) { + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, + "\tbase=0x%x size=0x%x type=%s ref=%08X\n", + (u32) pBT->base, pBT->uSize, _BTType(pBT->type), + pBT->psMapping); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + } + + *ppszStr = pszStr; + *pui32StrLen = ui32StrLen; + + return PVRSRV_OK; +} +#endif diff --git a/drivers/gpu/pvr/ra.h b/drivers/gpu/pvr/ra.h new file mode 100644 index 00000000000..2f9ceeaca62 --- /dev/null +++ b/drivers/gpu/pvr/ra.h @@ -0,0 +1,107 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _RA_H_ +#define _RA_H_ + +#include "img_types.h" +#include "hash.h" +#include "osfunc.h" + +struct RA_ARENA; +struct BM_MAPPING; + +#define RA_STATS + +struct RA_STATISTICS { + u32 uSpanCount; + u32 uLiveSegmentCount; + u32 uFreeSegmentCount; + u32 uTotalResourceCount; + u32 uFreeResourceCount; + u32 uCumulativeAllocs; + u32 uCumulativeFrees; + u32 uImportCount; + u32 uExportCount; +}; +struct RA_STATISTICS; + +struct RA_SEGMENT_DETAILS { + u32 uiSize; + struct IMG_CPU_PHYADDR sCpuPhyAddr; + void *hSegment; +}; +struct RA_SEGMENT_DETAILS; + +struct RA_ARENA *RA_Create(char *name, u32 base, size_t uSize, + struct BM_MAPPING *psMapping, size_t uQuantum, + IMG_BOOL(*imp_alloc)(void *_h, size_t uSize, + size_t *pActualSize, + struct BM_MAPPING **ppsMapping, + u32 uFlags, u32 *pBase), + void (*imp_free)(void *, u32, struct BM_MAPPING *), + void (*backingstore_free)(void *, u32, u32, void *), + void *import_handle); + +void RA_Delete(struct RA_ARENA *pArena); + +IMG_BOOL RA_TestDelete(struct RA_ARENA *pArena); + +IMG_BOOL RA_Add(struct RA_ARENA *pArena, u32 base, size_t uSize); + +IMG_BOOL RA_Alloc(struct RA_ARENA *pArena, size_t uSize, + struct BM_MAPPING **ppsMapping, u32 uFlags, u32 uAlignment, + u32 *pBase); + +void RA_Free(struct RA_ARENA *pArena, u32 base, IMG_BOOL bFreeBackingStore); + +#ifdef RA_STATS + +#define CHECK_SPACE(total) \ +{ \ + if (total < 100) \ + return PVRSRV_ERROR_INVALID_PARAMS; \ +} + +#define UPDATE_SPACE(str, count, total) \ +{ \ + if (count == -1) \ + return PVRSRV_ERROR_INVALID_PARAMS; \ + else { \ + str += count; \ + total -= count; \ + } \ +} + +IMG_BOOL RA_GetNextLiveSegment(void *hArena, + struct RA_SEGMENT_DETAILS *psSegDetails); + +enum PVRSRV_ERROR RA_GetStats(struct RA_ARENA *pArena, char **ppszStr, + u32 *pui32StrLen); + +#endif + +#endif diff --git a/drivers/gpu/pvr/resman.c b/drivers/gpu/pvr/resman.c new file mode 100644 index 00000000000..f05c2d7faa3 --- /dev/null +++ b/drivers/gpu/pvr/resman.c @@ -0,0 +1,568 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/version.h> +#include <linux/sched.h> +#include <linux/hardirq.h> + +#include <linux/semaphore.h> + +#include "services_headers.h" +#include "resman.h" + +static DEFINE_SEMAPHORE(lock); + +#define ACQUIRE_SYNC_OBJ do { \ + if (in_interrupt()) { \ + printk(KERN_ERR "ISR cannot take RESMAN mutex\n"); \ + BUG(); \ + } else \ + down(&lock); \ +} while (0) +#define RELEASE_SYNC_OBJ up(&lock) + + +#define RESMAN_SIGNATURE 0x12345678 + +struct RESMAN_ITEM { +#ifdef CONFIG_PVR_DEBUG + u32 ui32Signature; +#endif + struct RESMAN_ITEM **ppsThis; + struct RESMAN_ITEM *psNext; + + u32 ui32Flags; + u32 ui32ResType; + + void *pvParam; + u32 ui32Param; + + enum PVRSRV_ERROR (*pfnFreeResource)(void *pvParam, u32 ui32Param); +}; + +struct RESMAN_CONTEXT { +#ifdef CONFIG_PVR_DEBUG + u32 ui32Signature; +#endif + struct RESMAN_CONTEXT **ppsThis; + struct RESMAN_CONTEXT *psNext; + struct PVRSRV_PER_PROCESS_DATA *psPerProc; + struct RESMAN_ITEM *psResItemList; + +}; + +struct RESMAN_LIST { + struct RESMAN_CONTEXT *psContextList; +}; + +static struct RESMAN_LIST *gpsResList; + +#define PRINT_RESLIST(x, y, z) + +static void FreeResourceByPtr(struct RESMAN_ITEM *psItem, + IMG_BOOL bExecuteCallback); + +static int FreeResourceByCriteria(struct RESMAN_CONTEXT *psContext, + u32 ui32SearchCriteria, + u32 ui32ResType, void *pvParam, + u32 ui32Param, + IMG_BOOL bExecuteCallback); + +#ifdef CONFIG_PVR_DEBUG_EXTRA +static void ValidateResList(struct RESMAN_LIST *psResList); +#define VALIDATERESLIST() ValidateResList(gpsResList) +#else +#define VALIDATERESLIST() +#endif + +enum PVRSRV_ERROR ResManInit(void) +{ + if (gpsResList == NULL) { + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(*gpsResList), + (void **) &gpsResList, + NULL) != PVRSRV_OK) + return PVRSRV_ERROR_OUT_OF_MEMORY; + + gpsResList->psContextList = NULL; + + VALIDATERESLIST(); + } + + return PVRSRV_OK; +} + +void ResManDeInit(void) +{ + if (gpsResList != NULL) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*gpsResList), + gpsResList, NULL); +} + +enum PVRSRV_ERROR PVRSRVResManConnect(void *hPerProc, + struct RESMAN_CONTEXT **phResManContext) +{ + enum PVRSRV_ERROR eError; + struct RESMAN_CONTEXT *psResManContext; + + ACQUIRE_SYNC_OBJ; + + VALIDATERESLIST(); + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psResManContext), + (void **) &psResManContext, NULL); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVResManConnect: " + "ERROR allocating new RESMAN context struct"); + + VALIDATERESLIST(); + RELEASE_SYNC_OBJ; + + return eError; + } +#ifdef CONFIG_PVR_DEBUG + psResManContext->ui32Signature = RESMAN_SIGNATURE; +#endif + psResManContext->psResItemList = NULL; + psResManContext->psPerProc = hPerProc; + + psResManContext->psNext = gpsResList->psContextList; + psResManContext->ppsThis = &gpsResList->psContextList; + gpsResList->psContextList = psResManContext; + if (psResManContext->psNext) + psResManContext->psNext->ppsThis = &(psResManContext->psNext); + + VALIDATERESLIST(); + + RELEASE_SYNC_OBJ; + + *phResManContext = psResManContext; + + return PVRSRV_OK; +} + +static inline bool warn_unfreed_res(void) +{ + return !(current->flags & PF_SIGNALED); +} + +static int free_one_res(struct RESMAN_CONTEXT *ctx, u32 restype) +{ + int freed; + + freed = FreeResourceByCriteria(ctx, RESMAN_CRITERIA_RESTYPE, restype, + NULL, 0, IMG_TRUE); + if (freed && warn_unfreed_res()) + PVR_DPF(DBGPRIV_WARNING, "pvr: %s: cleaning up %d " + "unfreed resource of type %d\n", + current->comm, freed, restype); + + return freed; +} + +void PVRSRVResManDisconnect(struct RESMAN_CONTEXT *ctx, IMG_BOOL bKernelContext) +{ + + ACQUIRE_SYNC_OBJ; + + VALIDATERESLIST(); + + PRINT_RESLIST(gpsResList, ctx, IMG_TRUE); + + if (!bKernelContext) { + int i = 0; + + i += free_one_res(ctx, RESMAN_TYPE_OS_USERMODE_MAPPING); + i += free_one_res(ctx, RESMAN_TYPE_EVENT_OBJECT); + i += free_one_res(ctx, RESMAN_TYPE_HW_RENDER_CONTEXT); + i += free_one_res(ctx, RESMAN_TYPE_HW_TRANSFER_CONTEXT); + i += free_one_res(ctx, RESMAN_TYPE_HW_2D_CONTEXT); + i += free_one_res(ctx, RESMAN_TYPE_TRANSFER_CONTEXT); + i += free_one_res(ctx, RESMAN_TYPE_SHARED_PB_DESC_CREATE_LOCK); + i += free_one_res(ctx, RESMAN_TYPE_SHARED_PB_DESC); + i += free_one_res(ctx, RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN); + i += free_one_res(ctx, RESMAN_TYPE_DISPLAYCLASS_DEVICE); + i += free_one_res(ctx, RESMAN_TYPE_BUFFERCLASS_DEVICE); + i += free_one_res(ctx, RESMAN_TYPE_DEVICECLASSMEM_MAPPING); + i += free_one_res(ctx, RESMAN_TYPE_DEVICEMEM_WRAP); + i += free_one_res(ctx, RESMAN_TYPE_DEVICEMEM_MAPPING); + i += free_one_res(ctx, RESMAN_TYPE_KERNEL_DEVICEMEM_ALLOCATION); + i += free_one_res(ctx, RESMAN_TYPE_DEVICEMEM_ALLOCATION); + i += free_one_res(ctx, RESMAN_TYPE_DEVICEMEM_CONTEXT); + + if (i && warn_unfreed_res()) + pr_warning("pvr: %s: cleaning up %d " + "unfreed resources\n", + current->comm, i); + } + + PVR_ASSERT(ctx->psResItemList == NULL); + + *(ctx->ppsThis) = ctx->psNext; + if (ctx->psNext) + ctx->psNext->ppsThis = ctx->ppsThis; + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RESMAN_CONTEXT), + ctx, NULL); + + VALIDATERESLIST(); + + PRINT_RESLIST(gpsResList, ctx, IMG_FALSE); + + RELEASE_SYNC_OBJ; +} + +struct RESMAN_ITEM *ResManRegisterRes(struct RESMAN_CONTEXT *psResManContext, + u32 ui32ResType, void *pvParam, + u32 ui32Param, + enum PVRSRV_ERROR (*pfnFreeResource) + (void *pvParam, u32 ui32Param)) +{ + struct RESMAN_ITEM *psNewResItem; + + PVR_ASSERT(psResManContext != NULL); + PVR_ASSERT(ui32ResType != 0); + + if (psResManContext == NULL) { + PVR_DPF(PVR_DBG_ERROR, "ResManRegisterRes: " + "invalid parameter - psResManContext"); + return (struct RESMAN_ITEM *)NULL; + } + + ACQUIRE_SYNC_OBJ; + + VALIDATERESLIST(); + + PVR_DPF(PVR_DBG_MESSAGE, "ResManRegisterRes: register resource " + "Context 0x%x, ResType 0x%x, pvParam 0x%x, ui32Param 0x%x, " + "FreeFunc %08X", + psResManContext, ui32ResType, (u32) pvParam, + ui32Param, pfnFreeResource); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct RESMAN_ITEM), (void **) &psNewResItem, + NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "ResManRegisterRes: " + "ERROR allocating new resource item"); + + RELEASE_SYNC_OBJ; + + return (struct RESMAN_ITEM *)NULL; + } + +#ifdef CONFIG_PVR_DEBUG + psNewResItem->ui32Signature = RESMAN_SIGNATURE; +#endif + psNewResItem->ui32ResType = ui32ResType; + psNewResItem->pvParam = pvParam; + psNewResItem->ui32Param = ui32Param; + psNewResItem->pfnFreeResource = pfnFreeResource; + psNewResItem->ui32Flags = 0; + + psNewResItem->ppsThis = &psResManContext->psResItemList; + psNewResItem->psNext = psResManContext->psResItemList; + psResManContext->psResItemList = psNewResItem; + if (psNewResItem->psNext) + psNewResItem->psNext->ppsThis = &psNewResItem->psNext; + + VALIDATERESLIST(); + + RELEASE_SYNC_OBJ; + + return psNewResItem; +} + +void ResManFreeResByPtr(struct RESMAN_ITEM *psResItem) +{ + BUG_ON(!psResItem); + + PVR_DPF(PVR_DBG_MESSAGE, + "ResManFreeResByPtr: freeing resource at %08X", psResItem); + + ACQUIRE_SYNC_OBJ; + + VALIDATERESLIST(); + + FreeResourceByPtr(psResItem, IMG_TRUE); + + VALIDATERESLIST(); + + RELEASE_SYNC_OBJ; +} + +void ResManFreeResByCriteria(struct RESMAN_CONTEXT *psResManContext, + u32 ui32SearchCriteria, u32 ui32ResType, + void *pvParam, u32 ui32Param) +{ + PVR_ASSERT(psResManContext != NULL); + + ACQUIRE_SYNC_OBJ; + + VALIDATERESLIST(); + + PVR_DPF(PVR_DBG_MESSAGE, "ResManFreeResByCriteria: " + "Context 0x%x, Criteria 0x%x, Type 0x%x, Addr 0x%x, Param 0x%x", + psResManContext, ui32SearchCriteria, ui32ResType, + (u32) pvParam, ui32Param); + + (void)FreeResourceByCriteria(psResManContext, ui32SearchCriteria, + ui32ResType, pvParam, ui32Param, + IMG_TRUE); + + VALIDATERESLIST(); + + RELEASE_SYNC_OBJ; +} + +enum PVRSRV_ERROR ResManDissociateRes(struct RESMAN_ITEM *psResItem, + struct RESMAN_CONTEXT *psNewResManContext) +{ + PVR_ASSERT(psResItem != NULL); + + if (psResItem == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "ResManDissociateRes: invalid parameter - psResItem"); + PVR_DBG_BREAK; + return PVRSRV_ERROR_INVALID_PARAMS; + } +#ifdef CONFIG_PVR_DEBUG + PVR_ASSERT(psResItem->ui32Signature == RESMAN_SIGNATURE); +#endif + + if (psNewResManContext != NULL) { + if (psResItem->psNext) + psResItem->psNext->ppsThis = psResItem->ppsThis; + *psResItem->ppsThis = psResItem->psNext; + + psResItem->ppsThis = &psNewResManContext->psResItemList; + psResItem->psNext = psNewResManContext->psResItemList; + psNewResManContext->psResItemList = psResItem; + if (psResItem->psNext) + psResItem->psNext->ppsThis = &psResItem->psNext; + } else { + FreeResourceByPtr(psResItem, IMG_FALSE); + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR ResManFindResourceByPtr( + struct RESMAN_CONTEXT *psResManContext, + struct RESMAN_ITEM *psItem) +{ + struct RESMAN_ITEM *psCurItem; + + PVR_ASSERT(psResManContext != NULL); + PVR_ASSERT(psItem != NULL); + + if ((psItem == NULL) || (psResManContext == NULL)) { + PVR_DPF(PVR_DBG_ERROR, + "ResManFindResourceByPtr: invalid parameter"); + PVR_DBG_BREAK; + return PVRSRV_ERROR_INVALID_PARAMS; + } +#ifdef CONFIG_PVR_DEBUG + PVR_ASSERT(psItem->ui32Signature == RESMAN_SIGNATURE); +#endif + + ACQUIRE_SYNC_OBJ; + + PVR_DPF(PVR_DBG_MESSAGE, + "FindResourceByPtr: psItem=%08X, psItem->psNext=%08X", + psItem, psItem->psNext); + + PVR_DPF(PVR_DBG_MESSAGE, + "FindResourceByPtr: Resource Ctx 0x%x, Type 0x%x, Addr 0x%x, " + "Param 0x%x, FnCall %08X, Flags 0x%x", + psResManContext, + psItem->ui32ResType, (u32) psItem->pvParam, + psItem->ui32Param, psItem->pfnFreeResource, + psItem->ui32Flags); + + psCurItem = psResManContext->psResItemList; + + while (psCurItem != NULL) { + if (psCurItem != psItem) { + psCurItem = psCurItem->psNext; + } else { + RELEASE_SYNC_OBJ; + return PVRSRV_OK; + } + } + + RELEASE_SYNC_OBJ; + + return PVRSRV_ERROR_NOT_OWNER; +} + +static void FreeResourceByPtr(struct RESMAN_ITEM *psItem, + IMG_BOOL bExecuteCallback) +{ + PVR_ASSERT(psItem->ui32Signature == RESMAN_SIGNATURE); + + PVR_DPF(PVR_DBG_MESSAGE, + "FreeResourceByPtr: psItem=%08X, psItem->psNext=%08X", + psItem, psItem->psNext); + + PVR_DPF(PVR_DBG_MESSAGE, + "FreeResourceByPtr: Type 0x%x, Addr 0x%x, " + "Param 0x%x, FnCall %08X, Flags 0x%x", + psItem->ui32ResType, (u32) psItem->pvParam, + psItem->ui32Param, psItem->pfnFreeResource, + psItem->ui32Flags); + + if (psItem->psNext) + psItem->psNext->ppsThis = psItem->ppsThis; + *psItem->ppsThis = psItem->psNext; + + RELEASE_SYNC_OBJ; + + if (bExecuteCallback && + psItem->pfnFreeResource(psItem->pvParam, psItem->ui32Param) != + PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, "FreeResourceByPtr: " + "ERROR calling FreeResource function"); + + ACQUIRE_SYNC_OBJ; + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RESMAN_ITEM), psItem, + NULL); +} + +static struct RESMAN_ITEM *find_res_by_crit(struct RESMAN_CONTEXT *res_ctx, + u32 crit, u32 res_type, + void *ppar, u32 upar) +{ + struct RESMAN_ITEM *item; + + for (item = res_ctx->psResItemList; item; item = item->psNext) { + if ((crit & RESMAN_CRITERIA_RESTYPE) && + item->ui32ResType != res_type) + continue; + else if ((crit & RESMAN_CRITERIA_PVOID_PARAM) && + item->pvParam != ppar) + continue; + else if ((crit & RESMAN_CRITERIA_UI32_PARAM) && + item->ui32Param != upar) + continue; + + break; + } + + return item; +} + +struct RESMAN_CONTEXT *pvr_get_resman_ctx(void *resource) +{ + struct RESMAN_CONTEXT *ctx; + + for (ctx = gpsResList->psContextList; ctx; ctx = ctx->psNext) { + struct RESMAN_ITEM *item; + + item = find_res_by_crit(ctx, RESMAN_CRITERIA_PVOID_PARAM, + 0, resource, 0); + if (item) + return ctx; + } + return NULL; +} + +struct PVRSRV_PER_PROCESS_DATA *pvr_get_proc_by_ctx(struct RESMAN_CONTEXT *ctx) +{ + return ctx->psPerProc; +} + +static int FreeResourceByCriteria(struct RESMAN_CONTEXT *psResManContext, + u32 ui32SearchCriteria, u32 ui32ResType, + void *pvParam, u32 ui32Param, + IMG_BOOL bExecuteCallback) +{ + struct RESMAN_ITEM *item; + int freed = 0; + + do { + item = find_res_by_crit(psResManContext, + ui32SearchCriteria, ui32ResType, + pvParam, ui32Param); + if (item) { + FreeResourceByPtr(item, bExecuteCallback); + freed++; + } + } while (item); + + return freed; +} + +#ifdef CONFIG_PVR_DEBUG_EXTRA +static void ValidateResList(struct RESMAN_LIST *psResList) +{ + struct RESMAN_ITEM *psCurItem, **ppsThisItem; + struct RESMAN_CONTEXT *psCurContext, **ppsThisContext; + + if (psResList == NULL) { + PVR_DPF(PVR_DBG_MESSAGE, + "ValidateResList: resman not initialised yet"); + return; + } + + psCurContext = psResList->psContextList; + ppsThisContext = &psResList->psContextList; + + while (psCurContext != NULL) { + PVR_ASSERT(psCurContext->ui32Signature == RESMAN_SIGNATURE); + if (psCurContext->ppsThis != ppsThisContext) { + PVR_DPF(PVR_DBG_WARNING, "psCC=%08X " + "psCC->ppsThis=%08X psCC->psNext=%08X ppsTC=%08X", + psCurContext, psCurContext->ppsThis, + psCurContext->psNext, ppsThisContext); + PVR_ASSERT(psCurContext->ppsThis == ppsThisContext); + } + + psCurItem = psCurContext->psResItemList; + ppsThisItem = &psCurContext->psResItemList; + while (psCurItem != NULL) { + PVR_ASSERT(psCurItem->ui32Signature == + RESMAN_SIGNATURE); + if (psCurItem->ppsThis != ppsThisItem) { + PVR_DPF(PVR_DBG_WARNING, "psCurItem=%08X " + "psCurItem->ppsThis=%08X " + "psCurItem->psNext=%08X " + "ppsThisItem=%08X", + psCurItem, psCurItem->ppsThis, + psCurItem->psNext, ppsThisItem); + PVR_ASSERT(psCurItem->ppsThis == ppsThisItem); + } + + ppsThisItem = &psCurItem->psNext; + psCurItem = psCurItem->psNext; + } + + ppsThisContext = &psCurContext->psNext; + psCurContext = psCurContext->psNext; + } +} +#endif diff --git a/drivers/gpu/pvr/resman.h b/drivers/gpu/pvr/resman.h new file mode 100644 index 00000000000..f9a28f35315 --- /dev/null +++ b/drivers/gpu/pvr/resman.h @@ -0,0 +1,95 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __RESMAN_H__ +#define __RESMAN_H__ + +enum { + RESMAN_TYPE_SHARED_PB_DESC = 1, + RESMAN_TYPE_SHARED_PB_DESC_CREATE_LOCK, + RESMAN_TYPE_HW_RENDER_CONTEXT, + RESMAN_TYPE_HW_TRANSFER_CONTEXT, + RESMAN_TYPE_HW_2D_CONTEXT, + RESMAN_TYPE_TRANSFER_CONTEXT, + + RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN, + RESMAN_TYPE_DISPLAYCLASS_DEVICE, + + RESMAN_TYPE_BUFFERCLASS_DEVICE, + + RESMAN_TYPE_OS_USERMODE_MAPPING, + + RESMAN_TYPE_DEVICEMEM_CONTEXT, + RESMAN_TYPE_DEVICECLASSMEM_MAPPING, + RESMAN_TYPE_DEVICEMEM_MAPPING, + RESMAN_TYPE_DEVICEMEM_WRAP, + RESMAN_TYPE_DEVICEMEM_ALLOCATION, + RESMAN_TYPE_EVENT_OBJECT, + RESMAN_TYPE_SHARED_MEM_INFO, + + RESMAN_TYPE_KERNEL_DEVICEMEM_ALLOCATION +}; + +#define RESMAN_CRITERIA_ALL 0x00000000 +#define RESMAN_CRITERIA_RESTYPE 0x00000001 +#define RESMAN_CRITERIA_PVOID_PARAM 0x00000002 +#define RESMAN_CRITERIA_UI32_PARAM 0x00000004 + +struct RESMAN_ITEM; +struct RESMAN_CONTEXT; + +enum PVRSRV_ERROR ResManInit(void); +void ResManDeInit(void); + +struct RESMAN_ITEM *ResManRegisterRes(struct RESMAN_CONTEXT *hResManContext, + u32 ui32ResType, void *pvParam, + u32 ui32Param, + enum PVRSRV_ERROR (*pfnFreeResource) + (void *pvParam, u32 ui32Param)); + +void ResManFreeResByPtr(struct RESMAN_ITEM *psResItem); + +void ResManFreeResByCriteria(struct RESMAN_CONTEXT *hResManContext, + u32 ui32SearchCriteria, u32 ui32ResType, void *pvParam, + u32 ui32Param); + +enum PVRSRV_ERROR ResManDissociateRes(struct RESMAN_ITEM *psResItem, + struct RESMAN_CONTEXT + *psNewResManContext); + +enum PVRSRV_ERROR ResManFindResourceByPtr(struct RESMAN_CONTEXT *hResManContext, + struct RESMAN_ITEM *psItem); + +struct RESMAN_CONTEXT *pvr_get_resman_ctx(void *resource); +struct PVRSRV_PER_PROCESS_DATA *pvr_get_proc_by_ctx(struct RESMAN_CONTEXT *ctx); + +enum PVRSRV_ERROR PVRSRVResManConnect(void *hPerProc, + struct RESMAN_CONTEXT **phResManContext); + +void PVRSRVResManDisconnect(struct RESMAN_CONTEXT *hResManContext, + IMG_BOOL bKernelContext); + +#endif diff --git a/drivers/gpu/pvr/services.h b/drivers/gpu/pvr/services.h new file mode 100644 index 00000000000..33d4931317d --- /dev/null +++ b/drivers/gpu/pvr/services.h @@ -0,0 +1,237 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __SERVICES_H__ +#define __SERVICES_H__ + + +#include "img_defs.h" +#include "servicesext.h" +#include "pdumpdefs.h" + +struct SYS_DATA; + +#define PVRSRV_4K_PAGE_SIZE 4096UL + +#define PVRSRV_MAX_CMD_SIZE 1024 + +#define PVRSRV_MAX_DEVICES 16 + +#define EVENTOBJNAME_MAXLENGTH 50 + +#define PVRSRV_MEM_READ (1UL<<0) +#define PVRSRV_MEM_WRITE (1UL<<1) +#define PVRSRV_MEM_CACHE_CONSISTENT (1UL<<2) +#define PVRSRV_MEM_NO_SYNCOBJ (1UL<<3) +#define PVRSRV_MEM_INTERLEAVED (1UL<<4) +#define PVRSRV_MEM_DUMMY (1UL<<5) +#define PVRSRV_MEM_EDM_PROTECT (1UL<<6) +#define PVRSRV_MEM_ZERO (1UL<<7) +#define PVRSRV_MEM_USER_SUPPLIED_DEVVADDR (1UL<<8) +#define PVRSRV_MEM_RAM_BACKED_ALLOCATION (1UL<<9) +#define PVRSRV_MEM_NO_RESMAN (1UL<<10) +#define PVRSRV_MEM_EXPORTED (1UL<<11) + +#define PVRSRV_HAP_CACHED (1UL<<12) +#define PVRSRV_HAP_UNCACHED (1UL<<13) +#define PVRSRV_HAP_WRITECOMBINE (1UL<<14) +#define PVRSRV_HAP_CACHETYPE_MASK (PVRSRV_HAP_CACHED | \ + PVRSRV_HAP_UNCACHED | \ + PVRSRV_HAP_WRITECOMBINE) +#define PVRSRV_HAP_KERNEL_ONLY (1UL<<15) +#define PVRSRV_HAP_SINGLE_PROCESS (1UL<<16) +#define PVRSRV_HAP_MULTI_PROCESS (1UL<<17) +#define PVRSRV_HAP_FROM_EXISTING_PROCESS (1UL<<18) +#define PVRSRV_HAP_NO_CPU_VIRTUAL (1UL<<19) +#define PVRSRV_HAP_MAPTYPE_MASK (PVRSRV_HAP_KERNEL_ONLY | \ + PVRSRV_HAP_SINGLE_PROCESS | \ + PVRSRV_HAP_MULTI_PROCESS | \ + PVRSRV_HAP_FROM_EXISTING_PROCESS | \ + PVRSRV_HAP_NO_CPU_VIRTUAL) +#define PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT 24 + +#define PVRSRV_MAP_NOUSERVIRTUAL (1UL << 27) + +#define PVRSRV_NO_CONTEXT_LOSS 0 +#define PVRSRV_SEVERE_LOSS_OF_CONTEXT 1 +#define PVRSRV_PRE_STATE_CHANGE_MASK 0x80 + +#define PVRSRV_DEFAULT_DEV_COOKIE 1 + +#define PVRSRV_MISC_INFO_TIMER_PRESENT (1UL << 0) +#define PVRSRV_MISC_INFO_CLOCKGATE_PRESENT (1UL << 1) +#define PVRSRV_MISC_INFO_MEMSTATS_PRESENT (1UL << 2) +#define PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT (1UL << 3) +#define PVRSRV_MISC_INFO_DDKVERSION_PRESENT (1UL << 4) + +#define PVRSRV_PDUMP_MAX_FILENAME_SIZE 20 +#define PVRSRV_PDUMP_MAX_COMMENT_SIZE 200 + +#define PVRSRV_CHANGEDEVMEM_ATTRIBS_CACHECOHERENT 0x00000001 + +#define PVRSRV_MAPEXTMEMORY_FLAGS_ALTERNATEVA 0x00000001 +#define PVRSRV_MAPEXTMEMORY_FLAGS_PHYSCONTIG 0x00000002 + +#define PVRSRV_MODIFYSYNCOPS_FLAGS_WOP_INC 0x00000001 +#define PVRSRV_MODIFYSYNCOPS_FLAGS_ROP_INC 0x00000002 +#define PVRSRV_MODIFYSYNCOPS_FLAGS_WOC_INC 0x00000004 +#define PVRSRV_MODIFYSYNCOPS_FLAGS_ROC_INC 0x00000008 + +enum PVRSRV_DEVICE_TYPE { + PVRSRV_DEVICE_TYPE_UNKNOWN = 0, + PVRSRV_DEVICE_TYPE_MBX1 = 1, + PVRSRV_DEVICE_TYPE_MBX1_LITE = 2, + + PVRSRV_DEVICE_TYPE_M24VA = 3, + PVRSRV_DEVICE_TYPE_MVDA2 = 4, + PVRSRV_DEVICE_TYPE_MVED1 = 5, + PVRSRV_DEVICE_TYPE_MSVDX = 6, + + PVRSRV_DEVICE_TYPE_SGX = 7, + + PVRSRV_DEVICE_TYPE_VGX = 8, + + PVRSRV_DEVICE_TYPE_EXT = 9, + + PVRSRV_DEVICE_TYPE_LAST = 9, + + PVRSRV_DEVICE_TYPE_FORCE_I32 = 0x7fffffff +}; + +#define HEAP_ID(_dev_ , _dev_heap_idx_) \ + (((_dev_) << 24) | ((_dev_heap_idx_) & ((1 << 24) - 1))) + +#define HEAP_IDX(_heap_id_) \ + ((_heap_id_) & ((1 << 24) - 1)) + +#define HEAP_DEV(_heap_id_) \ + ((_heap_id_) >> 24) + +#define PVRSRV_UNDEFINED_HEAP_ID (~0LU) + +enum IMG_MODULE_ID { + IMG_EGL = 0x00000001, + IMG_OPENGLES1 = 0x00000002, + IMG_OPENGLES2 = 0x00000003, + IMG_D3DM = 0x00000004, + IMG_SRV_UM = 0x00000005, + IMG_OPENVG = 0x00000006, + IMG_SRVCLIENT = 0x00000007, + IMG_VISTAKMD = 0x00000008, + IMG_VISTA3DNODE = 0x00000009, + IMG_VISTAMVIDEONODE = 0x0000000A, + IMG_VISTAVPBNODE = 0x0000000B, + IMG_OPENGL = 0x0000000C, + IMG_D3D = 0x0000000D +}; + +struct PVRSRV_CONNECTION { + void *hServices; + u32 ui32ProcessID; +}; + +struct PVRSRV_DEV_DATA { + struct PVRSRV_CONNECTION sConnection; + void *hDevCookie; +}; + +struct PVRSRV_HWREG { + u32 ui32RegAddr; + u32 ui32RegVal; +}; + +struct PVRSRV_MEMBLK { + struct IMG_DEV_VIRTADDR sDevVirtAddr; + void *hOSMemHandle; + void *hOSWrapMem; + void *hBuffer; + void *hResItem; + struct IMG_SYS_PHYADDR *psIntSysPAddr; +}; + +struct PVRSRV_KERNEL_MEM_INFO; + +struct PVRSRV_CLIENT_MEM_INFO { + void *pvLinAddr; + void *pvLinAddrKM; + struct IMG_DEV_VIRTADDR sDevVAddr; + struct IMG_CPU_PHYADDR sCpuPAddr; + u32 ui32Flags; + u32 ui32ClientFlags; + u32 ui32AllocSize; + struct PVRSRV_CLIENT_SYNC_INFO *psClientSyncInfo; + void *hMappingInfo; + void *hKernelMemInfo; + void *hResItem; + struct PVRSRV_CLIENT_MEM_INFO *psNext; +}; + +#define PVRSRV_MAX_CLIENT_HEAPS (32) +struct PVRSRV_HEAP_INFO { + u32 ui32HeapID; + void *hDevMemHeap; + struct IMG_DEV_VIRTADDR sDevVAddrBase; + u32 ui32HeapByteSize; + u32 ui32Attribs; +}; + +struct PVRSRV_DEVICE_IDENTIFIER { + enum PVRSRV_DEVICE_TYPE eDeviceType; + enum PVRSRV_DEVICE_CLASS eDeviceClass; + u32 ui32DeviceIndex; + +}; + +struct PVRSRV_EVENTOBJECT { + char szName[EVENTOBJNAME_MAXLENGTH]; + void *hOSEventKM; +}; + +struct PVRSRV_MISC_INFO { + u32 ui32StateRequest; + u32 ui32StatePresent; + + void *pvSOCTimerRegisterKM; + void *pvSOCTimerRegisterUM; + void *hSOCTimerRegisterOSMemHandle; + void *hSOCTimerRegisterMappingInfo; + + void *pvSOCClockGateRegs; + u32 ui32SOCClockGateRegsSize; + + char *pszMemoryStr; + u32 ui32MemoryStrLen; + + struct PVRSRV_EVENTOBJECT sGlobalEventObject; + void *hOSGlobalEvent; + + u32 aui32DDKVersion[4]; +}; + +enum PVRSRV_ERROR AllocateDeviceID(struct SYS_DATA *psSysData, u32 *pui32DevID); +enum PVRSRV_ERROR FreeDeviceID(struct SYS_DATA *psSysData, u32 ui32DevID); + +#endif diff --git a/drivers/gpu/pvr/services_headers.h b/drivers/gpu/pvr/services_headers.h new file mode 100644 index 00000000000..d443faef645 --- /dev/null +++ b/drivers/gpu/pvr/services_headers.h @@ -0,0 +1,42 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef SERVICES_HEADERS_H +#define SERVICES_HEADERS_H + +#include "img_defs.h" +#include "services.h" +#include "servicesint.h" +#include "power.h" +#include "resman.h" +#include "queue.h" +#include "srvkm.h" +#include "kerneldisplay.h" +#include "syscommon.h" +#include "pvr_debug.h" +#include "osfunc.h" + +#endif diff --git a/drivers/gpu/pvr/servicesext.h b/drivers/gpu/pvr/servicesext.h new file mode 100644 index 00000000000..3a1cb43b286 --- /dev/null +++ b/drivers/gpu/pvr/servicesext.h @@ -0,0 +1,435 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__SERVICESEXT_H__) +#define __SERVICESEXT_H__ + +#include "img_types.h" + +#define PVRSRV_LOCKFLG_READONLY 1 + +enum PVRSRV_ERROR { + PVRSRV_OK = 0, + PVRSRV_ERROR_GENERIC = 1, + PVRSRV_ERROR_OUT_OF_MEMORY = 2, + PVRSRV_ERROR_TOO_FEW_BUFFERS = 3, + PVRSRV_ERROR_SYMBOL_NOT_FOUND = 4, + PVRSRV_ERROR_OUT_OF_HSPACE = 5, + PVRSRV_ERROR_INVALID_PARAMS = 6, + PVRSRV_ERROR_TILE_MAP_FAILED = 7, + PVRSRV_ERROR_INIT_FAILURE = 8, + PVRSRV_ERROR_CANT_REGISTER_CALLBACK = 9, + PVRSRV_ERROR_INVALID_DEVICE = 10, + PVRSRV_ERROR_NOT_OWNER = 11, + PVRSRV_ERROR_BAD_MAPPING = 12, + PVRSRV_ERROR_TIMEOUT = 13, + PVRSRV_ERROR_NO_PRIMARY = 14, + PVRSRV_ERROR_FLIP_CHAIN_EXISTS = 15, + PVRSRV_ERROR_CANNOT_ACQUIRE_SYSDATA = 16, + PVRSRV_ERROR_SCENE_INVALID = 17, + PVRSRV_ERROR_STREAM_ERROR = 18, + PVRSRV_ERROR_INVALID_INTERRUPT = 19, + PVRSRV_ERROR_FAILED_DEPENDENCIES = 20, + PVRSRV_ERROR_CMD_NOT_PROCESSED = 21, + PVRSRV_ERROR_CMD_TOO_BIG = 22, + PVRSRV_ERROR_DEVICE_REGISTER_FAILED = 23, + PVRSRV_ERROR_FIFO_SPACE = 24, + PVRSRV_ERROR_TA_RECOVERY = 25, + PVRSRV_ERROR_INDOSORLOWPOWER = 26, + PVRSRV_ERROR_TOOMANYBUFFERS = 27, + PVRSRV_ERROR_NOT_SUPPORTED = 28, + PVRSRV_ERROR_PROCESSING_BLOCKED = 29, + + PVRSRV_ERROR_CANNOT_FLUSH_QUEUE = 31, + PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE = 32, + PVRSRV_ERROR_CANNOT_GET_RENDERDETAILS = 33, + PVRSRV_ERROR_RETRY = 34, + + PVRSRV_ERROR_DDK_VERSION_MISMATCH = 35, + PVRSRV_ERROR_BUILD_MISMATCH = 36, + + PVRSRV_ERROR_FORCE_I32 = 0x7fffffff +}; + +enum PVRSRV_DEVICE_CLASS { + PVRSRV_DEVICE_CLASS_3D = 0, + PVRSRV_DEVICE_CLASS_DISPLAY = 1, + PVRSRV_DEVICE_CLASS_BUFFER = 2, + PVRSRV_DEVICE_CLASS_VIDEO = 3, + + PVRSRV_DEVICE_CLASS_FORCE_I32 = 0x7fffffff +}; + +enum PVR_POWER_STATE { + PVRSRV_POWER_Unspecified = -1, + PVRSRV_POWER_STATE_D0 = 0, + PVRSRV_POWER_STATE_D1 = 1, + PVRSRV_POWER_STATE_D2 = 2, + PVRSRV_POWER_STATE_D3 = 3, + PVRSRV_POWER_STATE_D4 = 4, + + PVRSRV_POWER_STATE_FORCE_I32 = 0x7fffffff +}; + +enum PVRSRV_PIXEL_FORMAT { + PVRSRV_PIXEL_FORMAT_UNKNOWN = 0, + PVRSRV_PIXEL_FORMAT_RGB565 = 1, + PVRSRV_PIXEL_FORMAT_RGB555 = 2, + PVRSRV_PIXEL_FORMAT_RGB888 = 3, + PVRSRV_PIXEL_FORMAT_BGR888 = 4, + PVRSRV_PIXEL_FORMAT_GREY_SCALE = 8, + PVRSRV_PIXEL_FORMAT_PAL12 = 13, + PVRSRV_PIXEL_FORMAT_PAL8 = 14, + PVRSRV_PIXEL_FORMAT_PAL4 = 15, + PVRSRV_PIXEL_FORMAT_PAL2 = 16, + PVRSRV_PIXEL_FORMAT_PAL1 = 17, + PVRSRV_PIXEL_FORMAT_ARGB1555 = 18, + PVRSRV_PIXEL_FORMAT_ARGB4444 = 19, + PVRSRV_PIXEL_FORMAT_ARGB8888 = 20, + PVRSRV_PIXEL_FORMAT_ABGR8888 = 21, + PVRSRV_PIXEL_FORMAT_YV12 = 22, + PVRSRV_PIXEL_FORMAT_I420 = 23, + PVRSRV_PIXEL_FORMAT_IMC2 = 25, + + PVRSRV_PIXEL_FORMAT_XRGB8888, + PVRSRV_PIXEL_FORMAT_XBGR8888, + PVRSRV_PIXEL_FORMAT_XRGB4444, + PVRSRV_PIXEL_FORMAT_ARGB8332, + PVRSRV_PIXEL_FORMAT_A2RGB10, + PVRSRV_PIXEL_FORMAT_A2BGR10, + PVRSRV_PIXEL_FORMAT_P8, + PVRSRV_PIXEL_FORMAT_L8, + PVRSRV_PIXEL_FORMAT_A8L8, + PVRSRV_PIXEL_FORMAT_A4L4, + PVRSRV_PIXEL_FORMAT_L16, + PVRSRV_PIXEL_FORMAT_L6V5U5, + PVRSRV_PIXEL_FORMAT_V8U8, + PVRSRV_PIXEL_FORMAT_V16U16, + PVRSRV_PIXEL_FORMAT_QWVU8888, + PVRSRV_PIXEL_FORMAT_XLVU8888, + PVRSRV_PIXEL_FORMAT_QWVU16, + PVRSRV_PIXEL_FORMAT_D16, + PVRSRV_PIXEL_FORMAT_D24S8, + PVRSRV_PIXEL_FORMAT_D24X8, + + PVRSRV_PIXEL_FORMAT_ABGR16, + PVRSRV_PIXEL_FORMAT_ABGR16F, + PVRSRV_PIXEL_FORMAT_ABGR32, + PVRSRV_PIXEL_FORMAT_ABGR32F, + PVRSRV_PIXEL_FORMAT_B10GR11, + PVRSRV_PIXEL_FORMAT_GR88, + PVRSRV_PIXEL_FORMAT_BGR32, + PVRSRV_PIXEL_FORMAT_GR32, + PVRSRV_PIXEL_FORMAT_E5BGR9, + + PVRSRV_PIXEL_FORMAT_DXT1, + PVRSRV_PIXEL_FORMAT_DXT23, + PVRSRV_PIXEL_FORMAT_DXT45, + + PVRSRV_PIXEL_FORMAT_R8G8_B8G8, + PVRSRV_PIXEL_FORMAT_G8R8_G8B8, + + PVRSRV_PIXEL_FORMAT_NV11, + PVRSRV_PIXEL_FORMAT_NV12, + + PVRSRV_PIXEL_FORMAT_YUY2, + PVRSRV_PIXEL_FORMAT_YUV420, + PVRSRV_PIXEL_FORMAT_YUV444, + PVRSRV_PIXEL_FORMAT_VUY444, + PVRSRV_PIXEL_FORMAT_YUYV, + PVRSRV_PIXEL_FORMAT_YVYU, + PVRSRV_PIXEL_FORMAT_UYVY, + PVRSRV_PIXEL_FORMAT_VYUY, + + PVRSRV_PIXEL_FORMAT_FOURCC_ORG_UYVY, + PVRSRV_PIXEL_FORMAT_FOURCC_ORG_YUYV, + PVRSRV_PIXEL_FORMAT_FOURCC_ORG_YVYU, + PVRSRV_PIXEL_FORMAT_FOURCC_ORG_VYUY, + + PVRSRV_PIXEL_FORMAT_A32B32G32R32, + PVRSRV_PIXEL_FORMAT_A32B32G32R32F, + PVRSRV_PIXEL_FORMAT_A32B32G32R32_UINT, + PVRSRV_PIXEL_FORMAT_A32B32G32R32_SINT, + + PVRSRV_PIXEL_FORMAT_B32G32R32, + PVRSRV_PIXEL_FORMAT_B32G32R32F, + PVRSRV_PIXEL_FORMAT_B32G32R32_UINT, + PVRSRV_PIXEL_FORMAT_B32G32R32_SINT, + + PVRSRV_PIXEL_FORMAT_G32R32, + PVRSRV_PIXEL_FORMAT_G32R32F, + PVRSRV_PIXEL_FORMAT_G32R32_UINT, + PVRSRV_PIXEL_FORMAT_G32R32_SINT, + + PVRSRV_PIXEL_FORMAT_D32F, + PVRSRV_PIXEL_FORMAT_R32, + PVRSRV_PIXEL_FORMAT_R32F, + PVRSRV_PIXEL_FORMAT_R32_UINT, + PVRSRV_PIXEL_FORMAT_R32_SINT, + + PVRSRV_PIXEL_FORMAT_A16B16G16R16, + PVRSRV_PIXEL_FORMAT_A16B16G16R16F, + PVRSRV_PIXEL_FORMAT_A16B16G16R16_SINT, + PVRSRV_PIXEL_FORMAT_A16B16G16R16_SNORM, + PVRSRV_PIXEL_FORMAT_A16B16G16R16_UINT, + PVRSRV_PIXEL_FORMAT_A16B16G16R16_UNORM, + + PVRSRV_PIXEL_FORMAT_G16R16, + PVRSRV_PIXEL_FORMAT_G16R16F, + PVRSRV_PIXEL_FORMAT_G16R16_UINT, + PVRSRV_PIXEL_FORMAT_G16R16_UNORM, + PVRSRV_PIXEL_FORMAT_G16R16_SINT, + PVRSRV_PIXEL_FORMAT_G16R16_SNORM, + + PVRSRV_PIXEL_FORMAT_R16, + PVRSRV_PIXEL_FORMAT_R16F, + PVRSRV_PIXEL_FORMAT_R16_UINT, + PVRSRV_PIXEL_FORMAT_R16_UNORM, + PVRSRV_PIXEL_FORMAT_R16_SINT, + PVRSRV_PIXEL_FORMAT_R16_SNORM, + + PVRSRV_PIXEL_FORMAT_A8B8G8R8, + PVRSRV_PIXEL_FORMAT_A8B8G8R8_UINT, + PVRSRV_PIXEL_FORMAT_A8B8G8R8_UNORM, + PVRSRV_PIXEL_FORMAT_A8B8G8R8_SINT, + PVRSRV_PIXEL_FORMAT_A8B8G8R8_SNORM, + + PVRSRV_PIXEL_FORMAT_G8R8, + PVRSRV_PIXEL_FORMAT_G8R8_UINT, + PVRSRV_PIXEL_FORMAT_G8R8_UNORM, + PVRSRV_PIXEL_FORMAT_G8R8_SINT, + PVRSRV_PIXEL_FORMAT_G8R8_SNORM, + + PVRSRV_PIXEL_FORMAT_A8, + PVRSRV_PIXEL_FORMAT_R8, + PVRSRV_PIXEL_FORMAT_R8_UINT, + PVRSRV_PIXEL_FORMAT_R8_UNORM, + PVRSRV_PIXEL_FORMAT_R8_SINT, + PVRSRV_PIXEL_FORMAT_R8_SNORM, + + PVRSRV_PIXEL_FORMAT_A2B10G10R10, + PVRSRV_PIXEL_FORMAT_A2B10G10R10_UNORM, + PVRSRV_PIXEL_FORMAT_A2B10G10R10_UINT, + + PVRSRV_PIXEL_FORMAT_B10G11R11, + PVRSRV_PIXEL_FORMAT_B10G11R11F, + + PVRSRV_PIXEL_FORMAT_X24G8R32, + PVRSRV_PIXEL_FORMAT_G8R24, + PVRSRV_PIXEL_FORMAT_E5B9G9R9, + PVRSRV_PIXEL_FORMAT_R1, + + PVRSRV_PIXEL_FORMAT_BC1, + PVRSRV_PIXEL_FORMAT_BC1_UNORM, + PVRSRV_PIXEL_FORMAT_BC1_SRGB, + PVRSRV_PIXEL_FORMAT_BC2, + PVRSRV_PIXEL_FORMAT_BC2_UNORM, + PVRSRV_PIXEL_FORMAT_BC2_SRGB, + PVRSRV_PIXEL_FORMAT_BC3, + PVRSRV_PIXEL_FORMAT_BC3_UNORM, + PVRSRV_PIXEL_FORMAT_BC3_SRGB, + PVRSRV_PIXEL_FORMAT_BC4, + PVRSRV_PIXEL_FORMAT_BC4_UNORM, + PVRSRV_PIXEL_FORMAT_BC4_SNORM, + PVRSRV_PIXEL_FORMAT_BC5, + PVRSRV_PIXEL_FORMAT_BC5_UNORM, + PVRSRV_PIXEL_FORMAT_BC5_SNORM, + + PVRSRV_PIXEL_FORMAT_FORCE_I32 = 0x7fffffff, +}; + +enum PVRSRV_ALPHA_FORMAT { + PVRSRV_ALPHA_FORMAT_UNKNOWN = 0x00000000, + PVRSRV_ALPHA_FORMAT_PRE = 0x00000001, + PVRSRV_ALPHA_FORMAT_NONPRE = 0x00000002, + PVRSRV_ALPHA_FORMAT_MASK = 0x0000000F, +}; + +enum PVRSRV_COLOURSPACE_FORMAT { + PVRSRV_COLOURSPACE_FORMAT_UNKNOWN = 0x00000000, + PVRSRV_COLOURSPACE_FORMAT_LINEAR = 0x00010000, + PVRSRV_COLOURSPACE_FORMAT_NONLINEAR = 0x00020000, + PVRSRV_COLOURSPACE_FORMAT_MASK = 0x000F0000, +}; + +enum PVRSRV_ROTATION { + PVRSRV_ROTATE_0 = 0, + PVRSRV_ROTATE_90 = 1, + PVRSRV_ROTATE_180 = 2, + PVRSRV_ROTATE_270 = 3, + PVRSRV_FLIP_Y +}; + +#define PVRSRV_CREATE_SWAPCHAIN_SHARED (1<<0) +#define PVRSRV_CREATE_SWAPCHAIN_QUERY (1<<1) +#define PVRSRV_CREATE_SWAPCHAIN_OEMOVERLAY (1<<2) + +struct PVRSRV_SYNC_DATA { + + u32 ui32WriteOpsPending; + volatile u32 ui32WriteOpsComplete; + + u32 ui32ReadOpsPending; + volatile u32 ui32ReadOpsComplete; + + u32 ui32LastOpDumpVal; + u32 ui32LastReadOpDumpVal; + +}; + +struct PVRSRV_CLIENT_SYNC_INFO { + struct PVRSRV_SYNC_DATA *psSyncData; + struct IMG_DEV_VIRTADDR sWriteOpsCompleteDevVAddr; + struct IMG_DEV_VIRTADDR sReadOpsCompleteDevVAddr; + void *hMappingInfo; + void *hKernelSyncInfo; +}; + +struct PVRSRV_RESOURCE { + volatile u32 ui32Lock; + u32 ui32ID; +}; + +struct IMG_RECT { + s32 x0; + s32 y0; + s32 x1; + s32 y1; +}; + +struct IMG_RECT_16 { + s16 x0; + s16 y0; + s16 x1; + s16 y1; +}; + +struct DISPLAY_DIMS { + u32 ui32ByteStride; + u32 ui32Width; + u32 ui32Height; +}; + +struct DISPLAY_FORMAT { + enum PVRSRV_PIXEL_FORMAT pixelformat; +}; + +struct DISPLAY_SURF_ATTRIBUTES { + enum PVRSRV_PIXEL_FORMAT pixelformat; + struct DISPLAY_DIMS sDims; +}; + +struct DISPLAY_MODE_INFO { + enum PVRSRV_PIXEL_FORMAT pixelformat; + struct DISPLAY_DIMS sDims; + u32 ui32RefreshHZ; + u32 ui32OEMFlags; +}; + +#define MAX_DISPLAY_NAME_SIZE (50) + +struct DISPLAY_INFO { + u32 ui32MaxSwapChains; + u32 ui32MaxSwapChainBuffers; + u32 ui32MinSwapInterval; + u32 ui32MaxSwapInterval; + char szDisplayName[MAX_DISPLAY_NAME_SIZE]; +}; + +struct ACCESS_INFO { + u32 ui32Size; + u32 ui32FBPhysBaseAddress; + u32 ui32FBMemAvailable; + u32 ui32SysPhysBaseAddress; + u32 ui32SysSize; + u32 ui32DevIRQ; +}; + +struct PVRSRV_CURSOR_SHAPE { + u16 ui16Width; + u16 ui16Height; + s16 i16XHot; + s16 i16YHot; + + void *pvMask; + s16 i16MaskByteStride; + + void *pvColour; + s16 i16ColourByteStride; + enum PVRSRV_PIXEL_FORMAT eColourPixelFormat; +}; + +#define PVRSRV_SET_CURSOR_VISIBILITY (1<<0) +#define PVRSRV_SET_CURSOR_POSITION (1<<1) +#define PVRSRV_SET_CURSOR_SHAPE (1<<2) +#define PVRSRV_SET_CURSOR_ROTATION (1<<3) + +struct PVRSRV_CURSOR_INFO { + u32 ui32Flags; + IMG_BOOL bVisible; + s16 i16XPos; + s16 i16YPos; + struct PVRSRV_CURSOR_SHAPE sCursorShape; + u32 ui32Rotation; +}; + +struct PVRSRV_REGISTRY_INFO { + u32 ui32DevCookie; + char *pszKey; + char *pszValue; + char *pszBuf; + u32 ui32BufSize; +}; + +enum PVRSRV_ERROR PVRSRVReadRegistryString( + struct PVRSRV_REGISTRY_INFO *psRegInfo); +enum PVRSRV_ERROR PVRSRVWriteRegistryString( + struct PVRSRV_REGISTRY_INFO *psRegInfo); + +#define PVRSRV_BC_FLAGS_YUVCSC_CONFORMANT_RANGE (0 << 0) +#define PVRSRV_BC_FLAGS_YUVCSC_FULL_RANGE (1 << 0) + +#define PVRSRV_BC_FLAGS_YUVCSC_BT601 (0 << 1) +#define PVRSRV_BC_FLAGS_YUVCSC_BT709 (1 << 1) + +struct BUFFER_INFO { + u32 ui32BufferCount; + u32 ui32BufferDeviceID; + enum PVRSRV_PIXEL_FORMAT pixelformat; + u32 ui32ByteStride; + u32 ui32Width; + u32 ui32Height; + u32 ui32Flags; +}; + +enum OVERLAY_DEINTERLACE_MODE { + WEAVE = 0x0, + BOB_ODD, + BOB_EVEN, + BOB_EVEN_NONINTERLEAVED +}; + +#endif diff --git a/drivers/gpu/pvr/servicesint.h b/drivers/gpu/pvr/servicesint.h new file mode 100644 index 00000000000..a81adff8f49 --- /dev/null +++ b/drivers/gpu/pvr/servicesint.h @@ -0,0 +1,181 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__SERVICESINT_H__) +#define __SERVICESINT_H__ + + +#include "services.h" +#include "sysinfo.h" + +#define HWREC_DEFAULT_TIMEOUT 500 + +#define DRIVERNAME_MAXLENGTH 100 + +struct PVRSRV_KERNEL_MEM_INFO { + + void *pvLinAddrKM; + struct IMG_DEV_VIRTADDR sDevVAddr; + u32 ui32Flags; + u32 ui32AllocSize; + struct PVRSRV_MEMBLK sMemBlk; + + void *pvSysBackupBuffer; + + u32 ui32RefCount; + + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; +}; + +struct PVRSRV_KERNEL_SYNC_INFO { + struct PVRSRV_SYNC_DATA *psSyncData; + struct IMG_DEV_VIRTADDR sWriteOpsCompleteDevVAddr; + struct IMG_DEV_VIRTADDR sReadOpsCompleteDevVAddr; + struct PVRSRV_KERNEL_MEM_INFO *psSyncDataMemInfoKM; + + /* + * This stores the physical address of the buffer that + * this syncobject manages (if provided) + */ + struct IMG_SYS_PHYADDR phys_addr; + void *dev_cookie; + u32 refcount; +}; + +struct PVRSRV_DEVICE_SYNC_OBJECT { + + u32 ui32ReadOpsPendingVal; + struct IMG_DEV_VIRTADDR sReadOpsCompleteDevVAddr; + u32 ui32WriteOpsPendingVal; + struct IMG_DEV_VIRTADDR sWriteOpsCompleteDevVAddr; +}; + +struct PVRSRV_SYNC_OBJECT { + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfoKM; + u32 ui32WriteOpsPending; + u32 ui32ReadOpsPending; +}; + +struct PVRSRV_COMMAND { + u32 ui32CmdSize; + u32 ui32DevIndex; + u32 CommandType; + u32 ui32DstSyncCount; + u32 ui32SrcSyncCount; + struct PVRSRV_SYNC_OBJECT *psDstSync; + struct PVRSRV_SYNC_OBJECT *psSrcSync; + u32 ui32DataSize; + u32 ui32ProcessID; + void *pvData; +}; + +struct PVRSRV_QUEUE_INFO { + void *pvLinQueueKM; + void *pvLinQueueUM; + volatile u32 ui32ReadOffset; + volatile u32 ui32WriteOffset; + u32 *pui32KickerAddrKM; + u32 *pui32KickerAddrUM; + u32 ui32QueueSize; + + u32 ui32ProcessID; + + void *hMemBlock[2]; + + struct PVRSRV_QUEUE_INFO *psNextKM; +}; + +struct PVRSRV_DEVICECLASS_BUFFER { + enum PVRSRV_ERROR (*pfnGetBufferAddr)(void *, void *, + struct IMG_SYS_PHYADDR **, u32 *, + void __iomem **, void **, IMG_BOOL *); + void *hDevMemContext; + void *hExtDevice; + void *hExtBuffer; + struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; +}; + +struct PVRSRV_CLIENT_DEVICECLASS_INFO { + void *hDeviceKM; + void *hServices; +}; + +static inline u32 PVRSRVGetWriteOpsPending( + struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp) +{ + u32 ui32WriteOpsPending; + + if (bIsReadOp) + ui32WriteOpsPending = + psSyncInfo->psSyncData->ui32WriteOpsPending; + else + ui32WriteOpsPending = + psSyncInfo->psSyncData->ui32WriteOpsPending++; + + return ui32WriteOpsPending; +} + +static inline u32 PVRSRVGetReadOpsPending( + struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp) +{ + u32 ui32ReadOpsPending; + + if (bIsReadOp) + ui32ReadOpsPending = + psSyncInfo->psSyncData->ui32ReadOpsPending++; + else + ui32ReadOpsPending = psSyncInfo->psSyncData->ui32ReadOpsPending; + + return ui32ReadOpsPending; +} + +enum PVRSRV_ERROR PVRSRVQueueCommand(void *hQueueInfo, + struct PVRSRV_COMMAND *psCommand); + +enum PVRSRV_ERROR PVRSRVGetMMUContextPDDevPAddr( + const struct PVRSRV_CONNECTION *psConnection, + void *hDevMemContext, + struct IMG_DEV_PHYADDR *sPDDevPAddr); + +enum PVRSRV_ERROR PVRSRVAllocSharedSysMem( + const struct PVRSRV_CONNECTION *psConnection, + u32 ui32Flags, u32 ui32Size, + struct PVRSRV_CLIENT_MEM_INFO **ppsClientMemInfo); + +enum PVRSRV_ERROR PVRSRVFreeSharedSysMem( + const struct PVRSRV_CONNECTION *psConnection, + struct PVRSRV_CLIENT_MEM_INFO *psClientMemInfo); + +enum PVRSRV_ERROR PVRSRVUnrefSharedSysMem( + const struct PVRSRV_CONNECTION *psConnection, + struct PVRSRV_CLIENT_MEM_INFO *psClientMemInfo); + +enum PVRSRV_ERROR PVRSRVMapMemInfoMem( + const struct PVRSRV_CONNECTION *psConnection, + void *hKernelMemInfo, + struct PVRSRV_CLIENT_MEM_INFO **ppsClientMemInfo); + +#endif diff --git a/drivers/gpu/pvr/sgx530defs.h b/drivers/gpu/pvr/sgx530defs.h new file mode 100644 index 00000000000..1a796eed27a --- /dev/null +++ b/drivers/gpu/pvr/sgx530defs.h @@ -0,0 +1,471 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _SGX530DEFS_KM_H_ +#define _SGX530DEFS_KM_H_ + +#define EUR_CR_CLKGATECTL 0x0000 +#define EUR_CR_CLKGATECTL_2D_CLKG_MASK 0x00000003 +#define EUR_CR_CLKGATECTL_2D_CLKG_SHIFT 0 +#define EUR_CR_CLKGATECTL_ISP_CLKG_MASK 0x00000030 +#define EUR_CR_CLKGATECTL_ISP_CLKG_SHIFT 4 +#define EUR_CR_CLKGATECTL_TSP_CLKG_MASK 0x00000300 +#define EUR_CR_CLKGATECTL_TSP_CLKG_SHIFT 8 +#define EUR_CR_CLKGATECTL_TA_CLKG_MASK 0x00003000 +#define EUR_CR_CLKGATECTL_TA_CLKG_SHIFT 12 +#define EUR_CR_CLKGATECTL_DPM_CLKG_MASK 0x00030000 +#define EUR_CR_CLKGATECTL_DPM_CLKG_SHIFT 16 +#define EUR_CR_CLKGATECTL_USE_CLKG_MASK 0x00300000 +#define EUR_CR_CLKGATECTL_USE_CLKG_SHIFT 20 +#define EUR_CR_CLKGATECTL_AUTO_MAN_REG_MASK 0x01000000 +#define EUR_CR_CLKGATECTL_AUTO_MAN_REG_SHIFT 24 + +#define EUR_CR_CLKGATESTATUS 0x0004 +#define EUR_CR_CLKGATESTATUS_2D_CLKS_MASK 0x00000001 +#define EUR_CR_CLKGATESTATUS_2D_CLKS_SHIFT 0 +#define EUR_CR_CLKGATESTATUS_ISP_CLKS_MASK 0x00000010 +#define EUR_CR_CLKGATESTATUS_ISP_CLKS_SHIFT 4 +#define EUR_CR_CLKGATESTATUS_TSP_CLKS_MASK 0x00000100 +#define EUR_CR_CLKGATESTATUS_TSP_CLKS_SHIFT 8 +#define EUR_CR_CLKGATESTATUS_TA_CLKS_MASK 0x00001000 +#define EUR_CR_CLKGATESTATUS_TA_CLKS_SHIFT 12 +#define EUR_CR_CLKGATESTATUS_DPM_CLKS_MASK 0x00010000 +#define EUR_CR_CLKGATESTATUS_DPM_CLKS_SHIFT 16 +#define EUR_CR_CLKGATESTATUS_USE_CLKS_MASK 0x00100000 +#define EUR_CR_CLKGATESTATUS_USE_CLKS_SHIFT 20 + +#define EUR_CR_CLKGATECTLOVR 0x0008 +#define EUR_CR_CLKGATECTLOVR_2D_CLKO_MASK 0x00000003 +#define EUR_CR_CLKGATECTLOVR_2D_CLKO_SHIFT 0 +#define EUR_CR_CLKGATECTLOVR_ISP_CLKO_MASK 0x00000030 +#define EUR_CR_CLKGATECTLOVR_ISP_CLKO_SHIFT 4 +#define EUR_CR_CLKGATECTLOVR_TSP_CLKO_MASK 0x00000300 +#define EUR_CR_CLKGATECTLOVR_TSP_CLKO_SHIFT 8 +#define EUR_CR_CLKGATECTLOVR_TA_CLKO_MASK 0x00003000 +#define EUR_CR_CLKGATECTLOVR_TA_CLKO_SHIFT 12 +#define EUR_CR_CLKGATECTLOVR_DPM_CLKO_MASK 0x00030000 +#define EUR_CR_CLKGATECTLOVR_DPM_CLKO_SHIFT 16 +#define EUR_CR_CLKGATECTLOVR_USE_CLKO_MASK 0x00300000 +#define EUR_CR_CLKGATECTLOVR_USE_CLKO_SHIFT 20 + +#define EUR_CR_CORE_ID 0x0010 +#define EUR_CR_CORE_ID_CONFIG_MASK 0x0000FFFF +#define EUR_CR_CORE_ID_CONFIG_SHIFT 0 +#define EUR_CR_CORE_ID_ID_MASK 0xFFFF0000 +#define EUR_CR_CORE_ID_ID_SHIFT 16 + +#define EUR_CR_CORE_REVISION 0x0014 +#define EUR_CR_CORE_REVISION_MAINTENANCE_MASK 0x000000FF +#define EUR_CR_CORE_REVISION_MAINTENANCE_SHIFT 0 +#define EUR_CR_CORE_REVISION_MINOR_MASK 0x0000FF00 +#define EUR_CR_CORE_REVISION_MINOR_SHIFT 8 +#define EUR_CR_CORE_REVISION_MAJOR_MASK 0x00FF0000 +#define EUR_CR_CORE_REVISION_MAJOR_SHIFT 16 +#define EUR_CR_CORE_MAKE_REV(maj, min, maint) ( \ + (((maj) << EUR_CR_CORE_REVISION_MAJOR_SHIFT) & \ + EUR_CR_CORE_REVISION_MAJOR_MASK) | \ + (((min) << EUR_CR_CORE_REVISION_MINOR_SHIFT) & \ + EUR_CR_CORE_REVISION_MINOR_MASK) | \ + (((maint) << EUR_CR_CORE_REVISION_MAINTENANCE_SHIFT) & \ + EUR_CR_CORE_REVISION_MAINTENANCE_MASK) \ + ) +#define EUR_CR_CORE_REVISION_DESIGNER_MASK 0xFF000000 +#define EUR_CR_CORE_REVISION_DESIGNER_SHIFT 24 + +#define EUR_CR_DESIGNER_REV_FIELD1 0x0018 +#define EUR_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_MASK 0xFFFFFFFF +#define EUR_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_SHIFT 0 + +#define EUR_CR_DESIGNER_REV_FIELD2 0x001C +#define EUR_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_MASK 0xFFFFFFFF +#define EUR_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_SHIFT 0 + +#define EUR_CR_SOFT_RESET 0x0080 +#define EUR_CR_SOFT_RESET_BIF_RESET_MASK 0x00000001 +#define EUR_CR_SOFT_RESET_BIF_RESET_SHIFT 0 +#define EUR_CR_SOFT_RESET_TWOD_RESET_MASK 0x00000002 +#define EUR_CR_SOFT_RESET_TWOD_RESET_SHIFT 1 +#define EUR_CR_SOFT_RESET_DPM_RESET_MASK 0x00000004 +#define EUR_CR_SOFT_RESET_DPM_RESET_SHIFT 2 +#define EUR_CR_SOFT_RESET_TA_RESET_MASK 0x00000008 +#define EUR_CR_SOFT_RESET_TA_RESET_SHIFT 3 +#define EUR_CR_SOFT_RESET_USE_RESET_MASK 0x00000010 +#define EUR_CR_SOFT_RESET_USE_RESET_SHIFT 4 +#define EUR_CR_SOFT_RESET_ISP_RESET_MASK 0x00000020 +#define EUR_CR_SOFT_RESET_ISP_RESET_SHIFT 5 +#define EUR_CR_SOFT_RESET_TSP_RESET_MASK 0x00000040 +#define EUR_CR_SOFT_RESET_TSP_RESET_SHIFT 6 + +#define EUR_CR_EVENT_HOST_ENABLE2 0x0110 +#define EUR_CR_EVENT_HOST_ENABLE2_DPM_3D_FREE_LOAD_MASK 0x00000002 +#define EUR_CR_EVENT_HOST_ENABLE2_DPM_3D_FREE_LOAD_SHIFT 1 +#define EUR_CR_EVENT_HOST_ENABLE2_DPM_TA_FREE_LOAD_MASK 0x00000001 +#define EUR_CR_EVENT_HOST_ENABLE2_DPM_TA_FREE_LOAD_SHIFT 0 + +#define EUR_CR_EVENT_HOST_CLEAR2 0x0114 +#define EUR_CR_EVENT_HOST_CLEAR2_DPM_3D_FREE_LOAD_MASK 0x00000002 +#define EUR_CR_EVENT_HOST_CLEAR2_DPM_3D_FREE_LOAD_SHIFT 1 +#define EUR_CR_EVENT_HOST_CLEAR2_DPM_TA_FREE_LOAD_MASK 0x00000001 +#define EUR_CR_EVENT_HOST_CLEAR2_DPM_TA_FREE_LOAD_SHIFT 0 + +#define EUR_CR_EVENT_STATUS2 0x0118 +#define EUR_CR_EVENT_STATUS2_DPM_3D_FREE_LOAD_MASK 0x00000002 +#define EUR_CR_EVENT_STATUS2_DPM_3D_FREE_LOAD_SHIFT 1 +#define EUR_CR_EVENT_STATUS2_DPM_TA_FREE_LOAD_MASK 0x00000001 +#define EUR_CR_EVENT_STATUS2_DPM_TA_FREE_LOAD_SHIFT 0 + +#define EUR_CR_EVENT_STATUS 0x012C +#define EUR_CR_EVENT_STATUS_MASTER_INTERRUPT_MASK 0x80000000 +#define EUR_CR_EVENT_STATUS_MASTER_INTERRUPT_SHIFT 31 +#define EUR_CR_EVENT_STATUS_TIMER_MASK 0x20000000 +#define EUR_CR_EVENT_STATUS_TIMER_SHIFT 29 +#define EUR_CR_EVENT_STATUS_TA_DPM_FAULT_MASK 0x10000000 +#define EUR_CR_EVENT_STATUS_TA_DPM_FAULT_SHIFT 28 +#define EUR_CR_EVENT_STATUS_TWOD_COMPLETE_MASK 0x08000000 +#define EUR_CR_EVENT_STATUS_TWOD_COMPLETE_SHIFT 27 +#define EUR_CR_EVENT_STATUS_MADD_CACHE_INVALCOMPLETE_MASK 0x04000000 +#define EUR_CR_EVENT_STATUS_MADD_CACHE_INVALCOMPLETE_SHIFT 26 +#define EUR_CR_EVENT_STATUS_DPM_OUT_OF_MEMORY_ZLS_MASK 0x02000000 +#define EUR_CR_EVENT_STATUS_DPM_OUT_OF_MEMORY_ZLS_SHIFT 25 +#define EUR_CR_EVENT_STATUS_DPM_TA_MEM_FREE_MASK 0x01000000 +#define EUR_CR_EVENT_STATUS_DPM_TA_MEM_FREE_SHIFT 24 +#define EUR_CR_EVENT_STATUS_ISP_END_TILE_MASK 0x00800000 +#define EUR_CR_EVENT_STATUS_ISP_END_TILE_SHIFT 23 +#define EUR_CR_EVENT_STATUS_DPM_INITEND_MASK 0x00400000 +#define EUR_CR_EVENT_STATUS_DPM_INITEND_SHIFT 22 +#define EUR_CR_EVENT_STATUS_OTPM_LOADED_MASK 0x00200000 +#define EUR_CR_EVENT_STATUS_OTPM_LOADED_SHIFT 21 +#define EUR_CR_EVENT_STATUS_OTPM_INV_MASK 0x00100000 +#define EUR_CR_EVENT_STATUS_OTPM_INV_SHIFT 20 +#define EUR_CR_EVENT_STATUS_OTPM_FLUSHED_MASK 0x00080000 +#define EUR_CR_EVENT_STATUS_OTPM_FLUSHED_SHIFT 19 +#define EUR_CR_EVENT_STATUS_PIXELBE_END_RENDER_MASK 0x00040000 +#define EUR_CR_EVENT_STATUS_PIXELBE_END_RENDER_SHIFT 18 +#define EUR_CR_EVENT_STATUS_ISP_HALT_MASK 0x00020000 +#define EUR_CR_EVENT_STATUS_ISP_HALT_SHIFT 17 +#define EUR_CR_EVENT_STATUS_ISP_VISIBILITY_FAIL_MASK 0x00010000 +#define EUR_CR_EVENT_STATUS_ISP_VISIBILITY_FAIL_SHIFT 16 +#define EUR_CR_EVENT_STATUS_BREAKPOINT_MASK 0x00008000 +#define EUR_CR_EVENT_STATUS_BREAKPOINT_SHIFT 15 +#define EUR_CR_EVENT_STATUS_SW_EVENT_MASK 0x00004000 +#define EUR_CR_EVENT_STATUS_SW_EVENT_SHIFT 14 +#define EUR_CR_EVENT_STATUS_TA_FINISHED_MASK 0x00002000 +#define EUR_CR_EVENT_STATUS_TA_FINISHED_SHIFT 13 +#define EUR_CR_EVENT_STATUS_TA_TERMINATE_MASK 0x00001000 +#define EUR_CR_EVENT_STATUS_TA_TERMINATE_SHIFT 12 +#define EUR_CR_EVENT_STATUS_TPC_CLEAR_MASK 0x00000800 +#define EUR_CR_EVENT_STATUS_TPC_CLEAR_SHIFT 11 +#define EUR_CR_EVENT_STATUS_TPC_FLUSH_MASK 0x00000400 +#define EUR_CR_EVENT_STATUS_TPC_FLUSH_SHIFT 10 +#define EUR_CR_EVENT_STATUS_DPM_CONTROL_CLEAR_MASK 0x00000200 +#define EUR_CR_EVENT_STATUS_DPM_CONTROL_CLEAR_SHIFT 9 +#define EUR_CR_EVENT_STATUS_DPM_CONTROL_LOAD_MASK 0x00000100 +#define EUR_CR_EVENT_STATUS_DPM_CONTROL_LOAD_SHIFT 8 +#define EUR_CR_EVENT_STATUS_DPM_CONTROL_STORE_MASK 0x00000080 +#define EUR_CR_EVENT_STATUS_DPM_CONTROL_STORE_SHIFT 7 +#define EUR_CR_EVENT_STATUS_DPM_STATE_CLEAR_MASK 0x00000040 +#define EUR_CR_EVENT_STATUS_DPM_STATE_CLEAR_SHIFT 6 +#define EUR_CR_EVENT_STATUS_DPM_STATE_LOAD_MASK 0x00000020 +#define EUR_CR_EVENT_STATUS_DPM_STATE_LOAD_SHIFT 5 +#define EUR_CR_EVENT_STATUS_DPM_STATE_STORE_MASK 0x00000010 +#define EUR_CR_EVENT_STATUS_DPM_STATE_STORE_SHIFT 4 +#define EUR_CR_EVENT_STATUS_DPM_REACHED_MEM_THRESH_MASK 0x00000008 +#define EUR_CR_EVENT_STATUS_DPM_REACHED_MEM_THRESH_SHIFT 3 +#define EUR_CR_EVENT_STATUS_DPM_OUT_OF_MEMORY_GBL_MASK 0x00000004 +#define EUR_CR_EVENT_STATUS_DPM_OUT_OF_MEMORY_GBL_SHIFT 2 +#define EUR_CR_EVENT_STATUS_DPM_OUT_OF_MEMORY_MT_MASK 0x00000002 +#define EUR_CR_EVENT_STATUS_DPM_OUT_OF_MEMORY_MT_SHIFT 1 +#define EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_MASK 0x00000001 +#define EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_SHIFT 0 + +#define EUR_CR_EVENT_HOST_ENABLE 0x0130 +#define EUR_CR_EVENT_HOST_ENABLE_MASTER_INTERRUPT_MASK 0x80000000 +#define EUR_CR_EVENT_HOST_ENABLE_MASTER_INTERRUPT_SHIFT 31 +#define EUR_CR_EVENT_HOST_ENABLE_TIMER_MASK 0x20000000 +#define EUR_CR_EVENT_HOST_ENABLE_TIMER_SHIFT 29 +#define EUR_CR_EVENT_HOST_ENABLE_TA_DPM_FAULT_MASK 0x10000000 +#define EUR_CR_EVENT_HOST_ENABLE_TA_DPM_FAULT_SHIFT 28 +#define EUR_CR_EVENT_HOST_ENABLE_TWOD_COMPLETE_MASK 0x08000000 +#define EUR_CR_EVENT_HOST_ENABLE_TWOD_COMPLETE_SHIFT 27 +#define EUR_CR_EVENT_HOST_ENABLE_MADD_CACHE_INVALCOMPLETE_MASK 0x04000000 +#define EUR_CR_EVENT_HOST_ENABLE_MADD_CACHE_INVALCOMPLETE_SHIFT 26 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_OUT_OF_MEMORY_ZLS_MASK 0x02000000 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_OUT_OF_MEMORY_ZLS_SHIFT 25 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_TA_MEM_FREE_MASK 0x01000000 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_TA_MEM_FREE_SHIFT 24 +#define EUR_CR_EVENT_HOST_ENABLE_ISP_END_TILE_MASK 0x00800000 +#define EUR_CR_EVENT_HOST_ENABLE_ISP_END_TILE_SHIFT 23 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_INITEND_MASK 0x00400000 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_INITEND_SHIFT 22 +#define EUR_CR_EVENT_HOST_ENABLE_OTPM_LOADED_MASK 0x00200000 +#define EUR_CR_EVENT_HOST_ENABLE_OTPM_LOADED_SHIFT 21 +#define EUR_CR_EVENT_HOST_ENABLE_OTPM_INV_MASK 0x00100000 +#define EUR_CR_EVENT_HOST_ENABLE_OTPM_INV_SHIFT 20 +#define EUR_CR_EVENT_HOST_ENABLE_OTPM_FLUSHED_MASK 0x00080000 +#define EUR_CR_EVENT_HOST_ENABLE_OTPM_FLUSHED_SHIFT 19 +#define EUR_CR_EVENT_HOST_ENABLE_PIXELBE_END_RENDER_MASK 0x00040000 +#define EUR_CR_EVENT_HOST_ENABLE_PIXELBE_END_RENDER_SHIFT 18 +#define EUR_CR_EVENT_HOST_ENABLE_ISP_HALT_MASK 0x00020000 +#define EUR_CR_EVENT_HOST_ENABLE_ISP_HALT_SHIFT 17 +#define EUR_CR_EVENT_HOST_ENABLE_ISP_VISIBILITY_FAIL_MASK 0x00010000 +#define EUR_CR_EVENT_HOST_ENABLE_ISP_VISIBILITY_FAIL_SHIFT 16 +#define EUR_CR_EVENT_HOST_ENABLE_BREAKPOINT_MASK 0x00008000 +#define EUR_CR_EVENT_HOST_ENABLE_BREAKPOINT_SHIFT 15 +#define EUR_CR_EVENT_HOST_ENABLE_SW_EVENT_MASK 0x00004000 +#define EUR_CR_EVENT_HOST_ENABLE_SW_EVENT_SHIFT 14 +#define EUR_CR_EVENT_HOST_ENABLE_TA_FINISHED_MASK 0x00002000 +#define EUR_CR_EVENT_HOST_ENABLE_TA_FINISHED_SHIFT 13 +#define EUR_CR_EVENT_HOST_ENABLE_TA_TERMINATE_MASK 0x00001000 +#define EUR_CR_EVENT_HOST_ENABLE_TA_TERMINATE_SHIFT 12 +#define EUR_CR_EVENT_HOST_ENABLE_TPC_CLEAR_MASK 0x00000800 +#define EUR_CR_EVENT_HOST_ENABLE_TPC_CLEAR_SHIFT 11 +#define EUR_CR_EVENT_HOST_ENABLE_TPC_FLUSH_MASK 0x00000400 +#define EUR_CR_EVENT_HOST_ENABLE_TPC_FLUSH_SHIFT 10 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_CONTROL_CLEAR_MASK 0x00000200 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_CONTROL_CLEAR_SHIFT 9 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_CONTROL_LOAD_MASK 0x00000100 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_CONTROL_LOAD_SHIFT 8 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_CONTROL_STORE_MASK 0x00000080 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_CONTROL_STORE_SHIFT 7 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_STATE_CLEAR_MASK 0x00000040 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_STATE_CLEAR_SHIFT 6 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_STATE_LOAD_MASK 0x00000020 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_STATE_LOAD_SHIFT 5 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_STATE_STORE_MASK 0x00000010 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_STATE_STORE_SHIFT 4 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_REACHED_MEM_THRESH_MASK 0x00000008 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_REACHED_MEM_THRESH_SHIFT 3 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_OUT_OF_MEMORY_GBL_MASK 0x00000004 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_OUT_OF_MEMORY_GBL_SHIFT 2 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_OUT_OF_MEMORY_MT_MASK 0x00000002 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_OUT_OF_MEMORY_MT_SHIFT 1 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_3D_MEM_FREE_MASK 0x00000001 +#define EUR_CR_EVENT_HOST_ENABLE_DPM_3D_MEM_FREE_SHIFT 0 + +#define EUR_CR_EVENT_HOST_CLEAR 0x0134 +#define EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_MASK 0x80000000 +#define EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_SHIFT 31 +#define EUR_CR_EVENT_HOST_CLEAR_TIMER_MASK 0x20000000 +#define EUR_CR_EVENT_HOST_CLEAR_TIMER_SHIFT 29 +#define EUR_CR_EVENT_HOST_CLEAR_TA_DPM_FAULT_MASK 0x10000000 +#define EUR_CR_EVENT_HOST_CLEAR_TA_DPM_FAULT_SHIFT 28 +#define EUR_CR_EVENT_HOST_CLEAR_TWOD_COMPLETE_MASK 0x08000000 +#define EUR_CR_EVENT_HOST_CLEAR_TWOD_COMPLETE_SHIFT 27 +#define EUR_CR_EVENT_HOST_CLEAR_MADD_CACHE_INVALCOMPLETE_MASK 0x04000000 +#define EUR_CR_EVENT_HOST_CLEAR_MADD_CACHE_INVALCOMPLETE_SHIFT 26 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_OUT_OF_MEMORY_ZLS_MASK 0x02000000 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_OUT_OF_MEMORY_ZLS_SHIFT 25 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_TA_MEM_FREE_MASK 0x01000000 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_TA_MEM_FREE_SHIFT 24 +#define EUR_CR_EVENT_HOST_CLEAR_ISP_END_TILE_MASK 0x00800000 +#define EUR_CR_EVENT_HOST_CLEAR_ISP_END_TILE_SHIFT 23 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_INITEND_MASK 0x00400000 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_INITEND_SHIFT 22 +#define EUR_CR_EVENT_HOST_CLEAR_OTPM_LOADED_MASK 0x00200000 +#define EUR_CR_EVENT_HOST_CLEAR_OTPM_LOADED_SHIFT 21 +#define EUR_CR_EVENT_HOST_CLEAR_OTPM_INV_MASK 0x00100000 +#define EUR_CR_EVENT_HOST_CLEAR_OTPM_INV_SHIFT 20 +#define EUR_CR_EVENT_HOST_CLEAR_OTPM_FLUSHED_MASK 0x00080000 +#define EUR_CR_EVENT_HOST_CLEAR_OTPM_FLUSHED_SHIFT 19 +#define EUR_CR_EVENT_HOST_CLEAR_PIXELBE_END_RENDER_MASK 0x00040000 +#define EUR_CR_EVENT_HOST_CLEAR_PIXELBE_END_RENDER_SHIFT 18 +#define EUR_CR_EVENT_HOST_CLEAR_ISP_HALT_MASK 0x00020000 +#define EUR_CR_EVENT_HOST_CLEAR_ISP_HALT_SHIFT 17 +#define EUR_CR_EVENT_HOST_CLEAR_ISP_VISIBILITY_FAIL_MASK 0x00010000 +#define EUR_CR_EVENT_HOST_CLEAR_ISP_VISIBILITY_FAIL_SHIFT 16 +#define EUR_CR_EVENT_HOST_CLEAR_BREAKPOINT_MASK 0x00008000 +#define EUR_CR_EVENT_HOST_CLEAR_BREAKPOINT_SHIFT 15 +#define EUR_CR_EVENT_HOST_CLEAR_SW_EVENT_MASK 0x00004000 +#define EUR_CR_EVENT_HOST_CLEAR_SW_EVENT_SHIFT 14 +#define EUR_CR_EVENT_HOST_CLEAR_TA_FINISHED_MASK 0x00002000 +#define EUR_CR_EVENT_HOST_CLEAR_TA_FINISHED_SHIFT 13 +#define EUR_CR_EVENT_HOST_CLEAR_TA_TERMINATE_MASK 0x00001000 +#define EUR_CR_EVENT_HOST_CLEAR_TA_TERMINATE_SHIFT 12 +#define EUR_CR_EVENT_HOST_CLEAR_TPC_CLEAR_MASK 0x00000800 +#define EUR_CR_EVENT_HOST_CLEAR_TPC_CLEAR_SHIFT 11 +#define EUR_CR_EVENT_HOST_CLEAR_TPC_FLUSH_MASK 0x00000400 +#define EUR_CR_EVENT_HOST_CLEAR_TPC_FLUSH_SHIFT 10 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_CONTROL_CLEAR_MASK 0x00000200 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_CONTROL_CLEAR_SHIFT 9 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_CONTROL_LOAD_MASK 0x00000100 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_CONTROL_LOAD_SHIFT 8 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_CONTROL_STORE_MASK 0x00000080 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_CONTROL_STORE_SHIFT 7 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_STATE_CLEAR_MASK 0x00000040 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_STATE_CLEAR_SHIFT 6 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_STATE_LOAD_MASK 0x00000020 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_STATE_LOAD_SHIFT 5 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_STATE_STORE_MASK 0x00000010 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_STATE_STORE_SHIFT 4 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_REACHED_MEM_THRESH_MASK 0x00000008 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_REACHED_MEM_THRESH_SHIFT 3 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_OUT_OF_MEMORY_GBL_MASK 0x00000004 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_OUT_OF_MEMORY_GBL_SHIFT 2 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_OUT_OF_MEMORY_MT_MASK 0x00000002 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_OUT_OF_MEMORY_MT_SHIFT 1 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_3D_MEM_FREE_MASK 0x00000001 +#define EUR_CR_EVENT_HOST_CLEAR_DPM_3D_MEM_FREE_SHIFT 0 + +#define EUR_CR_PDS 0x0ABC +#define EUR_CR_PDS_DOUT_TIMEOUT_DISABLE_MASK 0x00000040 +#define EUR_CR_PDS_DOUT_TIMEOUT_DISABLE_SHIFT 6 + +#define EUR_CR_PDS_EXEC_BASE 0x0AB8 +#define EUR_CR_PDS_EXEC_BASE_ADDR_MASK 0x0FF00000 +#define EUR_CR_PDS_EXEC_BASE_ADDR_SHIFT 20 + +#define EUR_CR_EVENT_KICKER 0x0AC4 +#define EUR_CR_EVENT_KICKER_ADDRESS_MASK 0x0FFFFFF0 +#define EUR_CR_EVENT_KICKER_ADDRESS_SHIFT 4 + +#define EUR_CR_EVENT_KICK 0x0AC8 +#define EUR_CR_EVENT_KICK_NOW_MASK 0x00000001 +#define EUR_CR_EVENT_KICK_NOW_SHIFT 0 + +#define EUR_CR_EVENT_TIMER 0x0ACC +#define EUR_CR_EVENT_TIMER_ENABLE_MASK 0x01000000 +#define EUR_CR_EVENT_TIMER_ENABLE_SHIFT 24 +#define EUR_CR_EVENT_TIMER_VALUE_MASK 0x00FFFFFF +#define EUR_CR_EVENT_TIMER_VALUE_SHIFT 0 + +#define EUR_CR_PDS_INV0 0x0AD0 +#define EUR_CR_PDS_INV0_DSC_MASK 0x00000001 +#define EUR_CR_PDS_INV0_DSC_SHIFT 0 + +#define EUR_CR_PDS_INV1 0x0AD4 +#define EUR_CR_PDS_INV1_DSC_MASK 0x00000001 +#define EUR_CR_PDS_INV1_DSC_SHIFT 0 + +#define EUR_CR_PDS_INV2 0x0AD8 +#define EUR_CR_PDS_INV2_DSC_MASK 0x00000001 +#define EUR_CR_PDS_INV2_DSC_SHIFT 0 + +#define EUR_CR_PDS_INV3 0x0ADC +#define EUR_CR_PDS_INV3_DSC_MASK 0x00000001 +#define EUR_CR_PDS_INV3_DSC_SHIFT 0 + +#define EUR_CR_PDS_INV_CSC 0x0AE0 +#define EUR_CR_PDS_INV_CSC_KICK_MASK 0x00000001 +#define EUR_CR_PDS_INV_CSC_KICK_SHIFT 0 + +#define EUR_CR_PDS_PC_BASE 0x0B2C +#define EUR_CR_PDS_PC_BASE_ADDRESS_MASK 0x3FFFFFFF +#define EUR_CR_PDS_PC_BASE_ADDRESS_SHIFT 0 + +#define EUR_CR_BIF_CTRL 0x0C00 +#define EUR_CR_BIF_CTRL_NOREORDER_MASK 0x00000001 +#define EUR_CR_BIF_CTRL_NOREORDER_SHIFT 0 +#define EUR_CR_BIF_CTRL_PAUSE_MASK 0x00000002 +#define EUR_CR_BIF_CTRL_PAUSE_SHIFT 1 +#define EUR_CR_BIF_CTRL_FLUSH_MASK 0x00000004 +#define EUR_CR_BIF_CTRL_FLUSH_SHIFT 2 +#define EUR_CR_BIF_CTRL_INVALDC_MASK 0x00000008 +#define EUR_CR_BIF_CTRL_INVALDC_SHIFT 3 +#define EUR_CR_BIF_CTRL_CLEAR_FAULT_MASK 0x00000010 +#define EUR_CR_BIF_CTRL_CLEAR_FAULT_SHIFT 4 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_CACHE_MASK 0x00000100 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_CACHE_SHIFT 8 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_VDM_MASK 0x00000200 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_VDM_SHIFT 9 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_TE_MASK 0x00000400 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_TE_SHIFT 10 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_TWOD_MASK 0x00000800 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_TWOD_SHIFT 11 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_PBE_MASK 0x00001000 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_PBE_SHIFT 12 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_TSPP_MASK 0x00002000 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_TSPP_SHIFT 13 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_ISP_MASK 0x00004000 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_ISP_SHIFT 14 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_USE_MASK 0x00008000 +#define EUR_CR_BIF_CTRL_MMU_BYPASS_USE_SHIFT 15 + +#define EUR_CR_BIF_INT_STAT 0x0C04 +#define EUR_CR_BIF_INT_STAT_FAULT_MASK 0x00003FFF +#define EUR_CR_BIF_INT_STAT_FAULT_SHIFT 0 +#define EUR_CR_BIF_INT_STAT_PF_N_RW_MASK 0x00004000 +#define EUR_CR_BIF_INT_STAT_PF_N_RW_SHIFT 14 +#define EUR_CR_BIF_FAULT 0x0C08 +#define EUR_CR_BIF_FAULT_ADDR_MASK 0x0FFFF000 +#define EUR_CR_BIF_FAULT_ADDR_SHIFT 12 + +#define EUR_CR_BIF_DIR_LIST_BASE0 0x0C84 +#define EUR_CR_BIF_DIR_LIST_BASE0_ADDR_MASK 0xFFFFF000 +#define EUR_CR_BIF_DIR_LIST_BASE0_ADDR_SHIFT 12 + +#define EUR_CR_BIF_TWOD_REQ_BASE 0x0C88 +#define EUR_CR_BIF_TWOD_REQ_BASE_ADDR_MASK 0x0FF00000 +#define EUR_CR_BIF_TWOD_REQ_BASE_ADDR_SHIFT 20 + +#define EUR_CR_BIF_TA_REQ_BASE 0x0C90 +#define EUR_CR_BIF_TA_REQ_BASE_ADDR_MASK 0x0FF00000 +#define EUR_CR_BIF_TA_REQ_BASE_ADDR_SHIFT 20 + +#define EUR_CR_BIF_MEM_REQ_STAT 0x0CA8 +#define EUR_CR_BIF_MEM_REQ_STAT_READS_MASK 0x000000FF +#define EUR_CR_BIF_MEM_REQ_STAT_READS_SHIFT 0 + +#define EUR_CR_BIF_3D_REQ_BASE 0x0CAC +#define EUR_CR_BIF_3D_REQ_BASE_ADDR_MASK 0x0FF00000 +#define EUR_CR_BIF_3D_REQ_BASE_ADDR_SHIFT 20 + +#define EUR_CR_BIF_ZLS_REQ_BASE 0x0CB0 +#define EUR_CR_BIF_ZLS_REQ_BASE_ADDR_MASK 0x0FF00000 +#define EUR_CR_BIF_ZLS_REQ_BASE_ADDR_SHIFT 20 + +#define EUR_CR_2D_BLIT_STATUS 0x0E04 +#define EUR_CR_2D_BLIT_STATUS_COMPLETE_MASK 0x00FFFFFF +#define EUR_CR_2D_BLIT_STATUS_COMPLETE_SHIFT 0 +#define EUR_CR_2D_BLIT_STATUS_BUSY_MASK 0x01000000 +#define EUR_CR_2D_BLIT_STATUS_BUSY_SHIFT 24 + +#define EUR_CR_2D_VIRTUAL_FIFO_0 0x0E10 +#define EUR_CR_2D_VIRTUAL_FIFO_0_ENABLE_MASK 0x00000001 +#define EUR_CR_2D_VIRTUAL_FIFO_0_ENABLE_SHIFT 0 +#define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MASK 0x0000000E +#define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_SHIFT 1 +#define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_DIV_MASK 0x00000FF0 +#define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_DIV_SHIFT 4 +#define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MUL_MASK 0x0000F000 +#define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MUL_SHIFT 12 + +#define EUR_CR_2D_VIRTUAL_FIFO_1 0x0E14 +#define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_ACC_MASK 0x00000FFF +#define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_ACC_SHIFT 0 +#define EUR_CR_2D_VIRTUAL_FIFO_1_MAX_ACC_MASK 0x00FFF000 +#define EUR_CR_2D_VIRTUAL_FIFO_1_MAX_ACC_SHIFT 12 +#define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_METRIC_MASK 0xFF000000 +#define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_METRIC_SHIFT 24 + +#define EUR_CR_USE_CODE_BASE(X) (0x0A0C + (4 * (X))) +#define EUR_CR_USE_CODE_BASE_ADDR_MASK 0x00FFFFFF +#define EUR_CR_USE_CODE_BASE_ADDR_SHIFT 0 +#define EUR_CR_USE_CODE_BASE_DM_MASK 0x03000000 +#define EUR_CR_USE_CODE_BASE_DM_SHIFT 24 +#define EUR_CR_USE_CODE_BASE_SIZE_UINT32 16 +#define EUR_CR_USE_CODE_BASE_NUM_ENTRIES 16 + +#endif diff --git a/drivers/gpu/pvr/sgx_bridge.h b/drivers/gpu/pvr/sgx_bridge.h new file mode 100644 index 00000000000..9b83616b920 --- /dev/null +++ b/drivers/gpu/pvr/sgx_bridge.h @@ -0,0 +1,397 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__SGX_BRIDGE_H__) +#define __SGX_BRIDGE_H__ + +#include "sgxapi_km.h" +#include "sgxinfo.h" +#include "pvr_bridge.h" + +#define PVRSRV_BRIDGE_SGX_CMD_BASE (PVRSRV_BRIDGE_LAST_NON_DEVICE_CMD+1) +#define PVRSRV_BRIDGE_SGX_GETCLIENTINFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+0) +#define PVRSRV_BRIDGE_SGX_RELEASECLIENTINFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+1) +#define PVRSRV_BRIDGE_SGX_GETINTERNALDEVINFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+2) +#define PVRSRV_BRIDGE_SGX_DOKICK \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+3) +#define PVRSRV_BRIDGE_SGX_GETPHYSPAGEADDR \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+4) +#define PVRSRV_BRIDGE_SGX_READREGISTRYDWORD \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+5) +#define PVRSRV_BRIDGE_SGX_SCHEDULECOMMAND \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+6) + +#define PVRSRV_BRIDGE_SGX_2DQUERYBLTSCOMPLETE \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+9) + +#define PVRSRV_BRIDGE_SGX_GETMMUPDADDR \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+10) + +#define PVRSRV_BRIDGE_SGX_SUBMITTRANSFER \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+13) +#define PVRSRV_BRIDGE_SGX_GETMISCINFO \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+14) +#define PVRSRV_BRIDGE_SGXINFO_FOR_SRVINIT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+15) +#define PVRSRV_BRIDGE_SGX_DEVINITPART2 \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+16) + +#define PVRSRV_BRIDGE_SGX_FINDSHAREDPBDESC \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+17) +#define PVRSRV_BRIDGE_SGX_UNREFSHAREDPBDESC \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+18) +#define PVRSRV_BRIDGE_SGX_ADDSHAREDPBDESC \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+19) +#define PVRSRV_BRIDGE_SGX_REGISTER_HW_RENDER_CONTEXT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+20) +#define PVRSRV_BRIDGE_SGX_FLUSH_HW_RENDER_TARGET \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+21) +#define PVRSRV_BRIDGE_SGX_UNREGISTER_HW_RENDER_CONTEXT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+22) +#define PVRSRV_BRIDGE_SGX_REGISTER_HW_TRANSFER_CONTEXT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+26) +#define PVRSRV_BRIDGE_SGX_UNREGISTER_HW_TRANSFER_CONTEXT \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+27) + +#define PVRSRV_BRIDGE_SGX_SCHEDULE_PROCESS_QUEUES \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+28) + +#define PVRSRV_BRIDGE_SGX_READ_DIFF_COUNTERS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+29) +#define PVRSRV_BRIDGE_SGX_READ_HWPERF_CB \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+30) + +#if defined(PDUMP) +#define PVRSRV_BRIDGE_SGX_PDUMP_BUFFER_ARRAY \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+31) +#define PVRSRV_BRIDGE_SGX_PDUMP_3D_SIGNATURE_REGISTERS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+32) +#define PVRSRV_BRIDGE_SGX_PDUMP_COUNTER_REGISTERS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+33) +#define PVRSRV_BRIDGE_SGX_PDUMP_TA_SIGNATURE_REGISTERS \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+34) +#define PVRSRV_BRIDGE_SGX_PDUMP_HWPERFCB \ + PVRSRV_IOWR(PVRSRV_BRIDGE_SGX_CMD_BASE+35) +#endif + +#define PVRSRV_BRIDGE_LAST_SGX_CMD (PVRSRV_BRIDGE_SGX_CMD_BASE+35) + +struct PVRSRV_BRIDGE_IN_GETPHYSPAGEADDR { + u32 ui32BridgeFlags; + void *hDevMemHeap; + struct IMG_DEV_VIRTADDR sDevVAddr; +}; + +struct PVRSRV_BRIDGE_OUT_GETPHYSPAGEADDR { + enum PVRSRV_ERROR eError; + struct IMG_DEV_PHYADDR DevPAddr; + struct IMG_CPU_PHYADDR CpuPAddr; +}; + +struct PVRSRV_BRIDGE_IN_SGX_GETMMU_PDADDR { + u32 ui32BridgeFlags; + void *hDevCookie; + void *hDevMemContext; +}; + +struct PVRSRV_BRIDGE_OUT_SGX_GETMMU_PDADDR { + struct IMG_DEV_PHYADDR sPDDevPAddr; + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_GETCLIENTINFO { + u32 ui32BridgeFlags; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_OUT_GETINTERNALDEVINFO { + struct SGX_INTERNAL_DEVINFO sSGXInternalDevInfo; + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_GETINTERNALDEVINFO { + u32 ui32BridgeFlags; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_OUT_GETCLIENTINFO { + struct SGX_CLIENT_INFO sClientInfo; + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_RELEASECLIENTINFO { + u32 ui32BridgeFlags; + void *hDevCookie; + struct SGX_CLIENT_INFO sClientInfo; +}; + +struct PVRSRV_BRIDGE_IN_ISPBREAKPOLL { + u32 ui32BridgeFlags; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_IN_DOKICK { + u32 ui32BridgeFlags; + void *hDevCookie; + struct SGX_CCB_KICK sCCBKick; +}; + +struct PVRSRV_BRIDGE_IN_SGX_SCHEDULE_PROCESS_QUEUES { + u32 ui32BridgeFlags; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_IN_SUBMITTRANSFER { + u32 ui32BridgeFlags; + void *hDevCookie; + struct PVRSRV_TRANSFER_SGX_KICK sKick; +}; + + +struct PVRSRV_BRIDGE_IN_READREGDWORD { + u32 ui32BridgeFlags; + void *hDevCookie; + char *pszKey; + char *pszValue; +}; + +struct PVRSRV_BRIDGE_OUT_READREGDWORD { + enum PVRSRV_ERROR eError; + u32 ui32Data; +}; + +struct PVRSRV_BRIDGE_IN_SCHEDULECOMMAND { + u32 ui32BridgeFlags; + void *hDevCookie; + enum SGXMKIF_COMMAND_TYPE eCommandType; + struct SGXMKIF_COMMAND *psCommandData; + +}; + +struct PVRSRV_BRIDGE_IN_SGXGETMISCINFO { + u32 ui32BridgeFlags; + void *hDevCookie; + struct SGX_MISC_INFO __user *psMiscInfo; +}; + +struct PVRSRV_BRIDGE_IN_SGXINFO_FOR_SRVINIT { + u32 ui32BridgeFlags; + void *hDevCookie; +}; + +struct PVRSRV_BRIDGE_OUT_SGXINFO_FOR_SRVINIT { + enum PVRSRV_ERROR eError; + struct SGX_BRIDGE_INFO_FOR_SRVINIT sInitInfo; +}; + +struct PVRSRV_BRIDGE_IN_SGXDEVINITPART2 { + u32 ui32BridgeFlags; + void *hDevCookie; + struct SGX_BRIDGE_INIT_INFO sInitInfo; +}; + +enum pvr_sync_wait_seq_type { + _PVR_SYNC_WAIT_BLOCK, + _PVR_SYNC_WAIT_NONBLOCK, + _PVR_SYNC_WAIT_EVENT, + _PVR_SYNC_WAIT_FLIP, + _PVR_SYNC_WAIT_UPDATE, +}; + +struct PVRSRV_BRIDGE_IN_2DQUERYBLTSCOMPLETE { + u32 ui32BridgeFlags; + void *hDevCookie; + void *hKernSyncInfo; + u64 user_data; + enum pvr_sync_wait_seq_type type; +}; + +#define PVRSRV_BRIDGE_SGX_SHAREDPBDESC_MAX_SUBMEMINFOS 10 + +struct PVRSRV_BRIDGE_IN_SGXFINDSHAREDPBDESC { + u32 ui32BridgeFlags; + void *hDevCookie; + IMG_BOOL bLockOnFailure; + u32 ui32TotalPBSize; +}; + +struct PVRSRV_BRIDGE_OUT_SGXFINDSHAREDPBDESC { + void *hKernelMemInfo; + void *hSharedPBDesc; + void *hSharedPBDescKernelMemInfoHandle; + void *hHWPBDescKernelMemInfoHandle; + void *hBlockKernelMemInfoHandle; + void *ahSharedPBDescSubKernelMemInfoHandles + [PVRSRV_BRIDGE_SGX_SHAREDPBDESC_MAX_SUBMEMINFOS]; + u32 ui32SharedPBDescSubKernelMemInfoHandlesCount; + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_SGXUNREFSHAREDPBDESC { + u32 ui32BridgeFlags; + void *hSharedPBDesc; +}; + +struct PVRSRV_BRIDGE_OUT_SGXUNREFSHAREDPBDESC { + enum PVRSRV_ERROR eError; +}; + +struct PVRSRV_BRIDGE_IN_SGXADDSHAREDPBDESC { + u32 ui32BridgeFlags; + void *hDevCookie; + void *hSharedPBDescKernelMemInfo; + void *hHWPBDescKernelMemInfo; + void *hBlockKernelMemInfo; + u32 ui32TotalPBSize; + void * __user *phKernelMemInfoHandles; + u32 ui32KernelMemInfoHandlesCount; +}; + +struct PVRSRV_BRIDGE_OUT_SGXADDSHAREDPBDESC { + enum PVRSRV_ERROR eError; + void *hSharedPBDesc; +}; + +#ifdef PDUMP +struct PVRSRV_BRIDGE_IN_PDUMP_BUFFER_ARRAY { + u32 ui32BridgeFlags; + struct SGX_KICKTA_DUMP_BUFFER __user *psBufferArray; + u32 ui32BufferArrayLength; + IMG_BOOL bDumpPolls; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_3D_SIGNATURE_REGISTERS { + u32 ui32BridgeFlags; + u32 ui32DumpFrameNum; + IMG_BOOL bLastFrame; + u32 *pui32Registers; + u32 ui32NumRegisters; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_COUNTER_REGISTERS { + u32 ui32BridgeFlags; + u32 ui32DumpFrameNum; + IMG_BOOL bLastFrame; + u32 *pui32Registers; + u32 ui32NumRegisters; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_TA_SIGNATURE_REGISTERS { + u32 ui32BridgeFlags; + u32 ui32DumpFrameNum; + u32 ui32TAKickCount; + IMG_BOOL bLastFrame; + u32 *pui32Registers; + u32 ui32NumRegisters; +}; + +struct PVRSRV_BRIDGE_IN_PDUMP_HWPERFCB { + u32 ui32BridgeFlags; + void *hDevCookie; + char szFileName[PVRSRV_PDUMP_MAX_FILENAME_SIZE]; + u32 ui32FileOffset; + u32 ui32PDumpFlags; + +}; + +#endif + +struct PVRSRV_BRIDGE_IN_SGX_REGISTER_HW_RENDER_CONTEXT { + u32 ui32BridgeFlags; + void *hDevCookie; + struct IMG_DEV_VIRTADDR sHWRenderContextDevVAddr; +}; + +struct PVRSRV_BRIDGE_OUT_SGX_REGISTER_HW_RENDER_CONTEXT { + enum PVRSRV_ERROR eError; + void *hHWRenderContext; +}; + +struct PVRSRV_BRIDGE_IN_SGX_UNREGISTER_HW_RENDER_CONTEXT { + u32 ui32BridgeFlags; + void *hDevCookie; + void *hHWRenderContext; +}; + +struct PVRSRV_BRIDGE_IN_SGX_REGISTER_HW_TRANSFER_CONTEXT { + u32 ui32BridgeFlags; + void *hDevCookie; + struct IMG_DEV_VIRTADDR sHWTransferContextDevVAddr; +}; + +struct PVRSRV_BRIDGE_OUT_SGX_REGISTER_HW_TRANSFER_CONTEXT { + enum PVRSRV_ERROR eError; + void *hHWTransferContext; +}; + +struct PVRSRV_BRIDGE_IN_SGX_UNREGISTER_HW_TRANSFER_CONTEXT { + u32 ui32BridgeFlags; + void *hDevCookie; + void *hHWTransferContext; +}; + +struct PVRSRV_BRIDGE_IN_SGX_FLUSH_HW_RENDER_TARGET { + u32 ui32BridgeFlags; + void *hDevCookie; + struct IMG_DEV_VIRTADDR sHWRTDataSetDevVAddr; +}; + +struct PVRSRV_BRIDGE_IN_SGX_READ_DIFF_COUNTERS { + u32 ui32BridgeFlags; + void *hDevCookie; + u32 ui32Reg; + IMG_BOOL bNew; + u32 ui32New; + u32 ui32NewReset; + u32 ui32CountersReg; +}; + +struct PVRSRV_BRIDGE_OUT_SGX_READ_DIFF_COUNTERS { + enum PVRSRV_ERROR eError; + u32 ui32Old; + u32 ui32Time; + IMG_BOOL bActive; + struct PVRSRV_SGXDEV_DIFF_INFO sDiffs; +}; + +struct PVRSRV_BRIDGE_IN_SGX_READ_HWPERF_CB { + u32 ui32BridgeFlags; + void *hDevCookie; + u32 ui32ArraySize; + struct PVRSRV_SGX_HWPERF_CB_ENTRY __user *psHWPerfCBData; +}; + +struct PVRSRV_BRIDGE_OUT_SGX_READ_HWPERF_CB { + enum PVRSRV_ERROR eError; + u32 ui32DataCount; + u32 ui32ClockSpeed; + u32 ui32HostTimeStamp; +}; + +#endif diff --git a/drivers/gpu/pvr/sgx_bridge_km.h b/drivers/gpu/pvr/sgx_bridge_km.h new file mode 100644 index 00000000000..3389b0cd23f --- /dev/null +++ b/drivers/gpu/pvr/sgx_bridge_km.h @@ -0,0 +1,109 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__SGX_BRIDGE_KM_H__) +#define __SGX_BRIDGE_KM_H__ + +#include "sgxapi_km.h" +#include "sgxinfo.h" +#include "sgxinfokm.h" +#include "sgx_bridge.h" +#include "pvr_bridge.h" +#include "perproc.h" + + +enum PVRSRV_ERROR SGXSubmitTransferKM(void *hDevHandle, + struct PVRSRV_TRANSFER_SGX_KICK *psKick); + + +enum PVRSRV_ERROR SGXDoKickKM(void *hDevHandle, struct SGX_CCB_KICK *psCCBKick, + int max_3dstat_val); + +enum PVRSRV_ERROR SGXGetPhysPageAddrKM(void *hDevMemHeap, + struct IMG_DEV_VIRTADDR sDevVAddr, + struct IMG_DEV_PHYADDR *pDevPAddr, + struct IMG_CPU_PHYADDR *pCpuPAddr); + +enum PVRSRV_ERROR SGXGetMMUPDAddrKM(void *hDevCookie, + void *hDevMemContext, struct IMG_DEV_PHYADDR *psPDDevPAddr); + +enum PVRSRV_ERROR SGXGetClientInfoKM(void *hDevCookie, + struct SGX_CLIENT_INFO *psClientInfo); + +enum PVRSRV_ERROR SGXGetMiscInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo, + struct SGX_MISC_INFO *psMiscInfo, + struct PVRSRV_DEVICE_NODE *psDeviceNode); + +enum PVRSRV_ERROR SGXReadDiffCountersKM(void *hDevHandle, u32 ui32Reg, + u32 *pui32Old, IMG_BOOL bNew, u32 ui32New, + u32 ui32NewReset, u32 ui32CountersReg, + u32 *pui32Time, IMG_BOOL *pbActive, + struct PVRSRV_SGXDEV_DIFF_INFO *psDiffs); +enum PVRSRV_ERROR SGXReadHWPerfCBKM(void *hDevHandle, u32 ui32ArraySize, + struct PVRSRV_SGX_HWPERF_CB_ENTRY *psHWPerfCBData, + u32 *pui32DataCount, u32 *pui32ClockSpeed, + u32 *pui32HostTimeStamp); + +enum PVRSRV_ERROR SGX2DQueryBlitsCompleteKM( + struct PVRSRV_SGXDEV_INFO *psDevInfo, + struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, + IMG_BOOL bWaitForComplete); + +enum PVRSRV_ERROR SGXGetInfoForSrvinitKM(void *hDevHandle, + struct SGX_BRIDGE_INFO_FOR_SRVINIT *psInitInfo); + +enum PVRSRV_ERROR DevInitSGXPart2KM(struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevHandle, + struct SGX_BRIDGE_INIT_INFO *psInitInfo); + +enum PVRSRV_ERROR SGXFindSharedPBDescKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevCookie, IMG_BOOL bLockOnFailure, u32 ui32TotalPBSize, + void **phSharedPBDesc, + struct PVRSRV_KERNEL_MEM_INFO **ppsSharedPBDescKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO **ppsHWPBDescKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO **ppsBlockKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO ***pppsSharedPBDescSubKernelMemInfos, + u32 *ui32SharedPBDescSubKernelMemInfosCount); + +enum PVRSRV_ERROR SGXUnrefSharedPBDescKM(void *hSharedPBDesc); + +enum PVRSRV_ERROR SGXAddSharedPBDescKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevCookie, + struct PVRSRV_KERNEL_MEM_INFO *psSharedPBDescKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO *psHWPBDescKernelMemInfo, + struct PVRSRV_KERNEL_MEM_INFO *psBlockKernelMemInfo, + u32 ui32TotalPBSize, void **phSharedPBDesc, + struct PVRSRV_KERNEL_MEM_INFO **psSharedPBDescSubKernelMemInfos, + u32 ui32SharedPBDescSubKernelMemInfosCount); + +enum PVRSRV_ERROR SGXGetInternalDevInfoKM(void *hDevCookie, + struct SGX_INTERNAL_DEVINFO *psSGXInternalDevInfo); + +int sgx_force_reset(void); + +#endif diff --git a/drivers/gpu/pvr/sgx_options.h b/drivers/gpu/pvr/sgx_options.h new file mode 100644 index 00000000000..67402fecd31 --- /dev/null +++ b/drivers/gpu/pvr/sgx_options.h @@ -0,0 +1,178 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if defined(CONFIG_PVR_DEBUG_EXTRA) || defined(INTERNAL_TEST) +#define DEBUG_SET_OFFSET OPTIONS_BIT0 +#define OPTIONS_BIT0 0x1 +#else +#define OPTIONS_BIT0 0x0 +#endif + +#if defined(PDUMP) || defined(INTERNAL_TEST) +#define PDUMP_SET_OFFSET OPTIONS_BIT1 +#define OPTIONS_BIT1 (0x1 << 1) +#else +#define OPTIONS_BIT1 0x0 +#endif + +#if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) || defined(INTERNAL_TEST) +#define PVRSRV_USSE_EDM_STATUS_DEBUG_SET_OFFSET OPTIONS_BIT2 +#define OPTIONS_BIT2 (0x1 << 2) +#else +#define OPTIONS_BIT2 0x0 +#endif + +#define SUPPORT_HW_RECOVERY_SET_OFFSET OPTIONS_BIT3 +#define OPTIONS_BIT3 (0x1 << 3) + +#define PVR_SECURE_HANDLES_SET_OFFSET OPTIONS_BIT4 +#define OPTIONS_BIT4 (0x1 << 4) + +#if defined(INTERNAL_TEST) +#define SGX_BYPASS_SYSTEM_CACHE_SET_OFFSET OPTIONS_BIT5 +#define OPTIONS_BIT5 (0x1 << 5) +#else +#define OPTIONS_BIT5 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_DMS_AGE_ENABLE_SET_OFFSET OPTIONS_BIT6 +#define OPTIONS_BIT6 (0x1 << 6) +#else +#define OPTIONS_BIT6 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_DONT_SWITCH_OFF_FEATURES_SET_OFFSET OPTIONS_BIT7 +#define OPTIONS_BIT7 (0x1 << 7) +#else +#define OPTIONS_BIT7 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_FAST_DPM_INIT_SET_OFFSET OPTIONS_BIT8 +#define OPTIONS_BIT8 (0x1 << 8) +#else +#define OPTIONS_BIT8 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_FEATURE_DCU_SET_OFFSET OPTIONS_BIT9 +#define OPTIONS_BIT9 (0x1 << 9) +#else +#define OPTIONS_BIT9 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_FEATURE_MP_SET_OFFSET OPTIONS_BIT10 +#define OPTIONS_BIT10 (0x1 << 10) +#else +#define OPTIONS_BIT10 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_FEATURE_MULTITHREADED_UKERNEL_SET_OFFSET OPTIONS_BIT11 +#define OPTIONS_BIT11 (0x1 << 11) +#else +#define OPTIONS_BIT11 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_FEATURE_OVERLAPPED_SPM_SET_OFFSET OPTIONS_BIT12 +#define OPTIONS_BIT12 (0x1 << 12) +#else +#define OPTIONS_BIT12 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_FEATURE_RENDER_TARGET_ARRAYS_SET_OFFSET OPTIONS_BIT13 +#define OPTIONS_BIT13 (0x1 << 13) +#else +#define OPTIONS_BIT13 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_FEATURE_SYSTEM_CACHE_SET_OFFSET OPTIONS_BIT14 +#define OPTIONS_BIT14 (0x1 << 14) +#else +#define OPTIONS_BIT14 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define SGX_SUPPORT_HWPROFILING_SET_OFFSET OPTIONS_BIT15 +#define OPTIONS_BIT15 (0x1 << 15) +#else +#define OPTIONS_BIT15 0x0 +#endif + +#define SUPPORT_ACTIVE_POWER_MANAGEMENT_SET_OFFSET OPTIONS_BIT16 +#define OPTIONS_BIT16 (0x1 << 16) + +#if defined(INTERNAL_TEST) +#define SUPPORT_DISPLAYCONTROLLER_TILING_SET_OFFSET OPTIONS_BIT17 +#define OPTIONS_BIT17 (0x1 << 17) +#else +#define OPTIONS_BIT17 0x0 +#endif + +#define SUPPORT_PERCONTEXT_PB_SET_OFFSET OPTIONS_BIT18 +#define OPTIONS_BIT18 (0x1 << 18) + +#define OPTIONS_BIT19 (0x1 << 19) + +#if defined(INTERNAL_TEST) +#define SUPPORT_SGX_MMU_DUMMY_PAGE_SET_OFFSET OPTIONS_BIT20 +#define OPTIONS_BIT20 (0x1 << 20) +#else +#define OPTIONS_BIT20 0x0 +#endif + +#define SUPPORT_SGX_PRIORITY_SCHEDULING_SET_OFFSET OPTIONS_BIT21 +#define OPTIONS_BIT21 (0x1 << 21) + +#if defined(INTERNAL_TEST) +#define USE_SUPPORT_NO_TA3D_OVERLAP_SET_OFFSET OPTIONS_BIT22 +#define OPTIONS_BIT22 (0x1 << 22) +#else +#define OPTIONS_BIT22 0x0 +#endif + +#if defined(INTERNAL_TEST) +#define OPTIONS_HIGHBYTE \ + ((SGX_FEATURE_MP_CORE_COUNT-1) << SGX_FEATURE_MP_CORE_COUNT_SET_OFFSET) +#define SGX_FEATURE_MP_CORE_COUNT_SET_OFFSET 28UL +#define SGX_FEATURE_MP_CORE_COUNT_SET_MASK 0xFF +#else +#define OPTIONS_HIGHBYTE 0x0 +#endif + +#define SGX_BUILD_OPTIONS ( \ + OPTIONS_BIT0 | OPTIONS_BIT1 | OPTIONS_BIT2 | OPTIONS_BIT3 | \ + OPTIONS_BIT4 | OPTIONS_BIT5 | OPTIONS_BIT6 | OPTIONS_BIT7 | \ + OPTIONS_BIT8 | OPTIONS_BIT9 | OPTIONS_BIT10 | OPTIONS_BIT11 | \ + OPTIONS_BIT12 | OPTIONS_BIT13 | OPTIONS_BIT14 | OPTIONS_BIT15 | \ + OPTIONS_BIT16 | OPTIONS_BIT17 | OPTIONS_BIT18 | OPTIONS_BIT19 | \ + OPTIONS_BIT20 | OPTIONS_BIT21 | OPTIONS_BIT22 | OPTIONS_HIGHBYTE) diff --git a/drivers/gpu/pvr/sgxapi_km.h b/drivers/gpu/pvr/sgxapi_km.h new file mode 100644 index 00000000000..8ca76ffbf49 --- /dev/null +++ b/drivers/gpu/pvr/sgxapi_km.h @@ -0,0 +1,238 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __SGXAPI_KM_H__ +#define __SGXAPI_KM_H__ + + +#include "sgxdefs.h" + +#if defined(__KERNEL__) +#include <linux/unistd.h> +#else +#include <unistd.h> +#endif + +#define SGX_UNDEFINED_HEAP_ID (~0LU) +#define SGX_GENERAL_HEAP_ID 0 +#define SGX_TADATA_HEAP_ID 1 +#define SGX_KERNEL_CODE_HEAP_ID 2 +#define SGX_KERNEL_DATA_HEAP_ID 3 +#define SGX_PIXELSHADER_HEAP_ID 4 +#define SGX_VERTEXSHADER_HEAP_ID 5 +#define SGX_PDSPIXEL_CODEDATA_HEAP_ID 6 +#define SGX_PDSVERTEX_CODEDATA_HEAP_ID 7 +#define SGX_SYNCINFO_HEAP_ID 8 +#define SGX_3DPARAMETERS_HEAP_ID 9 +#define SGX_MAX_HEAP_ID 10 + +#define SGX_MAX_TA_STATUS_VALS 32 +#define SGX_MAX_3D_STATUS_VALS_OLD 2 +#define SGX_MAX_3D_STATUS_VALS 4 + +#define SGX_MAX_SRC_SYNCS 4 + +#define PVRSRV_SGX_HWPERF_NUM_COUNTERS 9 + +#define PVRSRV_SGX_HWPERF_INVALID 0x1 + +#define PVRSRV_SGX_HWPERF_TRANSFER 0x2 +#define PVRSRV_SGX_HWPERF_TA 0x3 +#define PVRSRV_SGX_HWPERF_3D 0x4 +#define PVRSRV_SGX_HWPERF_2D 0x5 + +#define PVRSRV_SGX_HWPERF_MK_EVENT 0x101 +#define PVRSRV_SGX_HWPERF_MK_TA 0x102 +#define PVRSRV_SGX_HWPERF_MK_3D 0x103 +#define PVRSRV_SGX_HWPERF_MK_2D 0x104 + +#define PVRSRV_SGX_HWPERF_TYPE_STARTEND_BIT 28 +#define PVRSRV_SGX_HWPERF_TYPE_OP_MASK \ + ((1 << PVRSRV_SGX_HWPERF_TYPE_STARTEND_BIT) - 1) +#define PVRSRV_SGX_HWPERF_TYPE_OP_START \ + (0 << PVRSRV_SGX_HWPERF_TYPE_STARTEND_BIT) +#define PVRSRV_SGX_HWPERF_TYPE_OP_END \ + (1 << PVRSRV_SGX_HWPERF_TYPE_STARTEND_BIT) + +#define PVRSRV_SGX_HWPERF_TYPE_TRANSFER_START \ + (PVRSRV_SGX_HWPERF_TRANSFER | PVRSRV_SGX_HWPERF_TYPE_OP_START) +#define PVRSRV_SGX_HWPERF_TYPE_TRANSFER_END \ + (PVRSRV_SGX_HWPERF_TRANSFER | PVRSRV_SGX_HWPERF_TYPE_OP_END) +#define PVRSRV_SGX_HWPERF_TYPE_TA_START \ + (PVRSRV_SGX_HWPERF_TA | PVRSRV_SGX_HWPERF_TYPE_OP_START) +#define PVRSRV_SGX_HWPERF_TYPE_TA_END \ + (PVRSRV_SGX_HWPERF_TA | PVRSRV_SGX_HWPERF_TYPE_OP_END) +#define PVRSRV_SGX_HWPERF_TYPE_3D_START \ + (PVRSRV_SGX_HWPERF_3D | PVRSRV_SGX_HWPERF_TYPE_OP_START) +#define PVRSRV_SGX_HWPERF_TYPE_3D_END \ + (PVRSRV_SGX_HWPERF_3D | PVRSRV_SGX_HWPERF_TYPE_OP_END) +#define PVRSRV_SGX_HWPERF_TYPE_2D_START \ + (PVRSRV_SGX_HWPERF_2D | PVRSRV_SGX_HWPERF_TYPE_OP_START) +#define PVRSRV_SGX_HWPERF_TYPE_2D_END \ + (PVRSRV_SGX_HWPERF_2D | PVRSRV_SGX_HWPERF_TYPE_OP_END) + +#define PVRSRV_SGX_HWPERF_TYPE_MK_EVENT_START \ + (PVRSRV_SGX_HWPERF_MK_EVENT | PVRSRV_SGX_HWPERF_TYPE_OP_START) +#define PVRSRV_SGX_HWPERF_TYPE_MK_EVENT_END \ + (PVRSRV_SGX_HWPERF_MK_EVENT | PVRSRV_SGX_HWPERF_TYPE_OP_END) +#define PVRSRV_SGX_HWPERF_TYPE_MK_TA_START \ + (PVRSRV_SGX_HWPERF_MK_TA | PVRSRV_SGX_HWPERF_TYPE_OP_START) +#define PVRSRV_SGX_HWPERF_TYPE_MK_TA_END \ + (PVRSRV_SGX_HWPERF_MK_TA | PVRSRV_SGX_HWPERF_TYPE_OP_END) +#define PVRSRV_SGX_HWPERF_TYPE_MK_3D_START \ + (PVRSRV_SGX_HWPERF_MK_3D | PVRSRV_SGX_HWPERF_TYPE_OP_START) +#define PVRSRV_SGX_HWPERF_TYPE_MK_3D_END \ + (PVRSRV_SGX_HWPERF_MK_3D | PVRSRV_SGX_HWPERF_TYPE_OP_END) +#define PVRSRV_SGX_HWPERF_TYPE_MK_2D_START \ + (PVRSRV_SGX_HWPERF_MK_2D | PVRSRV_SGX_HWPERF_TYPE_OP_START) +#define PVRSRV_SGX_HWPERF_TYPE_MK_2D_END \ + (PVRSRV_SGX_HWPERF_MK_2D | PVRSRV_SGX_HWPERF_TYPE_OP_END) + +#define PVRSRV_SGX_HWPERF_OFF 0x0 +#define PVRSRV_SGX_HWPERF_GRAPHICS_ON (1UL << 0) +#define PVRSRV_SGX_HWPERF_MK_EXECUTION_ON (1UL << 1) + +struct PVRSRV_SGX_HWPERF_CB_ENTRY { + u32 ui32FrameNo; + u32 ui32Type; + u32 ui32Ordinal; + u32 ui32Clocksx16; + u32 ui32Counters[PVRSRV_SGX_HWPERF_NUM_COUNTERS]; +}; + +struct PVRSRV_SGX_HWPERF_CBDATA { + u32 ui32FrameNo; + u32 ui32Type; + u32 ui32StartTimeWraps; + u32 ui32StartTime; + u32 ui32EndTimeWraps; + u32 ui32EndTime; + u32 ui32ClockSpeed; + u32 ui32TimeMax; +}; + +struct SGX_MISC_INFO_HWPERF_RETRIEVE_CB { + struct PVRSRV_SGX_HWPERF_CBDATA *psHWPerfData; + u32 ui32ArraySize; + u32 ui32DataCount; + u32 ui32Time; +}; + +struct CTL_STATUS { + struct IMG_DEV_VIRTADDR sStatusDevAddr; + u32 ui32StatusValue; +}; + +enum SGX_MISC_INFO_REQUEST { + SGX_MISC_INFO_REQUEST_CLOCKSPEED = 0, + SGX_MISC_INFO_REQUEST_SGXREV, + SGX_MISC_INFO_REQUEST_DRIVER_SGXREV, + SGX_MISC_INFO_REQUEST_SET_HWPERF_STATUS, + SGX_MISC_INFO_REQUEST_HWPERF_CB_ON, + SGX_MISC_INFO_REQUEST_HWPERF_CB_OFF, + SGX_MISC_INFO_REQUEST_HWPERF_RETRIEVE_CB, + SGX_MISC_INFO_REQUEST_FORCE_I16 = 0x7fff +}; + +struct PVRSRV_SGX_MISCINFO_FEATURES { + u32 ui32CoreRev; + u32 ui32CoreID; + u32 ui32DDKVersion; + u32 ui32DDKBuild; + u32 ui32CoreIdSW; + u32 ui32CoreRevSW; + u32 ui32BuildOptions; +}; + +struct SGX_MISC_INFO { + enum SGX_MISC_INFO_REQUEST eRequest; + + union { + u32 reserved; + struct PVRSRV_SGX_MISCINFO_FEATURES sSGXFeatures; + u32 ui32SGXClockSpeed; + u32 ui32NewHWPerfStatus; + struct SGX_MISC_INFO_HWPERF_RETRIEVE_CB sRetrieveCB; + } uData; +}; + +#define SGX_KICKTA_DUMPBITMAP_MAX_NAME_LENGTH 256 + +struct SGX_KICKTA_DUMPBITMAP { + struct IMG_DEV_VIRTADDR sDevBaseAddr; + u32 ui32Flags; + u32 ui32Width; + u32 ui32Height; + u32 ui32Stride; + u32 ui32PDUMPFormat; + u32 ui32BytesPP; + char pszName[SGX_KICKTA_DUMPBITMAP_MAX_NAME_LENGTH]; +}; + +#define PVRSRV_SGX_PDUMP_CONTEXT_MAX_BITMAP_ARRAY_SIZE 16 + +struct PVRSRV_SGX_PDUMP_CONTEXT { + u32 ui32CacheControl; +}; + +struct SGX_KICKTA_DUMP_ROFF { + void *hKernelMemInfo; + u32 uiAllocIndex; + u32 ui32Offset; + u32 ui32Value; + char *pszName; +}; + +struct SGX_KICKTA_DUMP_BUFFER { + u32 ui32SpaceUsed; + u32 ui32Start; + u32 ui32End; + u32 ui32BufferSize; + u32 ui32BackEndLength; + u32 uiAllocIndex; + void *hKernelMemInfo; + void *pvLinAddr; + char *pszName; +}; + +#ifdef PDUMP +struct SGX_KICKTA_PDUMP { + + struct SGX_KICKTA_DUMPBITMAP *psPDumpBitmapArray; + u32 ui32PDumpBitmapSize; + + struct SGX_KICKTA_DUMP_BUFFER *psBufferArray; + u32 ui32BufferArraySize; + + struct SGX_KICKTA_DUMP_ROFF *psROffArray; + u32 ui32ROffArraySize; +}; +#endif + +#define SGX_MAX_TRANSFER_STATUS_VALS 2 +#define SGX_MAX_TRANSFER_SYNC_OPS 5 + +#endif diff --git a/drivers/gpu/pvr/sgxconfig.h b/drivers/gpu/pvr/sgxconfig.h new file mode 100644 index 00000000000..589e26475e1 --- /dev/null +++ b/drivers/gpu/pvr/sgxconfig.h @@ -0,0 +1,75 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __SGXCONFIG_H__ +#define __SGXCONFIG_H__ + +#define DEV_DEVICE_TYPE PVRSRV_DEVICE_TYPE_SGX +#define DEV_DEVICE_CLASS PVRSRV_DEVICE_CLASS_3D + +#define DEV_MAJOR_VERSION 1 +#define DEV_MINOR_VERSION 0 + +#define SGX_GENERAL_HEAP_BASE 0x01800000 +#define SGX_GENERAL_HEAP_SIZE (0x06C00000-0x00001000) + +#define SGX_3DPARAMETERS_HEAP_BASE 0x08400000 +#define SGX_3DPARAMETERS_HEAP_SIZE (0x04000000-0x00001000) + +#define SGX_TADATA_HEAP_BASE 0x0C400000 +#define SGX_TADATA_HEAP_SIZE (0x01000000-0x00001000) + +#define SGX_SYNCINFO_HEAP_BASE 0x0D400000 +#define SGX_SYNCINFO_HEAP_SIZE (0x00400000-0x00001000) + +#define SGX_PDSPIXEL_CODEDATA_HEAP_BASE 0x0D800000 +#define SGX_PDSPIXEL_CODEDATA_HEAP_SIZE (0x00800000-0x00001000) + +#define SGX_PDSVERTEX_CODEDATA_HEAP_BASE 0x0E000000 +#define SGX_PDSVERTEX_CODEDATA_HEAP_SIZE (0x00800000-0x00001000) + +#define SGX_RESERVED_CODE_HEAP_BASE 0x0E800000 +#define SGX_RESERVED_CODE_HEAP_SIZE (0x00080000-0x00001000) + +#define SGX_KERNEL_CODE_HEAP_BASE 0x0EC00000 +#define SGX_KERNEL_CODE_HEAP_SIZE (0x00080000-0x00001000) + +#define SGX_KERNEL_DATA_HEAP_BASE 0x0F000000 +#define SGX_KERNEL_DATA_HEAP_SIZE (0x00400000-0x00001000) + +#define SGX_PIXELSHADER_HEAP_BASE 0x0F400000 +#define SGX_PIXELSHADER_HEAP_SIZE (0x00500000-0x00001000) + +#define SGX_VERTEXSHADER_HEAP_BASE 0x0FC00000 +#define SGX_VERTEXSHADER_HEAP_SIZE (0x00200000-0x00001000) + +#define SGX_CORE_IDENTIFIED + +#if !defined(SGX_CORE_IDENTIFIED) +#error "sgxconfig.h: ERROR: unspecified SGX Core version" +#endif + +#endif diff --git a/drivers/gpu/pvr/sgxcoretypes.h b/drivers/gpu/pvr/sgxcoretypes.h new file mode 100644 index 00000000000..0eb51461fc9 --- /dev/null +++ b/drivers/gpu/pvr/sgxcoretypes.h @@ -0,0 +1,41 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _SGXCORETYPES_KM_H_ +#define _SGXCORETYPES_KM_H_ + +enum SGX_CORE_ID_TYPE { + SGX_CORE_ID_INVALID = 0, + SGX_CORE_ID_530 = 2, + SGX_CORE_ID_535 = 3, +}; + +struct SGX_CORE_INFO { + enum SGX_CORE_ID_TYPE eID; + u32 uiRev; +}; + +#endif diff --git a/drivers/gpu/pvr/sgxdefs.h b/drivers/gpu/pvr/sgxdefs.h new file mode 100644 index 00000000000..1e0cfec503e --- /dev/null +++ b/drivers/gpu/pvr/sgxdefs.h @@ -0,0 +1,38 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _SGXDEFS_H_ +#define _SGXDEFS_H_ + +#ifndef SGX530 +#error unsupported SGX revision +#endif + +#include "sgx530defs.h" +#include "sgxerrata.h" +#include "sgxfeaturedefs.h" + +#endif diff --git a/drivers/gpu/pvr/sgxerrata.h b/drivers/gpu/pvr/sgxerrata.h new file mode 100644 index 00000000000..1aeaa9abe85 --- /dev/null +++ b/drivers/gpu/pvr/sgxerrata.h @@ -0,0 +1,34 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _SGXERRATA_KM_H_ +#define _SGXERRATA_KM_H_ + +#ifndef SGX530 +#error unsupported SGX version +#endif + +#endif diff --git a/drivers/gpu/pvr/sgxfeaturedefs.h b/drivers/gpu/pvr/sgxfeaturedefs.h new file mode 100644 index 00000000000..b36e6be7227 --- /dev/null +++ b/drivers/gpu/pvr/sgxfeaturedefs.h @@ -0,0 +1,40 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef SGX530 +#error unsupported SGX version +#endif + +#define SGX_CORE_FRIENDLY_NAME "SGX530" +#define SGX_CORE_ID SGX_CORE_ID_530 +#define SGX_FEATURE_ADDRESS_SPACE_SIZE 28 +#define SGX_FEATURE_AUTOCLOCKGATING +#define SGX_FEATURE_MP_CORE_COUNT 1 +#define SUPPORT_SGX_PRIORITY_SCHEDULING + +#include "img_types.h" + +#include "sgxcoretypes.h" diff --git a/drivers/gpu/pvr/sgxinfo.h b/drivers/gpu/pvr/sgxinfo.h new file mode 100644 index 00000000000..11f599f414a --- /dev/null +++ b/drivers/gpu/pvr/sgxinfo.h @@ -0,0 +1,342 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__SGXINFO_H__) +#define __SGXINFO_H__ + +#include "sgxscript.h" + +#include "servicesint.h" + +#include "services.h" +#include "sgxapi_km.h" + +#define SGX_MP_CORE_SELECT(x, i) (x) + +#define SGX_MAX_DEV_DATA 24 +#define SGX_MAX_INIT_MEM_HANDLES 16 + +#define SGX_BIF_DIR_LIST_INDEX_EDM 0 + +struct SGX_BRIDGE_INFO_FOR_SRVINIT { + struct IMG_DEV_PHYADDR sPDDevPAddr; + struct PVRSRV_HEAP_INFO asHeapInfo[PVRSRV_MAX_CLIENT_HEAPS]; +}; + +struct SGX_BRIDGE_INIT_INFO { + void *hKernelCCBMemInfo; + void *hKernelCCBCtlMemInfo; + void *hKernelCCBEventKickerMemInfo; + void *hKernelSGXHostCtlMemInfo; + void *hKernelSGXTA3DCtlMemInfo; + void *hKernelSGXMiscMemInfo; + u32 ui32HostKickAddress; + u32 ui32GetMiscInfoAddress; + void *hKernelHWPerfCBMemInfo; +#if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) + void *hKernelEDMStatusBufferMemInfo; +#endif + + u32 ui32EDMTaskReg0; + u32 ui32EDMTaskReg1; + + u32 ui32ClkGateStatusReg; + u32 ui32ClkGateStatusMask; + + u32 ui32CacheControl; + + u32 asInitDevData[SGX_MAX_DEV_DATA]; + void *asInitMemHandles[SGX_MAX_INIT_MEM_HANDLES]; + + struct SGX_INIT_SCRIPTS sScripts; + +}; + +struct SGXMKIF_COMMAND { + u32 ui32ServiceAddress; + u32 ui32Data[3]; +}; + +struct PVRSRV_SGX_KERNEL_CCB { + struct SGXMKIF_COMMAND asCommands[256]; +}; + +struct PVRSRV_SGX_CCB_CTL { + u32 ui32WriteOffset; + u32 ui32ReadOffset; +}; + +#define SGX_AUXCCBFLAGS_SHARED 0x00000001 + +enum SGXMKIF_COMMAND_TYPE { + SGXMKIF_COMMAND_EDM_KICK = 0, + SGXMKIF_COMMAND_VIDEO_KICK = 1, + SGXMKIF_COMMAND_REQUEST_SGXMISCINFO = 2, + + SGXMKIF_COMMAND_FORCE_I32 = -1, + +}; + +#define PVRSRV_CCBFLAGS_RASTERCMD 0x1 +#define PVRSRV_CCBFLAGS_TRANSFERCMD 0x2 +#define PVRSRV_CCBFLAGS_PROCESS_QUEUESCMD 0x3 +#define PVRSRV_CCBFLAGS_POWERCMD 0x5 + +#define PVRSRV_POWERCMD_POWEROFF 0x1 +#define PVRSRV_POWERCMD_IDLE 0x2 + +#define SGX_BIF_INVALIDATE_PTCACHE 0x1 +#define SGX_BIF_INVALIDATE_PDCACHE 0x2 + +struct SGXMKIF_HWDEVICE_SYNC_LIST { + struct IMG_DEV_VIRTADDR sAccessDevAddr; + u32 ui32NumSyncObjects; + + struct PVRSRV_DEVICE_SYNC_OBJECT asSyncData[1]; +}; + +struct SGX_DEVICE_SYNC_LIST { + struct SGXMKIF_HWDEVICE_SYNC_LIST *psHWDeviceSyncList; + + void *hKernelHWSyncListMemInfo; + struct PVRSRV_CLIENT_MEM_INFO *psHWDeviceSyncListClientMemInfo; + struct PVRSRV_CLIENT_MEM_INFO *psAccessResourceClientMemInfo; + + volatile u32 *pui32Lock; + + struct SGX_DEVICE_SYNC_LIST *psNext; + + u32 ui32NumSyncObjects; + void *ahSyncHandles[1]; +}; + +struct SGX_INTERNEL_STATUS_UPDATE { + struct CTL_STATUS sCtlStatus; + void *hKernelMemInfo; + /* pdump specific - required? */ + u32 ui32LastStatusUpdateDumpVal; +}; + +struct SGX_CCB_KICK { + enum SGXMKIF_COMMAND_TYPE eCommand; + struct SGXMKIF_COMMAND sCommand; + void *hCCBKernelMemInfo; + + u32 ui32NumDstSyncObjects; + void *hKernelHWSyncListMemInfo; + void *sDstSyncHandle; + + u32 ui32NumTAStatusVals; + u32 ui32Num3DStatusVals; + + void *ahTAStatusSyncInfo[SGX_MAX_TA_STATUS_VALS]; + void *ah3DStatusSyncInfo[SGX_MAX_3D_STATUS_VALS]; + + IMG_BOOL bFirstKickOrResume; +#if (defined(NO_HARDWARE) || defined(PDUMP)) + IMG_BOOL bTerminateOrAbort; +#endif + IMG_BOOL bKickRender; + + u32 ui32CCBOffset; + + u32 ui32NumSrcSyncs; + void *ahSrcKernelSyncInfo[SGX_MAX_SRC_SYNCS]; + + IMG_BOOL bTADependency; + void *hTA3DSyncInfo; + + void *hTASyncInfo; + void *h3DSyncInfo; +#if defined(PDUMP) + u32 ui32CCBDumpWOff; +#endif +#if defined(NO_HARDWARE) + u32 ui32WriteOpsPendingVal; +#endif +}; + +#define SGX_KERNEL_USE_CODE_BASE_INDEX 15 + +struct SGXMKIF_HOST_CTL { + + u32 ui32PowerStatus; + u32 ui32uKernelDetectedLockups; + u32 ui32HostDetectedLockups; + u32 ui32HWRecoverySampleRate; + u32 ui32ActivePowManSampleRate; + u32 ui32InterruptFlags; + u32 ui32InterruptClearFlags; + + u32 ui32ResManFlags; + struct IMG_DEV_VIRTADDR sResManCleanupData; + + u32 ui32NumActivePowerEvents; + + u32 ui32HWPerfFlags; + +#if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) + /* !< See SGXMK_STATUS_BUFFER */ + struct IMG_DEV_VIRTADDR sEDMStatusBuffer; +#endif + + /*< to count time wraps in the Timer task */ + u32 ui32TimeWraps; +}; + +struct SGX_CLIENT_INFO { + u32 ui32ProcessID; + void *pvProcess; + struct PVRSRV_MISC_INFO sMiscInfo; + + u32 asDevData[SGX_MAX_DEV_DATA]; + +}; + +struct SGX_INTERNAL_DEVINFO { + u32 ui32Flags; + void *hHostCtlKernelMemInfoHandle; + IMG_BOOL bForcePTOff; +}; + +#define SGXTQ_MAX_STATUS (SGX_MAX_TRANSFER_STATUS_VALS + 2) + +#define SGXMKIF_TQFLAGS_NOSYNCUPDATE 0x00000001 +#define SGXMKIF_TQFLAGS_KEEPPENDING 0x00000002 +#define SGXMKIF_TQFLAGS_TATQ_SYNC 0x00000004 +#define SGXMKIF_TQFLAGS_3DTQ_SYNC 0x00000008 +struct SGXMKIF_CMDTA_SHARED { + u32 ui32NumTAStatusVals; + u32 ui32Num3DStatusVals; + + u32 ui32TATQSyncWriteOpsPendingVal; + struct IMG_DEV_VIRTADDR sTATQSyncWriteOpsCompleteDevVAddr; + u32 ui32TATQSyncReadOpsPendingVal; + struct IMG_DEV_VIRTADDR sTATQSyncReadOpsCompleteDevVAddr; + + u32 ui323DTQSyncWriteOpsPendingVal; + struct IMG_DEV_VIRTADDR s3DTQSyncWriteOpsCompleteDevVAddr; + u32 ui323DTQSyncReadOpsPendingVal; + struct IMG_DEV_VIRTADDR s3DTQSyncReadOpsCompleteDevVAddr; + + u32 ui32NumSrcSyncs; + struct PVRSRV_DEVICE_SYNC_OBJECT asSrcSyncs[SGX_MAX_SRC_SYNCS]; + + struct CTL_STATUS sCtlTAStatusInfo[SGX_MAX_TA_STATUS_VALS]; + /* + * Note that the actual size of sCtl3DStatusInfo changes based + * on the IOCTL ABI version used. + */ + struct CTL_STATUS sCtl3DStatusInfo[SGX_MAX_3D_STATUS_VALS]; + + struct PVRSRV_DEVICE_SYNC_OBJECT sTA3DDependency; + +}; + +struct SGXMKIF_TRANSFERCMD_SHARED { + + u32 ui32SrcReadOpPendingVal; + struct IMG_DEV_VIRTADDR sSrcReadOpsCompleteDevAddr; + + u32 ui32SrcWriteOpPendingVal; + struct IMG_DEV_VIRTADDR sSrcWriteOpsCompleteDevAddr; + + u32 ui32DstReadOpPendingVal; + struct IMG_DEV_VIRTADDR sDstReadOpsCompleteDevAddr; + + u32 ui32DstWriteOpPendingVal; + struct IMG_DEV_VIRTADDR sDstWriteOpsCompleteDevAddr; + + u32 ui32TASyncWriteOpsPendingVal; + struct IMG_DEV_VIRTADDR sTASyncWriteOpsCompleteDevVAddr; + u32 ui32TASyncReadOpsPendingVal; + struct IMG_DEV_VIRTADDR sTASyncReadOpsCompleteDevVAddr; + + u32 ui323DSyncWriteOpsPendingVal; + struct IMG_DEV_VIRTADDR s3DSyncWriteOpsCompleteDevVAddr; + u32 ui323DSyncReadOpsPendingVal; + struct IMG_DEV_VIRTADDR s3DSyncReadOpsCompleteDevVAddr; + + u32 ui32NumStatusVals; + struct CTL_STATUS sCtlStatusInfo[SGXTQ_MAX_STATUS]; +}; + +struct PVRSRV_TRANSFER_SGX_KICK { + void *hCCBMemInfo; + u32 ui32SharedCmdCCBOffset; + + struct IMG_DEV_VIRTADDR sHWTransferContextDevVAddr; + + void *hTASyncInfo; + void *h3DSyncInfo; + + u32 ui32NumSrcSync; + void *ahSrcSyncInfo[SGX_MAX_TRANSFER_SYNC_OPS]; + + u32 ui32NumDstSync; + void *ahDstSyncInfo[SGX_MAX_TRANSFER_SYNC_OPS]; + + u32 ui32Flags; + + u32 ui32PDumpFlags; +#if defined(PDUMP) + u32 ui32CCBDumpWOff; +#endif +}; + +#define PVRSRV_SGX_DIFF_NUM_COUNTERS 9 + +struct PVRSRV_SGXDEV_DIFF_INFO { + u32 aui32Counters[PVRSRV_SGX_DIFF_NUM_COUNTERS]; + u32 ui32Time[2]; + u32 ui32Marker[2]; +}; + +#define SGXMKIF_HWPERF_CB_SIZE 0x100 + +struct SGXMKIF_HWPERF_CB_ENTRY { + u32 ui32FrameNo; + u32 ui32Type; + u32 ui32Ordinal; + u32 ui32TimeWraps; + u32 ui32Time; + u32 ui32Counters[PVRSRV_SGX_HWPERF_NUM_COUNTERS]; +}; + +struct SGXMKIF_HWPERF_CB { + u32 ui32Woff; + u32 ui32Roff; + u32 ui32OrdinalGRAPHICS; + u32 ui32OrdinalMK_EXECUTION; + struct SGXMKIF_HWPERF_CB_ENTRY psHWPerfCBData[SGXMKIF_HWPERF_CB_SIZE]; +}; + +struct PVRSRV_SGX_MISCINFO_INFO { + u32 ui32MiscInfoFlags; + struct PVRSRV_SGX_MISCINFO_FEATURES sSGXFeatures; +}; + +#endif diff --git a/drivers/gpu/pvr/sgxinfokm.h b/drivers/gpu/pvr/sgxinfokm.h new file mode 100644 index 00000000000..6db6bb394e6 --- /dev/null +++ b/drivers/gpu/pvr/sgxinfokm.h @@ -0,0 +1,270 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __SGXINFOKM_H__ +#define __SGXINFOKM_H__ + +#include <linux/workqueue.h> +#include "sgxdefs.h" +#include "device.h" +#include "sysconfig.h" +#include "sgxscript.h" +#include "sgxinfo.h" + + +#define SGX_HOSTPORT_PRESENT 0x00000001UL + +#define PVRSRV_USSE_EDM_POWMAN_IDLE_COMPLETE (1UL << 2) +#define PVRSRV_USSE_EDM_POWMAN_POWEROFF_COMPLETE (1UL << 3) +#define PVRSRV_USSE_EDM_POWMAN_POWEROFF_RESTART_IMMEDIATE (1UL << 4) +#define PVRSRV_USSE_EDM_POWMAN_NO_WORK (1UL << 5) + +#define PVRSRV_USSE_EDM_INTERRUPT_HWR (1UL << 0) +#define PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER (1UL << 1) + +#define PVRSRV_USSE_EDM_RESMAN_CLEANUP_RT_REQUEST 0x01UL +#define PVRSRV_USSE_EDM_RESMAN_CLEANUP_RC_REQUEST 0x02UL +#define PVRSRV_USSE_EDM_RESMAN_CLEANUP_TC_REQUEST 0x04UL +#define PVRSRV_USSE_EDM_RESMAN_CLEANUP_2DC_REQUEST 0x08UL +#define PVRSRV_USSE_EDM_RESMAN_CLEANUP_SHAREDPBDESC 0x10UL +#define PVRSRV_USSE_EDM_RESMAN_CLEANUP_INVALPD 0x20UL +#define PVRSRV_USSE_EDM_RESMAN_CLEANUP_INVALPT 0x40UL +#define PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE 0x80UL + +#define PVRSRV_USSE_MISCINFO_READY 0x1UL + +struct PVRSRV_SGX_CCB_INFO; + +struct PVRSRV_SGXDEV_INFO { + enum PVRSRV_DEVICE_TYPE eDeviceType; + enum PVRSRV_DEVICE_CLASS eDeviceClass; + + u8 ui8VersionMajor; + u8 ui8VersionMinor; + u32 ui32CoreConfig; + u32 ui32CoreFlags; + + void __iomem *pvRegsBaseKM; + + void *hRegMapping; + + struct IMG_SYS_PHYADDR sRegsPhysBase; + + u32 ui32RegSize; + + u32 ui32CoreClockSpeed; + u32 ui32uKernelTimerClock; + + void *psStubPBDescListKM; + + struct IMG_DEV_PHYADDR sKernelPDDevPAddr; + + void *pvDeviceMemoryHeap; + struct PVRSRV_KERNEL_MEM_INFO *psKernelCCBMemInfo; + struct PVRSRV_SGX_KERNEL_CCB *psKernelCCB; + struct PVRSRV_SGX_CCB_INFO *psKernelCCBInfo; + struct PVRSRV_KERNEL_MEM_INFO *psKernelCCBCtlMemInfo; + struct PVRSRV_SGX_CCB_CTL *psKernelCCBCtl; + struct PVRSRV_KERNEL_MEM_INFO *psKernelCCBEventKickerMemInfo; + u32 *pui32KernelCCBEventKicker; + struct PVRSRV_KERNEL_MEM_INFO *psKernelSGXMiscMemInfo; + u32 ui32HostKickAddress; + u32 ui32GetMiscInfoAddress; + u32 ui32KickTACounter; + u32 ui32KickTARenderCounter; + struct PVRSRV_KERNEL_MEM_INFO *psKernelHWPerfCBMemInfo; + struct PVRSRV_SGXDEV_DIFF_INFO sDiffInfo; + u32 ui32HWGroupRequested; + u32 ui32HWReset; +#ifdef PVRSRV_USSE_EDM_STATUS_DEBUG + /*!< Meminfo for EDM status buffer */ + struct PVRSRV_KERNEL_MEM_INFO *psKernelEDMStatusBufferMemInfo; +#endif + + u32 ui32ClientRefCount; + + u32 ui32CacheControl; + + void *pvMMUContextList; + + IMG_BOOL bForcePTOff; + + u32 ui32EDMTaskReg0; + u32 ui32EDMTaskReg1; + + u32 ui32ClkGateStatusReg; + u32 ui32ClkGateStatusMask; + struct SGX_INIT_SCRIPTS sScripts; + + void *hBIFResetPDOSMemHandle; + struct IMG_DEV_PHYADDR sBIFResetPDDevPAddr; + struct IMG_DEV_PHYADDR sBIFResetPTDevPAddr; + struct IMG_DEV_PHYADDR sBIFResetPageDevPAddr; + u32 *pui32BIFResetPD; + u32 *pui32BIFResetPT; + + void *hTimer; + u32 ui32TimeStamp; + u32 ui32NumResets; + + unsigned long long last_idle; + unsigned long long burst_start; + int burst_size; + int burst_cnt; + int power_down_delay; + + struct PVRSRV_KERNEL_MEM_INFO *psKernelSGXHostCtlMemInfo; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl; + + struct PVRSRV_KERNEL_MEM_INFO *psKernelSGXTA3DCtlMemInfo; + + u32 ui32Flags; + +#if defined(PDUMP) + struct PVRSRV_SGX_PDUMP_CONTEXT sPDContext; +#endif + + + u32 asSGXDevData[SGX_MAX_DEV_DATA]; + +}; + +struct SGX_TIMING_INFORMATION { + u32 ui32CoreClockSpeed; + u32 ui32HWRecoveryFreq; + u32 ui32ActivePowManLatencyms; + u32 ui32uKernelFreq; +}; + +struct SGX_DEVICE_MAP { + u32 ui32Flags; + + struct IMG_SYS_PHYADDR sRegsSysPBase; + struct IMG_CPU_PHYADDR sRegsCpuPBase; + void __iomem *pvRegsCpuVBase; + u32 ui32RegsSize; + + struct IMG_SYS_PHYADDR sLocalMemSysPBase; + struct IMG_DEV_PHYADDR sLocalMemDevPBase; + struct IMG_CPU_PHYADDR sLocalMemCpuPBase; + u32 ui32LocalMemSize; + + u32 ui32IRQ; +}; + +struct PVRSRV_STUB_PBDESC; +struct PVRSRV_STUB_PBDESC { + u32 ui32RefCount; + u32 ui32TotalPBSize; + struct PVRSRV_KERNEL_MEM_INFO *psSharedPBDescKernelMemInfo; + struct PVRSRV_KERNEL_MEM_INFO *psHWPBDescKernelMemInfo; + struct PVRSRV_KERNEL_MEM_INFO **ppsSubKernelMemInfos; + u32 ui32SubKernelMemInfosCount; + void *hDevCookie; + struct PVRSRV_KERNEL_MEM_INFO *psBlockKernelMemInfo; + struct PVRSRV_STUB_PBDESC *psNext; +}; + +struct PVRSRV_SGX_CCB_INFO { + struct PVRSRV_KERNEL_MEM_INFO *psCCBMemInfo; + struct PVRSRV_KERNEL_MEM_INFO *psCCBCtlMemInfo; + struct SGXMKIF_COMMAND *psCommands; + u32 *pui32WriteOffset; + volatile u32 *pui32ReadOffset; +#if defined(PDUMP) + u32 ui32CCBDumpWOff; +#endif +}; + +struct timer_work_data { + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct delayed_work work; + struct workqueue_struct *work_queue; + unsigned int interval; + bool armed; +}; + +enum PVRSRV_ERROR SGXRegisterDevice(struct PVRSRV_DEVICE_NODE *psDeviceNode); +enum PVRSRV_ERROR SGXOSTimerEnable(struct timer_work_data *data); +enum PVRSRV_ERROR SGXOSTimerCancel(struct timer_work_data *data); +struct timer_work_data * +SGXOSTimerInit(struct PVRSRV_DEVICE_NODE *psDeviceNode); +void SGXOSTimerDeInit(struct timer_work_data *data); + +void HWRecoveryResetSGX(struct PVRSRV_DEVICE_NODE *psDeviceNode); +void SGXReset(struct PVRSRV_SGXDEV_INFO *psDevInfo, u32 ui32PDUMPFlags); + +enum PVRSRV_ERROR SGXInitialise(struct PVRSRV_SGXDEV_INFO *psDevInfo, + IMG_BOOL bHardwareRecovery); +enum PVRSRV_ERROR SGXDeinitialise(void *hDevCookie); + +void sgx_mark_new_command(struct PVRSRV_DEVICE_NODE *node); +void sgx_mark_power_down(struct PVRSRV_DEVICE_NODE *node); + +void SGXStartTimer(struct PVRSRV_SGXDEV_INFO *psDevInfo, + IMG_BOOL bStartOSTimer); + +enum PVRSRV_ERROR SGXPrePowerStateExt(void *hDevHandle, + enum PVR_POWER_STATE eNewPowerState, + enum PVR_POWER_STATE eCurrentPowerState); + +enum PVRSRV_ERROR SGXPostPowerStateExt(void *hDevHandle, + enum PVR_POWER_STATE eNewPowerState, + enum PVR_POWER_STATE eCurrentPowerState); + +enum PVRSRV_ERROR SGXPreClockSpeedChange(void *hDevHandle, + IMG_BOOL bIdleDevice, + enum PVR_POWER_STATE + eCurrentPowerState); + +enum PVRSRV_ERROR SGXPostClockSpeedChange(void *hDevHandle, + IMG_BOOL bIdleDevice, + enum PVR_POWER_STATE + eCurrentPowerState); + +enum PVRSRV_ERROR SGXDevInitCompatCheck(struct PVRSRV_DEVICE_NODE + *psDeviceNode); + +void SysGetSGXTimingInformation(struct SGX_TIMING_INFORMATION *psSGXTimingInfo); + +#if defined(NO_HARDWARE) +static inline void NoHardwareGenerateEvent(struct PVRSRV_SGXDEV_INFO *psDevInfo, + u32 ui32StatusRegister, + u32 ui32StatusValue, + u32 ui32StatusMask) +{ + u32 ui32RegVal; + + ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, ui32StatusRegister); + + ui32RegVal &= ~ui32StatusMask; + ui32RegVal |= (ui32StatusValue & ui32StatusMask); + + OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32StatusRegister, ui32RegVal); +} +#endif + +#endif diff --git a/drivers/gpu/pvr/sgxinit.c b/drivers/gpu/pvr/sgxinit.c new file mode 100644 index 00000000000..be7fa0f2c00 --- /dev/null +++ b/drivers/gpu/pvr/sgxinit.c @@ -0,0 +1,1663 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <stddef.h> + +#include <linux/workqueue.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/sched.h> + +#include "sgxdefs.h" +#include "sgxmmu.h" +#include "services_headers.h" +#include "buffer_manager.h" +#include "sgxapi_km.h" +#include "sgxinfo.h" +#include "sgxinfokm.h" +#include "sgxconfig.h" +#include "sysconfig.h" +#include "pvr_bridge_km.h" +#include "sgx_bridge_km.h" +#include "resman.h" + +#include "pdump_km.h" +#include "ra.h" +#include "mmu.h" +#include "handle.h" +#include "perproc.h" + +#include "sgxutils.h" +#include "pvrversion.h" +#include "sgx_options.h" + +static IMG_BOOL SGX_ISRHandler(void *pvData); + +static u32 gui32EventStatusServicesByISR; + +static enum PVRSRV_ERROR SGXGetBuildInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo, + struct PVRSRV_DEVICE_NODE *psDeviceNode); + +static void SGXCommandComplete(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + BUG_ON(in_irq()); + + SGXScheduleProcessQueuesKM(psDeviceNode); +} + +static u32 DeinitDevInfo(struct PVRSRV_SGXDEV_INFO *psDevInfo) +{ + if (psDevInfo->psKernelCCBInfo != NULL) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_SGX_CCB_INFO), + psDevInfo->psKernelCCBInfo, NULL); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR InitDevInfo(struct PVRSRV_PER_PROCESS_DATA *psPerProc, + struct PVRSRV_DEVICE_NODE *psDeviceNode, + struct SGX_BRIDGE_INIT_INFO *psInitInfo) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + enum PVRSRV_ERROR eError; + + struct PVRSRV_SGX_CCB_INFO *psKernelCCBInfo = NULL; + + PVR_UNREFERENCED_PARAMETER(psPerProc); + psDevInfo->sScripts = psInitInfo->sScripts; + + psDevInfo->psKernelCCBMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCCBMemInfo; + psDevInfo->psKernelCCB = + (struct PVRSRV_SGX_KERNEL_CCB *)psDevInfo->psKernelCCBMemInfo-> + pvLinAddrKM; + + psDevInfo->psKernelCCBCtlMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCCBCtlMemInfo; + psDevInfo->psKernelCCBCtl = + (struct PVRSRV_SGX_CCB_CTL *)psDevInfo->psKernelCCBCtlMemInfo-> + pvLinAddrKM; + + psDevInfo->psKernelCCBEventKickerMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *) + psInitInfo->hKernelCCBEventKickerMemInfo; + psDevInfo->pui32KernelCCBEventKicker = + (u32 *)psDevInfo->psKernelCCBEventKickerMemInfo->pvLinAddrKM; + + psDevInfo->psKernelSGXHostCtlMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo-> + hKernelSGXHostCtlMemInfo; + psDevInfo->psSGXHostCtl = (struct SGXMKIF_HOST_CTL __force __iomem *) + psDevInfo->psKernelSGXHostCtlMemInfo->pvLinAddrKM; + + psDevInfo->psKernelSGXTA3DCtlMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo-> + hKernelSGXTA3DCtlMemInfo; + + psDevInfo->psKernelSGXMiscMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelSGXMiscMemInfo; + + psDevInfo->psKernelHWPerfCBMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelHWPerfCBMemInfo; +#ifdef PVRSRV_USSE_EDM_STATUS_DEBUG + psDevInfo->psKernelEDMStatusBufferMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo-> + hKernelEDMStatusBufferMemInfo; +#endif + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_SGX_CCB_INFO), + (void **)&psKernelCCBInfo, NULL); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "InitDevInfo: Failed to alloc memory"); + goto failed_allockernelccb; + } + + OSMemSet(psKernelCCBInfo, 0, sizeof(struct PVRSRV_SGX_CCB_INFO)); + psKernelCCBInfo->psCCBMemInfo = psDevInfo->psKernelCCBMemInfo; + psKernelCCBInfo->psCCBCtlMemInfo = psDevInfo->psKernelCCBCtlMemInfo; + psKernelCCBInfo->psCommands = psDevInfo->psKernelCCB->asCommands; + psKernelCCBInfo->pui32WriteOffset = + &psDevInfo->psKernelCCBCtl->ui32WriteOffset; + psKernelCCBInfo->pui32ReadOffset = + &psDevInfo->psKernelCCBCtl->ui32ReadOffset; + psDevInfo->psKernelCCBInfo = psKernelCCBInfo; + + psDevInfo->ui32HostKickAddress = psInitInfo->ui32HostKickAddress; + + psDevInfo->ui32GetMiscInfoAddress = psInitInfo->ui32GetMiscInfoAddress; + + psDevInfo->bForcePTOff = IMG_FALSE; + + psDevInfo->ui32CacheControl = psInitInfo->ui32CacheControl; + + psDevInfo->ui32EDMTaskReg0 = psInitInfo->ui32EDMTaskReg0; + psDevInfo->ui32EDMTaskReg1 = psInitInfo->ui32EDMTaskReg1; + psDevInfo->ui32ClkGateStatusReg = psInitInfo->ui32ClkGateStatusReg; + psDevInfo->ui32ClkGateStatusMask = psInitInfo->ui32ClkGateStatusMask; + + OSMemCopy(&psDevInfo->asSGXDevData, &psInitInfo->asInitDevData, + sizeof(psDevInfo->asSGXDevData)); + + return PVRSRV_OK; + +failed_allockernelccb: + DeinitDevInfo(psDevInfo); + + return eError; +} + +static enum PVRSRV_ERROR SGXRunScript(struct PVRSRV_SGXDEV_INFO *psDevInfo, + union SGX_INIT_COMMAND *psScript, + u32 ui32NumInitCommands) +{ + u32 ui32PC; + union SGX_INIT_COMMAND *psComm; + + for (ui32PC = 0, psComm = psScript; + ui32PC < ui32NumInitCommands; ui32PC++, psComm++) { + switch (psComm->eOp) { + case SGX_INIT_OP_WRITE_HW_REG: + { + OSWriteHWReg(psDevInfo->pvRegsBaseKM, + psComm->sWriteHWReg.ui32Offset, + psComm->sWriteHWReg.ui32Value); + PDUMPREG(psComm->sWriteHWReg.ui32Offset, + psComm->sWriteHWReg.ui32Value); + break; + } +#if defined(PDUMP) + case SGX_INIT_OP_PDUMP_HW_REG: + { + PDUMPREG(psComm->sPDumpHWReg.ui32Offset, + psComm->sPDumpHWReg.ui32Value); + break; + } +#endif + case SGX_INIT_OP_HALT: + { + return PVRSRV_OK; + } + case SGX_INIT_OP_ILLEGAL: + + default: + { + PVR_DPF(PVR_DBG_ERROR, + "SGXRunScript: PC %d: Illegal command: %d", + ui32PC, psComm->eOp); + return PVRSRV_ERROR_GENERIC; + } + } + + } + + return PVRSRV_ERROR_GENERIC; +} + +enum PVRSRV_ERROR SGXInitialise(struct PVRSRV_SGXDEV_INFO *psDevInfo, + IMG_BOOL bHardwareRecovery) +{ + enum PVRSRV_ERROR eError; + + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "SGX initialisation script part 1\n"); + eError = + SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart1, + SGX_MAX_INIT_COMMANDS); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXInitialise: SGXRunScript (part 1) failed (%d)", + eError); + return PVRSRV_ERROR_GENERIC; + } + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "End of SGX initialisation script part 1\n"); + + SGXReset(psDevInfo, PDUMP_FLAGS_CONTINUOUS); + + + + *psDevInfo->pui32KernelCCBEventKicker = 0; +#if defined(PDUMP) + PDUMPMEM(NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0, + sizeof(*psDevInfo->pui32KernelCCBEventKicker), + PDUMP_FLAGS_CONTINUOUS, + MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo)); +#endif + + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "SGX initialisation script part 2\n"); + eError = + SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart2, + SGX_MAX_INIT_COMMANDS); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXInitialise: SGXRunScript (part 2) failed (%d)", + eError); + return PVRSRV_ERROR_GENERIC; + } + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "End of SGX initialisation script part 2\n"); + + SGXStartTimer(psDevInfo, (IMG_BOOL)!bHardwareRecovery); + + if (bHardwareRecovery) { + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; + + if (PollForValueKM(&psSGXHostCtl->ui32InterruptClearFlags, 0, + PVRSRV_USSE_EDM_INTERRUPT_HWR, + MAX_HW_TIME_US / WAIT_TRY_COUNT, 1000) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXInitialise: " + "Wait for uKernel HW Recovery failed"); + PVR_DBG_BREAK; + return PVRSRV_ERROR_RETRY; + } + } + + PVR_ASSERT(psDevInfo->psKernelCCBCtl->ui32ReadOffset == + psDevInfo->psKernelCCBCtl->ui32WriteOffset); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXDeinitialise(void *hDevCookie) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo = (struct PVRSRV_SGXDEV_INFO *) + hDevCookie; + enum PVRSRV_ERROR eError; + + if (psDevInfo->pvRegsBaseKM == NULL) + return PVRSRV_OK; + + eError = SGXRunScript(psDevInfo, psDevInfo->sScripts.asDeinitCommands, + SGX_MAX_DEINIT_COMMANDS); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXDeinitialise: SGXRunScript failed (%d)", eError); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR DevInitSGXPart1(void *pvDeviceNode) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo; + void *hKernelDevMemContext; + struct IMG_DEV_PHYADDR sPDDevPAddr; + u32 i; + struct PVRSRV_DEVICE_NODE *psDeviceNode = (struct PVRSRV_DEVICE_NODE *) + pvDeviceNode; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap = + psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; + enum PVRSRV_ERROR eError; + + PDUMPCOMMENT("SGX Initialisation Part 1"); + + PDUMPCOMMENT("SGX Core Version Information: %s", + SGX_CORE_FRIENDLY_NAME); + PDUMPCOMMENT("SGX Core Revision Information: multi rev support"); + + if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_SGXDEV_INFO), + (void **)&psDevInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "DevInitSGXPart1 : Failed to alloc memory for DevInfo"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psDevInfo, 0, sizeof(struct PVRSRV_SGXDEV_INFO)); + + psDevInfo->eDeviceType = DEV_DEVICE_TYPE; + psDevInfo->eDeviceClass = DEV_DEVICE_CLASS; + + psDeviceNode->pvDevice = (void *) psDevInfo; + + psDevInfo->pvDeviceMemoryHeap = (void *) psDeviceMemoryHeap; + + hKernelDevMemContext = BM_CreateContext(psDeviceNode, &sPDDevPAddr, + NULL, NULL); + + psDevInfo->sKernelPDDevPAddr = sPDDevPAddr; + + for (i = 0; i < psDeviceNode->sDevMemoryInfo.ui32HeapCount; i++) { + void *hDevMemHeap; + + switch (psDeviceMemoryHeap[i].DevMemHeapType) { + case DEVICE_MEMORY_HEAP_KERNEL: + case DEVICE_MEMORY_HEAP_SHARED: + case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: + { + hDevMemHeap = + BM_CreateHeap(hKernelDevMemContext, + &psDeviceMemoryHeap[i]); + + psDeviceMemoryHeap[i].hDevMemHeap = hDevMemHeap; + break; + } + } + } + + eError = MMU_BIFResetPDAlloc(psDevInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "DevInitSGX : Failed to alloc memory for BIF reset"); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXGetInfoForSrvinitKM(void *hDevHandle, + struct SGX_BRIDGE_INFO_FOR_SRVINIT *psInitInfo) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + enum PVRSRV_ERROR eError; + + PDUMPCOMMENT("SGXGetInfoForSrvinit"); + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevHandle; + psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + + psInitInfo->sPDDevPAddr = psDevInfo->sKernelPDDevPAddr; + + eError = + PVRSRVGetDeviceMemHeapsKM(hDevHandle, &psInitInfo->asHeapInfo[0]); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXGetInfoForSrvinit: " + "PVRSRVGetDeviceMemHeapsKM failed (%d)", + eError); + return PVRSRV_ERROR_GENERIC; + } + + return eError; +} + +enum PVRSRV_ERROR DevInitSGXPart2KM(struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevHandle, + struct SGX_BRIDGE_INIT_INFO *psInitInfo) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + enum PVRSRV_ERROR eError; + struct SGX_DEVICE_MAP *psSGXDeviceMap; + enum PVR_POWER_STATE eDefaultPowerState; + u32 l; + + PDUMPCOMMENT("SGX Initialisation Part 2"); + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevHandle; + psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + + eError = InitDevInfo(psPerProc, psDeviceNode, psInitInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM: " + "Failed to load EDM program"); + goto failed_init_dev_info; + } + + + eError = SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX, + (void **) &psSGXDeviceMap); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM: " + "Failed to get device memory map!"); + return PVRSRV_ERROR_INIT_FAILURE; + } + + if (psSGXDeviceMap->pvRegsCpuVBase) { + psDevInfo->pvRegsBaseKM = psSGXDeviceMap->pvRegsCpuVBase; + } else { + psDevInfo->pvRegsBaseKM = + OSMapPhysToLin(psSGXDeviceMap->sRegsCpuPBase, + psSGXDeviceMap->ui32RegsSize, + PVRSRV_HAP_KERNEL_ONLY | PVRSRV_HAP_UNCACHED, + NULL); + if (!psDevInfo->pvRegsBaseKM) { + PVR_DPF(PVR_DBG_ERROR, + "DevInitSGXPart2KM: Failed to map in regs\n"); + return PVRSRV_ERROR_BAD_MAPPING; + } + } + psDevInfo->ui32RegSize = psSGXDeviceMap->ui32RegsSize; + psDevInfo->sRegsPhysBase = psSGXDeviceMap->sRegsSysPBase; + + psDeviceNode->pvISRData = psDeviceNode; + + PVR_ASSERT(psDeviceNode->pfnDeviceISR == SGX_ISRHandler); + + pvr_dev_lock(); + l = readl(&psDevInfo->psSGXHostCtl->ui32PowerStatus); + l |= PVRSRV_USSE_EDM_POWMAN_NO_WORK; + writel(l, &psDevInfo->psSGXHostCtl->ui32PowerStatus); + pvr_dev_unlock(); + eDefaultPowerState = PVRSRV_POWER_STATE_D3; + + eError = PVRSRVRegisterPowerDevice(psDeviceNode->sDevId.ui32DeviceIndex, + SGXPrePowerStateExt, + SGXPostPowerStateExt, + SGXPreClockSpeedChange, + SGXPostClockSpeedChange, + (void *) psDeviceNode, + PVRSRV_POWER_STATE_D3, + eDefaultPowerState); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM: " + "failed to register device with power manager"); + return eError; + } + + OSMemSet(psDevInfo->psKernelCCB, 0, + sizeof(struct PVRSRV_SGX_KERNEL_CCB)); + OSMemSet(psDevInfo->psKernelCCBCtl, 0, + sizeof(struct PVRSRV_SGX_CCB_CTL)); + OSMemSet(psDevInfo->pui32KernelCCBEventKicker, 0, + sizeof(*psDevInfo->pui32KernelCCBEventKicker)); + PDUMPCOMMENT("Initialise Kernel CCB"); + PDUMPMEM(NULL, psDevInfo->psKernelCCBMemInfo, 0, + sizeof(struct PVRSRV_SGX_KERNEL_CCB), PDUMP_FLAGS_CONTINUOUS, + MAKEUNIQUETAG(psDevInfo->psKernelCCBMemInfo)); + PDUMPCOMMENT("Initialise Kernel CCB Control"); + PDUMPMEM(NULL, psDevInfo->psKernelCCBCtlMemInfo, 0, + sizeof(struct PVRSRV_SGX_CCB_CTL), PDUMP_FLAGS_CONTINUOUS, + MAKEUNIQUETAG(psDevInfo->psKernelCCBCtlMemInfo)); + PDUMPCOMMENT("Initialise Kernel CCB Event Kicker"); + PDUMPMEM(NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0, + sizeof(*psDevInfo->pui32KernelCCBEventKicker), + PDUMP_FLAGS_CONTINUOUS, + MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo)); + + psDevInfo->hTimer = SGXOSTimerInit(psDeviceNode); + if (!psDevInfo->hTimer) + PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM : " + "Failed to initialize HW recovery timer"); + + return PVRSRV_OK; + +failed_init_dev_info: + return eError; +} + +static enum PVRSRV_ERROR DevDeInitSGX(void *pvDeviceNode) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode = + (struct PVRSRV_DEVICE_NODE *)pvDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + enum PVRSRV_ERROR eError; + u32 ui32Heap; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + struct SGX_DEVICE_MAP *psSGXDeviceMap; + + if (!psDevInfo) { + PVR_DPF(PVR_DBG_ERROR, "DevDeInitSGX: Null DevInfo"); + return PVRSRV_OK; + } + if (psDevInfo->hTimer) { + SGXOSTimerCancel(psDevInfo->hTimer); + SGXOSTimerDeInit(psDevInfo->hTimer); + psDevInfo->hTimer = NULL; + } + + MMU_BIFResetPDFree(psDevInfo); + + DeinitDevInfo(psDevInfo); + + + psDeviceMemoryHeap = + (struct DEVICE_MEMORY_HEAP_INFO *)psDevInfo->pvDeviceMemoryHeap; + for (ui32Heap = 0; + ui32Heap < psDeviceNode->sDevMemoryInfo.ui32HeapCount; + ui32Heap++) { + switch (psDeviceMemoryHeap[ui32Heap].DevMemHeapType) { + case DEVICE_MEMORY_HEAP_KERNEL: + case DEVICE_MEMORY_HEAP_SHARED: + case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: + { + if (psDeviceMemoryHeap[ui32Heap].hDevMemHeap != + NULL) + BM_DestroyHeap(psDeviceMemoryHeap + [ui32Heap].hDevMemHeap); + break; + } + } + } + + if (!pvr_put_ctx(psDeviceNode->sDevMemoryInfo.pBMKernelContext)) + pr_err("%s: kernel context still in use, can't free it", + __func__); + + eError = PVRSRVRemovePowerDevice( + ((struct PVRSRV_DEVICE_NODE *)pvDeviceNode)-> + sDevId.ui32DeviceIndex); + if (eError != PVRSRV_OK) + return eError; + + eError = SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX, + (void **)&psSGXDeviceMap); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "DevDeInitSGX: Failed to get device memory map!"); + return eError; + } + + if (!psSGXDeviceMap->pvRegsCpuVBase) + if (psDevInfo->pvRegsBaseKM != NULL) + OSUnMapPhysToLin(psDevInfo->pvRegsBaseKM, + psDevInfo->ui32RegSize, + PVRSRV_HAP_KERNEL_ONLY | + PVRSRV_HAP_UNCACHED, + NULL); + + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_SGXDEV_INFO), psDevInfo, NULL); + + psDeviceNode->pvDevice = NULL; + + if (psDeviceMemoryHeap != NULL) + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct DEVICE_MEMORY_HEAP_INFO) * + psDeviceNode->sDevMemoryInfo.ui32HeapCount, + psDeviceMemoryHeap, NULL); + + return PVRSRV_OK; +} + +#ifdef PVRSRV_USSE_EDM_STATUS_DEBUG + +#define SGXMK_TRACE_BUFFER_SIZE 512 + +static void dump_edm(struct PVRSRV_SGXDEV_INFO *psDevInfo) +{ + u32 *trace_buffer = + psDevInfo->psKernelEDMStatusBufferMemInfo->pvLinAddrKM; + u32 last_code, write_offset; + int i; + + last_code = *trace_buffer; + trace_buffer++; + write_offset = *trace_buffer; + + pr_err("Last SGX microkernel status code: 0x%x\n", last_code); + + trace_buffer++; + /* Dump the status values */ + + for (i = 0; i < SGXMK_TRACE_BUFFER_SIZE; i++) { + u32 *buf; + buf = trace_buffer + (((write_offset + i) % + SGXMK_TRACE_BUFFER_SIZE) * 4); + pr_err("(MKT%u) %8.8X %8.8X %8.8X %8.8X\n", i, + buf[2], buf[3], buf[1], buf[0]); + } +} +#else +static void dump_edm(struct PVRSRV_SGXDEV_INFO *psDevInfo) {} +#endif + +static void dump_process_info(struct PVRSRV_DEVICE_NODE *dev) +{ + struct PVRSRV_SGXDEV_INFO *dev_info = dev->pvDevice; + u32 page_dir = readl(dev_info->pvRegsBaseKM + + EUR_CR_BIF_DIR_LIST_BASE0); + struct BM_CONTEXT *bm_ctx; + struct RESMAN_CONTEXT *res_ctx = NULL; + + bm_ctx = bm_find_context(dev->sDevMemoryInfo.pBMContext, page_dir); + if (bm_ctx) + res_ctx = pvr_get_resman_ctx(bm_ctx); + + if (res_ctx) { + struct task_struct *tsk; + struct PVRSRV_PER_PROCESS_DATA *proc; + int pid; + + proc = pvr_get_proc_by_ctx(res_ctx); + pid = proc->ui32PID; + rcu_read_lock(); + tsk = pid_task(find_vpid(pid), PIDTYPE_PID); + pr_err("PID = %d, process name = %s\n", pid, tsk->comm); + rcu_read_unlock(); + } +} + +static void dump_sgx_registers(struct PVRSRV_SGXDEV_INFO *psDevInfo) +{ + pr_err("EVENT_STATUS = 0x%08X\n" + "EVENT_STATUS2 = 0x%08X\n" + "BIF_CTRL = 0x%08X\n" + "BIF_INT_STAT = 0x%08X\n" + "BIF_MEM_REQ_STAT = 0x%08X\n" + "BIF_FAULT = 0x%08X\n" + "CLKGATECTL = 0x%08X\n", + readl(psDevInfo->pvRegsBaseKM + EUR_CR_EVENT_STATUS), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_EVENT_STATUS2), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_CTRL), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_INT_STAT), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_MEM_REQ_STAT), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_FAULT), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_CLKGATECTL)); +} + +/* Should be called with pvr_lock held */ +void HWRecoveryResetSGX(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; + u32 l; + int max_retries = 10; + + BUG_ON(!pvr_is_locked()); + + l = readl(&psSGXHostCtl->ui32InterruptClearFlags); + l |= PVRSRV_USSE_EDM_INTERRUPT_HWR; + writel(l, &psSGXHostCtl->ui32InterruptClearFlags); + + pr_err("%s: SGX Hardware Recovery triggered\n", __func__); + + dump_process_info(psDeviceNode); + dump_sgx_registers(psDevInfo); + dump_edm(psDevInfo); + + PDUMPSUSPEND(); + + do { + eError = SGXInitialise(psDevInfo, IMG_TRUE); + if (eError != PVRSRV_ERROR_RETRY) + break; + } while (max_retries--); + + if (eError != PVRSRV_OK) { + pr_err("%s: recovery failed (%d). Disabling the driver", + __func__, eError); + pvr_disable(); + + PDUMPRESUME(); + + return; + } + + PDUMPRESUME(); + + SGXScheduleProcessQueues(psDeviceNode); + + PVRSRVProcessQueues(IMG_TRUE); +} + +static unsigned long sgx_reset_forced; + +static void SGXOSTimer(struct work_struct *work) +{ + struct timer_work_data *data = container_of(work, + struct timer_work_data, + work.work); + struct PVRSRV_DEVICE_NODE *psDeviceNode = data->psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + static u32 ui32EDMTasks; + static u32 ui32LockupCounter; + static u32 ui32NumResets; + u32 ui32CurrentEDMTasks; + IMG_BOOL bLockup = IMG_FALSE; + IMG_BOOL bPoweredDown; + + pvr_lock(); + + if (!data->armed || pvr_is_disabled()) { + pvr_unlock(); + return; + } + + psDevInfo->ui32TimeStamp++; + +#if defined(NO_HARDWARE) + bPoweredDown = IMG_TRUE; +#else + bPoweredDown = (IMG_BOOL) !SGXIsDevicePowered(psDeviceNode); +#endif + + if (bPoweredDown) { + ui32LockupCounter = 0; + } else { + pvr_dev_lock(); + ui32CurrentEDMTasks = OSReadHWReg(psDevInfo->pvRegsBaseKM, + psDevInfo->ui32EDMTaskReg0); + if (psDevInfo->ui32EDMTaskReg1 != 0) + ui32CurrentEDMTasks ^= + OSReadHWReg(psDevInfo->pvRegsBaseKM, + psDevInfo->ui32EDMTaskReg1); + if ((ui32CurrentEDMTasks == ui32EDMTasks) && + (psDevInfo->ui32NumResets == ui32NumResets)) { + ui32LockupCounter++; + if (ui32LockupCounter == 3) { + ui32LockupCounter = 0; + PVR_DPF(PVR_DBG_ERROR, "SGXOSTimer() " + "detected SGX lockup (0x%x tasks)", + ui32EDMTasks); + + bLockup = IMG_TRUE; + } + } else { + ui32LockupCounter = 0; + ui32EDMTasks = ui32CurrentEDMTasks; + ui32NumResets = psDevInfo->ui32NumResets; + } + pvr_dev_unlock(); + } + + bLockup |= cmpxchg(&sgx_reset_forced, 1, 0); + + if (bLockup) { + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; + u32 l; + + pvr_dev_lock(); + l = readl(&psSGXHostCtl->ui32HostDetectedLockups); + l++; + writel(l, &psSGXHostCtl->ui32HostDetectedLockups); + + HWRecoveryResetSGX(psDeviceNode); + pvr_dev_unlock(); + } + + queue_delayed_work(data->work_queue, &data->work, + msecs_to_jiffies(data->interval)); + + pvr_unlock(); +} + +struct timer_work_data * +SGXOSTimerInit(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + struct timer_work_data *data; + + data = kzalloc(sizeof(struct timer_work_data), GFP_KERNEL); + if (!data) + return NULL; + + data->work_queue = create_workqueue("SGXOSTimer"); + if (!data->work_queue) { + kfree(data); + return NULL; + } + + data->interval = 150; + data->psDeviceNode = psDeviceNode; + INIT_DELAYED_WORK(&data->work, SGXOSTimer); + + return data; +} + +void SGXOSTimerDeInit(struct timer_work_data *data) +{ + data->armed = false; + destroy_workqueue(data->work_queue); + kfree(data); +} + +enum PVRSRV_ERROR SGXOSTimerEnable(struct timer_work_data *data) +{ + if (!data) + return PVRSRV_ERROR_GENERIC; + + if (queue_delayed_work(data->work_queue, &data->work, + msecs_to_jiffies(data->interval))) { + data->armed = true; + return PVRSRV_OK; + } + + return PVRSRV_ERROR_GENERIC; +} + +enum PVRSRV_ERROR SGXOSTimerCancel(struct timer_work_data *data) +{ + if (!data) + return PVRSRV_ERROR_GENERIC; + + data->armed = false; + cancel_delayed_work(&data->work); + + return PVRSRV_OK; +} + +int sgx_force_reset(void) +{ + return !cmpxchg(&sgx_reset_forced, 0, 1); +} + +static IMG_BOOL SGX_ISRHandler(void *pvData) +{ + IMG_BOOL bInterruptProcessed = IMG_FALSE; + + { + u32 ui32EventStatus, ui32EventEnable; + u32 ui32EventClear = 0; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + + if (pvData == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "SGX_ISRHandler: Invalid params\n"); + return bInterruptProcessed; + } + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)pvData; + psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + + ui32EventStatus = + OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS); + ui32EventEnable = OSReadHWReg(psDevInfo->pvRegsBaseKM, + EUR_CR_EVENT_HOST_ENABLE); + + gui32EventStatusServicesByISR = ui32EventStatus; + + ui32EventStatus &= ui32EventEnable; + + if (ui32EventStatus & EUR_CR_EVENT_STATUS_SW_EVENT_MASK) + ui32EventClear |= EUR_CR_EVENT_HOST_CLEAR_SW_EVENT_MASK; + + if (ui32EventClear) { + bInterruptProcessed = IMG_TRUE; + + ui32EventClear |= + EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_MASK; + + OSWriteHWReg(psDevInfo->pvRegsBaseKM, + EUR_CR_EVENT_HOST_CLEAR, ui32EventClear); + } + } + + return bInterruptProcessed; +} + +static void SGX_MISRHandler(void *pvData) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode = + (struct PVRSRV_DEVICE_NODE *)pvData; + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; + u32 l1, l2; + int dev_idx; + enum PVRSRV_ERROR err; + + dev_idx = psDeviceNode->sDevId.ui32DeviceIndex; + + pvr_dev_lock(); + + err = PVRSRVSetDevicePowerStateKM(dev_idx, PVRSRV_POWER_STATE_D0); + BUG_ON(err != PVRSRV_OK); + + l1 = readl(&psSGXHostCtl->ui32InterruptFlags); + l2 = readl(&psSGXHostCtl->ui32InterruptClearFlags); + + if ((l1 & PVRSRV_USSE_EDM_INTERRUPT_HWR) && + !(l2 & PVRSRV_USSE_EDM_INTERRUPT_HWR)) + HWRecoveryResetSGX(psDeviceNode); + + if (psDeviceNode->bReProcessDeviceCommandComplete) + SGXScheduleProcessQueues(psDeviceNode); + + SGXTestActivePowerEvent(psDeviceNode); + + pvr_dev_unlock(); +} + +enum PVRSRV_ERROR SGXRegisterDevice(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + struct DEVICE_MEMORY_INFO *psDevMemoryInfo; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + + psDeviceNode->sDevId.eDeviceType = DEV_DEVICE_TYPE; + psDeviceNode->sDevId.eDeviceClass = DEV_DEVICE_CLASS; + + psDeviceNode->pfnInitDevice = DevInitSGXPart1; + psDeviceNode->pfnDeInitDevice = DevDeInitSGX; + + psDeviceNode->pfnInitDeviceCompatCheck = SGXDevInitCompatCheck; + + psDeviceNode->pfnMMUInitialise = MMU_Initialise; + psDeviceNode->pfnMMUFinalise = MMU_Finalise; + psDeviceNode->pfnMMUInsertHeap = MMU_InsertHeap; + psDeviceNode->pfnMMUCreate = MMU_Create; + psDeviceNode->pfnMMUDelete = MMU_Delete; + psDeviceNode->pfnMMUAlloc = MMU_Alloc; + psDeviceNode->pfnMMUFree = MMU_Free; + psDeviceNode->pfnMMUMapPages = MMU_MapPages; + psDeviceNode->pfnMMUMapShadow = MMU_MapShadow; + psDeviceNode->pfnMMUUnmapPages = MMU_UnmapPages; + psDeviceNode->pfnMMUMapScatter = MMU_MapScatter; + psDeviceNode->pfnMMUGetPhysPageAddr = MMU_GetPhysPageAddr; + psDeviceNode->pfnMMUGetPDDevPAddr = MMU_GetPDDevPAddr; + + psDeviceNode->pfnDeviceISR = SGX_ISRHandler; + psDeviceNode->pfnDeviceMISR = SGX_MISRHandler; + + psDeviceNode->pfnDeviceCommandComplete = SGXCommandComplete; + + psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; + + psDevMemoryInfo->ui32AddressSpaceSizeLog2 = + SGX_FEATURE_ADDRESS_SPACE_SIZE; + + psDevMemoryInfo->ui32Flags = 0; + psDevMemoryInfo->ui32HeapCount = SGX_MAX_HEAP_ID; + psDevMemoryInfo->ui32SyncHeapID = SGX_SYNCINFO_HEAP_ID; + + psDevMemoryInfo->ui32MappingHeapID = SGX_GENERAL_HEAP_ID; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct DEVICE_MEMORY_HEAP_INFO) * + psDevMemoryInfo->ui32HeapCount, + (void **) &psDevMemoryInfo->psDeviceMemoryHeap, + NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXRegisterDevice : " + "Failed to alloc memory for " + "struct DEVICE_MEMORY_HEAP_INFO"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psDevMemoryInfo->psDeviceMemoryHeap, 0, + sizeof(struct DEVICE_MEMORY_HEAP_INFO) * + psDevMemoryInfo->ui32HeapCount); + + psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap; + + psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_GENERAL_HEAP_ID); + psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_GENERAL_HEAP_BASE; + psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].ui32HeapSize = + SGX_GENERAL_HEAP_SIZE; + psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_SINGLE_PROCESS; + psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].pszName = "General"; + psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].pszBSName = "General BS"; + psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_PERCONTEXT; + + psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_TADATA_HEAP_ID); + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_TADATA_HEAP_BASE; + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].ui32HeapSize = + SGX_TADATA_HEAP_SIZE; + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION + | PVRSRV_HAP_MULTI_PROCESS; + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].pszName = "TA Data"; + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].pszBSName = "TA Data BS"; + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_PERCONTEXT; + + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_CODE_HEAP_ID); + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_KERNEL_CODE_HEAP_BASE; + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32HeapSize = + SGX_KERNEL_CODE_HEAP_SIZE; + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_MULTI_PROCESS; + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszName = "Kernel Code"; + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszBSName = + "Kernel Code BS"; + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_SHARED_EXPORTED; + + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_DATA_HEAP_ID); + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_KERNEL_DATA_HEAP_BASE; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32HeapSize = + SGX_KERNEL_DATA_HEAP_SIZE; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_MULTI_PROCESS; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].pszName = "KernelData"; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].pszBSName = "KernelData BS"; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_SHARED_EXPORTED; + + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_PIXELSHADER_HEAP_ID); + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_PIXELSHADER_HEAP_BASE; + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].ui32HeapSize = + SGX_PIXELSHADER_HEAP_SIZE; + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_SINGLE_PROCESS; + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].pszName = "PixelShaderUSSE"; + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].pszBSName = + "PixelShaderUSSE BS"; + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_PERCONTEXT; + + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_VERTEXSHADER_HEAP_ID); + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_VERTEXSHADER_HEAP_BASE; + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].ui32HeapSize = + SGX_VERTEXSHADER_HEAP_SIZE; + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_SINGLE_PROCESS; + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].pszName = + "VertexShaderUSSE"; + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].pszBSName = + "VertexShaderUSSE BS"; + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_PERCONTEXT; + + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_PDSPIXEL_CODEDATA_HEAP_ID); + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_PDSPIXEL_CODEDATA_HEAP_BASE; + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].ui32HeapSize = + SGX_PDSPIXEL_CODEDATA_HEAP_SIZE; + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_SINGLE_PROCESS; + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].pszName = + "PDSPixelCodeData"; + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].pszBSName = + "PDSPixelCodeData BS"; + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_PERCONTEXT; + + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_PDSVERTEX_CODEDATA_HEAP_ID); + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].sDevVAddrBase. + uiAddr = SGX_PDSVERTEX_CODEDATA_HEAP_BASE; + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].ui32HeapSize = + SGX_PDSVERTEX_CODEDATA_HEAP_SIZE; + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_SINGLE_PROCESS; + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].pszName = + "PDSVertexCodeData"; + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].pszBSName = + "PDSVertexCodeData BS"; + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_PERCONTEXT; + + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_SYNCINFO_HEAP_ID); + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_SYNCINFO_HEAP_BASE; + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].ui32HeapSize = + SGX_SYNCINFO_HEAP_SIZE; + + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_MULTI_PROCESS; + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].pszName = "CacheCoherent"; + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].pszBSName = "CacheCoherent BS"; + + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_SHARED_EXPORTED; + + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_3DPARAMETERS_HEAP_ID); + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_3DPARAMETERS_HEAP_BASE; + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].ui32HeapSize = + SGX_3DPARAMETERS_HEAP_SIZE; + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].pszName = "3DParameters"; + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].pszBSName = + "3DParameters BS"; + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].ui32Attribs = + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_SINGLE_PROCESS; + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].DevMemHeapType = + DEVICE_MEMORY_HEAP_PERCONTEXT; + + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXGetClientInfoKM(void *hDevCookie, + struct SGX_CLIENT_INFO *psClientInfo) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *) + ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice; + + psDevInfo->ui32ClientRefCount++; +#ifdef PDUMP + if (psDevInfo->ui32ClientRefCount == 1) + psDevInfo->psKernelCCBInfo->ui32CCBDumpWOff = 0; +#endif + psClientInfo->ui32ProcessID = OSGetCurrentProcessIDKM(); + + OSMemCopy(&psClientInfo->asDevData, &psDevInfo->asSGXDevData, + sizeof(psClientInfo->asDevData)); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXDevInitCompatCheck(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo; + enum PVRSRV_ERROR eError; +#if !defined(NO_HARDWARE) + u32 ui32BuildOptions, ui32BuildOptionsMismatch; + struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; +#endif + + if (psDeviceNode->sDevId.eDeviceType != PVRSRV_DEVICE_TYPE_SGX) { + PVR_DPF(PVR_DBG_ERROR, + "SGXDevInitCompatCheck: Device not of type SGX"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + goto exit; + } + psDevInfo = psDeviceNode->pvDevice; + psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; + +#if !defined(NO_HARDWARE) + + eError = SGXGetBuildInfoKM(psDevInfo, psDeviceNode); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXDevInitCompatCheck: " + "Unable to validate device DDK version"); + goto exit; + } + psSGXFeatures = + &((struct PVRSRV_SGX_MISCINFO_INFO *)(psMemInfo->pvLinAddrKM))-> + sSGXFeatures; + if ((psSGXFeatures->ui32DDKVersion != + ((PVRVERSION_MAJ << 16) | (PVRVERSION_MIN << 8) | + PVRVERSION_BRANCH)) || + (psSGXFeatures->ui32DDKBuild != PVRVERSION_BUILD)) { + PVR_DPF(PVR_DBG_ERROR, "SGXDevInitCompatCheck: " + "Incompatible driver DDK revision (%ld)" + "/device DDK revision (%ld).", + PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild); + eError = PVRSRV_ERROR_DDK_VERSION_MISMATCH; + goto exit; + } else { + PVR_DPF(PVR_DBG_WARNING, "(Success) SGXInit: " + "driver DDK (%ld) and device DDK (%ld) match", + PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild); + } + + ui32BuildOptions = psSGXFeatures->ui32BuildOptions; + if (ui32BuildOptions != (SGX_BUILD_OPTIONS)) { + ui32BuildOptionsMismatch = + ui32BuildOptions ^ (SGX_BUILD_OPTIONS); + if (((SGX_BUILD_OPTIONS) & ui32BuildOptionsMismatch) != 0) + PVR_DPF(PVR_DBG_ERROR, "SGXInit: " + "Mismatch in driver and microkernel build " + "options; extra options present in driver: " + "(0x%lx)", + (SGX_BUILD_OPTIONS) & + ui32BuildOptionsMismatch); + + if ((ui32BuildOptions & ui32BuildOptionsMismatch) != 0) + PVR_DPF(PVR_DBG_ERROR, "SGXInit: " + "Mismatch in driver and microkernel build " + "options; extra options present in " + "microkernel: (0x%lx)", + ui32BuildOptions & ui32BuildOptionsMismatch); + eError = PVRSRV_ERROR_BUILD_MISMATCH; + goto exit; + } else { + PVR_DPF(PVR_DBG_WARNING, "(Success) SGXInit: " + "Driver and microkernel build options match."); + } + +#endif + eError = PVRSRV_OK; +exit: + return eError; +} + +static +enum PVRSRV_ERROR SGXGetBuildInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo, + struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + enum PVRSRV_ERROR eError; + struct SGXMKIF_COMMAND sCommandData; + struct PVRSRV_SGX_MISCINFO_INFO *psSGXMiscInfoInt; + struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; + + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = + psDevInfo->psKernelSGXMiscMemInfo; + + if (!psMemInfo->pvLinAddrKM) { + PVR_DPF(PVR_DBG_ERROR, "SGXGetMiscInfoKM: Invalid address."); + return PVRSRV_ERROR_INVALID_PARAMS; + } + psSGXMiscInfoInt = psMemInfo->pvLinAddrKM; + psSGXMiscInfoInt->ui32MiscInfoFlags &= ~PVRSRV_USSE_MISCINFO_READY; + psSGXFeatures = &psSGXMiscInfoInt->sSGXFeatures; + + OSMemSet(psMemInfo->pvLinAddrKM, 0, + sizeof(struct PVRSRV_SGX_MISCINFO_INFO)); + + sCommandData.ui32Data[1] = psMemInfo->sDevVAddr.uiAddr; + + OSMemSet(psSGXFeatures, 0, sizeof(*psSGXFeatures)); + + mb(); + + eError = SGXScheduleCCBCommandKM(psDeviceNode, + SGXMKIF_COMMAND_REQUEST_SGXMISCINFO, + &sCommandData, KERNEL_ID, 0); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXGetMiscInfoKM: SGXScheduleCCBCommandKM failed."); + return eError; + } + +#if !defined(NO_HARDWARE) + { + IMG_BOOL bTimeout = IMG_TRUE; + + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + if ((psSGXMiscInfoInt-> + ui32MiscInfoFlags & PVRSRV_USSE_MISCINFO_READY) != + 0) { + bTimeout = IMG_FALSE; + break; + } + } + END_LOOP_UNTIL_TIMEOUT(); + + if (bTimeout) + return PVRSRV_ERROR_TIMEOUT; + } +#endif + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXGetMiscInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo, + struct SGX_MISC_INFO *psMiscInfo, + struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + switch (psMiscInfo->eRequest) { + case SGX_MISC_INFO_REQUEST_CLOCKSPEED: + { + psMiscInfo->uData.ui32SGXClockSpeed = + psDevInfo->ui32CoreClockSpeed; + return PVRSRV_OK; + } + + case SGX_MISC_INFO_REQUEST_SGXREV: + { + struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = + psDevInfo->psKernelSGXMiscMemInfo; + + SGXGetBuildInfoKM(psDevInfo, psDeviceNode); + psSGXFeatures = + &((struct PVRSRV_SGX_MISCINFO_INFO *)(psMemInfo-> + pvLinAddrKM))->sSGXFeatures; + + psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; + + PVR_DPF(PVR_DBG_MESSAGE, "SGXGetMiscInfoKM: " + "Core 0x%lx, sw ID 0x%lx, " + "sw Rev 0x%lx\n", + psSGXFeatures->ui32CoreRev, + psSGXFeatures->ui32CoreIdSW, + psSGXFeatures->ui32CoreRevSW); + PVR_DPF(PVR_DBG_MESSAGE, "SGXGetMiscInfoKM: " + "DDK version 0x%lx, DDK build 0x%lx\n", + psSGXFeatures->ui32DDKVersion, + psSGXFeatures->ui32DDKBuild); + + return PVRSRV_OK; + } + + case SGX_MISC_INFO_REQUEST_DRIVER_SGXREV: + { + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = + psDevInfo->psKernelSGXMiscMemInfo; + struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; + + psSGXFeatures = &((struct PVRSRV_SGX_MISCINFO_INFO *)( + psMemInfo->pvLinAddrKM))->sSGXFeatures; + + OSMemSet(psMemInfo->pvLinAddrKM, 0, + sizeof(struct PVRSRV_SGX_MISCINFO_INFO)); + + psSGXFeatures->ui32DDKVersion = + (PVRVERSION_MAJ << 16) | + (PVRVERSION_MIN << 8) | PVRVERSION_BRANCH; + psSGXFeatures->ui32DDKBuild = PVRVERSION_BUILD; + + psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; + return PVRSRV_OK; + } + + case SGX_MISC_INFO_REQUEST_SET_HWPERF_STATUS: + { + struct SGXMKIF_HWPERF_CB *psHWPerfCB = + psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM; + unsigned ui32MatchingFlags; + + if ((psMiscInfo->uData.ui32NewHWPerfStatus & + ~(PVRSRV_SGX_HWPERF_GRAPHICS_ON | + PVRSRV_SGX_HWPERF_MK_EXECUTION_ON)) != 0) { + return PVRSRV_ERROR_INVALID_PARAMS; + } + + pvr_dev_lock(); + ui32MatchingFlags = readl(&psDevInfo-> + psSGXHostCtl->ui32HWPerfFlags); + ui32MatchingFlags &= + psMiscInfo->uData.ui32NewHWPerfStatus; + if ((ui32MatchingFlags & PVRSRV_SGX_HWPERF_GRAPHICS_ON) + == 0UL) { + psHWPerfCB->ui32OrdinalGRAPHICS = 0xffffffff; + } + if ((ui32MatchingFlags & + PVRSRV_SGX_HWPERF_MK_EXECUTION_ON) == 0UL) { + psHWPerfCB->ui32OrdinalMK_EXECUTION = + 0xffffffffUL; + } + + + writel(psMiscInfo->uData.ui32NewHWPerfStatus, + &psDevInfo->psSGXHostCtl->ui32HWPerfFlags); + pvr_dev_unlock(); +#if defined(PDUMP) + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "SGX ukernel HWPerf status %u\n", + readl(&psDevInfo->psSGXHostCtl-> + ui32HWPerfFlags)); + PDUMPMEM(NULL, psDevInfo->psKernelSGXHostCtlMemInfo, + offsetof(struct SGXMKIF_HOST_CTL, + ui32HWPerfFlags), + sizeof(psDevInfo->psSGXHostCtl-> + ui32HWPerfFlags), + PDUMP_FLAGS_CONTINUOUS, + MAKEUNIQUETAG(psDevInfo-> + psKernelSGXHostCtlMemInfo)); +#endif + + return PVRSRV_OK; + } + case SGX_MISC_INFO_REQUEST_HWPERF_CB_ON: + { + + struct SGXMKIF_HWPERF_CB *psHWPerfCB = + psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM; + u32 l; + + psHWPerfCB->ui32OrdinalGRAPHICS = 0xffffffffUL; + + pvr_dev_lock();; + l = readl(&psDevInfo->psSGXHostCtl->ui32HWPerfFlags); + l |= PVRSRV_SGX_HWPERF_GRAPHICS_ON; + writel(l, &psDevInfo->psSGXHostCtl->ui32HWPerfFlags); + pvr_dev_unlock(); + + return PVRSRV_OK; + } + case SGX_MISC_INFO_REQUEST_HWPERF_CB_OFF: + { + pvr_dev_lock(); + writel(0, &psDevInfo->psSGXHostCtl->ui32HWPerfFlags); + pvr_dev_unlock(); + + return PVRSRV_OK; + } + case SGX_MISC_INFO_REQUEST_HWPERF_RETRIEVE_CB: + { + struct SGX_MISC_INFO_HWPERF_RETRIEVE_CB *psRetrieve = + &psMiscInfo->uData.sRetrieveCB; + struct SGXMKIF_HWPERF_CB *psHWPerfCB = + psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM; + unsigned i; + + for (i = 0; + psHWPerfCB->ui32Woff != psHWPerfCB->ui32Roff + && i < psRetrieve->ui32ArraySize; i++) { + struct SGXMKIF_HWPERF_CB_ENTRY *psData = + &psHWPerfCB->psHWPerfCBData[psHWPerfCB-> + ui32Roff]; + + psRetrieve->psHWPerfData[i].ui32FrameNo = + psData->ui32FrameNo; + psRetrieve->psHWPerfData[i].ui32Type = + (psData->ui32Type & + PVRSRV_SGX_HWPERF_TYPE_OP_MASK); + psRetrieve->psHWPerfData[i].ui32StartTime = + psData->ui32Time; + psRetrieve->psHWPerfData[i].ui32StartTimeWraps = + psData->ui32TimeWraps; + psRetrieve->psHWPerfData[i].ui32EndTime = + psData->ui32Time; + psRetrieve->psHWPerfData[i].ui32EndTimeWraps = + psData->ui32TimeWraps; + psRetrieve->psHWPerfData[i].ui32ClockSpeed = + psDevInfo->ui32CoreClockSpeed; + psRetrieve->psHWPerfData[i].ui32TimeMax = + psDevInfo->ui32uKernelTimerClock; + psHWPerfCB->ui32Roff = + (psHWPerfCB->ui32Roff + 1) & + (SGXMKIF_HWPERF_CB_SIZE - 1); + } + psRetrieve->ui32DataCount = i; + psRetrieve->ui32Time = OSClockus(); + return PVRSRV_OK; + } + default: + { + return PVRSRV_ERROR_INVALID_PARAMS; + } + } +} + +enum PVRSRV_ERROR SGXReadDiffCountersKM(void *hDevHandle, u32 ui32Reg, + u32 *pui32Old, IMG_BOOL bNew, u32 ui32New, + u32 ui32NewReset, u32 ui32CountersReg, + u32 *pui32Time, IMG_BOOL *pbActive, + struct PVRSRV_SGXDEV_DIFF_INFO *psDiffs) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_POWER_DEV *psPowerDevice; + IMG_BOOL bPowered = IMG_FALSE; + struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + + if (bNew) + psDevInfo->ui32HWGroupRequested = ui32New; + psDevInfo->ui32HWReset |= ui32NewReset; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return PVRSRV_ERROR_GENERIC; + + psPowerDevice = psSysData->psPowerDeviceList; + while (psPowerDevice) { + if (psPowerDevice->ui32DeviceIndex == + psDeviceNode->sDevId.ui32DeviceIndex) { + bPowered = + (IMG_BOOL)(psPowerDevice->eCurrentPowerState == + PVRSRV_POWER_STATE_D0); + break; + } + + psPowerDevice = psPowerDevice->psNext; + } + + *pbActive = bPowered; + + pvr_dev_lock(); + + { + struct PVRSRV_SGXDEV_DIFF_INFO sNew, + *psPrev = &psDevInfo->sDiffInfo; + u32 i; + + sNew.ui32Time[0] = OSClockus(); + *pui32Time = sNew.ui32Time[0]; + if (sNew.ui32Time[0] != psPrev->ui32Time[0] && bPowered) { + + *pui32Old = + OSReadHWReg(psDevInfo->pvRegsBaseKM, ui32Reg); + + for (i = 0; i < PVRSRV_SGX_DIFF_NUM_COUNTERS; ++i) { + sNew.aui32Counters[i] = + OSReadHWReg(psDevInfo->pvRegsBaseKM, + ui32CountersReg + (i * 4)); + } + + if (psDevInfo->ui32HWGroupRequested != *pui32Old) { + if (psDevInfo->ui32HWReset != 0) { + OSWriteHWReg(psDevInfo->pvRegsBaseKM, + ui32Reg, + psDevInfo-> + ui32HWGroupRequested | + psDevInfo->ui32HWReset); + psDevInfo->ui32HWReset = 0; + } + OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Reg, + psDevInfo->ui32HWGroupRequested); + } + + sNew.ui32Marker[0] = psDevInfo->ui32KickTACounter; + sNew.ui32Marker[1] = psDevInfo->ui32KickTARenderCounter; + + sNew.ui32Time[1] = readl( + &psDevInfo->psSGXHostCtl->ui32TimeWraps); + + for (i = 0; i < PVRSRV_SGX_DIFF_NUM_COUNTERS; ++i) { + psDiffs->aui32Counters[i] = + sNew.aui32Counters[i] - + psPrev->aui32Counters[i]; + } + + psDiffs->ui32Marker[0] = + sNew.ui32Marker[0] - psPrev->ui32Marker[0]; + psDiffs->ui32Marker[1] = + sNew.ui32Marker[1] - psPrev->ui32Marker[1]; + + psDiffs->ui32Time[0] = + sNew.ui32Time[0] - psPrev->ui32Time[0]; + psDiffs->ui32Time[1] = + sNew.ui32Time[1] - psPrev->ui32Time[1]; + + *psPrev = sNew; + } else { + for (i = 0; i < PVRSRV_SGX_DIFF_NUM_COUNTERS; ++i) + psDiffs->aui32Counters[i] = 0; + + psDiffs->ui32Marker[0] = 0; + psDiffs->ui32Marker[1] = 0; + + psDiffs->ui32Time[0] = 0; + psDiffs->ui32Time[1] = 0; + } + } + + SGXTestActivePowerEvent(psDeviceNode); + + pvr_dev_unlock(); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXReadHWPerfCBKM(void *hDevHandle, u32 ui32ArraySize, + struct PVRSRV_SGX_HWPERF_CB_ENTRY *psClientHWPerfEntry, + u32 *pui32DataCount, u32 *pui32ClockSpeed, + u32 *pui32HostTimeStamp) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + struct SGXMKIF_HWPERF_CB *psHWPerfCB = + psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM; + unsigned i; + + for (i = 0; + psHWPerfCB->ui32Woff != psHWPerfCB->ui32Roff && i < ui32ArraySize; + i++) { + struct SGXMKIF_HWPERF_CB_ENTRY *psMKPerfEntry = + &psHWPerfCB->psHWPerfCBData[psHWPerfCB->ui32Roff]; + + psClientHWPerfEntry[i].ui32FrameNo = psMKPerfEntry->ui32FrameNo; + psClientHWPerfEntry[i].ui32Type = psMKPerfEntry->ui32Type; + psClientHWPerfEntry[i].ui32Ordinal = psMKPerfEntry->ui32Ordinal; + psClientHWPerfEntry[i].ui32Clocksx16 = + SGXConvertTimeStamp(psDevInfo, psMKPerfEntry->ui32TimeWraps, + psMKPerfEntry->ui32Time); + OSMemCopy(&psClientHWPerfEntry[i].ui32Counters[0], + &psMKPerfEntry->ui32Counters[0], + sizeof(psMKPerfEntry->ui32Counters)); + + psHWPerfCB->ui32Roff = + (psHWPerfCB->ui32Roff + 1) & (SGXMKIF_HWPERF_CB_SIZE - 1); + } + + *pui32DataCount = i; + *pui32ClockSpeed = psDevInfo->ui32CoreClockSpeed; + *pui32HostTimeStamp = OSClockus(); + + return eError; +} diff --git a/drivers/gpu/pvr/sgxkick.c b/drivers/gpu/pvr/sgxkick.c new file mode 100644 index 00000000000..045de0fc764 --- /dev/null +++ b/drivers/gpu/pvr/sgxkick.c @@ -0,0 +1,521 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <stddef.h> +#include "services_headers.h" +#include "sgxinfo.h" +#include "sgxinfokm.h" +#if defined(PDUMP) +#include "sgxapi_km.h" +#include "pdump_km.h" +#endif +#include "sgx_bridge_km.h" +#include "osfunc.h" +#include "pvr_debug.h" +#include "sgxutils.h" + +enum PVRSRV_ERROR SGXDoKickKM(void *hDevHandle, struct SGX_CCB_KICK *psCCBKick, + int max_3dstat_vals) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo; + struct PVRSRV_KERNEL_MEM_INFO *psCCBMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psCCBKick->hCCBKernelMemInfo; + struct SGXMKIF_CMDTA_SHARED *psTACmd; + u32 i; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevHandle; + psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + + if (psCCBKick->bKickRender) + ++psDevInfo->ui32KickTARenderCounter; + ++psDevInfo->ui32KickTACounter; + + if (!CCB_OFFSET_IS_VALID + (struct SGXMKIF_CMDTA_SHARED, psCCBMemInfo, psCCBKick, + ui32CCBOffset)) { + PVR_DPF(PVR_DBG_ERROR, "SGXDoKickKM: Invalid CCB offset"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + psTACmd = + CCB_DATA_FROM_OFFSET(struct SGXMKIF_CMDTA_SHARED, psCCBMemInfo, + psCCBKick, ui32CCBOffset); + + if (psCCBKick->hTA3DSyncInfo) { + struct PVRSRV_DEVICE_SYNC_OBJECT *ta3d_dep; + + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick->hTA3DSyncInfo; + + ta3d_dep = &psTACmd->sTA3DDependency; + /* + * Ugly hack to account for the two possible sizes of + * struct SGXMKIF_CMDTA_SHARED which is based on the + * corresponding IOCTL ABI version used. + */ + if (max_3dstat_vals != SGX_MAX_3D_STATUS_VALS) + ta3d_dep = (struct PVRSRV_DEVICE_SYNC_OBJECT *) + ((u8 *)ta3d_dep - sizeof(struct CTL_STATUS) * + (SGX_MAX_3D_STATUS_VALS - max_3dstat_vals)); + + ta3d_dep->sWriteOpsCompleteDevVAddr = + psSyncInfo->sWriteOpsCompleteDevVAddr; + + ta3d_dep->ui32WriteOpsPendingVal = + psSyncInfo->psSyncData->ui32WriteOpsPending; + + if (psCCBKick->bTADependency) + psSyncInfo->psSyncData->ui32WriteOpsPending++; + } + + if (psCCBKick->hTASyncInfo != NULL) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + psCCBKick->hTASyncInfo; + + psTACmd->sTATQSyncReadOpsCompleteDevVAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + psTACmd->sTATQSyncWriteOpsCompleteDevVAddr = + psSyncInfo->sWriteOpsCompleteDevVAddr; + + psTACmd->ui32TATQSyncReadOpsPendingVal = + psSyncInfo->psSyncData->ui32ReadOpsPending++; + psTACmd->ui32TATQSyncWriteOpsPendingVal = + psSyncInfo->psSyncData->ui32WriteOpsPending; + } + + if (psCCBKick->h3DSyncInfo != NULL) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + psCCBKick->h3DSyncInfo; + + psTACmd->s3DTQSyncReadOpsCompleteDevVAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + psTACmd->s3DTQSyncWriteOpsCompleteDevVAddr = + psSyncInfo->sWriteOpsCompleteDevVAddr; + + psTACmd->ui323DTQSyncReadOpsPendingVal = + psSyncInfo->psSyncData->ui32ReadOpsPending++; + psTACmd->ui323DTQSyncWriteOpsPendingVal = + psSyncInfo->psSyncData->ui32WriteOpsPending; + } + + psTACmd->ui32NumTAStatusVals = psCCBKick->ui32NumTAStatusVals; + if (psCCBKick->ui32NumTAStatusVals != 0) { + for (i = 0; i < psCCBKick->ui32NumTAStatusVals; i++) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + psCCBKick->ahTAStatusSyncInfo[i]; + + psTACmd->sCtlTAStatusInfo[i].sStatusDevAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + + psTACmd->sCtlTAStatusInfo[i].ui32StatusValue = + psSyncInfo->psSyncData->ui32ReadOpsPending; + } + } + + psTACmd->ui32Num3DStatusVals = psCCBKick->ui32Num3DStatusVals; + if (psCCBKick->ui32Num3DStatusVals != 0) { + for (i = 0; i < psCCBKick->ui32Num3DStatusVals; i++) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + ah3DStatusSyncInfo[i]; + + psTACmd->sCtl3DStatusInfo[i].sStatusDevAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + + psTACmd->sCtl3DStatusInfo[i].ui32StatusValue = + psSyncInfo->psSyncData->ui32ReadOpsPending; + } + } + + psTACmd->ui32NumSrcSyncs = psCCBKick->ui32NumSrcSyncs; + for (i = 0; i < psCCBKick->ui32NumSrcSyncs; i++) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + ahSrcKernelSyncInfo[i]; + + psTACmd->asSrcSyncs[i].sWriteOpsCompleteDevVAddr = + psSyncInfo->sWriteOpsCompleteDevVAddr; + psTACmd->asSrcSyncs[i].sReadOpsCompleteDevVAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + + psTACmd->asSrcSyncs[i].ui32ReadOpsPendingVal = + psSyncInfo->psSyncData->ui32ReadOpsPending++; + + psTACmd->asSrcSyncs[i].ui32WriteOpsPendingVal = + psSyncInfo->psSyncData->ui32WriteOpsPending; + + } + + if (psCCBKick->bFirstKickOrResume && + psCCBKick->ui32NumDstSyncObjects > 0) { + struct PVRSRV_KERNEL_MEM_INFO *psHWDstSyncListMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psCCBKick-> + hKernelHWSyncListMemInfo; + struct SGXMKIF_HWDEVICE_SYNC_LIST *psHWDeviceSyncList = + psHWDstSyncListMemInfo->pvLinAddrKM; + u32 ui32NumDstSyncs = psCCBKick->ui32NumDstSyncObjects; + + PVR_ASSERT(((struct PVRSRV_KERNEL_MEM_INFO *)psCCBKick-> + hKernelHWSyncListMemInfo)->ui32AllocSize >= + (sizeof(struct SGXMKIF_HWDEVICE_SYNC_LIST) + + (sizeof(struct PVRSRV_DEVICE_SYNC_OBJECT) * + ui32NumDstSyncs))); + + psHWDeviceSyncList->ui32NumSyncObjects = ui32NumDstSyncs; +#if defined(PDUMP) + if (PDumpIsCaptureFrameKM()) { + PDUMPCOMMENT("HWDeviceSyncList for TACmd\r\n"); + PDUMPMEM(NULL, + psHWDstSyncListMemInfo, 0, + sizeof(struct SGXMKIF_HWDEVICE_SYNC_LIST), + 0, MAKEUNIQUETAG(psHWDstSyncListMemInfo)); + } +#endif + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + sDstSyncHandle; + i = 0; + if (psSyncInfo) { + psHWDeviceSyncList->asSyncData[i]. + sWriteOpsCompleteDevVAddr = + psSyncInfo->sWriteOpsCompleteDevVAddr; + + psHWDeviceSyncList->asSyncData[i]. + sReadOpsCompleteDevVAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + + psHWDeviceSyncList->asSyncData[i]. + ui32ReadOpsPendingVal = + psSyncInfo->psSyncData->ui32ReadOpsPending; + + psHWDeviceSyncList->asSyncData[i]. + ui32WriteOpsPendingVal = + psSyncInfo->psSyncData-> + ui32WriteOpsPending++; + +#if defined(PDUMP) + if (PDumpIsCaptureFrameKM()) { + u32 ui32ModifiedValue; + u32 ui32SyncOffset = offsetof( + struct SGXMKIF_HWDEVICE_SYNC_LIST, + asSyncData) + (i * + sizeof( + struct PVRSRV_DEVICE_SYNC_OBJECT)); + u32 ui32WOpsOffset = ui32SyncOffset + + offsetof( + struct PVRSRV_DEVICE_SYNC_OBJECT, + ui32WriteOpsPendingVal); + u32 ui32ROpsOffset = ui32SyncOffset + + offsetof( + struct PVRSRV_DEVICE_SYNC_OBJECT, + ui32ReadOpsPendingVal); + + PDUMPCOMMENT("HWDeviceSyncObject for RT: " + "%i\r\n", i); + + PDUMPMEM(NULL, psHWDstSyncListMemInfo, + ui32SyncOffset, sizeof( + struct PVRSRV_DEVICE_SYNC_OBJECT), + 0, MAKEUNIQUETAG( + psHWDstSyncListMemInfo)); + + if ((psSyncInfo->psSyncData-> + ui32LastOpDumpVal == 0) && + (psSyncInfo->psSyncData-> + ui32LastReadOpDumpVal == 0)) { + + PDUMPCOMMENT("Init RT ROpsComplete\r\n", + i); + PDUMPMEM(&psSyncInfo->psSyncData-> + ui32LastReadOpDumpVal, + psSyncInfo->psSyncDataMemInfoKM, + offsetof(struct + PVRSRV_SYNC_DATA, + ui32ReadOpsComplete), + sizeof(psSyncInfo->psSyncData-> + ui32ReadOpsComplete), + 0, + MAKEUNIQUETAG(psSyncInfo-> + psSyncDataMemInfoKM)); + + PDUMPCOMMENT("Init RT WOpsComplete\r\n"); + PDUMPMEM(&psSyncInfo->psSyncData-> + ui32LastOpDumpVal, + psSyncInfo->psSyncDataMemInfoKM, + offsetof(struct PVRSRV_SYNC_DATA, + ui32WriteOpsComplete), + sizeof(psSyncInfo->psSyncData-> + ui32WriteOpsComplete), + 0, MAKEUNIQUETAG(psSyncInfo-> + psSyncDataMemInfoKM)); + } + + psSyncInfo->psSyncData->ui32LastOpDumpVal++; + + ui32ModifiedValue = psSyncInfo->psSyncData-> + ui32LastOpDumpVal - 1; + + PDUMPCOMMENT("Modify RT %d WOpPendingVal " + "in HWDevSyncList\r\n", i); + + PDUMPMEM(&ui32ModifiedValue, + psHWDstSyncListMemInfo, ui32WOpsOffset, + sizeof(u32), 0, + MAKEUNIQUETAG(psHWDstSyncListMemInfo)); + + PDUMPCOMMENT("Modify RT %d ROpsPendingVal " + "in HWDevSyncList\r\n", i); + + PDUMPMEM(&psSyncInfo->psSyncData-> + ui32LastReadOpDumpVal, + psHWDstSyncListMemInfo, + ui32ROpsOffset, sizeof(u32), 0, + MAKEUNIQUETAG(psHWDstSyncListMemInfo)); + } +#endif + } else { + psHWDeviceSyncList->asSyncData[i]. + sWriteOpsCompleteDevVAddr.uiAddr = 0; + psHWDeviceSyncList->asSyncData[i]. + sReadOpsCompleteDevVAddr.uiAddr = 0; + + psHWDeviceSyncList->asSyncData[i]. + ui32ReadOpsPendingVal = 0; + psHWDeviceSyncList->asSyncData[i]. + ui32WriteOpsPendingVal = 0; + } + } +#if defined(PDUMP) + if (PDumpIsCaptureFrameKM()) { + PDUMPCOMMENT("Shared part of TA command\r\n"); + + PDUMPMEM(psTACmd, psCCBMemInfo, psCCBKick->ui32CCBDumpWOff, + sizeof(struct SGXMKIF_CMDTA_SHARED), 0, + MAKEUNIQUETAG(psCCBMemInfo)); + + for (i = 0; i < psCCBKick->ui32NumSrcSyncs; i++) { + u32 ui32ModifiedValue; + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + ahSrcKernelSyncInfo[i]; + + if ((psSyncInfo->psSyncData->ui32LastOpDumpVal == 0) && + (psSyncInfo->psSyncData->ui32LastReadOpDumpVal == + 0)) { + PDUMPCOMMENT("Init RT ROpsComplete\r\n", i); + PDUMPMEM(&psSyncInfo->psSyncData-> + ui32LastReadOpDumpVal, + psSyncInfo->psSyncDataMemInfoKM, + offsetof(struct PVRSRV_SYNC_DATA, + ui32ReadOpsComplete), + sizeof(psSyncInfo->psSyncData-> + ui32ReadOpsComplete), 0, + MAKEUNIQUETAG(psSyncInfo-> + psSyncDataMemInfoKM)); + PDUMPCOMMENT("Init RT WOpsComplete\r\n"); + PDUMPMEM(&psSyncInfo->psSyncData-> + ui32LastOpDumpVal, + psSyncInfo->psSyncDataMemInfoKM, + offsetof(struct PVRSRV_SYNC_DATA, + ui32WriteOpsComplete), + sizeof(psSyncInfo->psSyncData-> + ui32WriteOpsComplete), 0, + MAKEUNIQUETAG(psSyncInfo-> + psSyncDataMemInfoKM)); + } + + psSyncInfo->psSyncData->ui32LastReadOpDumpVal++; + + ui32ModifiedValue = + psSyncInfo->psSyncData->ui32LastReadOpDumpVal - 1; + + PDUMPCOMMENT("Modify SrcSync %d ROpsPendingVal\r\n", i); + + PDUMPMEM(&ui32ModifiedValue, + psCCBMemInfo, + psCCBKick->ui32CCBDumpWOff + + offsetof(struct SGXMKIF_CMDTA_SHARED, + asSrcSyncs) + + (i * + sizeof(struct PVRSRV_DEVICE_SYNC_OBJECT)) + + offsetof(struct PVRSRV_DEVICE_SYNC_OBJECT, + ui32ReadOpsPendingVal), sizeof(u32), + 0, MAKEUNIQUETAG(psCCBMemInfo)); + + PDUMPCOMMENT("Modify SrcSync %d WOpPendingVal\r\n", i); + + PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, + psCCBMemInfo, + psCCBKick->ui32CCBDumpWOff + + offsetof(struct SGXMKIF_CMDTA_SHARED, + asSrcSyncs) + + (i * + sizeof(struct PVRSRV_DEVICE_SYNC_OBJECT)) + + offsetof(struct PVRSRV_DEVICE_SYNC_OBJECT, + ui32WriteOpsPendingVal), sizeof(u32), + 0, MAKEUNIQUETAG(psCCBMemInfo)); + + } + + for (i = 0; i < psCCBKick->ui32NumTAStatusVals; i++) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + ahTAStatusSyncInfo[i]; + PDUMPCOMMENT("Modify TA status value in TA cmd\r\n"); + PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, + psCCBMemInfo, + psCCBKick->ui32CCBDumpWOff + + offsetof(struct SGXMKIF_CMDTA_SHARED, + sCtlTAStatusInfo[i].ui32StatusValue), + sizeof(u32), 0, MAKEUNIQUETAG(psCCBMemInfo)); + } + + for (i = 0; i < psCCBKick->ui32Num3DStatusVals; i++) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + psCCBKick->ah3DStatusSyncInfo[i]; + + PDUMPCOMMENT("Modify 3D status value in TA cmd\r\n"); + + PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, + psCCBMemInfo, + psCCBKick->ui32CCBDumpWOff + + offsetof(struct SGXMKIF_CMDTA_SHARED, + sCtl3DStatusInfo[i].ui32StatusValue), + sizeof(u32), 0, MAKEUNIQUETAG(psCCBMemInfo)); + } + } +#endif + + /* to aid in determining the next power down delay */ + sgx_mark_new_command(psDeviceNode); + + eError = SGXScheduleCCBCommandKM(hDevHandle, psCCBKick->eCommand, + &psCCBKick->sCommand, KERNEL_ID, 0); + if (eError == PVRSRV_ERROR_RETRY) { + if (psCCBKick->bFirstKickOrResume && + psCCBKick->ui32NumDstSyncObjects > 0) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + psCCBKick->sDstSyncHandle; + if (psSyncInfo) { + psSyncInfo->psSyncData->ui32WriteOpsPending--; +#if defined(PDUMP) + if (PDumpIsCaptureFrameKM()) + psSyncInfo->psSyncData-> + ui32LastOpDumpVal--; +#endif + } + } + + for (i = 0; i < psCCBKick->ui32NumSrcSyncs; i++) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + ahSrcKernelSyncInfo[i]; + psSyncInfo->psSyncData->ui32ReadOpsPending--; + } + + return eError; + } else if (PVRSRV_OK != eError) { + PVR_DPF(PVR_DBG_ERROR, + "SGXDoKickKM: SGXScheduleCCBCommandKM failed."); + return eError; + } + +#if defined(NO_HARDWARE) + + if (psCCBKick->hTA3DSyncInfo) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick->hTA3DSyncInfo; + + if (psCCBKick->bTADependency) { + psSyncInfo->psSyncData->ui32WriteOpsComplete = + psSyncInfo->psSyncData->ui32WriteOpsPending; + } + } + + if (psCCBKick->hTASyncInfo != NULL) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick->hTASyncInfo; + + psSyncInfo->psSyncData->ui32ReadOpsComplete = + psSyncInfo->psSyncData->ui32ReadOpsPending; + } + + if (psCCBKick->h3DSyncInfo != NULL) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick->h3DSyncInfo; + + psSyncInfo->psSyncData->ui32ReadOpsComplete = + psSyncInfo->psSyncData->ui32ReadOpsPending; + } + + for (i = 0; i < psCCBKick->ui32NumTAStatusVals; i++) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + ahTAStatusSyncInfo[i]; + psSyncInfo->psSyncData->ui32ReadOpsComplete = + psTACmd->sCtlTAStatusInfo[i].ui32StatusValue; + } + + for (i = 0; i < psCCBKick->ui32NumSrcSyncs; i++) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + ahSrcKernelSyncInfo[i]; + + psSyncInfo->psSyncData->ui32ReadOpsComplete = + psSyncInfo->psSyncData->ui32ReadOpsPending; + + } + + if (psCCBKick->bTerminateOrAbort) { + if (psCCBKick->ui32NumDstSyncObjects > 0) { + struct PVRSRV_KERNEL_MEM_INFO *psHWDstSyncListMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psCCBKick-> + hKernelHWSyncListMemInfo; + struct SGXMKIF_HWDEVICE_SYNC_LIST *psHWDeviceSyncList = + psHWDstSyncListMemInfo->pvLinAddrKM; + + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + sDstSyncHandle; + if (psSyncInfo) + psSyncInfo->psSyncData->ui32WriteOpsComplete = + psHWDeviceSyncList->asSyncData[0]. + ui32WriteOpsPendingVal + 1; + } + + for (i = 0; i < psCCBKick->ui32Num3DStatusVals; i++) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psCCBKick-> + ah3DStatusSyncInfo[i]; + psSyncInfo->psSyncData->ui32ReadOpsComplete = + psTACmd->sCtl3DStatusInfo[i].ui32StatusValue; + } + } +#endif + + return eError; +} diff --git a/drivers/gpu/pvr/sgxmmu.h b/drivers/gpu/pvr/sgxmmu.h new file mode 100644 index 00000000000..d633e299e67 --- /dev/null +++ b/drivers/gpu/pvr/sgxmmu.h @@ -0,0 +1,57 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__SGXMMU_KM_H__) +#define __SGXMMU_KM_H__ + +#define SGX_MMU_PAGE_SHIFT 12 +#define SGX_MMU_PAGE_SIZE (1UL << SGX_MMU_PAGE_SHIFT) +#define SGX_MMU_PAGE_MASK (SGX_MMU_PAGE_SIZE - 1UL) + +#define SGX_MMU_PD_SHIFT 10 +#define SGX_MMU_PD_SIZE (1UL << SGX_MMU_PD_SHIFT) +#define SGX_MMU_PD_MASK 0xFFC00000UL + +#define SGX_MMU_PDE_ADDR_MASK 0xFFFFF000UL +#define SGX_MMU_PDE_VALID 0x00000001UL +#define SGX_MMU_PDE_PAGE_SIZE_4K 0x00000000UL +#define SGX_MMU_PDE_WRITEONLY 0x00000002UL +#define SGX_MMU_PDE_READONLY 0x00000004UL +#define SGX_MMU_PDE_CACHECONSISTENT 0x00000008UL +#define SGX_MMU_PDE_EDMPROTECT 0x00000010UL + +#define SGX_MMU_PT_SHIFT 10 +#define SGX_MMU_PT_SIZE (1UL << SGX_MMU_PT_SHIFT) +#define SGX_MMU_PT_MASK 0x003FF000UL + +#define SGX_MMU_PTE_ADDR_MASK 0xFFFFF000UL +#define SGX_MMU_PTE_VALID 0x00000001UL +#define SGX_MMU_PTE_WRITEONLY 0x00000002UL +#define SGX_MMU_PTE_READONLY 0x00000004UL +#define SGX_MMU_PTE_CACHECONSISTENT 0x00000008UL +#define SGX_MMU_PTE_EDMPROTECT 0x00000010UL + +#endif diff --git a/drivers/gpu/pvr/sgxpower.c b/drivers/gpu/pvr/sgxpower.c new file mode 100644 index 00000000000..899613ff245 --- /dev/null +++ b/drivers/gpu/pvr/sgxpower.c @@ -0,0 +1,488 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <stddef.h> +#include <linux/io.h> +#include <linux/sched.h> + +#include "sgxdefs.h" +#include "services_headers.h" +#include "sgxapi_km.h" +#include "sgxinfokm.h" +#include "sgxutils.h" +#include "pdump_km.h" + +#define MS_TO_NS(x) ((x) * 1000000ULL) +#define SGX_CMD_BURST_THRESHOLD_NS MS_TO_NS(3) +#define SGX_CMD_BURST_MAX_SIZE 4 +#define SGX_POWER_DOWN_DELAY_LONG_MS 4 +#define SGX_POWER_DOWN_DELAY_SHORT_MS 0 + +enum PVR_DEVICE_POWER_STATE { + + PVR_DEVICE_POWER_STATE_ON = 0, + PVR_DEVICE_POWER_STATE_IDLE = 1, + PVR_DEVICE_POWER_STATE_OFF = 2, + + PVR_DEVICE_POWER_STATE_FORCE_I32 = 0x7fffffff +}; + +static enum PVR_DEVICE_POWER_STATE MapDevicePowerState(enum PVR_POWER_STATE + ePowerState) +{ + enum PVR_DEVICE_POWER_STATE eDevicePowerState; + + switch (ePowerState) { + case PVRSRV_POWER_STATE_D0: + { + eDevicePowerState = PVR_DEVICE_POWER_STATE_ON; + break; + } + case PVRSRV_POWER_STATE_D3: + { + eDevicePowerState = PVR_DEVICE_POWER_STATE_OFF; + break; + } + default: + { + PVR_DPF(PVR_DBG_ERROR, + "MapDevicePowerState: Invalid state: %ld", + ePowerState); + eDevicePowerState = PVR_DEVICE_POWER_STATE_FORCE_I32; + PVR_DBG_BREAK; + } + } + + return eDevicePowerState; +} + +static void sgx_set_pwrdown_delay(struct PVRSRV_DEVICE_NODE *node, + unsigned ukernel_freq, int msec) +{ + struct PVRSRV_SGXDEV_INFO *dev_info = node->pvDevice; + unsigned delay; + + delay = ukernel_freq * msec / 1000 + 1; + if (dev_info->power_down_delay != delay) { + writel(delay, + &dev_info->psSGXHostCtl->ui32ActivePowManSampleRate); + dev_info->power_down_delay = delay; + } +} + +static int sgx_calc_power_down_delay(struct PVRSRV_DEVICE_NODE *node) +{ + struct PVRSRV_SGXDEV_INFO *info = node->pvDevice; + + /* + * Set the power down delay to short if the command to be executed is + * the last one in the burst, except if the burst size is at the + * maximum. + */ + if (info->burst_size < SGX_CMD_BURST_MAX_SIZE && + info->burst_cnt == info->burst_size) + return SGX_POWER_DOWN_DELAY_SHORT_MS; + else + return SGX_POWER_DOWN_DELAY_LONG_MS; + +} + +void sgx_mark_new_command(struct PVRSRV_DEVICE_NODE *node) +{ + struct PVRSRV_SGXDEV_INFO *info = node->pvDevice; + struct SGX_TIMING_INFORMATION tinfo = { 0 }; + unsigned long long cmd_start; + bool new_burst = false; + + cmd_start = cpu_clock(smp_processor_id()); + + if (unlikely(info->last_idle == info->burst_start)) { + /* + * This is the initial case, when we haven't yet any commands + * issued. + */ + new_burst = true; + } else { + /* + * If the last idle occurred after the current burst started + * and the time since the idle is greater than the threshold + * allowed for delays within a burst then this is a new burst. + */ + if (time_after64(info->last_idle, info->burst_start) && + cmd_start - info->last_idle > SGX_CMD_BURST_THRESHOLD_NS) + new_burst = true; + } + + if (new_burst) { + info->burst_start = cmd_start; + /* + * We predict the length of this new burst to be that of the + * previous burst. + */ + info->burst_size = info->burst_cnt; + info->burst_cnt = 0; + } else if (info->burst_cnt < SGX_CMD_BURST_MAX_SIZE) { + info->burst_cnt++; + } + + SysGetSGXTimingInformation(&tinfo); + sgx_set_pwrdown_delay(node, tinfo.ui32uKernelFreq, + sgx_calc_power_down_delay(node)); +} + +void sgx_mark_power_down(struct PVRSRV_DEVICE_NODE *node) +{ + struct PVRSRV_SGXDEV_INFO *info = node->pvDevice; + + info->last_idle = cpu_clock(smp_processor_id()); + /* + * After the last command completes power down happens in a delayed + * manner. The current value of this delay is in power_down_delay. + * To get the command complete time - which is the actual idle start + * time - we have to deduct the amount of delay from the current time. + */ + info->last_idle -= MS_TO_NS(info->power_down_delay); +} + +static void SGXGetTimingInfo(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + struct SGX_TIMING_INFORMATION sSGXTimingInfo = { 0 }; + struct timer_work_data *data = psDevInfo->hTimer; + + SysGetSGXTimingInformation(&sSGXTimingInfo); + + if (data) { + BUG_ON(data->armed); + /* + * The magic calculation below sets the hardware lock-up + * detection and recovery timer interval to ~150msecs. + * The interval length will be scaled based on the SGX + * functional clock frequency. The higher the frequency + * the shorter the interval and vice versa. + */ + data->interval = 150 * SYS_SGX_PDS_TIMER_FREQ / + sSGXTimingInfo.ui32uKernelFreq; + } + + writel(sSGXTimingInfo.ui32uKernelFreq / + sSGXTimingInfo.ui32HWRecoveryFreq, + &psDevInfo->psSGXHostCtl->ui32HWRecoverySampleRate); + + psDevInfo->ui32CoreClockSpeed = sSGXTimingInfo.ui32CoreClockSpeed; + psDevInfo->ui32uKernelTimerClock = + sSGXTimingInfo.ui32CoreClockSpeed / + sSGXTimingInfo.ui32uKernelFreq; + + sgx_set_pwrdown_delay(psDeviceNode, sSGXTimingInfo.ui32uKernelFreq, + sgx_calc_power_down_delay(psDeviceNode)); +} + +void SGXStartTimer(struct PVRSRV_SGXDEV_INFO *psDevInfo, IMG_BOOL bStartOSTimer) +{ + u32 ui32RegVal; + + ui32RegVal = + EUR_CR_EVENT_TIMER_ENABLE_MASK | psDevInfo->ui32uKernelTimerClock; + OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_TIMER, ui32RegVal); + PDUMPREGWITHFLAGS(EUR_CR_EVENT_TIMER, ui32RegVal, + PDUMP_FLAGS_CONTINUOUS); + + if (bStartOSTimer) { + enum PVRSRV_ERROR eError; + + eError = SGXOSTimerEnable(psDevInfo->hTimer); + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, + "SGXStartTimer : Failed to enable host timer"); + } +} + +static void SGXPollForClockGating(struct PVRSRV_SGXDEV_INFO *psDevInfo, + u32 ui32Register, + u32 ui32RegisterValue, char *pszComment) +{ + PVR_UNREFERENCED_PARAMETER(psDevInfo); + PVR_UNREFERENCED_PARAMETER(ui32Register); + PVR_UNREFERENCED_PARAMETER(ui32RegisterValue); + PVR_UNREFERENCED_PARAMETER(pszComment); + +#if !defined(NO_HARDWARE) + if (psDevInfo != NULL) + if (PollForValueKM + ((u32 __iomem *)psDevInfo->pvRegsBaseKM + + (ui32Register >> 2), 0, + ui32RegisterValue, MAX_HW_TIME_US / WAIT_TRY_COUNT, + WAIT_TRY_COUNT) != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, "SGXPrePowerState: %s failed.", + pszComment); + +#endif + + PDUMPCOMMENT(pszComment); + PDUMPREGPOL(ui32Register, 0, ui32RegisterValue); +} + +static enum PVRSRV_ERROR SGXPrePowerState(void *hDevHandle, + enum PVR_DEVICE_POWER_STATE eNewPowerState, + enum PVR_DEVICE_POWER_STATE eCurrentPowerState) +{ + if ((eNewPowerState != eCurrentPowerState) && + (eNewPowerState != PVR_DEVICE_POWER_STATE_ON)) { + enum PVRSRV_ERROR eError; + struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + u32 ui32PowerCmd, ui32CompleteStatus; + struct SGXMKIF_COMMAND sCommand = { 0 }; + + eError = SGXOSTimerCancel(psDevInfo->hTimer); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXPrePowerState: Failed to disable timer"); + return eError; + } + + if (eNewPowerState == PVR_DEVICE_POWER_STATE_OFF) { + + ui32PowerCmd = PVRSRV_POWERCMD_POWEROFF; + ui32CompleteStatus = + PVRSRV_USSE_EDM_POWMAN_POWEROFF_COMPLETE; + PDUMPCOMMENT("SGX power off request"); + } else { + + ui32PowerCmd = PVRSRV_POWERCMD_IDLE; + ui32CompleteStatus = + PVRSRV_USSE_EDM_POWMAN_IDLE_COMPLETE; + PDUMPCOMMENT("SGX idle request"); + } + + sCommand.ui32Data[0] = PVRSRV_CCBFLAGS_POWERCMD; + sCommand.ui32Data[1] = ui32PowerCmd; + + eError = + SGXScheduleCCBCommand(psDevInfo, SGXMKIF_COMMAND_EDM_KICK, + &sCommand, KERNEL_ID, 0); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXPrePowerState: " + "Failed to submit power down command"); + return eError; + } + +#if !defined(NO_HARDWARE) + if (PollForValueKM(&psDevInfo->psSGXHostCtl->ui32PowerStatus, + ui32CompleteStatus, + ui32CompleteStatus, + MAX_HW_TIME_US / WAIT_TRY_COUNT, + WAIT_TRY_COUNT) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXPrePowerState: " + "Wait for SGX ukernel power transition failed."); + PVR_DBG_BREAK; + } +#endif + +#if defined(PDUMP) + PDUMPCOMMENT + ("TA/3D CCB Control - Wait for power event on uKernel."); + PDUMPMEMPOL(psDevInfo->psKernelSGXHostCtlMemInfo, + offsetof(struct SGXMKIF_HOST_CTL, ui32PowerStatus), + ui32CompleteStatus, ui32CompleteStatus, + PDUMP_POLL_OPERATOR_EQUAL, IMG_FALSE, IMG_FALSE, + MAKEUNIQUETAG(psDevInfo-> + psKernelSGXHostCtlMemInfo)); +#endif + + SGXPollForClockGating(psDevInfo, + psDevInfo->ui32ClkGateStatusReg, + psDevInfo->ui32ClkGateStatusMask, + "Wait for SGX clock gating"); + + if (eNewPowerState == PVR_DEVICE_POWER_STATE_OFF) { + eError = SGXDeinitialise(psDevInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXPrePowerState: " + "SGXDeinitialise failed: %lu", + eError); + return eError; + } + } + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR SGXPostPowerState(void *hDevHandle, + enum PVR_DEVICE_POWER_STATE eNewPowerState, + enum PVR_DEVICE_POWER_STATE eCurrentPowerState) +{ + if ((eNewPowerState != eCurrentPowerState) && + (eCurrentPowerState != PVR_DEVICE_POWER_STATE_ON)) { + enum PVRSRV_ERROR eError; + struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; + + writel(0, &psSGXHostCtl->ui32PowerStatus); + PDUMPCOMMENT("TA/3D CCB Control - Reset power status"); +#if defined(PDUMP) + PDUMPMEM(NULL, psDevInfo->psKernelSGXHostCtlMemInfo, + offsetof(struct SGXMKIF_HOST_CTL, ui32PowerStatus), + sizeof(u32), PDUMP_FLAGS_CONTINUOUS, + MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); +#endif + + if (eCurrentPowerState == PVR_DEVICE_POWER_STATE_OFF) { + + SGXGetTimingInfo(psDeviceNode); + + eError = SGXInitialise(psDevInfo, IMG_FALSE); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXPostPowerState: SGXInitialise failed"); + return eError; + } + } else { + + struct SGXMKIF_COMMAND sCommand = { 0 }; + + SGXStartTimer(psDevInfo, IMG_TRUE); + + sCommand.ui32Data[0] = + PVRSRV_CCBFLAGS_PROCESS_QUEUESCMD; + eError = + SGXScheduleCCBCommand(psDevInfo, + SGXMKIF_COMMAND_EDM_KICK, + &sCommand, ISR_ID, 0); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXPostPowerState failed to schedule CCB command: %lu", + eError); + return PVRSRV_ERROR_GENERIC; + } + } + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXPrePowerStateExt(void *hDevHandle, + enum PVR_POWER_STATE eNewPowerState, + enum PVR_POWER_STATE eCurrentPowerState) +{ + enum PVR_DEVICE_POWER_STATE eNewDevicePowerState = + MapDevicePowerState(eNewPowerState); + enum PVR_DEVICE_POWER_STATE eCurrentDevicePowerState = + MapDevicePowerState(eCurrentPowerState); + + return SGXPrePowerState(hDevHandle, eNewDevicePowerState, + eCurrentDevicePowerState); +} + +enum PVRSRV_ERROR SGXPostPowerStateExt(void *hDevHandle, + enum PVR_POWER_STATE eNewPowerState, + enum PVR_POWER_STATE eCurrentPowerState) +{ + enum PVRSRV_ERROR eError; + enum PVR_DEVICE_POWER_STATE eNewDevicePowerState = + MapDevicePowerState(eNewPowerState); + enum PVR_DEVICE_POWER_STATE eCurrentDevicePowerState = + MapDevicePowerState(eCurrentPowerState); + + eError = + SGXPostPowerState(hDevHandle, eNewDevicePowerState, + eCurrentDevicePowerState); + if (eError != PVRSRV_OK) + return eError; + + PVR_DPF(PVR_DBG_MESSAGE, + "SGXPostPowerState : SGX Power Transition from %d to %d OK", + eCurrentPowerState, eNewPowerState); + + return eError; +} + +enum PVRSRV_ERROR SGXPreClockSpeedChange(void *hDevHandle, IMG_BOOL bIdleDevice, + enum PVR_POWER_STATE eCurrentPowerState) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + + PVR_UNREFERENCED_PARAMETER(psDevInfo); + + if (eCurrentPowerState == PVRSRV_POWER_STATE_D0) + if (bIdleDevice) { + PDUMPSUSPEND(); + eError = + SGXPrePowerState(hDevHandle, + PVR_DEVICE_POWER_STATE_IDLE, + PVR_DEVICE_POWER_STATE_ON); + if (eError != PVRSRV_OK) { + PDUMPRESUME(); + return eError; + } + } + + PVR_DPF(PVR_DBG_MESSAGE, + "SGXPreClockSpeedChange: SGX clock speed was %luHz", + psDevInfo->ui32CoreClockSpeed); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXPostClockSpeedChange(void *hDevHandle, + IMG_BOOL bIdleDevice, + enum PVR_POWER_STATE eCurrentPowerState) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + u32 ui32OldClockSpeed = psDevInfo->ui32CoreClockSpeed; + + PVR_UNREFERENCED_PARAMETER(ui32OldClockSpeed); + + if (eCurrentPowerState == PVRSRV_POWER_STATE_D0) { + SGXGetTimingInfo(psDeviceNode); + if (bIdleDevice) { + enum PVRSRV_ERROR eError; + eError = + SGXPostPowerState(hDevHandle, + PVR_DEVICE_POWER_STATE_ON, + PVR_DEVICE_POWER_STATE_IDLE); + PDUMPRESUME(); + if (eError != PVRSRV_OK) + return eError; + } else { + SGXStartTimer(psDevInfo, IMG_TRUE); + } + + } + + PVR_DPF(PVR_DBG_MESSAGE, "SGXPostClockSpeedChange: " + "SGX clock speed changed from %luHz to %luHz", + ui32OldClockSpeed, psDevInfo->ui32CoreClockSpeed); + + return PVRSRV_OK; +} diff --git a/drivers/gpu/pvr/sgxreset.c b/drivers/gpu/pvr/sgxreset.c new file mode 100644 index 00000000000..ad76a01fe31 --- /dev/null +++ b/drivers/gpu/pvr/sgxreset.c @@ -0,0 +1,223 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "sgxdefs.h" +#include "sgxmmu.h" +#include "services_headers.h" +#include "sgxinfokm.h" +#include "sgxconfig.h" + +#include "pdump_km.h" + +static void SGXResetSoftReset(struct PVRSRV_SGXDEV_INFO *psDevInfo, + IMG_BOOL bResetBIF, u32 ui32PDUMPFlags, + IMG_BOOL bPDump) +{ + u32 ui32SoftResetRegVal = + EUR_CR_SOFT_RESET_DPM_RESET_MASK | + EUR_CR_SOFT_RESET_TA_RESET_MASK | + EUR_CR_SOFT_RESET_USE_RESET_MASK | + EUR_CR_SOFT_RESET_ISP_RESET_MASK | EUR_CR_SOFT_RESET_TSP_RESET_MASK; + +#ifdef EUR_CR_SOFT_RESET_TWOD_RESET_MASK + ui32SoftResetRegVal |= EUR_CR_SOFT_RESET_TWOD_RESET_MASK; +#endif + +#if !defined(PDUMP) + PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); +#endif + + if (bResetBIF) + ui32SoftResetRegVal |= EUR_CR_SOFT_RESET_BIF_RESET_MASK; + + OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_SOFT_RESET, + ui32SoftResetRegVal); + if (bPDump) + PDUMPREGWITHFLAGS(EUR_CR_SOFT_RESET, ui32SoftResetRegVal, + ui32PDUMPFlags); +} + +static void SGXResetSleep(struct PVRSRV_SGXDEV_INFO *psDevInfo, + u32 ui32PDUMPFlags, IMG_BOOL bPDump) +{ +#if !defined(PDUMP) + PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); +#endif + + OSWaitus(1000 * 1000000 / psDevInfo->ui32CoreClockSpeed); + if (bPDump) { + PDUMPIDLWITHFLAGS(30, ui32PDUMPFlags); +#if defined(PDUMP) + PDumpRegRead(EUR_CR_SOFT_RESET, ui32PDUMPFlags); +#endif + } + +} + +static void SGXResetInvalDC(struct PVRSRV_SGXDEV_INFO *psDevInfo, + u32 ui32PDUMPFlags, IMG_BOOL bPDump) +{ + u32 ui32RegVal; + + ui32RegVal = EUR_CR_BIF_CTRL_INVALDC_MASK; + OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32RegVal); + if (bPDump) + PDUMPREGWITHFLAGS(EUR_CR_BIF_CTRL, ui32RegVal, ui32PDUMPFlags); + SGXResetSleep(psDevInfo, ui32PDUMPFlags, bPDump); + + ui32RegVal = 0; + OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32RegVal); + if (bPDump) + PDUMPREGWITHFLAGS(EUR_CR_BIF_CTRL, ui32RegVal, ui32PDUMPFlags); + SGXResetSleep(psDevInfo, ui32PDUMPFlags, bPDump); + + if (PollForValueKM( + (u32 __iomem *)((u8 __iomem *)psDevInfo->pvRegsBaseKM + + EUR_CR_BIF_MEM_REQ_STAT), + 0, EUR_CR_BIF_MEM_REQ_STAT_READS_MASK, + MAX_HW_TIME_US / WAIT_TRY_COUNT, WAIT_TRY_COUNT) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "Wait for DC invalidate failed."); + PVR_DBG_BREAK; + } + + if (bPDump) + PDUMPREGPOLWITHFLAGS(EUR_CR_BIF_MEM_REQ_STAT, 0, + EUR_CR_BIF_MEM_REQ_STAT_READS_MASK, + ui32PDUMPFlags); +} + +void SGXReset(struct PVRSRV_SGXDEV_INFO *psDevInfo, u32 ui32PDUMPFlags) +{ + u32 ui32RegVal; + + const u32 ui32BifFaultMask = EUR_CR_BIF_INT_STAT_FAULT_MASK; + + +#ifndef PDUMP + PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); +#endif + + psDevInfo->ui32NumResets++; + + PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, + "Start of SGX reset sequence\r\n"); + + SGXResetSoftReset(psDevInfo, IMG_TRUE, ui32PDUMPFlags, IMG_TRUE); + + SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_TRUE); + + + ui32RegVal = psDevInfo->sBIFResetPDDevPAddr.uiAddr; + OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_DIR_LIST_BASE0, + ui32RegVal); + + SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_FALSE); + + SGXResetSoftReset(psDevInfo, IMG_FALSE, ui32PDUMPFlags, IMG_TRUE); + SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_FALSE); + + SGXResetInvalDC(psDevInfo, ui32PDUMPFlags, IMG_FALSE); + + for (;;) { + u32 ui32BifIntStat = + OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_INT_STAT); + struct IMG_DEV_VIRTADDR sBifFault; + u32 ui32PDIndex, ui32PTIndex; + + if ((ui32BifIntStat & ui32BifFaultMask) == 0) + break; + + sBifFault.uiAddr = + OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_FAULT); + PVR_DPF(PVR_DBG_WARNING, "SGXReset: Page fault 0x%x/0x%x", + ui32BifIntStat, sBifFault.uiAddr); + ui32PDIndex = + sBifFault.uiAddr >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); + ui32PTIndex = + (sBifFault.uiAddr & SGX_MMU_PT_MASK) >> SGX_MMU_PAGE_SHIFT; + + SGXResetSoftReset(psDevInfo, IMG_TRUE, ui32PDUMPFlags, + IMG_FALSE); + + psDevInfo->pui32BIFResetPD[ui32PDIndex] = + psDevInfo->sBIFResetPTDevPAddr.uiAddr | + SGX_MMU_PDE_PAGE_SIZE_4K | SGX_MMU_PDE_VALID; + psDevInfo->pui32BIFResetPT[ui32PTIndex] = + psDevInfo->sBIFResetPageDevPAddr.uiAddr | SGX_MMU_PTE_VALID; + + ui32RegVal = + OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS); + OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_CLEAR, + ui32RegVal); + ui32RegVal = + OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS2); + OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_CLEAR2, + ui32RegVal); + + SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_FALSE); + + SGXResetSoftReset(psDevInfo, IMG_FALSE, ui32PDUMPFlags, + IMG_FALSE); + SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_FALSE); + + SGXResetInvalDC(psDevInfo, ui32PDUMPFlags, IMG_FALSE); + + psDevInfo->pui32BIFResetPD[ui32PDIndex] = 0; + psDevInfo->pui32BIFResetPT[ui32PTIndex] = 0; + } + + { + u32 ui32EDMDirListReg; + +#if (SGX_BIF_DIR_LIST_INDEX_EDM == 0) + ui32EDMDirListReg = EUR_CR_BIF_DIR_LIST_BASE0; +#else + + ui32EDMDirListReg = + EUR_CR_BIF_DIR_LIST_BASE1 + + 4 * (SGX_BIF_DIR_LIST_INDEX_EDM - 1); +#endif + + OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32EDMDirListReg, + psDevInfo->sKernelPDDevPAddr.uiAddr); + PDUMPPDREGWITHFLAGS(ui32EDMDirListReg, + psDevInfo->sKernelPDDevPAddr.uiAddr, + ui32PDUMPFlags, PDUMP_PD_UNIQUETAG); + } + + SGXResetInvalDC(psDevInfo, ui32PDUMPFlags, IMG_TRUE); + + PVR_DPF(PVR_DBG_MESSAGE, "Soft Reset of SGX"); + SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_TRUE); + + ui32RegVal = 0; + OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_SOFT_RESET, ui32RegVal); + PDUMPREGWITHFLAGS(EUR_CR_SOFT_RESET, ui32RegVal, ui32PDUMPFlags); + + SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_TRUE); + + PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "End of SGX reset sequence\r\n"); +} diff --git a/drivers/gpu/pvr/sgxscript.h b/drivers/gpu/pvr/sgxscript.h new file mode 100644 index 00000000000..2bbb0ba03ed --- /dev/null +++ b/drivers/gpu/pvr/sgxscript.h @@ -0,0 +1,65 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __SGXSCRIPT_H__ +#define __SGXSCRIPT_H__ + + +#define SGX_MAX_INIT_COMMANDS 64 +#define SGX_MAX_DEINIT_COMMANDS 16 + +enum SGX_INIT_OPERATION { + SGX_INIT_OP_ILLEGAL = 0, + SGX_INIT_OP_WRITE_HW_REG, +#if defined(PDUMP) + SGX_INIT_OP_PDUMP_HW_REG, +#endif + SGX_INIT_OP_HALT +}; + +union SGX_INIT_COMMAND { + enum SGX_INIT_OPERATION eOp; + struct { + enum SGX_INIT_OPERATION eOp; + u32 ui32Offset; + u32 ui32Value; + } sWriteHWReg; +#if defined(PDUMP) + struct { + enum SGX_INIT_OPERATION eOp; + u32 ui32Offset; + u32 ui32Value; + } sPDumpHWReg; +#endif +}; + +struct SGX_INIT_SCRIPTS { + union SGX_INIT_COMMAND asInitCommandsPart1[SGX_MAX_INIT_COMMANDS]; + union SGX_INIT_COMMAND asInitCommandsPart2[SGX_MAX_INIT_COMMANDS]; + union SGX_INIT_COMMAND asDeinitCommands[SGX_MAX_DEINIT_COMMANDS]; +}; + +#endif diff --git a/drivers/gpu/pvr/sgxtransfer.c b/drivers/gpu/pvr/sgxtransfer.c new file mode 100644 index 00000000000..410b97ed629 --- /dev/null +++ b/drivers/gpu/pvr/sgxtransfer.c @@ -0,0 +1,293 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + + +#include <stddef.h> + +#include "sgxdefs.h" +#include "services_headers.h" +#include "buffer_manager.h" +#include "sgxinfo.h" +#include "sysconfig.h" +#include "pdump_km.h" +#include "mmu.h" +#include "pvr_bridge.h" +#include "sgx_bridge_km.h" +#include "sgxinfokm.h" +#include "osfunc.h" +#include "pvr_debug.h" +#include "sgxutils.h" + +enum PVRSRV_ERROR SGXSubmitTransferKM(void *hDevHandle, + struct PVRSRV_TRANSFER_SGX_KICK *psKick) +{ + struct PVRSRV_KERNEL_MEM_INFO *psCCBMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psKick->hCCBMemInfo; + struct SGXMKIF_COMMAND sCommand = { 0 }; + struct SGXMKIF_TRANSFERCMD_SHARED *psSharedTransferCmd; + struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo; + enum PVRSRV_ERROR eError; + + if (!CCB_OFFSET_IS_VALID + (struct SGXMKIF_TRANSFERCMD_SHARED, psCCBMemInfo, psKick, + ui32SharedCmdCCBOffset)) { + PVR_DPF(PVR_DBG_ERROR, + "SGXSubmitTransferKM: Invalid CCB offset"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psSharedTransferCmd = + CCB_DATA_FROM_OFFSET(struct SGXMKIF_TRANSFERCMD_SHARED, + psCCBMemInfo, psKick, ui32SharedCmdCCBOffset); + + if (psKick->hTASyncInfo != NULL) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + psKick->hTASyncInfo; + + psSharedTransferCmd->ui32TASyncWriteOpsPendingVal = + psSyncInfo->psSyncData->ui32WriteOpsPending++; + psSharedTransferCmd->ui32TASyncReadOpsPendingVal = + psSyncInfo->psSyncData->ui32ReadOpsPending; + + psSharedTransferCmd->sTASyncWriteOpsCompleteDevVAddr = + psSyncInfo->sWriteOpsCompleteDevVAddr; + psSharedTransferCmd->sTASyncReadOpsCompleteDevVAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + } else { + psSharedTransferCmd->sTASyncWriteOpsCompleteDevVAddr.uiAddr = 0; + psSharedTransferCmd->sTASyncReadOpsCompleteDevVAddr.uiAddr = 0; + } + + if (psKick->h3DSyncInfo != NULL) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + psKick->h3DSyncInfo; + + psSharedTransferCmd->ui323DSyncWriteOpsPendingVal = + psSyncInfo->psSyncData->ui32WriteOpsPending++; + psSharedTransferCmd->ui323DSyncReadOpsPendingVal = + psSyncInfo->psSyncData->ui32ReadOpsPending; + + psSharedTransferCmd->s3DSyncWriteOpsCompleteDevVAddr = + psSyncInfo->sWriteOpsCompleteDevVAddr; + psSharedTransferCmd->s3DSyncReadOpsCompleteDevVAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + } else { + psSharedTransferCmd->s3DSyncWriteOpsCompleteDevVAddr.uiAddr = 0; + psSharedTransferCmd->s3DSyncReadOpsCompleteDevVAddr.uiAddr = 0; + } + + if ((psKick->ui32Flags & SGXMKIF_TQFLAGS_KEEPPENDING) == 0UL) { + if (psKick->ui32NumSrcSync > 0) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *) + psKick->ahSrcSyncInfo[0]; + + psSharedTransferCmd->ui32SrcWriteOpPendingVal = + psSyncInfo->psSyncData->ui32WriteOpsPending; + psSharedTransferCmd->ui32SrcReadOpPendingVal = + psSyncInfo->psSyncData->ui32ReadOpsPending; + + psSharedTransferCmd->sSrcWriteOpsCompleteDevAddr = + psSyncInfo->sWriteOpsCompleteDevVAddr; + psSharedTransferCmd->sSrcReadOpsCompleteDevAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + } + if (psKick->ui32NumDstSync > 0) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + psKick->ahDstSyncInfo[0]; + psSharedTransferCmd->ui32DstWriteOpPendingVal = + psSyncInfo->psSyncData->ui32WriteOpsPending; + psSharedTransferCmd->ui32DstReadOpPendingVal = + psSyncInfo->psSyncData->ui32ReadOpsPending; + psSharedTransferCmd->sDstWriteOpsCompleteDevAddr = + psSyncInfo->sWriteOpsCompleteDevVAddr; + psSharedTransferCmd->sDstReadOpsCompleteDevAddr = + psSyncInfo->sReadOpsCompleteDevVAddr; + } + + if (psKick->ui32NumSrcSync > 0) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *) + psKick->ahSrcSyncInfo[0]; + psSyncInfo->psSyncData->ui32ReadOpsPending++; + + } + if (psKick->ui32NumDstSync > 0) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psKick-> + ahDstSyncInfo[0]; + psSyncInfo->psSyncData->ui32WriteOpsPending++; + } + } + + if (psKick->ui32NumDstSync > 1 || psKick->ui32NumSrcSync > 1) { + PVR_DPF(PVR_DBG_ERROR, + "Transfer command doesn't support " + "more than 1 sync object per src/dst\ndst: %d, src: %d", + psKick->ui32NumDstSync, psKick->ui32NumSrcSync); + } +#if defined(PDUMP) + if (PDumpIsCaptureFrameKM() || + ((psKick->ui32PDumpFlags & PDUMP_FLAGS_CONTINUOUS) != 0)) { + PDUMPCOMMENT("Shared part of transfer command\r\n"); + PDUMPMEM(psSharedTransferCmd, + psCCBMemInfo, + psKick->ui32CCBDumpWOff, + sizeof(struct SGXMKIF_TRANSFERCMD_SHARED), + psKick->ui32PDumpFlags, MAKEUNIQUETAG(psCCBMemInfo)); + + if ((psKick->ui32NumSrcSync > 0) && + ((psKick->ui32Flags & SGXMKIF_TQFLAGS_KEEPPENDING) == + 0UL)) { + psSyncInfo = psKick->ahSrcSyncInfo[0]; + + PDUMPCOMMENT + ("Hack src surface write op in transfer cmd\r\n"); + PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, + psCCBMemInfo, + psKick->ui32CCBDumpWOff + + offsetof(struct SGXMKIF_TRANSFERCMD_SHARED, + ui32SrcWriteOpPendingVal), + sizeof(psSyncInfo->psSyncData-> + ui32LastOpDumpVal), + psKick->ui32PDumpFlags, + MAKEUNIQUETAG(psCCBMemInfo)); + + PDUMPCOMMENT + ("Hack src surface read op in transfer cmd\r\n"); + PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, + psCCBMemInfo, + psKick->ui32CCBDumpWOff + + offsetof(struct SGXMKIF_TRANSFERCMD_SHARED, + ui32SrcReadOpPendingVal), + sizeof(psSyncInfo->psSyncData-> + ui32LastReadOpDumpVal), + psKick->ui32PDumpFlags, + MAKEUNIQUETAG(psCCBMemInfo)); + } + if ((psKick->ui32NumDstSync > 0) && + ((psKick->ui32Flags & SGXMKIF_TQFLAGS_KEEPPENDING) == + 0UL)) { + psSyncInfo = psKick->ahDstSyncInfo[0]; + + PDUMPCOMMENT + ("Hack dest surface write op in transfer cmd\r\n"); + PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, + psCCBMemInfo, + psKick->ui32CCBDumpWOff + + offsetof(struct SGXMKIF_TRANSFERCMD_SHARED, + ui32DstWriteOpPendingVal), + sizeof(psSyncInfo->psSyncData-> + ui32LastOpDumpVal), + psKick->ui32PDumpFlags, + MAKEUNIQUETAG(psCCBMemInfo)); + + PDUMPCOMMENT + ("Hack dest surface read op in transfer cmd\r\n"); + PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, + psCCBMemInfo, + psKick->ui32CCBDumpWOff + + offsetof(struct SGXMKIF_TRANSFERCMD_SHARED, + ui32DstReadOpPendingVal), + sizeof(psSyncInfo->psSyncData-> + ui32LastReadOpDumpVal), + psKick->ui32PDumpFlags, + MAKEUNIQUETAG(psCCBMemInfo)); + } + + if ((psKick->ui32NumSrcSync > 0) && + ((psKick->ui32Flags & SGXMKIF_TQFLAGS_KEEPPENDING) == + 0UL)) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psKick-> + ahSrcSyncInfo[0]; + psSyncInfo->psSyncData->ui32LastReadOpDumpVal++; + + } + + if ((psKick->ui32NumDstSync > 0) && + ((psKick->ui32Flags & SGXMKIF_TQFLAGS_KEEPPENDING) == + 0UL)) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psKick-> + ahDstSyncInfo[0]; + psSyncInfo->psSyncData->ui32LastOpDumpVal++; + } + } +#endif + + sCommand.ui32Data[0] = PVRSRV_CCBFLAGS_TRANSFERCMD; + sCommand.ui32Data[1] = psKick->sHWTransferContextDevVAddr.uiAddr; + + /* To aid in determining the next power down delay */ + sgx_mark_new_command(hDevHandle); + + eError = SGXScheduleCCBCommandKM(hDevHandle, SGXMKIF_COMMAND_EDM_KICK, + &sCommand, KERNEL_ID, + psKick->ui32PDumpFlags); + +#if defined(NO_HARDWARE) + if (!(psKick->ui32Flags & SGXMKIF_TQFLAGS_NOSYNCUPDATE)) { + u32 i; + + for (i = 0; i < psKick->ui32NumSrcSync; i++) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psKick-> + ahSrcSyncInfo[i]; + psSyncInfo->psSyncData->ui32ReadOpsComplete = + psSyncInfo->psSyncData->ui32ReadOpsPending; + } + + for (i = 0; i < psKick->ui32NumDstSync; i++) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psKick-> + ahDstSyncInfo[i]; + psSyncInfo->psSyncData->ui32WriteOpsComplete = + psSyncInfo->psSyncData->ui32WriteOpsPending; + + } + + if (psKick->hTASyncInfo != NULL) { + psSyncInfo = + (struct PVRSRV_KERNEL_SYNC_INFO *)psKick-> + hTASyncInfo; + + psSyncInfo->psSyncData->ui32WriteOpsComplete = + psSyncInfo->psSyncData->ui32WriteOpsPending; + } + + if (psKick->h3DSyncInfo != NULL) { + psSyncInfo = (struct PVRSRV_KERNEL_SYNC_INFO *)psKick-> + h3DSyncInfo; + + psSyncInfo->psSyncData->ui32WriteOpsComplete = + psSyncInfo->psSyncData->ui32WriteOpsPending; + } + } +#endif + + return eError; +} + diff --git a/drivers/gpu/pvr/sgxutils.c b/drivers/gpu/pvr/sgxutils.c new file mode 100644 index 00000000000..b92d5023958 --- /dev/null +++ b/drivers/gpu/pvr/sgxutils.c @@ -0,0 +1,749 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <stddef.h> + +#include "sgxdefs.h" +#include "services_headers.h" +#include "buffer_manager.h" +#include "sgxapi_km.h" +#include "sgxinfo.h" +#include "sgxinfokm.h" +#include "sysconfig.h" +#include "pdump_km.h" +#include "mmu.h" +#include "pvr_bridge_km.h" +#include "sgx_bridge_km.h" +#include "osfunc.h" +#include "pvr_debug.h" +#include "sgxutils.h" + +#include <linux/tty.h> +#include <linux/io.h> + +static void SGXPostActivePowerEvent(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; + u32 l; + + /* To aid in calculating the next power down delay */ + sgx_mark_power_down(psDeviceNode); + + l = readl(&psSGXHostCtl->ui32NumActivePowerEvents); + l++; + writel(l, &psSGXHostCtl->ui32NumActivePowerEvents); + + l = readl(&psSGXHostCtl->ui32PowerStatus); + if (l & PVRSRV_USSE_EDM_POWMAN_POWEROFF_RESTART_IMMEDIATE) + SGXScheduleProcessQueues(psDeviceNode); +} + +void SGXTestActivePowerEvent(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = psDevInfo->psSGXHostCtl; + u32 l; + + l = readl(&psSGXHostCtl->ui32InterruptFlags); + if (!(l & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER)) + return; + + l = readl(&psSGXHostCtl->ui32InterruptClearFlags); + if (l & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER) + return; + + /* Microkernel is idle and is requesting to be powered down. */ + l = readl(&psSGXHostCtl->ui32InterruptClearFlags); + l |= PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER; + writel(l, &psSGXHostCtl->ui32InterruptClearFlags); + + PDUMPSUSPEND(); + + eError = PVRSRVSetDevicePowerStateKM( + psDeviceNode->sDevId.ui32DeviceIndex, + PVRSRV_POWER_STATE_D3); + if (eError == PVRSRV_OK) + SGXPostActivePowerEvent(psDeviceNode); + + PDUMPRESUME(); + + if (eError != PVRSRV_OK) + PVR_DPF(PVR_DBG_ERROR, "SGXTestActivePowerEvent error:%lu", + eError); +} + +static inline struct SGXMKIF_COMMAND *SGXAcquireKernelCCBSlot( + struct PVRSRV_SGX_CCB_INFO *psCCB) +{ + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + if (((*psCCB->pui32WriteOffset + 1) & 255) != + *psCCB->pui32ReadOffset) { + return &psCCB->psCommands[*psCCB->pui32WriteOffset]; + } + } + END_LOOP_UNTIL_TIMEOUT(); + + return NULL; +} + +enum PVRSRV_ERROR SGXScheduleCCBCommand(struct PVRSRV_SGXDEV_INFO *psDevInfo, + enum SGXMKIF_COMMAND_TYPE eCommandType, + struct SGXMKIF_COMMAND *psCommandData, + u32 ui32CallerID, u32 ui32PDumpFlags) +{ + struct PVRSRV_SGX_CCB_INFO *psKernelCCB; + enum PVRSRV_ERROR eError = PVRSRV_OK; + struct SGXMKIF_COMMAND *psSGXCommand; +#if defined(PDUMP) + void *pvDumpCommand; +#else + PVR_UNREFERENCED_PARAMETER(ui32CallerID); + PVR_UNREFERENCED_PARAMETER(ui32PDumpFlags); +#endif + + psKernelCCB = psDevInfo->psKernelCCBInfo; + + psSGXCommand = SGXAcquireKernelCCBSlot(psKernelCCB); + + if (!psSGXCommand) { + eError = PVRSRV_ERROR_TIMEOUT; + goto Exit; + } + + psCommandData->ui32Data[2] = psDevInfo->ui32CacheControl; + +#if defined(PDUMP) + + psDevInfo->sPDContext.ui32CacheControl |= psDevInfo->ui32CacheControl; +#endif + + psDevInfo->ui32CacheControl = 0; + + *psSGXCommand = *psCommandData; + + switch (eCommandType) { + case SGXMKIF_COMMAND_EDM_KICK: + psSGXCommand->ui32ServiceAddress = + psDevInfo->ui32HostKickAddress; + break; + case SGXMKIF_COMMAND_REQUEST_SGXMISCINFO: + psSGXCommand->ui32ServiceAddress = + psDevInfo->ui32GetMiscInfoAddress; + break; + case SGXMKIF_COMMAND_VIDEO_KICK: + default: + PVR_DPF(PVR_DBG_ERROR, + "SGXScheduleCCBCommandKM: Unknown command type: %d", + eCommandType); + eError = PVRSRV_ERROR_GENERIC; + goto Exit; + } + +#if defined(PDUMP) + if (ui32CallerID != ISR_ID) { + PDUMPCOMMENTWITHFLAGS(0, + "Poll for space in the Kernel CCB\r\n"); + PDUMPMEMPOL(psKernelCCB->psCCBCtlMemInfo, + offsetof(struct PVRSRV_SGX_CCB_CTL, ui32ReadOffset), + (psKernelCCB->ui32CCBDumpWOff + 1) & 0xff, 0xff, + PDUMP_POLL_OPERATOR_NOTEQUAL, IMG_FALSE, IMG_FALSE, + MAKEUNIQUETAG(psKernelCCB->psCCBCtlMemInfo)); + + PDUMPCOMMENTWITHFLAGS(0, "Kernel CCB command\r\n"); + pvDumpCommand = + (void *)((u8 *)psKernelCCB->psCCBMemInfo-> + pvLinAddrKM + + (*psKernelCCB->pui32WriteOffset * + sizeof(struct SGXMKIF_COMMAND))); + + PDUMPMEM(pvDumpCommand, + psKernelCCB->psCCBMemInfo, + psKernelCCB->ui32CCBDumpWOff * + sizeof(struct SGXMKIF_COMMAND), + sizeof(struct SGXMKIF_COMMAND), ui32PDumpFlags, + MAKEUNIQUETAG(psKernelCCB->psCCBMemInfo)); + + PDUMPMEM(&psDevInfo->sPDContext.ui32CacheControl, + psKernelCCB->psCCBMemInfo, + psKernelCCB->ui32CCBDumpWOff * + sizeof(struct SGXMKIF_COMMAND) + + offsetof(struct SGXMKIF_COMMAND, ui32Data[2]), + sizeof(u32), ui32PDumpFlags, + MAKEUNIQUETAG(psKernelCCB->psCCBMemInfo)); + + if (PDumpIsCaptureFrameKM() || + ((ui32PDumpFlags & PDUMP_FLAGS_CONTINUOUS) != 0)) + psDevInfo->sPDContext.ui32CacheControl = 0; + } +#endif + *psKernelCCB->pui32WriteOffset = + (*psKernelCCB->pui32WriteOffset + 1) & 255; + +#if defined(PDUMP) + if (ui32CallerID != ISR_ID) { + if (PDumpIsCaptureFrameKM() || + ((ui32PDumpFlags & PDUMP_FLAGS_CONTINUOUS) != 0)) + psKernelCCB->ui32CCBDumpWOff = + (psKernelCCB->ui32CCBDumpWOff + 1) & 0xFF; + + PDUMPCOMMENTWITHFLAGS(0, "Kernel CCB write offset\r\n"); + PDUMPMEM(&psKernelCCB->ui32CCBDumpWOff, + psKernelCCB->psCCBCtlMemInfo, + offsetof(struct PVRSRV_SGX_CCB_CTL, ui32WriteOffset), + sizeof(u32), ui32PDumpFlags, + MAKEUNIQUETAG(psKernelCCB->psCCBCtlMemInfo)); + PDUMPCOMMENTWITHFLAGS(0, "Kernel CCB event kicker\r\n"); + PDUMPMEM(&psKernelCCB->ui32CCBDumpWOff, + psDevInfo->psKernelCCBEventKickerMemInfo, 0, + sizeof(u32), ui32PDumpFlags, + MAKEUNIQUETAG(psDevInfo-> + psKernelCCBEventKickerMemInfo)); + PDUMPCOMMENTWITHFLAGS(0, "Event kick\r\n"); + PDUMPREGWITHFLAGS(SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK, 0), + EUR_CR_EVENT_KICK_NOW_MASK, 0); + } +#endif + *psDevInfo->pui32KernelCCBEventKicker = + (*psDevInfo->pui32KernelCCBEventKicker + 1) & 0xFF; + OSWriteHWReg(psDevInfo->pvRegsBaseKM, + SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK, 0), + EUR_CR_EVENT_KICK_NOW_MASK); + +#if defined(NO_HARDWARE) + + *psKernelCCB->pui32ReadOffset = + (*psKernelCCB->pui32ReadOffset + 1) & 255; +#endif + +Exit: + return eError; +} + +enum PVRSRV_ERROR SGXScheduleCCBCommandKM( + struct PVRSRV_DEVICE_NODE *psDeviceNode, + enum SGXMKIF_COMMAND_TYPE eCommandType, + struct SGXMKIF_COMMAND *psCommandData, + u32 ui32CallerID, u32 ui32PDumpFlags) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + + PDUMPSUSPEND(); + + pvr_dev_lock(); + + eError = + PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex, + PVRSRV_POWER_STATE_D0); + + PDUMPRESUME(); + + if (eError == PVRSRV_OK) { + psDeviceNode->bReProcessDeviceCommandComplete = IMG_FALSE; + } else { + PVR_DPF(PVR_DBG_ERROR, "%s: can't power on device (%d)", + __func__, eError); + pvr_dev_unlock(); + return eError; + } + + eError = SGXScheduleCCBCommand(psDevInfo, eCommandType, psCommandData, + ui32CallerID, ui32PDumpFlags); + + if (ui32CallerID != ISR_ID) + SGXTestActivePowerEvent(psDeviceNode); + + pvr_dev_unlock(); + + return eError; +} + +enum PVRSRV_ERROR SGXScheduleProcessQueues(struct PVRSRV_DEVICE_NODE + *psDeviceNode) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + struct SGXMKIF_HOST_CTL *psHostCtl = + psDevInfo->psKernelSGXHostCtlMemInfo->pvLinAddrKM; + u32 ui32PowerStatus; + struct SGXMKIF_COMMAND sCommand = { 0 }; + + ui32PowerStatus = psHostCtl->ui32PowerStatus; + if ((ui32PowerStatus & PVRSRV_USSE_EDM_POWMAN_NO_WORK) != 0) + return PVRSRV_OK; + + eError = + PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex, + PVRSRV_POWER_STATE_D0); + if (eError != PVRSRV_OK) + return eError; + + sCommand.ui32Data[0] = PVRSRV_CCBFLAGS_PROCESS_QUEUESCMD; + eError = SGXScheduleCCBCommand(psDeviceNode->pvDevice, + SGXMKIF_COMMAND_EDM_KICK, &sCommand, + ISR_ID, 0); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "%s failed to schedule CCB command: %lu", + __func__, eError); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXScheduleProcessQueuesKM(struct PVRSRV_DEVICE_NODE + *psDeviceNode) +{ + enum PVRSRV_ERROR eError; + + pvr_dev_lock(); + eError = SGXScheduleProcessQueues(psDeviceNode); + pvr_dev_unlock(); + + return eError; +} + +IMG_BOOL SGXIsDevicePowered(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + return PVRSRVIsDevicePowered(psDeviceNode->sDevId.ui32DeviceIndex); +} + +enum PVRSRV_ERROR SGXGetInternalDevInfoKM(void *hDevCookie, + struct SGX_INTERNAL_DEVINFO + *psSGXInternalDevInfo) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo = (struct PVRSRV_SGXDEV_INFO *) + ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice; + + psSGXInternalDevInfo->ui32Flags = psDevInfo->ui32Flags; + psSGXInternalDevInfo->bForcePTOff = (IMG_BOOL)psDevInfo->bForcePTOff; + + psSGXInternalDevInfo->hHostCtlKernelMemInfoHandle = + (void *)psDevInfo->psKernelSGXHostCtlMemInfo; + + return PVRSRV_OK; +} + +#if defined(PDUMP) && !defined(EDM_USSE_HWDEBUG) +#define PDUMP_SGX_CLEANUP +#endif + +void SGXCleanupRequest(struct PVRSRV_DEVICE_NODE *psDeviceNode, + struct IMG_DEV_VIRTADDR *psHWDataDevVAddr, + u32 ui32ResManRequestFlag) +{ + struct PVRSRV_SGXDEV_INFO *psSGXDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + struct PVRSRV_KERNEL_MEM_INFO *psSGXHostCtlMemInfo = + psSGXDevInfo->psKernelSGXHostCtlMemInfo; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + (struct SGXMKIF_HOST_CTL __iomem __force *) + psSGXHostCtlMemInfo->pvLinAddrKM; +#if defined(PDUMP_SGX_CLEANUP) + void *hUniqueTag = MAKEUNIQUETAG(psSGXHostCtlMemInfo); +#endif + u32 l; + + pvr_dev_lock(); + if (readl(&psSGXHostCtl->ui32PowerStatus) & + PVRSRV_USSE_EDM_POWMAN_NO_WORK) { + ; + } else { + if (psSGXDevInfo->ui32CacheControl & + SGX_BIF_INVALIDATE_PDCACHE) { + l = readl(&psSGXHostCtl->ui32ResManFlags); + l |= PVRSRV_USSE_EDM_RESMAN_CLEANUP_INVALPD; + writel(l, &psSGXHostCtl->ui32ResManFlags); + + psSGXDevInfo->ui32CacheControl ^= + SGX_BIF_INVALIDATE_PDCACHE; + } + if (psSGXDevInfo->ui32CacheControl & + SGX_BIF_INVALIDATE_PTCACHE) { + l = readl(&psSGXHostCtl->ui32ResManFlags); + l |= PVRSRV_USSE_EDM_RESMAN_CLEANUP_INVALPT; + writel(l, &psSGXHostCtl->ui32ResManFlags); + + psSGXDevInfo->ui32CacheControl ^= + SGX_BIF_INVALIDATE_PTCACHE; + } + + if (psHWDataDevVAddr == NULL) + writel(0, &psSGXHostCtl->sResManCleanupData.uiAddr); + else + writel(psHWDataDevVAddr->uiAddr, + &psSGXHostCtl->sResManCleanupData.uiAddr); + + l = readl(&psSGXHostCtl->ui32ResManFlags); + l |= ui32ResManRequestFlag; + writel(l, &psSGXHostCtl->ui32ResManFlags); + +#if defined(PDUMP_SGX_CLEANUP) + + PDUMPCOMMENTWITHFLAGS(0, + "TA/3D CCB Control - Request clean-up event on uKernel..."); + PDUMPMEM(NULL, psSGXHostCtlMemInfo, + offsetof(struct SGXMKIF_HOST_CTL, + sResManCleanupData.uiAddr), sizeof(u32), 0, + hUniqueTag); + PDUMPMEM(&ui32ResManRequestFlag, psSGXHostCtlMemInfo, + offsetof(struct SGXMKIF_HOST_CTL, ui32ResManFlags), + sizeof(u32), 0, hUniqueTag); +#else + PDUMPCOMMENTWITHFLAGS(0, "Clean-up event on uKernel disabled"); +#endif + + SGXScheduleProcessQueues(psDeviceNode); + +#if !defined(NO_HARDWARE) + if (PollForValueKM(&psSGXHostCtl->ui32ResManFlags, + PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE, + PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE, + MAX_HW_TIME_US / WAIT_TRY_COUNT, + WAIT_TRY_COUNT) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXCleanupRequest: " + "Wait for uKernel to clean up failed"); + PVR_DBG_BREAK; + } +#endif + +#if defined(PDUMP_SGX_CLEANUP) + + PDUMPCOMMENTWITHFLAGS(0, "TA/3D CCB Control - " + "Wait for clean-up request to complete..."); + PDUMPMEMPOL(psSGXHostCtlMemInfo, + offsetof(struct SGXMKIF_HOST_CTL, ui32ResManFlags), + PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE, + PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE, + PDUMP_POLL_OPERATOR_EQUAL, IMG_FALSE, IMG_FALSE, + hUniqueTag); +#endif + + l = readl(&psSGXHostCtl->ui32ResManFlags); + l &= ~ui32ResManRequestFlag; + writel(l, &psSGXHostCtl->ui32ResManFlags); + + l = readl(&psSGXHostCtl->ui32ResManFlags); + l &= ~PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE; + writel(l, &psSGXHostCtl->ui32ResManFlags); + +#if defined(PDUMP_SGX_CLEANUP) + PDUMPMEM(NULL, psSGXHostCtlMemInfo, + offsetof(struct SGXMKIF_HOST_CTL, ui32ResManFlags), + sizeof(u32), 0, hUniqueTag); +#endif + } + pvr_dev_unlock(); +} + +struct SGX_HW_RENDER_CONTEXT_CLEANUP { + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct IMG_DEV_VIRTADDR sHWRenderContextDevVAddr; + void *hBlockAlloc; + struct RESMAN_ITEM *psResItem; +}; + +static enum PVRSRV_ERROR SGXCleanupHWRenderContextCallback(void *pvParam, + u32 ui32Param) +{ + struct SGX_HW_RENDER_CONTEXT_CLEANUP *psCleanup = pvParam; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + SGXCleanupRequest(psCleanup->psDeviceNode, + &psCleanup->sHWRenderContextDevVAddr, + PVRSRV_USSE_EDM_RESMAN_CLEANUP_RC_REQUEST); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct SGX_HW_RENDER_CONTEXT_CLEANUP), + psCleanup, psCleanup->hBlockAlloc); + + return PVRSRV_OK; +} + +struct SGX_HW_TRANSFER_CONTEXT_CLEANUP { + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct IMG_DEV_VIRTADDR sHWTransferContextDevVAddr; + void *hBlockAlloc; + struct RESMAN_ITEM *psResItem; +}; + +static enum PVRSRV_ERROR SGXCleanupHWTransferContextCallback(void *pvParam, + u32 ui32Param) +{ + struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *psCleanup = + (struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *)pvParam; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + SGXCleanupRequest(psCleanup->psDeviceNode, + &psCleanup->sHWTransferContextDevVAddr, + PVRSRV_USSE_EDM_RESMAN_CLEANUP_TC_REQUEST); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct SGX_HW_TRANSFER_CONTEXT_CLEANUP), + psCleanup, psCleanup->hBlockAlloc); + + return PVRSRV_OK; +} + +void *SGXRegisterHWRenderContextKM(void *psDeviceNode, + struct IMG_DEV_VIRTADDR *psHWRenderContextDevVAddr, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + enum PVRSRV_ERROR eError; + void *hBlockAlloc; + struct SGX_HW_RENDER_CONTEXT_CLEANUP *psCleanup; + struct RESMAN_ITEM *psResItem; + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct SGX_HW_RENDER_CONTEXT_CLEANUP), + (void **) &psCleanup, &hBlockAlloc); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXRegisterHWRenderContextKM: " + "Couldn't allocate memory for struct " + "SGX_HW_RENDER_CONTEXT_CLEANUP structure"); + return NULL; + } + + psCleanup->hBlockAlloc = hBlockAlloc; + psCleanup->psDeviceNode = psDeviceNode; + psCleanup->sHWRenderContextDevVAddr = *psHWRenderContextDevVAddr; + + psResItem = ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_HW_RENDER_CONTEXT, + (void *) psCleanup, + 0, &SGXCleanupHWRenderContextCallback); + + if (psResItem == NULL) { + PVR_DPF(PVR_DBG_ERROR, "SGXRegisterHWRenderContextKM: " + "ResManRegisterRes failed"); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct SGX_HW_RENDER_CONTEXT_CLEANUP), + psCleanup, psCleanup->hBlockAlloc); + + return NULL; + } + + psCleanup->psResItem = psResItem; + + return (void *)psCleanup; +} + +enum PVRSRV_ERROR SGXUnregisterHWRenderContextKM(void *hHWRenderContext) +{ + struct SGX_HW_RENDER_CONTEXT_CLEANUP *psCleanup; + + PVR_ASSERT(hHWRenderContext != NULL); + + psCleanup = (struct SGX_HW_RENDER_CONTEXT_CLEANUP *)hHWRenderContext; + + if (psCleanup == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "SGXUnregisterHWRenderContextKM: invalid parameter"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + ResManFreeResByPtr(psCleanup->psResItem); + + return PVRSRV_OK; +} + +void *SGXRegisterHWTransferContextKM(void *psDeviceNode, + struct IMG_DEV_VIRTADDR *psHWTransferContextDevVAddr, + struct PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + enum PVRSRV_ERROR eError; + void *hBlockAlloc; + struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *psCleanup; + struct RESMAN_ITEM *psResItem; + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct SGX_HW_TRANSFER_CONTEXT_CLEANUP), + (void **) &psCleanup, &hBlockAlloc); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXRegisterHWTransferContextKM: " + "Couldn't allocate memory for struct " + "SGX_HW_TRANSFER_CONTEXT_CLEANUP structure"); + return NULL; + } + + psCleanup->hBlockAlloc = hBlockAlloc; + psCleanup->psDeviceNode = psDeviceNode; + psCleanup->sHWTransferContextDevVAddr = *psHWTransferContextDevVAddr; + + psResItem = ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_HW_TRANSFER_CONTEXT, + psCleanup, + 0, &SGXCleanupHWTransferContextCallback); + + if (psResItem == NULL) { + PVR_DPF(PVR_DBG_ERROR, "SGXRegisterHWTransferContextKM: " + "ResManRegisterRes failed"); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct SGX_HW_TRANSFER_CONTEXT_CLEANUP), + psCleanup, psCleanup->hBlockAlloc); + + return NULL; + } + + psCleanup->psResItem = psResItem; + + return (void *)psCleanup; +} + +enum PVRSRV_ERROR SGXUnregisterHWTransferContextKM(void *hHWTransferContext) +{ + struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *psCleanup; + + PVR_ASSERT(hHWTransferContext != NULL); + + psCleanup = + (struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *)hHWTransferContext; + + if (psCleanup == NULL) { + PVR_DPF(PVR_DBG_ERROR, "SGXUnregisterHWTransferContextKM: " + "invalid parameter"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + ResManFreeResByPtr(psCleanup->psResItem); + + return PVRSRV_OK; +} + +static inline IMG_BOOL SGX2DQuerySyncOpsComplete( + struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, + u32 ui32ReadOpsPending, u32 ui32WriteOpsPending) +{ + struct PVRSRV_SYNC_DATA *psSyncData = psSyncInfo->psSyncData; + + return (IMG_BOOL)((psSyncData->ui32ReadOpsComplete >= + ui32ReadOpsPending) && + (psSyncData->ui32WriteOpsComplete >= + ui32WriteOpsPending)); +} + +enum PVRSRV_ERROR SGX2DQueryBlitsCompleteKM( + struct PVRSRV_SGXDEV_INFO *psDevInfo, + struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, + IMG_BOOL bWaitForComplete) +{ + u32 ui32ReadOpsPending, ui32WriteOpsPending; + + PVR_UNREFERENCED_PARAMETER(psDevInfo); + + PVR_DPF(PVR_DBG_CALLTRACE, "SGX2DQueryBlitsCompleteKM: Start"); + + ui32ReadOpsPending = psSyncInfo->psSyncData->ui32ReadOpsPending; + ui32WriteOpsPending = psSyncInfo->psSyncData->ui32WriteOpsPending; + + if (SGX2DQuerySyncOpsComplete + (psSyncInfo, ui32ReadOpsPending, ui32WriteOpsPending)) { + + PVR_DPF(PVR_DBG_CALLTRACE, + "SGX2DQueryBlitsCompleteKM: No wait. Blits complete."); + return PVRSRV_OK; + } + + if (!bWaitForComplete) { + + PVR_DPF(PVR_DBG_CALLTRACE, + "SGX2DQueryBlitsCompleteKM: No wait. Ops pending."); + return PVRSRV_ERROR_CMD_NOT_PROCESSED; + } + + PVR_DPF(PVR_DBG_MESSAGE, + "SGX2DQueryBlitsCompleteKM: Ops pending. Start polling."); + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT); + + if (SGX2DQuerySyncOpsComplete + (psSyncInfo, ui32ReadOpsPending, ui32WriteOpsPending)) { + + PVR_DPF(PVR_DBG_CALLTRACE, + "SGX2DQueryBlitsCompleteKM: " + "Wait over. Blits complete."); + return PVRSRV_OK; + } + } + END_LOOP_UNTIL_TIMEOUT(); + + PVR_DPF(PVR_DBG_ERROR, + "SGX2DQueryBlitsCompleteKM: Timed out. Ops pending."); + +#if defined(CONFIG_PVR_DEBUG_EXTRA) + { + struct PVRSRV_SYNC_DATA *psSyncData = psSyncInfo->psSyncData; + + PVR_TRACE("SGX2DQueryBlitsCompleteKM: " + "Syncinfo: %p, Syncdata: %p", + psSyncInfo, psSyncData); + + PVR_TRACE("SGX2DQueryBlitsCompleteKM: " + "Read ops complete: %d, Read ops pending: %d", + psSyncData->ui32ReadOpsComplete, + psSyncData->ui32ReadOpsPending); + PVR_TRACE("SGX2DQueryBlitsCompleteKM: " + "Write ops complete: %d, Write ops pending: %d", + psSyncData->ui32WriteOpsComplete, + psSyncData->ui32WriteOpsPending); + + } +#endif + return PVRSRV_ERROR_TIMEOUT; +} + +void SGXFlushHWRenderTargetKM(void *psDeviceNode, + struct IMG_DEV_VIRTADDR sHWRTDataSetDevVAddr) +{ + PVR_ASSERT(sHWRTDataSetDevVAddr.uiAddr); + + SGXCleanupRequest((struct PVRSRV_DEVICE_NODE *)psDeviceNode, + &sHWRTDataSetDevVAddr, + PVRSRV_USSE_EDM_RESMAN_CLEANUP_RT_REQUEST); +} + +u32 SGXConvertTimeStamp(struct PVRSRV_SGXDEV_INFO *psDevInfo, u32 ui32TimeWraps, + u32 ui32Time) +{ + u64 ui64Clocks; + u32 ui32Clocksx16; + + ui64Clocks = ((u64) ui32TimeWraps * psDevInfo->ui32uKernelTimerClock) + + (psDevInfo->ui32uKernelTimerClock - + (ui32Time & EUR_CR_EVENT_TIMER_VALUE_MASK)); + ui32Clocksx16 = (u32) (ui64Clocks / 16); + + return ui32Clocksx16; +} diff --git a/drivers/gpu/pvr/sgxutils.h b/drivers/gpu/pvr/sgxutils.h new file mode 100644 index 00000000000..0a9060611e4 --- /dev/null +++ b/drivers/gpu/pvr/sgxutils.h @@ -0,0 +1,78 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "perproc.h" + +#define CCB_OFFSET_IS_VALID(type, psCCBMemInfo, psCCBKick, offset) \ + ((sizeof(type) <= (psCCBMemInfo)->ui32AllocSize) && \ + ((psCCBKick)->offset <= (psCCBMemInfo)->ui32AllocSize - sizeof(type))) + +#define CCB_DATA_FROM_OFFSET(type, psCCBMemInfo, psCCBKick, offset) \ + ((type *)(((char *)(psCCBMemInfo)->pvLinAddrKM) + \ + (psCCBKick)->offset)) + +void SGXTestActivePowerEvent(struct PVRSRV_DEVICE_NODE *psDeviceNode); + +enum PVRSRV_ERROR SGXScheduleCCBCommand( + struct PVRSRV_SGXDEV_INFO *psDevInfo, + enum SGXMKIF_COMMAND_TYPE eCommandType, + struct SGXMKIF_COMMAND *psCommandData, + u32 ui32CallerID, u32 ui32PDumpFlags); +enum PVRSRV_ERROR SGXScheduleCCBCommandKM( + struct PVRSRV_DEVICE_NODE *psDeviceNode, + enum SGXMKIF_COMMAND_TYPE eCommandType, + struct SGXMKIF_COMMAND *psCommandData, + u32 ui32CallerID, u32 ui32PDumpFlags); + +enum PVRSRV_ERROR SGXScheduleProcessQueues( + struct PVRSRV_DEVICE_NODE *psDeviceNode); +enum PVRSRV_ERROR SGXScheduleProcessQueuesKM( + struct PVRSRV_DEVICE_NODE *psDeviceNode); + +IMG_BOOL SGXIsDevicePowered(struct PVRSRV_DEVICE_NODE *psDeviceNode); + +void *SGXRegisterHWRenderContextKM(void *psDeviceNode, + struct IMG_DEV_VIRTADDR *psHWRenderContextDevVAddr, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +void *SGXRegisterHWTransferContextKM(void *psDeviceNode, + struct IMG_DEV_VIRTADDR *psHWTransferContextDevVAddr, + struct PVRSRV_PER_PROCESS_DATA *psPerProc); + +void SGXFlushHWRenderTargetKM(void *psSGXDevInfo, + struct IMG_DEV_VIRTADDR psHWRTDataSetDevVAddr); + +enum PVRSRV_ERROR SGXUnregisterHWRenderContextKM(void *hHWRenderContext); + +enum PVRSRV_ERROR SGXUnregisterHWTransferContextKM(void *hHWTransferContext); + +u32 SGXConvertTimeStamp(struct PVRSRV_SGXDEV_INFO *psDevInfo, + u32 ui32TimeWraps, u32 ui32Time); + +void SGXCleanupRequest(struct PVRSRV_DEVICE_NODE *psDeviceNode, + struct IMG_DEV_VIRTADDR *psHWDataDevVAddr, + u32 ui32ResManRequestFlag); + diff --git a/drivers/gpu/pvr/srvkm.h b/drivers/gpu/pvr/srvkm.h new file mode 100644 index 00000000000..3dbcd24eabd --- /dev/null +++ b/drivers/gpu/pvr/srvkm.h @@ -0,0 +1,50 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef SRVKM_H +#define SRVKM_H + +enum PVRSRV_ERROR PVRSRVProcessConnect(u32 ui32PID); +void PVRSRVProcessDisconnect(u32 ui32PID); + void PVRSRVSetDCState(u32 ui32State); + enum PVRSRV_ERROR PVRSRVSaveRestoreLiveSegments(void *hArena, + u8 *pbyBuffer, + u32 *puiBufSize, + IMG_BOOL bSave); + +#define LOOP_UNTIL_TIMEOUT(TIMEOUT) \ +{ \ + u32 uiOffset, uiStart, uiCurrent; \ + for (uiOffset = 0, uiStart = OSClockus(), uiCurrent = uiStart+1; \ + (uiCurrent - uiStart + uiOffset) < TIMEOUT; \ + uiCurrent = OSClockus(), \ + uiOffset = uiCurrent < uiStart ? \ + IMG_UINT32_MAX - uiStart : uiOffset, \ + uiStart = uiCurrent < uiStart ? 0 : uiStart) + +#define END_LOOP_UNTIL_TIMEOUT() \ +} +#endif diff --git a/drivers/gpu/pvr/syscommon.h b/drivers/gpu/pvr/syscommon.h new file mode 100644 index 00000000000..c55ac3893e5 --- /dev/null +++ b/drivers/gpu/pvr/syscommon.h @@ -0,0 +1,177 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _SYSCOMMON_H +#define _SYSCOMMON_H + +#include "sysconfig.h" +#include "sysinfo.h" +#include "servicesint.h" +#include "queue.h" +#include "power.h" +#include "resman.h" +#include "ra.h" +#include "device.h" +#include "buffer_manager.h" + +#include <linux/platform_device.h> +#include <linux/pvr.h> + +#if defined(NO_HARDWARE) && defined(__KERNEL__) +#include <linux/io.h> +#endif + +struct SYS_DEVICE_ID { + u32 uiID; + IMG_BOOL bInUse; + +}; + +#define SYS_MAX_LOCAL_DEVMEM_ARENAS 4 + +struct SYS_DATA { + u32 ui32NumDevices; + struct SYS_DEVICE_ID sDeviceID[SYS_DEVICE_COUNT]; + struct PVRSRV_DEVICE_NODE *psDeviceNodeList; + struct PVRSRV_POWER_DEV *psPowerDeviceList; + enum PVR_POWER_STATE eCurrentPowerState; + enum PVR_POWER_STATE eFailedPowerState; + u32 ui32CurrentOSPowerState; + struct PVRSRV_QUEUE_INFO *psQueueList; + struct PVRSRV_KERNEL_SYNC_INFO *psSharedSyncInfoList; + void *pvEnvSpecificData; + void *pvSysSpecificData; + void *pvSOCRegsBase; + void *hSOCTimerRegisterOSMemHandle; + u32 *pvSOCTimerRegisterKM; + void *pvSOCClockGateRegsBase; + u32 ui32SOCClockGateRegsSize; + IMG_BOOL (**ppfnCmdProcList[SYS_DEVICE_COUNT])(void *, u32, void *); + + struct COMMAND_COMPLETE_DATA **ppsCmdCompleteData[SYS_DEVICE_COUNT]; + + struct RA_ARENA *apsLocalDevMemArena[SYS_MAX_LOCAL_DEVMEM_ARENAS]; + + char *pszVersionString; + struct PVRSRV_EVENTOBJECT *psGlobalEventObject; +#if defined(PDUMP) + IMG_BOOL bPowerUpPDumped; +#endif +}; + +enum PVRSRV_ERROR SysInitialise(struct platform_device *spd); +enum PVRSRV_ERROR SysFinalise(void); + +enum PVRSRV_ERROR SysDeinitialise(struct SYS_DATA *psSysData); + +enum PVRSRV_ERROR SysGetDeviceMemoryMap(enum PVRSRV_DEVICE_TYPE eDeviceType, + void **ppvDeviceMap); + +void SysRegisterExternalDevice(struct PVRSRV_DEVICE_NODE *psDeviceNode); +void SysRemoveExternalDevice(struct PVRSRV_DEVICE_NODE *psDeviceNode); + +u32 SysGetInterruptSource(struct SYS_DATA *psSysData, + struct PVRSRV_DEVICE_NODE *psDeviceNode); + +void SysClearInterrupts(struct SYS_DATA *psSysData, + u32 ui32ClearBits); + +enum PVRSRV_ERROR SysResetDevice(u32 ui32DeviceIndex); + +enum PVRSRV_ERROR SysSystemPrePowerState(enum PVR_POWER_STATE eNewPowerState); +enum PVRSRV_ERROR SysSystemPostPowerState(enum PVR_POWER_STATE eNewPowerState); +enum PVRSRV_ERROR SysDevicePrePowerState(u32 ui32DeviceIndex, + enum PVR_POWER_STATE eNewPowerState, + enum PVR_POWER_STATE eCurrentPowerState); +enum PVRSRV_ERROR SysDevicePostPowerState(u32 ui32DeviceIndex, + enum PVR_POWER_STATE eNewPowerState, + enum PVR_POWER_STATE + eCurrentPowerState); + +enum PVRSRV_ERROR SysOEMFunction(u32 ui32ID, + void *pvIn, + u32 ulInSize, + void *pvOut, u32 ulOutSize); + +struct IMG_DEV_PHYADDR SysCpuPAddrToDevPAddr( + enum PVRSRV_DEVICE_TYPE eDeviceType, + struct IMG_CPU_PHYADDR cpu_paddr); +struct IMG_DEV_PHYADDR SysSysPAddrToDevPAddr( + enum PVRSRV_DEVICE_TYPE eDeviceType, + struct IMG_SYS_PHYADDR SysPAddr); +struct IMG_SYS_PHYADDR SysDevPAddrToSysPAddr( + enum PVRSRV_DEVICE_TYPE eDeviceType, + struct IMG_DEV_PHYADDR SysPAddr); +struct IMG_CPU_PHYADDR SysSysPAddrToCpuPAddr(struct IMG_SYS_PHYADDR SysPAddr); +struct IMG_SYS_PHYADDR SysCpuPAddrToSysPAddr(struct IMG_CPU_PHYADDR cpu_paddr); + +extern struct SYS_DATA *gpsSysData; + + +static inline enum PVRSRV_ERROR SysAcquireData(struct SYS_DATA **ppsSysData) +{ + *ppsSysData = gpsSysData; + + if (!gpsSysData) + return PVRSRV_ERROR_GENERIC; + + return PVRSRV_OK; +} + +static inline enum PVRSRV_ERROR SysInitialiseCommon(struct SYS_DATA *psSysData) +{ + enum PVRSRV_ERROR eError; + eError = PVRSRVInit(psSysData); + return eError; +} + +static inline void SysDeinitialiseCommon(struct SYS_DATA *psSysData) +{ + PVRSRVDeInit(psSysData); +} + +#if !(defined(NO_HARDWARE) && defined(__KERNEL__)) +#define SysReadHWReg(p, o) OSReadHWReg(p, o) +#define SysWriteHWReg(p, o, v) OSWriteHWReg(p, o, v) +#else +static inline u32 SysReadHWReg(void *pvLinRegBaseAddr, u32 ui32Offset) +{ + return (u32)readl(pvLinRegBaseAddr + ui32Offset); +} + +static inline void SysWriteHWReg(void *pvLinRegBaseAddr, u32 ui32Offset, + u32 ui32Value) +{ + writel(ui32Value, pvLinRegBaseAddr + ui32Offset); +} +#endif + +bool sgx_is_530(void); +u32 sgx_get_rev(void); +void sgx_ocp_write_reg(u32 reg, u32 val); +unsigned long sgx_get_max_freq(void); + +#endif diff --git a/drivers/gpu/pvr/sysconfig.c b/drivers/gpu/pvr/sysconfig.c new file mode 100644 index 00000000000..8ce48e4efb7 --- /dev/null +++ b/drivers/gpu/pvr/sysconfig.c @@ -0,0 +1,836 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/platform_device.h> + +#include "services_headers.h" +#include "kerneldisplay.h" +#include "oemfuncs.h" +#include "sgxinfo.h" +#include "pdump_km.h" +#include "sgxinfokm.h" +#include "syslocal.h" +#include "sysconfig.h" +#include "syscommon.h" +#include "img_types.h" +#include "ocpdefs.h" +#include "pvr_bridge_km.h" + +struct SYS_DATA *gpsSysData; +static struct SYS_DATA gsSysData; + +static struct SYS_SPECIFIC_DATA gsSysSpecificData; +struct SYS_SPECIFIC_DATA *gpsSysSpecificData; + +static u32 gui32SGXDeviceID; +static struct SGX_DEVICE_MAP gsSGXDeviceMap; +static struct PVRSRV_DEVICE_NODE *gpsSGXDevNode; + +#define DEVICE_SGX_INTERRUPT (1 << 0) + +#if defined(NO_HARDWARE) +static void *gsSGXRegsCPUVAddr; +#endif + +static void __iomem *ocp_base; + +static enum PVRSRV_ERROR SysLocateDevices(struct SYS_DATA *psSysData) +{ +#if defined(NO_HARDWARE) + enum PVRSRV_ERROR eError; + struct IMG_CPU_PHYADDR sCpuPAddr; +#endif + + PVR_UNREFERENCED_PARAMETER(psSysData); + + gsSGXDeviceMap.ui32Flags = 0x0; + +#if defined(NO_HARDWARE) + + eError = OSBaseAllocContigMemory(SYS_OMAP3430_SGX_REGS_SIZE, + &gsSGXRegsCPUVAddr, &sCpuPAddr); + if (eError != PVRSRV_OK) + return eError; + gsSGXDeviceMap.sRegsCpuPBase = sCpuPAddr; + gsSGXDeviceMap.sRegsSysPBase = + SysCpuPAddrToSysPAddr(gsSGXDeviceMap.sRegsCpuPBase); + gsSGXDeviceMap.ui32RegsSize = SYS_OMAP3430_SGX_REGS_SIZE; + + gsSGXDeviceMap.pvRegsCpuVBase = gsSGXRegsCPUVAddr; + + OSMemSet(gsSGXRegsCPUVAddr, 0, SYS_OMAP3430_SGX_REGS_SIZE); + + gsSGXDeviceMap.ui32IRQ = 0; + +#else + + gsSGXDeviceMap.sRegsSysPBase.uiAddr = + SYS_OMAP3430_SGX_REGS_SYS_PHYS_BASE; + gsSGXDeviceMap.sRegsCpuPBase = + SysSysPAddrToCpuPAddr(gsSGXDeviceMap.sRegsSysPBase); + gsSGXDeviceMap.ui32RegsSize = SYS_OMAP3430_SGX_REGS_SIZE; + + gsSGXDeviceMap.ui32IRQ = SYS_OMAP3430_SGX_IRQ; + +#endif + + return PVRSRV_OK; +} + +#ifndef NO_HARDWARE +u32 sgx_get_rev(void) +{ + /* + * Ugly solution, used until we have proper per device instances + * passed to functions and get rid of most if not all globals. + */ + struct SYS_SPECIFIC_DATA *sysd = gpsSysSpecificData; + void __iomem *regs; + static u32 rev = -1UL; + int err; + + if (rev != -1UL) + return rev; + + regs = OSMapPhysToLin(gsSGXDeviceMap.sRegsCpuPBase, + SYS_OMAP3430_SGX_REGS_SIZE, + PVRSRV_HAP_UNCACHED | PVRSRV_HAP_KERNEL_ONLY, + NULL); + if (!regs) + return 0; + + err = clk_enable(sysd->psSGX_FCK); + BUG_ON(err); + err = clk_enable(sysd->psSGX_ICK); + BUG_ON(err); + + rev = OSReadHWReg(regs, EUR_CR_CORE_REVISION); + + clk_disable(sysd->psSGX_ICK); + clk_disable(sysd->psSGX_FCK); + + OSUnMapPhysToLin(regs, SYS_OMAP3430_SGX_REGS_SIZE, + PVRSRV_HAP_UNCACHED | PVRSRV_HAP_KERNEL_ONLY, NULL); + + return rev; +} + +unsigned long sgx_get_max_freq(void) +{ + struct SYS_SPECIFIC_DATA *sysd = gpsSysSpecificData; + + BUG_ON(!sysd); + + if (sysd->sgx_fck_max) + return sysd->sgx_fck_max; + + /* + * In case there's no board specific setting for this, return + * some revision specific defaults. + */ + if (sgx_is_530()) { + switch (sgx_get_rev()) { + case EUR_CR_CORE_MAKE_REV(1, 2, 1): + return SYS_SGX_MAX_FREQ_530R121; + case EUR_CR_CORE_MAKE_REV(1, 2, 5): + return SYS_SGX_MAX_FREQ_530R125; + } + } + BUG(); +} + +#else + +u32 sgx_get_rev(void) +{ + return 0; +} + +unsigned long sgx_get_max_freq() +{ + return SYS_SGX_MAX_FREQ_NO_HW; +} + +#endif + +bool sgx_is_530(void) +{ +#ifdef SGX530 + return true; +#endif + return false; +} + +char *SysCreateVersionString(struct IMG_CPU_PHYADDR sRegRegion) +{ + static char aszVersionString[100]; + struct SYS_DATA *psSysData; + u32 ui32SGXRevision; + s32 i32Count; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return NULL; + + ui32SGXRevision = sgx_get_rev(); + + i32Count = OSSNPrintf(aszVersionString, 100, + "SGX revision = %u.%u.%u", + (unsigned)((ui32SGXRevision & + EUR_CR_CORE_REVISION_MAJOR_MASK) + >> EUR_CR_CORE_REVISION_MAJOR_SHIFT), + (unsigned)((ui32SGXRevision & + EUR_CR_CORE_REVISION_MINOR_MASK) + >> EUR_CR_CORE_REVISION_MINOR_SHIFT), + (unsigned)((ui32SGXRevision & + EUR_CR_CORE_REVISION_MAINTENANCE_MASK) + >> EUR_CR_CORE_REVISION_MAINTENANCE_SHIFT) + ); + + if (i32Count == -1) + return NULL; + + return aszVersionString; +} + +static int sgx_ocp_init(void) +{ + struct IMG_SYS_PHYADDR sys_pbase; + struct IMG_CPU_PHYADDR cpu_pbase; + + sys_pbase.uiAddr = SYS_OMAP3430_OCP_REGS_SYS_PHYS_BASE; + cpu_pbase = SysSysPAddrToCpuPAddr(sys_pbase); + + ocp_base = OSMapPhysToLin(cpu_pbase, SYS_OMAP3430_OCP_REGS_SIZE, + PVRSRV_HAP_UNCACHED | PVRSRV_HAP_KERNEL_ONLY, + NULL); + + if (!ocp_base) { + PVR_DPF(PVR_DBG_ERROR, "%s: Failed to map OCP registers", + __func__); + return -ENOMEM; + } + + return 0; +} + +static void sgx_ocp_cleanup(void) +{ + OSUnMapPhysToLin(ocp_base, SYS_OMAP3430_OCP_REGS_SIZE, + PVRSRV_HAP_UNCACHED | PVRSRV_HAP_KERNEL_ONLY, NULL); +} + +void sgx_ocp_write_reg(u32 reg, u32 val) +{ + BUG_ON(!ocp_base); + + /* OCP offsets are based at EUR_CR_OCP_REVISION */ + reg -= EUR_CR_OCP_REVISION; + OSWriteHWReg(ocp_base, reg, val); +} + +enum PVRSRV_ERROR SysInitialise(struct platform_device *pdev) +{ + u32 i; + enum PVRSRV_ERROR eError; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct IMG_CPU_PHYADDR TimerRegPhysBase; + struct sgx_platform_data *spd; + + gpsSysData = &gsSysData; + + gpsSysSpecificData = &gsSysSpecificData; + + gpsSysData->pvSysSpecificData = gpsSysSpecificData; + + spd = pdev->dev.platform_data; + if (spd) + gpsSysSpecificData->sgx_fck_max = spd->fclock_max; + + eError = OSInitEnvData(&gpsSysData->pvEnvSpecificData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed to setup env structure"); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_ENVDATA); + + gpsSysData->ui32NumDevices = SYS_DEVICE_COUNT; + + for (i = 0; i < SYS_DEVICE_COUNT; i++) { + gpsSysData->sDeviceID[i].uiID = i; + gpsSysData->sDeviceID[i].bInUse = IMG_FALSE; + } + + gpsSysData->psDeviceNodeList = NULL; + gpsSysData->psQueueList = NULL; + + eError = SysInitialiseCommon(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed in SysInitialiseCommon"); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + + TimerRegPhysBase.uiAddr = + SYS_OMAP3430_GP11TIMER_PHYS_BASE + SYS_OMAP3430_GPTIMER_REGS; + gpsSysData->pvSOCTimerRegisterKM = NULL; + gpsSysData->hSOCTimerRegisterOSMemHandle = NULL; + OSReservePhys(TimerRegPhysBase, 4, + PVRSRV_HAP_MULTI_PROCESS | PVRSRV_HAP_UNCACHED, + (void **)&gpsSysData->pvSOCTimerRegisterKM, + &gpsSysData->hSOCTimerRegisterOSMemHandle); + + gpsSysSpecificData->ui32SrcClockDiv = 3; + + eError = SysLocateDevices(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed to locate devices"); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_LOCATEDEV); + + if (sgx_ocp_init() < 0) { + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + + return PVRSRV_ERROR_GENERIC; + } + + eError = PVRSRVRegisterDevice(gpsSysData, SGXRegisterDevice, + DEVICE_SGX_INTERRUPT, &gui32SGXDeviceID); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed to register device!"); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_REGDEV); + + psDeviceNode = gpsSysData->psDeviceNodeList; + while (psDeviceNode) { + switch (psDeviceNode->sDevId.eDeviceType) { + case PVRSRV_DEVICE_TYPE_SGX: + { + struct DEVICE_MEMORY_INFO *psDevMemoryInfo; + struct DEVICE_MEMORY_HEAP_INFO + *psDeviceMemoryHeap; + + psDeviceNode->psLocalDevMemArena = NULL; + + psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; + psDeviceMemoryHeap = + psDevMemoryInfo->psDeviceMemoryHeap; + + for (i = 0; i < psDevMemoryInfo->ui32HeapCount; + i++) + psDeviceMemoryHeap[i].ui32Attribs |= + PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG; + + gpsSGXDevNode = psDeviceNode; + gsSysSpecificData.psSGXDevNode = psDeviceNode; + + break; + } + default: + PVR_DPF(PVR_DBG_ERROR, "SysInitialise: " + "Failed to find SGX device node!"); + return PVRSRV_ERROR_INIT_FAILURE; + } + + psDeviceNode = psDeviceNode->psNext; + } + + PDUMPINIT(); + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_PDUMPINIT); + + eError = InitSystemClocks(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed to init system clocks (%d)", + eError); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + + eError = EnableSystemClocks(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed to Enable system clocks (%d)", + eError); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS); + + eError = OSInitPerf(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed to init DVFS (%d)", eError); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_PERF); + + eError = EnableSGXClocks(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed to Enable SGX clocks (%d)", + eError); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + + eError = PVRSRVInitialiseDevice(gui32SGXDeviceID); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed to initialise device!"); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_INITDEV); + + gpsSysData->pszVersionString = + SysCreateVersionString(gsSGXDeviceMap.sRegsCpuPBase); + if (!gpsSysData->pszVersionString) + PVR_DPF(PVR_DBG_ERROR, + "SysFinalise: Failed to create a system version string"); + else + PVR_DPF(PVR_DBG_WARNING, "SysFinalise: Version string: %s", + gpsSysData->pszVersionString); + + DisableSGXClocks(gpsSysData); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SysFinalise(void) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + eError = EnableSGXClocks(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysInitialise: Failed to Enable SGX clocks (%d)", + eError); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + + + eError = OSInstallMISR(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SysFinalise: Failed to install MISR"); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_MISR); + + eError = + OSInstallDeviceLISR(gpsSysData, gsSGXDeviceMap.ui32IRQ, "SGX ISR", + gpsSGXDevNode); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SysFinalise: Failed to install ISR"); + SysDeinitialise(gpsSysData); + gpsSysData = NULL; + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_LISR); + + DisableSGXClocks(gpsSysData); + + gpsSysSpecificData->bSGXInitComplete = IMG_TRUE; + + return eError; +} + +enum PVRSRV_ERROR SysDeinitialise(struct SYS_DATA *psSysData) +{ + enum PVRSRV_ERROR eError; + + if (SYS_SPECIFIC_DATA_TEST + (gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LISR)) { + eError = OSUninstallDeviceLISR(psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SysDeinitialise: " + "OSUninstallDeviceLISR failed"); + return eError; + } + } + + if (SYS_SPECIFIC_DATA_TEST + (gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_MISR)) { + eError = OSUninstallMISR(psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SysDeinitialise: " + "OSUninstallMISR failed"); + return eError; + } + } + + if (SYS_SPECIFIC_DATA_TEST + (gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_INITDEV)) { + PVR_ASSERT(SYS_SPECIFIC_DATA_TEST + (gpsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS)); + + eError = EnableSGXClocks(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysDeinitialise: EnableSGXClocks failed"); + return eError; + } + + eError = PVRSRVDeinitialiseDevice(gui32SGXDeviceID); + + DisableSGXClocks(gpsSysData); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SysDeinitialise: " + "failed to de-init the device"); + return eError; + } + } + + if (SYS_SPECIFIC_DATA_TEST + (gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS)) + DisableSystemClocks(gpsSysData); + + CleanupSystemClocks(gpsSysData); + + if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_PERF)) { + eError = OSCleanupPerf(psSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysDeinitialise: OSCleanupDvfs failed"); + return eError; + } + } + + sgx_ocp_cleanup(); + + if (SYS_SPECIFIC_DATA_TEST + (gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_ENVDATA)) { + eError = OSDeInitEnvData(gpsSysData->pvEnvSpecificData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysDeinitialise: failed to de-init env structure"); + return eError; + } + } + + if (gpsSysData->pvSOCTimerRegisterKM) + OSUnReservePhys(gpsSysData->pvSOCTimerRegisterKM, 4, + PVRSRV_HAP_MULTI_PROCESS | PVRSRV_HAP_UNCACHED, + gpsSysData->hSOCTimerRegisterOSMemHandle); + + SysDeinitialiseCommon(gpsSysData); + +#if defined(NO_HARDWARE) + if (SYS_SPECIFIC_DATA_TEST + (gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LOCATEDEV)) + + OSBaseFreeContigMemory(SYS_OMAP3430_SGX_REGS_SIZE, + gsSGXRegsCPUVAddr, + gsSGXDeviceMap.sRegsCpuPBase); +#endif + + if (SYS_SPECIFIC_DATA_TEST + (gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_PDUMPINIT)) + PDUMPDEINIT(); + + gpsSysSpecificData->ui32SysSpecificData = 0; + gpsSysSpecificData->bSGXInitComplete = IMG_FALSE; + + gpsSysData = NULL; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SysGetDeviceMemoryMap(enum PVRSRV_DEVICE_TYPE eDeviceType, + void **ppvDeviceMap) +{ + switch (eDeviceType) { + case PVRSRV_DEVICE_TYPE_SGX: + *ppvDeviceMap = (void *) &gsSGXDeviceMap; + break; + default: + PVR_DPF(PVR_DBG_ERROR, "SysGetDeviceMemoryMap: " + "unsupported device type"); + } + return PVRSRV_OK; +} + +struct IMG_DEV_PHYADDR SysCpuPAddrToDevPAddr( + enum PVRSRV_DEVICE_TYPE eDeviceType, + struct IMG_CPU_PHYADDR CpuPAddr) +{ + struct IMG_DEV_PHYADDR DevPAddr; + + PVR_UNREFERENCED_PARAMETER(eDeviceType); + + DevPAddr.uiAddr = CpuPAddr.uiAddr; + + return DevPAddr; +} + +struct IMG_CPU_PHYADDR SysSysPAddrToCpuPAddr(struct IMG_SYS_PHYADDR sys_paddr) +{ + struct IMG_CPU_PHYADDR cpu_paddr; + + cpu_paddr.uiAddr = sys_paddr.uiAddr; + return cpu_paddr; +} + +struct IMG_SYS_PHYADDR SysCpuPAddrToSysPAddr(struct IMG_CPU_PHYADDR cpu_paddr) +{ + struct IMG_SYS_PHYADDR sys_paddr; + + sys_paddr.uiAddr = cpu_paddr.uiAddr; + return sys_paddr; +} + +struct IMG_DEV_PHYADDR SysSysPAddrToDevPAddr( + enum PVRSRV_DEVICE_TYPE eDeviceType, + struct IMG_SYS_PHYADDR SysPAddr) +{ + struct IMG_DEV_PHYADDR DevPAddr; + + PVR_UNREFERENCED_PARAMETER(eDeviceType); + + DevPAddr.uiAddr = SysPAddr.uiAddr; + + return DevPAddr; +} + +struct IMG_SYS_PHYADDR SysDevPAddrToSysPAddr( + enum PVRSRV_DEVICE_TYPE eDeviceType, + struct IMG_DEV_PHYADDR DevPAddr) +{ + struct IMG_SYS_PHYADDR SysPAddr; + + PVR_UNREFERENCED_PARAMETER(eDeviceType); + + SysPAddr.uiAddr = DevPAddr.uiAddr; + + return SysPAddr; +} + +void SysRegisterExternalDevice(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + PVR_UNREFERENCED_PARAMETER(psDeviceNode); +} + +void SysRemoveExternalDevice(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + PVR_UNREFERENCED_PARAMETER(psDeviceNode); +} + +u32 SysGetInterruptSource(struct SYS_DATA *psSysData, + struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + PVR_UNREFERENCED_PARAMETER(psSysData); +#if defined(NO_HARDWARE) + + return 0xFFFFFFFF; +#else + + return psDeviceNode->ui32SOCInterruptBit; +#endif +} + +void SysClearInterrupts(struct SYS_DATA *psSysData, u32 ui32ClearBits) +{ + PVR_UNREFERENCED_PARAMETER(psSysData); + PVR_UNREFERENCED_PARAMETER(ui32ClearBits); + + OSReadHWReg(((struct PVRSRV_SGXDEV_INFO *)gpsSGXDevNode->pvDevice)-> + pvRegsBaseKM, EUR_CR_EVENT_HOST_CLEAR); +} + +enum PVRSRV_ERROR SysSystemPrePowerState(enum PVR_POWER_STATE eNewPowerState) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (eNewPowerState == PVRSRV_POWER_STATE_D3) { + PVR_TRACE("SysSystemPrePowerState: Entering state D3"); + + if (SYS_SPECIFIC_DATA_TEST + (&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LISR)) { + eError = OSUninstallDeviceLISR(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysSystemPrePowerState: " + "OSUninstallDeviceLISR failed " + "(%d)", + eError); + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_PM_UNINSTALL_LISR); + SYS_SPECIFIC_DATA_CLEAR(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_LISR); + } + + if (SYS_SPECIFIC_DATA_TEST + (&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS)) { + DisableSystemClocks(gpsSysData); + + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_PM_DISABLE_SYSCLOCKS); + SYS_SPECIFIC_DATA_CLEAR(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS); + } + } + + return eError; +} + +enum PVRSRV_ERROR SysSystemPostPowerState(enum PVR_POWER_STATE eNewPowerState) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + if (eNewPowerState == PVRSRV_POWER_STATE_D0) { + PVR_TRACE("SysSystemPostPowerState: Entering state D0"); + + if (SYS_SPECIFIC_DATA_TEST + (&gsSysSpecificData, + SYS_SPECIFIC_DATA_PM_DISABLE_SYSCLOCKS)) { + eError = EnableSystemClocks(gpsSysData); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysSystemPostPowerState: " + "EnableSystemClocks failed (%d)", + eError); + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS); + SYS_SPECIFIC_DATA_CLEAR(&gsSysSpecificData, + SYS_SPECIFIC_DATA_PM_DISABLE_SYSCLOCKS); + } + if (SYS_SPECIFIC_DATA_TEST + (&gsSysSpecificData, SYS_SPECIFIC_DATA_PM_UNINSTALL_LISR)) { + eError = + OSInstallDeviceLISR(gpsSysData, + gsSGXDeviceMap.ui32IRQ, + "SGX ISR", gpsSGXDevNode); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SysSystemPostPowerState: " + "OSInstallDeviceLISR failed " + "to install ISR (%d)", + eError); + return eError; + } + SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, + SYS_SPECIFIC_DATA_ENABLE_LISR); + SYS_SPECIFIC_DATA_CLEAR(&gsSysSpecificData, + SYS_SPECIFIC_DATA_PM_UNINSTALL_LISR); + } + } + return eError; +} + +enum PVRSRV_ERROR SysDevicePrePowerState(u32 ui32DeviceIndex, + enum PVR_POWER_STATE eNewPowerState, + enum PVR_POWER_STATE eCurrentPowerState) +{ + PVR_UNREFERENCED_PARAMETER(eCurrentPowerState); + + if (ui32DeviceIndex != gui32SGXDeviceID) + return PVRSRV_OK; + if (eNewPowerState == PVRSRV_POWER_STATE_D3) { + PVR_DPF(PVR_DBG_MESSAGE, + "SysDevicePrePowerState: SGX Entering state D3"); + DisableSGXClocks(gpsSysData); + } + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SysDevicePostPowerState(u32 ui32DeviceIndex, + enum PVR_POWER_STATE eNewPowerState, + enum PVR_POWER_STATE eCurrentPowerState) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + + PVR_UNREFERENCED_PARAMETER(eNewPowerState); + + if (ui32DeviceIndex != gui32SGXDeviceID) + return eError; + if (eCurrentPowerState == PVRSRV_POWER_STATE_D3) { + PVR_DPF(PVR_DBG_MESSAGE, + "SysDevicePostPowerState: SGX Leaving state D3"); + eError = EnableSGXClocks(gpsSysData); + } + + return eError; +} + +enum PVRSRV_ERROR SysOEMFunction(u32 ui32ID, void *pvIn, u32 ulInSize, + void *pvOut, u32 ulOutSize) +{ + PVR_UNREFERENCED_PARAMETER(ui32ID); + PVR_UNREFERENCED_PARAMETER(pvIn); + PVR_UNREFERENCED_PARAMETER(ulInSize); + PVR_UNREFERENCED_PARAMETER(pvOut); + PVR_UNREFERENCED_PARAMETER(ulOutSize); + + if ((ui32ID == OEM_GET_EXT_FUNCS) && + (ulOutSize == sizeof(struct PVRSRV_DC_OEM_JTABLE))) { + + struct PVRSRV_DC_OEM_JTABLE *psOEMJTable = + (struct PVRSRV_DC_OEM_JTABLE *)pvOut; + psOEMJTable->pfnOEMBridgeDispatch = &PVRSRV_BridgeDispatchKM; + return PVRSRV_OK; + } + + return PVRSRV_ERROR_INVALID_PARAMS; +} diff --git a/drivers/gpu/pvr/sysconfig.h b/drivers/gpu/pvr/sysconfig.h new file mode 100644 index 00000000000..3ae1c6d00f7 --- /dev/null +++ b/drivers/gpu/pvr/sysconfig.h @@ -0,0 +1,53 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__SOCCONFIG_H__) +#define __SOCCONFIG_H__ + +#include "syscommon.h" + +#define VS_PRODUCT_NAME "OMAP3430" + +#define SYS_SGX_MAX_FREQ_NO_HW 200000000 +#define SYS_SGX_MAX_FREQ_530R121 110000000 +#define SYS_SGX_MAX_FREQ_530R125 200000000 + +#define SYS_SGX_HWRECOVERY_TIMEOUT_FREQ 100 +#define SYS_SGX_PDS_TIMER_FREQ 1000 +#define SYS_SGX_ACTIVE_POWER_LATENCY_MS 1 + +#define SYS_OMAP3430_SGX_REGS_SYS_PHYS_BASE 0x50000000 +#define SYS_OMAP3430_SGX_REGS_SIZE 0x4000 + +#define SYS_OMAP3430_SGX_IRQ 21 + +#define SYS_OMAP3430_GP11TIMER_PHYS_BASE 0x48088000 +#define SYS_OMAP3430_GPTIMER_ENABLE 0x24 +#define SYS_OMAP3430_GPTIMER_REGS 0x28 +#define SYS_OMAP3430_GPTIMER_TSICR 0x40 +#define SYS_OMAP3430_GPTIMER_SIZE 1024 + +#endif diff --git a/drivers/gpu/pvr/sysinfo.h b/drivers/gpu/pvr/sysinfo.h new file mode 100644 index 00000000000..2af219da763 --- /dev/null +++ b/drivers/gpu/pvr/sysinfo.h @@ -0,0 +1,94 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__SYSINFO_H__) +#define __SYSINFO_H__ + +#define MAX_HW_TIME_US 500000 +#define WAIT_TRY_COUNT 10000 + +enum SYS_DEVICE_TYPE { + SYS_DEVICE_SGX = 0, + SYS_DEVICE_FORCE_I16 = 0x7fff +}; + +#define SYS_DEVICE_COUNT 3 + +#define PRM_REG32(offset) (offset) +#define CM_REG32(offset) (offset) + +#define CM_FCLKEN_SGX CM_REG32(0xB00) +#define CM_FCLKEN_SGX_EN_3D 0x00000002 + +#define CM_ICLKEN_SGX CM_REG32(0xB10) +#define CM_ICLKEN_SGX_EN_SGX 0x00000001 + +#define CM_IDLEST_SGX CM_REG32(0xB20) +#define CM_IDLEST_SGX_ST_SGX 0x00000001 + +#define CM_CLKSEL_SGX CM_REG32(0xB40) +#define CM_CLKSEL_SGX_MASK 0x0000000f +#define CM_CLKSEL_SGX_L3DIV3 0x00000000 +#define CM_CLKSEL_SGX_L3DIV4 0x00000001 +#define CM_CLKSEL_SGX_L3DIV6 0x00000002 +#define CM_CLKSEL_SGX_96M 0x00000003 + +#define CM_SLEEPDEP_SGX CM_REG32(0xB44) +#define CM_CLKSTCTRL_SGX CM_REG32(0xB48) +#define CM_CLKSTCTRL_SGX_AUTOSTATE 0x00008001 + +#define CM_CLKSTST_SGX CM_REG32(0xB4C) +#define CM_CLKSTST_SGX_STATUS_VALID 0x00000001 + +#define RM_RSTST_SGX PRM_REG32(0xB58) +#define RM_RSTST_SGX_RST_MASK 0x0000000F +#define RM_RSTST_SGX_COREDOMAINWKUP_RST 0x00000008 +#define RM_RSTST_SGX_DOMAINWKUP_RST 0x00000004 +#define RM_RSTST_SGX_GLOBALWARM_RST 0x00000002 +#define RM_RSTST_SGX_GLOBALCOLD_RST 0x00000001 + +#define PM_WKDEP_SGXi PRM_REG32(0xBC8) +#define PM_WKDEP_SGX_EN_WAKEUP 0x00000010 +#define PM_WKDEP_SGX_EN_MPU 0x00000002 +#define PM_WKDEP_SGX_EN_CORE 0x00000001 + +#define PM_PWSTCTRL_SGX PRM_REG32(0xBE0) +#define PM_PWSTCTRL_SGX_POWERSTATE_MASK 0x00000003 +#define PM_PWSTCTRL_SGX_OFF 0x00000000 +#define PM_PWSTCTRL_SGX_RETENTION 0x00000001 +#define PM_PWSTCTRL_SGX_ON 0x00000003 + +#define PM_PWSTST_SGX PRM_REG32(0xBE4) +#define PM_PWSTST_SGX_INTRANSITION 0x00100000 +#define PM_PWSTST_SGX_CLKACTIVITY 0x00080000 +#define PM_PWSTST_SGX_POWERSTATE_MASK 0x00000003 +#define PM_PWSTST_SGX_OFF 0x00000003 +#define PM_PWSTST_SGX_RETENTION 0x00000001 +#define PM_PWSTST_SGX_ON 0x00000000 + +#define PM_PREPWSTST_SGX PRM_REG32(0xBE8) + +#endif diff --git a/drivers/gpu/pvr/syslocal.h b/drivers/gpu/pvr/syslocal.h new file mode 100644 index 00000000000..0cda586c114 --- /dev/null +++ b/drivers/gpu/pvr/syslocal.h @@ -0,0 +1,100 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#if !defined(__SYSLOCAL_H__) +#define __SYSLOCAL_H__ + +#include <linux/version.h> +#include <linux/clk.h> +#include <linux/spinlock.h> +#include <asm/atomic.h> + +#include <linux/semaphore.h> +#include <linux/resource.h> + +char *SysCreateVersionString(struct IMG_CPU_PHYADDR sRegRegion); + +enum PVRSRV_ERROR InitSystemClocks(struct SYS_DATA *psSysData); +void CleanupSystemClocks(struct SYS_DATA *psSysData); +void DisableSystemClocks(struct SYS_DATA *psSysData); +enum PVRSRV_ERROR EnableSystemClocks(struct SYS_DATA *psSysData); + +void DisableSGXClocks(struct SYS_DATA *psSysData); +enum PVRSRV_ERROR EnableSGXClocks(struct SYS_DATA *psSysData); + +#define SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS 0x00000001 +#define SYS_SPECIFIC_DATA_ENABLE_LISR 0x00000002 +#define SYS_SPECIFIC_DATA_ENABLE_MISR 0x00000004 +#define SYS_SPECIFIC_DATA_ENABLE_ENVDATA 0x00000008 +#define SYS_SPECIFIC_DATA_ENABLE_LOCDEV 0x00000010 +#define SYS_SPECIFIC_DATA_ENABLE_REGDEV 0x00000020 +#define SYS_SPECIFIC_DATA_ENABLE_PDUMPINIT 0x00000040 +#define SYS_SPECIFIC_DATA_ENABLE_INITDEV 0x00000080 +#define SYS_SPECIFIC_DATA_ENABLE_LOCATEDEV 0x00000100 + +#define SYS_SPECIFIC_DATA_PM_UNINSTALL_LISR 0x00000200 +#define SYS_SPECIFIC_DATA_PM_DISABLE_SYSCLOCKS 0x00000400 +#define SYS_SPECIFIC_DATA_ENABLE_PERF 0x00000800 + +#define SYS_SPECIFIC_DATA_SET(psSysSpecData, flag) \ + ((void)((psSysSpecData)->ui32SysSpecificData |= (flag))) + +#define SYS_SPECIFIC_DATA_CLEAR(psSysSpecData, flag) \ + ((void)((psSysSpecData)->ui32SysSpecificData &= ~(flag))) + +#define SYS_SPECIFIC_DATA_TEST(psSysSpecData, flag) \ + (((psSysSpecData)->ui32SysSpecificData & (flag)) != 0) + +struct SYS_SPECIFIC_DATA { + u32 ui32SysSpecificData; + struct PVRSRV_DEVICE_NODE *psSGXDevNode; + IMG_BOOL bSGXInitComplete; + u32 ui32SrcClockDiv; + IMG_BOOL bConstraintNotificationsEnabled; + atomic_t sSGXClocksEnabled; + spinlock_t sPowerLock; + atomic_t sPowerLockCPU; + spinlock_t sNotifyLock; + atomic_t sNotifyLockCPU; + IMG_BOOL bCallVDD2PostFunc; + + struct clk *psCORE_CK; + struct clk *psSGX_FCK; + struct clk *psSGX_ICK; + struct clk *psMPU_CK; +#if defined(CONFIG_PVR_DEBUG_EXTRA) || defined(TIMING) + struct clk *psGPT11_FCK; + struct clk *psGPT11_ICK; + void __iomem *gpt_base; +#endif + struct constraint_handle *pVdd2Handle; + + unsigned long sgx_fck_max; +}; + +extern struct SYS_SPECIFIC_DATA *gpsSysSpecificData; + +#endif diff --git a/drivers/gpu/pvr/sysutils.c b/drivers/gpu/pvr/sysutils.c new file mode 100644 index 00000000000..96870f3bca1 --- /dev/null +++ b/drivers/gpu/pvr/sysutils.c @@ -0,0 +1,731 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/version.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/hardirq.h> +#include <plat/omap-pm.h> +#include <linux/bug.h> +#include <plat/clock.h> +#include <plat/cpu.h> +#include "sgxdefs.h" +#include "services_headers.h" +#include "sysinfo.h" +#include "sgxapi_km.h" +#include "sysconfig.h" +#include "sgxinfokm.h" +#include "syslocal.h" +#include "env_data.h" +#include "ocpdefs.h" +#include "pvr_bridge_km.h" + +#define HZ_TO_MHZ(m) ((m) / 1000000) + +static inline unsigned long scale_by_rate(unsigned long val, + unsigned long rate1, + unsigned long rate2) +{ + if (rate1 >= rate2) + return val * (rate1 / rate2); + + return val / (rate2 / rate1); +} + +static inline unsigned long scale_prop_to_SGX_clock(unsigned long val, + unsigned long rate) +{ + return scale_by_rate(val, rate, sgx_get_max_freq()); +} + +void SysGetSGXTimingInformation(struct SGX_TIMING_INFORMATION *psTimingInfo) +{ + unsigned long rate; + +#if defined(NO_HARDWARE) + rate = SYS_SGX_MAX_FREQ_NO_HW; +#else + rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK); + PVR_ASSERT(rate != 0); +#endif + psTimingInfo->ui32CoreClockSpeed = rate; + psTimingInfo->ui32HWRecoveryFreq = + scale_prop_to_SGX_clock(SYS_SGX_HWRECOVERY_TIMEOUT_FREQ, rate); + psTimingInfo->ui32uKernelFreq = + scale_prop_to_SGX_clock(SYS_SGX_PDS_TIMER_FREQ, rate); + psTimingInfo->ui32ActivePowManLatencyms = + SYS_SGX_ACTIVE_POWER_LATENCY_MS; +} + +static int vdd2_post_func(struct notifier_block *n, unsigned long event, + void *ptr) +{ + PVR_UNREFERENCED_PARAMETER(n); + PVR_UNREFERENCED_PARAMETER(event); + PVR_UNREFERENCED_PARAMETER(ptr); + + if (atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0 && + gpsSysSpecificData->bSGXInitComplete) { +#if defined(CONFIG_PVR_DEBUG_EXTRA) + unsigned long rate; + + rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK); + + PVR_ASSERT(rate != 0); + + PVR_TRACE("%s: SGX clock rate: %dMHz", __func__, + HZ_TO_MHZ(rate)); +#endif + PVRSRVDevicePostClockSpeedChange(gpsSysSpecificData-> + psSGXDevNode->sDevId. + ui32DeviceIndex, IMG_TRUE, + NULL); + } + return 0; +} + +static int vdd2_pre_func(struct notifier_block *n, unsigned long event, + void *ptr) +{ + PVR_UNREFERENCED_PARAMETER(n); + PVR_UNREFERENCED_PARAMETER(event); + PVR_UNREFERENCED_PARAMETER(ptr); + + if (atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0 && + gpsSysSpecificData->bSGXInitComplete) { + BUG_ON(gpsSysData->eCurrentPowerState > PVRSRV_POWER_STATE_D1); + PVRSRVDevicePreClockSpeedChange(gpsSysSpecificData-> + psSGXDevNode->sDevId. + ui32DeviceIndex, IMG_TRUE, + NULL); + } + + return 0; +} + +static int vdd2_pre_post_func(struct notifier_block *n, unsigned long event, + void *ptr) +{ + PVR_UNREFERENCED_PARAMETER(n); + + if (CPUFREQ_PRECHANGE == event) { + pvr_dev_lock(); + PVR_TRACE("vdd2_pre_post_func: CPUFREQ_PRECHANGE event"); + vdd2_pre_func(n, event, ptr); + } else if (CPUFREQ_POSTCHANGE == event) { + PVR_TRACE("vdd2_pre_post_func: CPUFREQ_POSTCHANGE event"); + vdd2_post_func(n, event, ptr); + pvr_dev_unlock(); + } else { + printk(KERN_ERR "vdd2_pre_post_func: unexpected event (%lu)\n", + event); + PVR_DPF(PVR_DBG_ERROR, + "vdd2_pre_post_func: unexpected event (%lu)", event); + } + PVR_TRACE("vdd2_pre_post_func end."); + return 0; +} + +static struct notifier_block vdd2_pre_post = { + vdd2_pre_post_func, + NULL +}; + +static void RegisterConstraintNotifications(struct SYS_SPECIFIC_DATA + *psSysSpecData) +{ + PVR_TRACE("Registering constraint notifications"); + + cpufreq_register_notifier(&vdd2_pre_post, CPUFREQ_TRANSITION_NOTIFIER); + + PVR_TRACE("VDD2 constraint notifications registered"); +} + +static void UnRegisterConstraintNotifications(struct SYS_SPECIFIC_DATA + *psSysSpecData) +{ + PVR_TRACE("Unregistering constraint notifications"); + + cpufreq_unregister_notifier(&vdd2_pre_post, CPUFREQ_TRANSITION_NOTIFIER); +} + +static struct device sgx_dev; +static int sgx_clock_enabled; + +/* return value: current sgx load + * 0 - not busy + * 100 - busy + */ +static unsigned int sgx_current_load(void) +{ + enum PVRSRV_ERROR eError; + struct SYS_DATA *psSysData; + struct SYS_SPECIFIC_DATA *psSysSpecData; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + static unsigned int kicks_prev; + static long time_prev; + + eError = SysAcquireData(&psSysData); + if (eError != PVRSRV_OK) + return 0; + psSysSpecData = + (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData; + if (!psSysSpecData || + atomic_read(&psSysSpecData->sSGXClocksEnabled) == 0) + return 0; + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + if ((psDeviceNode->sDevId.eDeviceType == + PVRSRV_DEVICE_TYPE_SGX) && + psDeviceNode->pvDevice) { + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + unsigned int kicks = psDevInfo->ui32KickTACounter; + unsigned int load; + long time_elapsed; + + time_elapsed = jiffies - time_prev; + if (likely(time_elapsed)) + load = + 1000 * (kicks - kicks_prev) / time_elapsed; + else + load = 0; + kicks_prev = kicks; + time_prev += time_elapsed; + /* + * if the period between calls to this function was + * too long, then load stats are invalid + */ + if (time_elapsed > 5 * HZ) + return 0; + /*pr_err("SGX load %u\n", load); */ + + /* + * 'load' shows how many times sgx was kicked + * per 1000 jiffies + * 150 is arbitrarily chosen threshold. + * If the number of kicks is below threshold + * then sgx is doing + * some small jobs and we can keep the clock freq low. + */ + if (load < 150) + return 0; + else + return 100; + } + psDeviceNode = psDeviceNode->psNext; + } + return 0; +} + +static void sgx_lock_perf(struct work_struct *work) +{ + int vdd1, vdd2; + static int bHigh; + int high; + unsigned int load; + struct delayed_work *d_work = + container_of(work, struct delayed_work, work); + struct ENV_DATA *psEnvData = + container_of(d_work, struct ENV_DATA, sPerfWork); + + pvr_lock(); + + if (pvr_is_disabled()) { + pvr_unlock(); + return; + } + + load = sgx_current_load(); + + pvr_unlock(); + + if (load) { + vdd1 = 500000000; + vdd2 = 400000; + high = 1; + } else { + vdd1 = 0; + vdd2 = 0; + high = 0; + } + if (high != bHigh) { + omap_pm_set_min_bus_tput(&sgx_dev, OCP_INITIATOR_AGENT, vdd2); + bHigh = high; + } + + if (sgx_clock_enabled || load) + queue_delayed_work(psEnvData->psPerfWorkqueue, + &psEnvData->sPerfWork, HZ / 5); +} + +static void sgx_need_perf(struct SYS_DATA *psSysData, int ena) +{ + struct ENV_DATA *psEnvData = + (struct ENV_DATA *)psSysData->pvEnvSpecificData; + + sgx_clock_enabled = ena; + cancel_delayed_work(&psEnvData->sPerfWork); + queue_delayed_work(psEnvData->psPerfWorkqueue, &psEnvData->sPerfWork, + 0); +} + +enum PVRSRV_ERROR OSInitPerf(void *pvSysData) +{ + struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData; + struct ENV_DATA *psEnvData = + (struct ENV_DATA *)psSysData->pvEnvSpecificData; + + if (psEnvData->psPerfWorkqueue) { + PVR_DPF(PVR_DBG_ERROR, "OSInitPerf: already inited"); + return PVRSRV_ERROR_GENERIC; + } + + PVR_TRACE("Initing DVFS %x", pvSysData); + + psEnvData->psPerfWorkqueue = create_singlethread_workqueue("sgx_perf"); + INIT_DELAYED_WORK(&psEnvData->sPerfWork, sgx_lock_perf); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR OSCleanupPerf(void *pvSysData) +{ + struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData; + struct ENV_DATA *psEnvData = + (struct ENV_DATA *)psSysData->pvEnvSpecificData; + + if (!psEnvData->psPerfWorkqueue) { + PVR_DPF(PVR_DBG_ERROR, "OSCleanupPerf: not inited"); + return PVRSRV_ERROR_GENERIC; + } + + PVR_TRACE("Cleaning up DVFS"); + + sgx_clock_enabled = 0; + flush_workqueue(psEnvData->psPerfWorkqueue); + destroy_workqueue(psEnvData->psPerfWorkqueue); + + return PVRSRV_OK; +} + +static inline void setup_int_bypass(void) +{ + if (cpu_is_omap3630()) + sgx_ocp_write_reg(EUR_CR_OCP_DEBUG_CONFIG, + EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_MASK); +} + +#ifndef NO_HARDWARE + +static enum PVRSRV_ERROR sgx_force_enable_clocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = + (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData; + int res; + + res = clk_enable(psSysSpecData->psSGX_FCK); + if (res < 0) { + PVR_DPF(PVR_DBG_ERROR, "%s: " + "Couldn't enable SGX functional clock (%d)", + __func__, res); + return PVRSRV_ERROR_GENERIC; + } + + res = clk_enable(psSysSpecData->psSGX_ICK); + if (res < 0) { + PVR_DPF(PVR_DBG_ERROR, "%s: " + "Couldn't enable SGX interface clock (%d)", + __func__, res); + + clk_disable(psSysSpecData->psSGX_FCK); + return PVRSRV_ERROR_GENERIC; + } + + setup_int_bypass(); + + return PVRSRV_OK; +} + +static void sgx_force_disable_clocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = + (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData; + + if (psSysSpecData->psSGX_ICK) + clk_disable(psSysSpecData->psSGX_ICK); + + if (psSysSpecData->psSGX_FCK) + clk_disable(psSysSpecData->psSGX_FCK); +} + +#else /* NO_HARDWARE */ + +static enum PVRSRV_ERROR sgx_force_enable_clocks(struct SYS_DATA *psSYsData) +{ + return PVRSRV_OK; +} + +static void sgx_force_disable_clocks(struct SYS_DATA *psSYsData) +{ +} + +#endif /* NO_HARDWARE */ + +static bool force_clocks_on(void) +{ +#ifdef CONFIG_PVR_FORCE_CLOCKS_ON + return true; +#else + return false; +#endif +} + +enum PVRSRV_ERROR EnableSGXClocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = + (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData; + enum PVRSRV_ERROR res = PVRSRV_OK; + + if (atomic_xchg(&psSysSpecData->sSGXClocksEnabled, 1)) + return PVRSRV_OK; + + /* + * In case of force clocks on we have already enabled the clocks + * at init time. + */ + if (!force_clocks_on()) + res = sgx_force_enable_clocks(psSysData); + + if (res == PVRSRV_OK) { + BUG_ON(!atomic_read(&psSysSpecData->sSGXClocksEnabled)); + sgx_need_perf(psSysData, 1); + } else { + atomic_set(&psSysSpecData->sSGXClocksEnabled, 0); + } + + return res; +} + +void DisableSGXClocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = + (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData; + + if (!atomic_xchg(&psSysSpecData->sSGXClocksEnabled, 0)) + return; + + if (!force_clocks_on()) + sgx_force_disable_clocks(psSysData); + + BUG_ON(atomic_read(&psSysSpecData->sSGXClocksEnabled)); + + sgx_need_perf(psSysData, 0); +} + +static enum PVRSRV_ERROR InitSgxClocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData; + struct clk *psCLK; + struct clk *core_ck = NULL; + unsigned long rate; + int r; + + psCLK = clk_get(NULL, "sgx_fck"); + if (IS_ERR(psCLK)) + goto err0; + psSysSpecData->psSGX_FCK = psCLK; + + psCLK = clk_get(NULL, "sgx_ick"); + if (IS_ERR(psCLK)) + goto err1; + psSysSpecData->psSGX_ICK = psCLK; + + core_ck = clk_get(NULL, "core_ck"); + if (IS_ERR(core_ck)) + goto err2; + if (clk_set_parent(psSysSpecData->psSGX_FCK, core_ck) < 0) { + clk_put(core_ck); + goto err2; + } + clk_put(core_ck); + + /* +1 to account for rounding errors */ + rate = clk_round_rate(psSysSpecData->psSGX_FCK, sgx_get_max_freq() + 1); + r = clk_set_rate(psSysSpecData->psSGX_FCK, rate); + if (r < 0) { + unsigned long current_rate; + + current_rate = clk_get_rate(psSysSpecData->psSGX_FCK); + pr_warning("error %d when setting SGX fclk to %lu Hz, " + "falling back to %lu Hz\n", r, rate, current_rate); + } else { + pr_info("SGX clock rate %lu MHz\n", rate / 1000000); + }; + + RegisterConstraintNotifications(psSysSpecData); + return PVRSRV_OK; + +err2: + clk_put(psSysSpecData->psSGX_ICK); +err1: + clk_put(psSysSpecData->psSGX_FCK); +err0: + PVR_DPF(PVR_DBG_ERROR, + "%s: couldn't init clocks fck %p ick %p core %p", __func__, + psSysSpecData->psSGX_FCK, psSysSpecData->psSGX_ICK, core_ck); + psSysSpecData->psSGX_FCK = NULL; + psSysSpecData->psSGX_ICK = NULL; + + return PVRSRV_ERROR_GENERIC; +} + +static void CleanupSgxClocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData; + UnRegisterConstraintNotifications(psSysSpecData); + + if (psSysSpecData->psSGX_ICK) { + clk_put(psSysSpecData->psSGX_ICK); + psSysSpecData->psSGX_ICK = NULL; + } + + if (psSysSpecData->psSGX_FCK) { + clk_put(psSysSpecData->psSGX_FCK); + psSysSpecData->psSGX_FCK = NULL; + } +} + +#if defined(CONFIG_PVR_DEBUG_EXTRA) || defined(TIMING) +static inline u32 gpt_read_reg(struct SYS_DATA *psSysData, u32 reg) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData; + + return __raw_readl(psSysSpecData->gpt_base + reg); +} + +static inline void gpt_write_reg(struct SYS_DATA *psSysData, u32 reg, u32 val) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData; + + __raw_writel(val, psSysSpecData->gpt_base + reg); +} + +static enum PVRSRV_ERROR InitDebugClocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData; + struct clk *psCLK; + struct clk *sys_ck = NULL; + u32 rate; + + psCLK = clk_get(NULL, "mpu_ck"); + if (IS_ERR(psCLK)) + goto err0; + psSysSpecData->psMPU_CK = psCLK; + + psCLK = clk_get(NULL, "gpt11_fck"); + if (IS_ERR(psCLK)) + goto err1; + psSysSpecData->psGPT11_FCK = psCLK; + + psCLK = clk_get(NULL, "gpt11_ick"); + if (IS_ERR(psCLK)) + goto err2; + psSysSpecData->psGPT11_ICK = psCLK; + + sys_ck = clk_get(NULL, "sys_ck"); + if (IS_ERR(sys_ck)) + goto err3; + if (clk_get_parent(psSysSpecData->psGPT11_FCK) != sys_ck) + if (clk_set_parent(psSysSpecData->psGPT11_FCK, sys_ck) < 0) { + clk_put(sys_ck); + goto err3; + } + clk_put(sys_ck); + + PVR_TRACE("GPTIMER11 clock is %dMHz", + HZ_TO_MHZ(clk_get_rate(psSysSpecData->psGPT11_FCK))); + + psSysSpecData->gpt_base = ioremap(SYS_OMAP3430_GP11TIMER_PHYS_BASE, + SYS_OMAP3430_GPTIMER_SIZE); + if (!psSysSpecData->gpt_base) + goto err3; + + clk_enable(psSysSpecData->psGPT11_ICK); + clk_enable(psSysSpecData->psGPT11_FCK); + + rate = gpt_read_reg(psSysData, SYS_OMAP3430_GPTIMER_TSICR); + if (!(rate & 4)) { + PVR_TRACE("Setting GPTIMER11 mode to posted " + "(currently is non-posted)"); + gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_TSICR, rate | 4); + } + + clk_disable(psSysSpecData->psGPT11_FCK); + clk_disable(psSysSpecData->psGPT11_ICK); + + return PVRSRV_OK; + +err3: + clk_put(psSysSpecData->psGPT11_ICK); +err2: + clk_put(psSysSpecData->psGPT11_FCK); +err1: + clk_put(psSysSpecData->psMPU_CK); +err0: + PVR_DPF(PVR_DBG_ERROR, + "%s: couldn't init clocks: mpu %p sys %p fck %p ick %p", + __func__, psSysSpecData->psMPU_CK, sys_ck, + psSysSpecData->psGPT11_FCK, psSysSpecData->psGPT11_ICK); + + psSysSpecData->psMPU_CK = NULL; + psSysSpecData->psGPT11_FCK = NULL; + psSysSpecData->psGPT11_ICK = NULL; + + return PVRSRV_ERROR_GENERIC; +} + +static void CleanupDebugClocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData; + + if (psSysSpecData->psMPU_CK) { + clk_put(psSysSpecData->psMPU_CK); + psSysSpecData->psMPU_CK = NULL; + } + if (psSysSpecData->psGPT11_FCK) { + clk_put(psSysSpecData->psGPT11_FCK); + psSysSpecData->psGPT11_FCK = NULL; + } + if (psSysSpecData->psGPT11_ICK) { + clk_put(psSysSpecData->psGPT11_ICK); + psSysSpecData->psGPT11_ICK = NULL; + } +} + +static enum PVRSRV_ERROR EnableDebugClocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData; + + if (clk_enable(psSysSpecData->psGPT11_FCK) < 0) + goto err0; + + if (clk_enable(psSysSpecData->psGPT11_ICK) < 0) + goto err1; + + gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_ENABLE, 3); + + return PVRSRV_OK; + +err1: + clk_disable(psSysSpecData->psGPT11_FCK); +err0: + PVR_DPF(PVR_DBG_ERROR, "%s: can't enable clocks", __func__); + + return PVRSRV_ERROR_GENERIC; +} + +static inline void DisableDebugClocks(struct SYS_DATA *psSysData) +{ + struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData; + + gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_ENABLE, 0); + + clk_disable(psSysSpecData->psGPT11_ICK); + clk_disable(psSysSpecData->psGPT11_FCK); +} + +#else + +inline enum PVRSRV_ERROR InitDebugClocks(struct SYS_DATA *psSysData) +{ + return PVRSRV_OK; +} + +static inline void CleanupDebugClocks(struct SYS_DATA *psSysData) +{ +} + +static inline enum PVRSRV_ERROR EnableDebugClocks(struct SYS_DATA *psSysData) +{ + return PVRSRV_OK; +} + +static inline void DisableDebugClocks(struct SYS_DATA *psSysData) +{ +} +#endif + +enum PVRSRV_ERROR InitSystemClocks(struct SYS_DATA *psSysData) +{ + if (InitSgxClocks(psSysData) != PVRSRV_OK) + goto err0; + + if (InitDebugClocks(psSysData) != PVRSRV_OK) + goto err1; + + return PVRSRV_OK; + +err1: + CleanupSgxClocks(psSysData); +err0: + return PVRSRV_ERROR_GENERIC; +} + +void CleanupSystemClocks(struct SYS_DATA *psSysData) +{ + CleanupDebugClocks(psSysData); + CleanupSgxClocks(psSysData); +} + +enum PVRSRV_ERROR EnableSystemClocks(struct SYS_DATA *psSysData) +{ + PVR_TRACE("EnableSystemClocks: Enabling System Clocks"); + + /* + * We force clocks on by increasing their refcount here during + * module init time and decreasing it at cleanup time. + */ + if (force_clocks_on()) + sgx_force_enable_clocks(gpsSysData); + if (EnableDebugClocks(psSysData) != PVRSRV_OK) + goto err1; + + return PVRSRV_OK; + +err1: + return PVRSRV_ERROR_GENERIC; +} + +void DisableSystemClocks(struct SYS_DATA *psSysData) +{ + PVR_TRACE("DisableSystemClocks: Disabling System Clocks"); + + DisableDebugClocks(psSysData); + /* Decrease the clocks' refcount that was increased at init time. */ + if (force_clocks_on()) + sgx_force_disable_clocks(gpsSysData); +} diff --git a/drivers/gpu/pvr/tools/Makefile b/drivers/gpu/pvr/tools/Makefile new file mode 100644 index 00000000000..27314dabcb3 --- /dev/null +++ b/drivers/gpu/pvr/tools/Makefile @@ -0,0 +1,29 @@ +# +# Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful but, except +# as otherwise stated in writing, 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. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# +# The full GNU General Public License is included in this distribution in +# the file called "COPYING". +# +# Contact Information: +# Imagination Technologies Ltd. <gpl-support@imgtec.com> +# Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + + +objs-$(CONFIG_PVR_TOOLS) += dbgdrv + +dbgdrv-objs := main.c dbgdriv.c ioctl.c hostfunc.c \ + hotkey.c + diff --git a/drivers/gpu/pvr/tools/dbgdriv.c b/drivers/gpu/pvr/tools/dbgdriv.c new file mode 100644 index 00000000000..1ab5e70e762 --- /dev/null +++ b/drivers/gpu/pvr/tools/dbgdriv.c @@ -0,0 +1,1652 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/string.h> + +#include "img_types.h" +#include "pvr_debug.h" +#include "dbgdrvif.h" +#include "dbgdriv.h" +#include "hotkey.h" +#include "hostfunc.h" + +#define LAST_FRAME_BUF_SIZE 1024 + +struct DBG_LASTFRAME_BUFFER { + struct DBG_STREAM *psStream; + u8 ui8Buffer[LAST_FRAME_BUF_SIZE]; + u32 ui32BufLen; + struct DBG_LASTFRAME_BUFFER *psNext; +}; + +static struct DBG_STREAM *g_psStreamList; +static struct DBG_LASTFRAME_BUFFER *g_psLFBufferList; + +static u32 g_ui32LOff; +static u32 g_ui32Line; +static u32 g_ui32MonoLines = 25; + +static IMG_BOOL g_bHotkeyMiddump = IMG_FALSE; +static u32 g_ui32HotkeyMiddumpStart = 0xffffffff; +static u32 g_ui32HotkeyMiddumpEnd = 0xffffffff; + +void *g_pvAPIMutex; + +IMG_BOOL gbDumpThisFrame = IMG_FALSE; + +static u32 SpaceInStream(struct DBG_STREAM *psStream); +static IMG_BOOL ExpandStreamBuffer(struct DBG_STREAM *psStream, + u32 ui32NewSize); +struct DBG_LASTFRAME_BUFFER *FindLFBuf(struct DBG_STREAM *psStream); + +struct DBGKM_SERVICE_TABLE g_sDBGKMServices = { + sizeof(struct DBGKM_SERVICE_TABLE), + ExtDBGDrivCreateStream, + ExtDBGDrivDestroyStream, + ExtDBGDrivFindStream, + ExtDBGDrivWriteString, + ExtDBGDrivReadString, + ExtDBGDrivWrite, + ExtDBGDrivRead, + ExtDBGDrivSetCaptureMode, + ExtDBGDrivSetOutputMode, + ExtDBGDrivSetDebugLevel, + ExtDBGDrivSetFrame, + ExtDBGDrivGetFrame, + ExtDBGDrivOverrideMode, + ExtDBGDrivDefaultMode, + ExtDBGDrivWrite2, + ExtDBGDrivWriteStringCM, + ExtDBGDrivWriteCM, + ExtDBGDrivSetMarker, + ExtDBGDrivGetMarker, + ExtDBGDrivStartInitPhase, + ExtDBGDrivStopInitPhase, + ExtDBGDrivIsCaptureFrame, + ExtDBGDrivWriteLF, + ExtDBGDrivReadLF, + ExtDBGDrivGetStreamOffset, + ExtDBGDrivSetStreamOffset, + ExtDBGDrivIsLastCaptureFrame, + ExtDBGDrivWaitForEvent +}; + +void *ExtDBGDrivCreateStream(char *pszName, + u32 ui32CapMode, + u32 ui32OutMode, + u32 ui32Flags, + u32 ui32Size) +{ + void *pvRet; + + HostAquireMutex(g_pvAPIMutex); + + pvRet = + DBGDrivCreateStream(pszName, ui32CapMode, ui32OutMode, ui32Flags, + ui32Size); + + HostReleaseMutex(g_pvAPIMutex); + + return pvRet; +} + +void ExtDBGDrivDestroyStream(struct DBG_STREAM *psStream) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivDestroyStream(psStream); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +void *ExtDBGDrivFindStream(char *pszName, + IMG_BOOL bResetStream) +{ + void *pvRet; + + HostAquireMutex(g_pvAPIMutex); + + pvRet = DBGDrivFindStream(pszName, bResetStream); + + HostReleaseMutex(g_pvAPIMutex); + + return pvRet; +} + +u32 ExtDBGDrivWriteString(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Level) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivWriteString(psStream, pszString, ui32Level); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +u32 ExtDBGDrivReadString(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Limit) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivReadString(psStream, pszString, ui32Limit); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +u32 ExtDBGDrivWrite(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivWrite(psStream, pui8InBuf, ui32InBuffSize, ui32Level); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +u32 ExtDBGDrivRead(struct DBG_STREAM *psStream, + IMG_BOOL bReadInitBuffer, + u32 ui32OutBuffSize, + u8 *pui8OutBuf) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = + DBGDrivRead(psStream, bReadInitBuffer, ui32OutBuffSize, pui8OutBuf); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +void ExtDBGDrivSetCaptureMode(struct DBG_STREAM *psStream, + u32 ui32Mode, + u32 ui32Start, + u32 ui32End, + u32 ui32SampleRate) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivSetCaptureMode(psStream, ui32Mode, ui32Start, ui32End, + ui32SampleRate); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +void ExtDBGDrivSetOutputMode(struct DBG_STREAM *psStream, + u32 ui32OutMode) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivSetOutputMode(psStream, ui32OutMode); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +void ExtDBGDrivSetDebugLevel(struct DBG_STREAM *psStream, + u32 ui32DebugLevel) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivSetDebugLevel(psStream, ui32DebugLevel); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +void ExtDBGDrivSetFrame(struct DBG_STREAM *psStream, u32 ui32Frame) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivSetFrame(psStream, ui32Frame); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +u32 ExtDBGDrivGetFrame(struct DBG_STREAM *psStream) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivGetFrame(psStream); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +u32 ExtDBGDrivIsLastCaptureFrame(struct DBG_STREAM *psStream) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivIsLastCaptureFrame(psStream); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +u32 ExtDBGDrivIsCaptureFrame(struct DBG_STREAM *psStream, + IMG_BOOL bCheckPreviousFrame) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivIsCaptureFrame(psStream, bCheckPreviousFrame); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +void ExtDBGDrivOverrideMode(struct DBG_STREAM *psStream, + u32 ui32Mode) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivOverrideMode(psStream, ui32Mode); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +void ExtDBGDrivDefaultMode(struct DBG_STREAM *psStream) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivDefaultMode(psStream); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +u32 ExtDBGDrivWrite2(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivWrite2(psStream, pui8InBuf, ui32InBuffSize, ui32Level); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +u32 ExtDBGDrivWriteStringCM(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Level) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivWriteStringCM(psStream, pszString, ui32Level); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +u32 ExtDBGDrivWriteCM(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = + DBGDrivWriteCM(psStream, pui8InBuf, ui32InBuffSize, ui32Level); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +void ExtDBGDrivSetMarker(struct DBG_STREAM *psStream, + u32 ui32Marker) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivSetMarker(psStream, ui32Marker); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +u32 ExtDBGDrivGetMarker(struct DBG_STREAM *psStream) +{ + u32 ui32Marker; + + HostAquireMutex(g_pvAPIMutex); + + ui32Marker = DBGDrivGetMarker(psStream); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Marker; +} + +u32 ExtDBGDrivWriteLF(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level, + u32 ui32Flags) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = + DBGDrivWriteLF(psStream, pui8InBuf, ui32InBuffSize, ui32Level, + ui32Flags); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +u32 ExtDBGDrivReadLF(struct DBG_STREAM *psStream, + u32 ui32OutBuffSize, + u8 *pui8OutBuf) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivReadLF(psStream, ui32OutBuffSize, pui8OutBuf); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +void ExtDBGDrivStartInitPhase(struct DBG_STREAM *psStream) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivStartInitPhase(psStream); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +void ExtDBGDrivStopInitPhase(struct DBG_STREAM *psStream) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivStopInitPhase(psStream); + + HostReleaseMutex(g_pvAPIMutex); + + return; +} + +u32 ExtDBGDrivGetStreamOffset(struct DBG_STREAM *psStream) +{ + u32 ui32Ret; + + HostAquireMutex(g_pvAPIMutex); + + ui32Ret = DBGDrivGetStreamOffset(psStream); + + HostReleaseMutex(g_pvAPIMutex); + + return ui32Ret; +} + +void ExtDBGDrivSetStreamOffset(struct DBG_STREAM *psStream, + u32 ui32StreamOffset) +{ + + HostAquireMutex(g_pvAPIMutex); + + DBGDrivSetStreamOffset(psStream, ui32StreamOffset); + + HostReleaseMutex(g_pvAPIMutex); +} + +void ExtDBGDrivWaitForEvent(enum DBG_EVENT eEvent) +{ +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) + DBGDrivWaitForEvent(eEvent); +#else + PVR_UNREFERENCED_PARAMETER(eEvent); +#endif +} + +u32 AtoI(char *szIn) +{ + u32 ui32Len = 0; + u32 ui32Value = 0; + u32 ui32Digit = 1; + u32 ui32Base = 10; + int iPos; + char bc; + + while (szIn[ui32Len] > 0) + ui32Len++; + + if (ui32Len == 0) + return 0; + + iPos = 0; + while (szIn[iPos] == '0') + iPos++; + if (szIn[iPos] == '\0') + return 0; + if (szIn[iPos] == 'x' || szIn[iPos] == 'X') { + ui32Base = 16; + szIn[iPos] = '0'; + } + + for (iPos = ui32Len - 1; iPos >= 0; iPos--) { + bc = szIn[iPos]; + + if ((bc >= 'a') && (bc <= 'f') && ui32Base == 16) + bc -= 'a' - 0xa; + else if ((bc >= 'A') && (bc <= 'F') && ui32Base == 16) + bc -= 'A' - 0xa; + else if ((bc >= '0') && (bc <= '9')) + bc -= '0'; + else + return 0; + + ui32Value += bc * ui32Digit; + + ui32Digit = ui32Digit * ui32Base; + } + return ui32Value; +} + +IMG_BOOL StreamValid(struct DBG_STREAM *psStream) +{ + struct DBG_STREAM *psThis; + + psThis = g_psStreamList; + + while (psThis) + if (psStream && (psThis == psStream)) + return IMG_TRUE; + else + psThis = psThis->psNext; + + return IMG_FALSE; +} + +void Write(struct DBG_STREAM *psStream, u8 *pui8Data, + u32 ui32InBuffSize) +{ + + if ((psStream->ui32WPtr + ui32InBuffSize) > psStream->ui32Size) { + u32 ui32B1 = psStream->ui32Size - psStream->ui32WPtr; + u32 ui32B2 = ui32InBuffSize - ui32B1; + + HostMemCopy((void *) (psStream->ui32Base + + psStream->ui32WPtr), + (void *) pui8Data, ui32B1); + + HostMemCopy((void *) psStream->ui32Base, + (void *) ((u32) pui8Data + ui32B1), + ui32B2); + + psStream->ui32WPtr = ui32B2; + } else { + HostMemCopy((void *) (psStream->ui32Base + + psStream->ui32WPtr), + (void *) pui8Data, ui32InBuffSize); + + psStream->ui32WPtr += ui32InBuffSize; + + if (psStream->ui32WPtr == psStream->ui32Size) + psStream->ui32WPtr = 0; + } + psStream->ui32DataWritten += ui32InBuffSize; +} + +void MonoOut(char *pszString, IMG_BOOL bNewLine) +{ + u32 i; + char *pScreen; + + pScreen = (char *)DBGDRIV_MONOBASE; + + pScreen += g_ui32Line * 160; + + i = 0; + do { + pScreen[g_ui32LOff + (i * 2)] = pszString[i]; + pScreen[g_ui32LOff + (i * 2) + 1] = 127; + i++; + } while ((pszString[i] != 0) && (i < 4096)); + + g_ui32LOff += i * 2; + + if (bNewLine) { + g_ui32LOff = 0; + g_ui32Line++; + } + + if (g_ui32Line == g_ui32MonoLines) { + g_ui32Line = g_ui32MonoLines - 1; + + HostMemCopy((void *) DBGDRIV_MONOBASE, + (void *) (DBGDRIV_MONOBASE + 160), + 160 * (g_ui32MonoLines - 1)); + + HostMemSet((void *) (DBGDRIV_MONOBASE + + (160 * (g_ui32MonoLines - 1))), 0, + 160); + } +} + +void AppendName(char *pszOut, char *pszBase, char *pszName) +{ + u32 i; + u32 ui32Off; + + i = 0; + + while (pszBase[i] != 0) { + pszOut[i] = pszBase[i]; + i++; + } + + ui32Off = i; + i = 0; + + while (pszName[i] != 0) { + pszOut[ui32Off + i] = pszName[i]; + i++; + } + + pszOut[ui32Off + i] = pszName[i]; +} + +void *DBGDrivCreateStream(char *pszName, + u32 ui32CapMode, + u32 ui32OutMode, + u32 ui32Flags, + u32 ui32Size) +{ + struct DBG_STREAM *psStream; + struct DBG_STREAM *psInitStream; + struct DBG_LASTFRAME_BUFFER *psLFBuffer; + u32 ui32Off; + void *pvBase; + + psStream = (struct DBG_STREAM *)DBGDrivFindStream(pszName, IMG_FALSE); + + if (psStream) + return (void *)psStream; + + psStream = HostNonPageablePageAlloc(1); + psInitStream = HostNonPageablePageAlloc(1); + psLFBuffer = HostNonPageablePageAlloc(1); + if ((!psStream) || (!psInitStream) || (!psLFBuffer) + ) { + PVR_DPF(PVR_DBG_ERROR, + "DBGDriv: Couldn't create buffer !!!!!\n\r"); + return NULL; + } + + if ((ui32Flags & DEBUG_FLAGS_USE_NONPAGED_MEM) != 0) + pvBase = HostNonPageablePageAlloc(ui32Size); + else + pvBase = HostPageablePageAlloc(ui32Size); + + if (!pvBase) { + PVR_DPF(PVR_DBG_ERROR, + "DBGDriv: Couldn't create buffer !!!!!\n\r"); + HostNonPageablePageFree(psStream); + return NULL; + } + + psStream->psNext = 0; + psStream->ui32Flags = ui32Flags; + psStream->ui32Base = (u32) pvBase; + psStream->ui32Size = ui32Size * 4096; + psStream->ui32RPtr = 0; + psStream->ui32WPtr = 0; + psStream->ui32DataWritten = 0; + psStream->ui32CapMode = ui32CapMode; + psStream->ui32OutMode = ui32OutMode; + psStream->ui32DebugLevel = DEBUG_LEVEL_0; + psStream->ui32DefaultMode = ui32CapMode; + psStream->ui32Start = 0; + psStream->ui32End = 0; + psStream->ui32Current = 0; + psStream->ui32SampleRate = 1; + psStream->ui32Access = 0; + psStream->ui32Timeout = 0; + psStream->ui32Marker = 0; + psStream->bInitPhaseComplete = IMG_FALSE; + + if ((ui32Flags & DEBUG_FLAGS_USE_NONPAGED_MEM) != 0) + pvBase = HostNonPageablePageAlloc(ui32Size); + else + pvBase = HostPageablePageAlloc(ui32Size); + + if (!pvBase) { + PVR_DPF(PVR_DBG_ERROR, + "DBGDriv: Couldn't create buffer !!!!!\n\r"); + + if ((psStream->ui32Flags & DEBUG_FLAGS_USE_NONPAGED_MEM) != 0) + HostNonPageablePageFree((void *) psStream-> + ui32Base); + else + HostPageablePageFree((void *) psStream->ui32Base); + HostNonPageablePageFree(psStream); + return NULL; + } + + psInitStream->psNext = 0; + psInitStream->ui32Flags = ui32Flags; + psInitStream->ui32Base = (u32) pvBase; + psInitStream->ui32Size = ui32Size * 4096; + psInitStream->ui32RPtr = 0; + psInitStream->ui32WPtr = 0; + psInitStream->ui32DataWritten = 0; + psInitStream->ui32CapMode = ui32CapMode; + psInitStream->ui32OutMode = ui32OutMode; + psInitStream->ui32DebugLevel = DEBUG_LEVEL_0; + psInitStream->ui32DefaultMode = ui32CapMode; + psInitStream->ui32Start = 0; + psInitStream->ui32End = 0; + psInitStream->ui32Current = 0; + psInitStream->ui32SampleRate = 1; + psInitStream->ui32Access = 0; + psInitStream->ui32Timeout = 0; + psInitStream->ui32Marker = 0; + psInitStream->bInitPhaseComplete = IMG_FALSE; + + psStream->psInitStream = psInitStream; + + psLFBuffer->psStream = psStream; + psLFBuffer->ui32BufLen = 0; + + g_bHotkeyMiddump = IMG_FALSE; + g_ui32HotkeyMiddumpStart = 0xffffffff; + g_ui32HotkeyMiddumpEnd = 0xffffffff; + + ui32Off = 0; + + do { + psStream->szName[ui32Off] = pszName[ui32Off]; + + ui32Off++; + } while ((pszName[ui32Off] != 0) + && (ui32Off < (4096 - sizeof(struct DBG_STREAM)))); + + psStream->szName[ui32Off] = pszName[ui32Off]; + + psStream->psNext = g_psStreamList; + g_psStreamList = psStream; + + psLFBuffer->psNext = g_psLFBufferList; + g_psLFBufferList = psLFBuffer; + + return (void *)psStream; +} + +void DBGDrivDestroyStream(struct DBG_STREAM *psStream) +{ + struct DBG_STREAM *psStreamThis; + struct DBG_STREAM *psStreamPrev; + struct DBG_LASTFRAME_BUFFER *psLFBuffer; + struct DBG_LASTFRAME_BUFFER *psLFThis; + struct DBG_LASTFRAME_BUFFER *psLFPrev; + + PVR_DPF(PVR_DBG_MESSAGE, "DBGDriv: Destroying stream %s\r\n", + psStream->szName); + + if (!StreamValid(psStream)) + return; + + psLFBuffer = FindLFBuf(psStream); + + psStreamThis = g_psStreamList; + psStreamPrev = 0; + + while (psStreamThis) + if (psStreamThis == psStream) { + if (psStreamPrev) + psStreamPrev->psNext = psStreamThis->psNext; + else + g_psStreamList = psStreamThis->psNext; + + psStreamThis = 0; + } else { + psStreamPrev = psStreamThis; + psStreamThis = psStreamThis->psNext; + } + + psLFThis = g_psLFBufferList; + psLFPrev = 0; + + while (psLFThis) + if (psLFThis == psLFBuffer) { + if (psLFPrev) + psLFPrev->psNext = psLFThis->psNext; + else + g_psLFBufferList = psLFThis->psNext; + + psLFThis = 0; + } else { + psLFPrev = psLFThis; + psLFThis = psLFThis->psNext; + } + + if (psStream->ui32CapMode & DEBUG_CAPMODE_HOTKEY) + DeactivateHotKeys(); + + if ((psStream->ui32Flags & DEBUG_FLAGS_USE_NONPAGED_MEM) != 0) { + HostNonPageablePageFree((void *) psStream->ui32Base); + HostNonPageablePageFree((void *) psStream->psInitStream-> + ui32Base); + } else { + HostPageablePageFree((void *) psStream->ui32Base); + HostPageablePageFree((void *) psStream->psInitStream-> + ui32Base); + } + + HostNonPageablePageFree(psStream->psInitStream); + HostNonPageablePageFree(psStream); + HostNonPageablePageFree(psLFBuffer); + + if (g_psStreamList == 0) + PVR_DPF(PVR_DBG_MESSAGE, "DBGDriv: Stream list now empty"); + + return; +} + +void *DBGDrivFindStream(char *pszName, + IMG_BOOL bResetStream) +{ + struct DBG_STREAM *psStream; + struct DBG_STREAM *psThis; + u32 ui32Off; + IMG_BOOL bAreSame; + + psStream = 0; + + for (psThis = g_psStreamList; psThis != NULL; + psThis = psThis->psNext) { + bAreSame = IMG_TRUE; + ui32Off = 0; + + if (strlen(psThis->szName) == strlen(pszName)) { + while ((psThis->szName[ui32Off] != 0) + && (pszName[ui32Off] != 0) && (ui32Off < 128) + && bAreSame) { + if (psThis->szName[ui32Off] != pszName[ui32Off]) + bAreSame = IMG_FALSE; + + ui32Off++; + } + } else { + bAreSame = IMG_FALSE; + } + + if (bAreSame) { + psStream = psThis; + break; + } + } + + if (bResetStream && psStream) { + static char szComment[] = "-- Init phase terminated\r\n"; + psStream->psInitStream->ui32RPtr = 0; + psStream->ui32RPtr = 0; + psStream->ui32WPtr = 0; + psStream->ui32DataWritten = + psStream->psInitStream->ui32DataWritten; + if (psStream->bInitPhaseComplete == IMG_FALSE) { + if (psStream->ui32Flags & DEBUG_FLAGS_TEXTSTREAM) + DBGDrivWrite2(psStream, (u8 *) szComment, + sizeof(szComment) - 1, 0x01); + psStream->bInitPhaseComplete = IMG_TRUE; + } + } + + return (void *)psStream; +} + +u32 DBGDrivWriteStringCM(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Level) +{ + + if (!StreamValid(psStream)) + return 0xFFFFFFFF; + + if (psStream->ui32CapMode & DEBUG_CAPMODE_FRAMED) { + if (!(psStream->ui32Flags & DEBUG_FLAGS_ENABLESAMPLE)) + return 0; + } else { + if (psStream->ui32CapMode == DEBUG_CAPMODE_HOTKEY) + if ((psStream->ui32Current != g_ui32HotKeyFrame) + || (g_bHotKeyPressed == IMG_FALSE)) + return 0; + } + + return DBGDrivWriteString(psStream, pszString, ui32Level); + +} + +u32 DBGDrivWriteString(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Level) +{ + u32 ui32Len; + u32 ui32Space; + u32 ui32WPtr; + u8 *pui8Buffer; + + if (!StreamValid(psStream)) + return 0xFFFFFFFF; + + if (!(psStream->ui32DebugLevel & ui32Level)) + return 0xFFFFFFFF; + + if (!(psStream->ui32OutMode & DEBUG_OUTMODE_ASYNC)) { + if (psStream->ui32OutMode & DEBUG_OUTMODE_STANDARDDBG) + PVR_DPF(PVR_DBG_MESSAGE, "%s: %s\r\n", + psStream->szName, pszString); + + if (psStream->ui32OutMode & DEBUG_OUTMODE_MONO) { + MonoOut(psStream->szName, IMG_FALSE); + MonoOut(": ", IMG_FALSE); + MonoOut(pszString, IMG_TRUE); + } + } + + if (!((psStream->ui32OutMode & DEBUG_OUTMODE_STREAMENABLE) || + (psStream->ui32OutMode & DEBUG_OUTMODE_ASYNC) + ) + ) + return 0xFFFFFFFF; + + ui32Space = SpaceInStream(psStream); + + if (ui32Space > 0) + ui32Space--; + + ui32Len = 0; + ui32WPtr = psStream->ui32WPtr; + pui8Buffer = (u8 *) psStream->ui32Base; + + while ((pszString[ui32Len] != 0) && (ui32Len < ui32Space)) { + pui8Buffer[ui32WPtr] = pszString[ui32Len]; + ui32Len++; + ui32WPtr++; + if (ui32WPtr == psStream->ui32Size) + ui32WPtr = 0; + } + + if (ui32Len < ui32Space) { + + pui8Buffer[ui32WPtr] = pszString[ui32Len]; + ui32Len++; + ui32WPtr++; + if (ui32WPtr == psStream->ui32Size) + ui32WPtr = 0; + + psStream->ui32WPtr = ui32WPtr; + psStream->ui32DataWritten += ui32Len; + } else { + ui32Len = 0; + } + +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) + if (ui32Len) + HostSignalEvent(DBG_EVENT_STREAM_DATA); +#endif + + return ui32Len; +} + +u32 DBGDrivReadString(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Limit) +{ + u32 ui32OutLen; + u32 ui32Len; + u32 ui32Offset; + u8 *pui8Buff; + + if (!StreamValid(psStream)) + return 0; + + pui8Buff = (u8 *) psStream->ui32Base; + ui32Offset = psStream->ui32RPtr; + + if (psStream->ui32RPtr == psStream->ui32WPtr) + return 0; + + ui32Len = 0; + while ((pui8Buff[ui32Offset] != 0) + && (ui32Offset != psStream->ui32WPtr)) { + ui32Offset++; + ui32Len++; + + if (ui32Offset == psStream->ui32Size) + ui32Offset = 0; + } + + ui32OutLen = ui32Len + 1; + + if (ui32Len > ui32Limit) + return 0; + + ui32Offset = psStream->ui32RPtr; + ui32Len = 0; + + while ((pui8Buff[ui32Offset] != 0) && (ui32Len < ui32Limit)) { + pszString[ui32Len] = pui8Buff[ui32Offset]; + ui32Offset++; + ui32Len++; + + if (ui32Offset == psStream->ui32Size) + ui32Offset = 0; + } + + pszString[ui32Len] = pui8Buff[ui32Offset]; + + psStream->ui32RPtr = ui32Offset + 1; + + if (psStream->ui32RPtr == psStream->ui32Size) + psStream->ui32RPtr = 0; + + return ui32OutLen; +} + +u32 DBGDrivWrite(struct DBG_STREAM *psMainStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level) +{ + u32 ui32Space; + struct DBG_STREAM *psStream; + + if (!StreamValid(psMainStream)) + return 0xFFFFFFFF; + + if (!(psMainStream->ui32DebugLevel & ui32Level)) + return 0xFFFFFFFF; + + if (psMainStream->ui32CapMode & DEBUG_CAPMODE_FRAMED) { + if (!(psMainStream->ui32Flags & DEBUG_FLAGS_ENABLESAMPLE)) + return 0xFFFFFFFF; + } else { + if (psMainStream->ui32CapMode == DEBUG_CAPMODE_HOTKEY) + if ((psMainStream->ui32Current != g_ui32HotKeyFrame) + || (g_bHotKeyPressed == IMG_FALSE)) + return 0xFFFFFFFF; + + } + + if (psMainStream->bInitPhaseComplete) + psStream = psMainStream; + else + psStream = psMainStream->psInitStream; + + ui32Space = SpaceInStream(psStream); + + if (!(psStream->ui32OutMode & DEBUG_OUTMODE_STREAMENABLE)) + return 0; + + if (ui32Space < 8) + return 0; + + if (ui32Space <= (ui32InBuffSize + 4)) + ui32InBuffSize = ui32Space - 8; + + Write(psStream, (u8 *) &ui32InBuffSize, 4); + Write(psStream, pui8InBuf, ui32InBuffSize); + +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) + if (ui32InBuffSize) + HostSignalEvent(DBG_EVENT_STREAM_DATA); +#endif + return ui32InBuffSize; +} + +u32 DBGDrivWriteCM(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level) +{ + + if (!StreamValid(psStream)) + return 0xFFFFFFFF; + + if (psStream->ui32CapMode & DEBUG_CAPMODE_FRAMED) { + if (!(psStream->ui32Flags & DEBUG_FLAGS_ENABLESAMPLE)) + return 0xFFFFFFFF; + } else { + if (psStream->ui32CapMode == DEBUG_CAPMODE_HOTKEY) + if ((psStream->ui32Current != g_ui32HotKeyFrame) + || (g_bHotKeyPressed == IMG_FALSE)) + return 0xFFFFFFFF; + } + + return DBGDrivWrite2(psStream, pui8InBuf, ui32InBuffSize, ui32Level); +} + +u32 DBGDrivWrite2(struct DBG_STREAM *psMainStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level) +{ + u32 ui32Space; + struct DBG_STREAM *psStream; + + if (!StreamValid(psMainStream)) + return 0xFFFFFFFF; + + if (!(psMainStream->ui32DebugLevel & ui32Level)) + return 0xFFFFFFFF; + + if (psMainStream->bInitPhaseComplete) + psStream = psMainStream; + else + psStream = psMainStream->psInitStream; + + ui32Space = SpaceInStream(psStream); + + if (!(psStream->ui32OutMode & DEBUG_OUTMODE_STREAMENABLE)) + return 0; + + if (psStream->ui32Flags & DEBUG_FLAGS_NO_BUF_EXPANDSION) { + + if (ui32Space < 32) + return 0; + } else { + if ((ui32Space < 32) || (ui32Space <= (ui32InBuffSize + 4))) { + u32 ui32NewBufSize; + + ui32NewBufSize = 2 * psStream->ui32Size; + + if (ui32InBuffSize > psStream->ui32Size) + ui32NewBufSize += ui32InBuffSize; + + if (!ExpandStreamBuffer(psStream, ui32NewBufSize)) + if (ui32Space < 32) + return 0; + + ui32Space = SpaceInStream(psStream); + } + } + + if (ui32Space <= (ui32InBuffSize + 4)) + ui32InBuffSize = ui32Space - 4; + + Write(psStream, pui8InBuf, ui32InBuffSize); + +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) + if (ui32InBuffSize) + HostSignalEvent(DBG_EVENT_STREAM_DATA); +#endif + return ui32InBuffSize; +} + +u32 DBGDrivRead(struct DBG_STREAM *psMainStream, + IMG_BOOL bReadInitBuffer, + u32 ui32OutBuffSize, + u8 *pui8OutBuf) +{ + u32 ui32Data; + struct DBG_STREAM *psStream; + + if (!StreamValid(psMainStream)) + return 0; + + if (bReadInitBuffer) + psStream = psMainStream->psInitStream; + else + psStream = psMainStream; + + if (psStream->ui32RPtr == psStream->ui32WPtr) + return 0; + + if (psStream->ui32RPtr <= psStream->ui32WPtr) { + ui32Data = psStream->ui32WPtr - psStream->ui32RPtr; + } else { + ui32Data = + psStream->ui32WPtr + (psStream->ui32Size - + psStream->ui32RPtr); + } + + if (ui32Data > ui32OutBuffSize) + ui32Data = ui32OutBuffSize; + + if ((psStream->ui32RPtr + ui32Data) > psStream->ui32Size) { + u32 ui32B1 = psStream->ui32Size - psStream->ui32RPtr; + u32 ui32B2 = ui32Data - ui32B1; + + HostMemCopy((void *) pui8OutBuf, + (void *) (psStream->ui32Base + + psStream->ui32RPtr), ui32B1); + + HostMemCopy((void *) ((u32) pui8OutBuf + ui32B1), + (void *) psStream->ui32Base, ui32B2); + + psStream->ui32RPtr = ui32B2; + } else { + HostMemCopy((void *) pui8OutBuf, + (void *) (psStream->ui32Base + + psStream->ui32RPtr), ui32Data); + + psStream->ui32RPtr += ui32Data; + + if (psStream->ui32RPtr == psStream->ui32Size) + psStream->ui32RPtr = 0; + } + + return ui32Data; +} + +void DBGDrivSetCaptureMode(struct DBG_STREAM *psStream, + u32 ui32Mode, + u32 ui32Start, + u32 ui32End, + u32 ui32SampleRate) +{ + + if (!StreamValid(psStream)) + return; + + psStream->ui32CapMode = ui32Mode; + psStream->ui32DefaultMode = ui32Mode; + psStream->ui32Start = ui32Start; + psStream->ui32End = ui32End; + psStream->ui32SampleRate = ui32SampleRate; + + if (psStream->ui32CapMode & DEBUG_CAPMODE_HOTKEY) + ActivateHotKeys(psStream); +} + +void DBGDrivSetOutputMode(struct DBG_STREAM *psStream, + u32 ui32OutMode) +{ + + if (!StreamValid(psStream)) + return; + + psStream->ui32OutMode = ui32OutMode; +} + +void DBGDrivSetDebugLevel(struct DBG_STREAM *psStream, + u32 ui32DebugLevel) +{ + + if (!StreamValid(psStream)) + return; + + psStream->ui32DebugLevel = ui32DebugLevel; +} + +void DBGDrivSetFrame(struct DBG_STREAM *psStream, u32 ui32Frame) +{ + + if (!StreamValid(psStream)) + return; + + psStream->ui32Current = ui32Frame; + + if ((ui32Frame >= psStream->ui32Start) && + (ui32Frame <= psStream->ui32End) && + (((ui32Frame - psStream->ui32Start) % psStream->ui32SampleRate) == + 0)) + psStream->ui32Flags |= DEBUG_FLAGS_ENABLESAMPLE; + else + psStream->ui32Flags &= ~DEBUG_FLAGS_ENABLESAMPLE; + + if (g_bHotkeyMiddump) { + if ((ui32Frame >= g_ui32HotkeyMiddumpStart) && + (ui32Frame <= g_ui32HotkeyMiddumpEnd) && + (((ui32Frame - + g_ui32HotkeyMiddumpStart) % psStream->ui32SampleRate) == + 0)) { + psStream->ui32Flags |= DEBUG_FLAGS_ENABLESAMPLE; + } else { + psStream->ui32Flags &= ~DEBUG_FLAGS_ENABLESAMPLE; + if (psStream->ui32Current > g_ui32HotkeyMiddumpEnd) + g_bHotkeyMiddump = IMG_FALSE; + } + } + + if (g_bHotKeyRegistered) { + g_bHotKeyRegistered = IMG_FALSE; + + PVR_DPF(PVR_DBG_MESSAGE, "Hotkey pressed (%08x)!\n", + psStream); + + if (!g_bHotKeyPressed) { + + g_ui32HotKeyFrame = psStream->ui32Current + 2; + + g_bHotKeyPressed = IMG_TRUE; + } + + if ((psStream->ui32CapMode & DEBUG_CAPMODE_FRAMED) + && (psStream->ui32CapMode & DEBUG_CAPMODE_HOTKEY)) { + if (!g_bHotkeyMiddump) { + + g_ui32HotkeyMiddumpStart = + g_ui32HotKeyFrame + 1; + g_ui32HotkeyMiddumpEnd = 0xffffffff; + g_bHotkeyMiddump = IMG_TRUE; + PVR_DPF(PVR_DBG_MESSAGE, + "Sampling every %d frame(s)\n", + psStream->ui32SampleRate); + } else { + + g_ui32HotkeyMiddumpEnd = g_ui32HotKeyFrame; + PVR_DPF(PVR_DBG_MESSAGE, + "Turning off sampling\n"); + } + } + + } + + if (psStream->ui32Current > g_ui32HotKeyFrame) + g_bHotKeyPressed = IMG_FALSE; +} + +u32 DBGDrivGetFrame(struct DBG_STREAM *psStream) +{ + + if (!StreamValid(psStream)) + return 0; + + return psStream->ui32Current; +} + +u32 DBGDrivIsLastCaptureFrame(struct DBG_STREAM *psStream) +{ + u32 ui32NextFrame; + + if (!StreamValid(psStream)) + return IMG_FALSE; + + if (psStream->ui32CapMode & DEBUG_CAPMODE_FRAMED) { + ui32NextFrame = + psStream->ui32Current + psStream->ui32SampleRate; + if (ui32NextFrame > psStream->ui32End) + return IMG_TRUE; + } + return IMG_FALSE; +} + +u32 DBGDrivIsCaptureFrame(struct DBG_STREAM *psStream, + IMG_BOOL bCheckPreviousFrame) +{ + u32 ui32FrameShift = bCheckPreviousFrame ? 1 : 0; + + if (!StreamValid(psStream)) + return IMG_FALSE; + + if (psStream->ui32CapMode & DEBUG_CAPMODE_FRAMED) { + + if (g_bHotkeyMiddump) { + if ((psStream->ui32Current >= + (g_ui32HotkeyMiddumpStart - ui32FrameShift)) + && (psStream->ui32Current <= + (g_ui32HotkeyMiddumpEnd - ui32FrameShift)) + && + ((((psStream->ui32Current + ui32FrameShift) - + g_ui32HotkeyMiddumpStart) % + psStream->ui32SampleRate) == 0)) + return IMG_TRUE; + } else { + if ((psStream->ui32Current >= + (psStream->ui32Start - ui32FrameShift)) + && (psStream->ui32Current <= + (psStream->ui32End - ui32FrameShift)) + && + ((((psStream->ui32Current + ui32FrameShift) - + psStream->ui32Start) % + psStream->ui32SampleRate) == 0)) + return IMG_TRUE; + } + } else if (psStream->ui32CapMode == DEBUG_CAPMODE_HOTKEY) { + if ((psStream->ui32Current == + (g_ui32HotKeyFrame - ui32FrameShift)) + && (g_bHotKeyPressed)) + return IMG_TRUE; + } + + + return IMG_FALSE; +} + +void DBGDrivOverrideMode(struct DBG_STREAM *psStream, u32 ui32Mode) +{ + + if (!StreamValid(psStream)) + return; + + psStream->ui32CapMode = ui32Mode; +} + +void DBGDrivDefaultMode(struct DBG_STREAM *psStream) +{ + + if (!StreamValid(psStream)) + return; + + psStream->ui32CapMode = psStream->ui32DefaultMode; +} + +void DBGDrivSetMarker(struct DBG_STREAM *psStream, u32 ui32Marker) +{ + + if (!StreamValid(psStream)) + return; + + psStream->ui32Marker = ui32Marker; +} + +u32 DBGDrivGetMarker(struct DBG_STREAM *psStream) +{ + + if (!StreamValid(psStream)) + return 0; + + return psStream->ui32Marker; +} + +u32 DBGDrivGetStreamOffset(struct DBG_STREAM *psMainStream) +{ + struct DBG_STREAM *psStream; + + if (!StreamValid(psMainStream)) + return 0; + + if (psMainStream->bInitPhaseComplete) + psStream = psMainStream; + else + psStream = psMainStream->psInitStream; + + return psStream->ui32DataWritten; +} + +void DBGDrivSetStreamOffset(struct DBG_STREAM *psMainStream, + u32 ui32StreamOffset) +{ + struct DBG_STREAM *psStream; + + if (!StreamValid(psMainStream)) + return; + + if (psMainStream->bInitPhaseComplete) + psStream = psMainStream; + else + psStream = psMainStream->psInitStream; + + psStream->ui32DataWritten = ui32StreamOffset; +} + +u32 DBGDrivGetServiceTable(void) +{ + return (u32)&g_sDBGKMServices; +} + +u32 DBGDrivWriteLF(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level, + u32 ui32Flags) +{ + struct DBG_LASTFRAME_BUFFER *psLFBuffer; + + if (!StreamValid(psStream)) + return 0xFFFFFFFF; + + if (!(psStream->ui32DebugLevel & ui32Level)) + return 0xFFFFFFFF; + + if (psStream->ui32CapMode & DEBUG_CAPMODE_FRAMED) { + if (!(psStream->ui32Flags & DEBUG_FLAGS_ENABLESAMPLE)) + return 0xFFFFFFFF; + } else if (psStream->ui32CapMode == DEBUG_CAPMODE_HOTKEY) { + if ((psStream->ui32Current != g_ui32HotKeyFrame) + || (g_bHotKeyPressed == IMG_FALSE)) + return 0xFFFFFFFF; + } + + psLFBuffer = FindLFBuf(psStream); + + if (ui32Flags & WRITELF_FLAGS_RESETBUF) { + + ui32InBuffSize = + (ui32InBuffSize > + LAST_FRAME_BUF_SIZE) ? LAST_FRAME_BUF_SIZE : + ui32InBuffSize; + HostMemCopy((void *) psLFBuffer->ui8Buffer, + (void *) pui8InBuf, ui32InBuffSize); + psLFBuffer->ui32BufLen = ui32InBuffSize; + } else { + + ui32InBuffSize = + ((psLFBuffer->ui32BufLen + ui32InBuffSize) > + LAST_FRAME_BUF_SIZE) ? (LAST_FRAME_BUF_SIZE - + psLFBuffer-> + ui32BufLen) : ui32InBuffSize; + HostMemCopy((void *) (&psLFBuffer-> + ui8Buffer[psLFBuffer->ui32BufLen]), + (void *) pui8InBuf, ui32InBuffSize); + psLFBuffer->ui32BufLen += ui32InBuffSize; + } + + return ui32InBuffSize; +} + +u32 DBGDrivReadLF(struct DBG_STREAM *psStream, + u32 ui32OutBuffSize, + u8 *pui8OutBuf) +{ + struct DBG_LASTFRAME_BUFFER *psLFBuffer; + u32 ui32Data; + + if (!StreamValid(psStream)) + return 0; + + psLFBuffer = FindLFBuf(psStream); + + ui32Data = + (ui32OutBuffSize < + psLFBuffer->ui32BufLen) ? ui32OutBuffSize : psLFBuffer->ui32BufLen; + + HostMemCopy((void *) pui8OutBuf, (void *) psLFBuffer->ui8Buffer, + ui32Data); + + return ui32Data; +} + +void DBGDrivStartInitPhase(struct DBG_STREAM *psStream) +{ + psStream->bInitPhaseComplete = IMG_FALSE; +} + +void DBGDrivStopInitPhase(struct DBG_STREAM *psStream) +{ + psStream->bInitPhaseComplete = IMG_TRUE; +} + +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) +void DBGDrivWaitForEvent(enum DBG_EVENT eEvent) +{ + HostWaitForEvent(eEvent); +} +#endif + +static IMG_BOOL ExpandStreamBuffer(struct DBG_STREAM *psStream, u32 ui32NewSize) +{ + void *pvNewBuf; + u32 ui32NewSizeInPages; + u32 ui32NewWOffset; + u32 ui32SpaceInOldBuf; + + if (psStream->ui32Size >= ui32NewSize) + return IMG_FALSE; + + ui32SpaceInOldBuf = SpaceInStream(psStream); + + ui32NewSizeInPages = ((ui32NewSize + 0xfff) & ~0xfff) / 4096; + + if ((psStream->ui32Flags & DEBUG_FLAGS_USE_NONPAGED_MEM) != 0) + pvNewBuf = HostNonPageablePageAlloc(ui32NewSizeInPages); + else + pvNewBuf = HostPageablePageAlloc(ui32NewSizeInPages); + + if (pvNewBuf == NULL) + return IMG_FALSE; + + if (psStream->ui32RPtr <= psStream->ui32WPtr) { + + HostMemCopy((void *) pvNewBuf, + (void *) (psStream->ui32Base + + psStream->ui32RPtr), + psStream->ui32WPtr - psStream->ui32RPtr); + } else { + u32 ui32FirstCopySize; + + ui32FirstCopySize = psStream->ui32Size - psStream->ui32RPtr; + + HostMemCopy((void *) pvNewBuf, + (void *) (psStream->ui32Base + + psStream->ui32RPtr), + ui32FirstCopySize); + + HostMemCopy((void *) ((u32) pvNewBuf + + ui32FirstCopySize), + (void *) psStream->ui32Base, + psStream->ui32WPtr); + } + + ui32NewWOffset = psStream->ui32Size - ui32SpaceInOldBuf; + + if ((psStream->ui32Flags & DEBUG_FLAGS_USE_NONPAGED_MEM) != 0) + HostNonPageablePageFree((void *) psStream->ui32Base); + else + HostPageablePageFree((void *) psStream->ui32Base); + + psStream->ui32Base = (u32) pvNewBuf; + psStream->ui32RPtr = 0; + psStream->ui32WPtr = ui32NewWOffset; + psStream->ui32Size = ui32NewSizeInPages * 4096; + + return IMG_TRUE; +} + +static u32 SpaceInStream(struct DBG_STREAM *psStream) +{ + u32 ui32Space; + + if (psStream->ui32RPtr > psStream->ui32WPtr) + ui32Space = psStream->ui32RPtr - psStream->ui32WPtr; + else + ui32Space = + psStream->ui32RPtr + (psStream->ui32Size - + psStream->ui32WPtr); + + return ui32Space; +} + +void DestroyAllStreams(void) +{ + while (g_psStreamList != NULL) + DBGDrivDestroyStream(g_psStreamList); + return; +} + +struct DBG_LASTFRAME_BUFFER *FindLFBuf(struct DBG_STREAM *psStream) +{ + struct DBG_LASTFRAME_BUFFER *psLFBuffer; + + psLFBuffer = g_psLFBufferList; + + while (psLFBuffer) { + if (psLFBuffer->psStream == psStream) + break; + + psLFBuffer = psLFBuffer->psNext; + } + + return psLFBuffer; +} diff --git a/drivers/gpu/pvr/tools/dbgdriv.h b/drivers/gpu/pvr/tools/dbgdriv.h new file mode 100644 index 00000000000..4e2ebc30ded --- /dev/null +++ b/drivers/gpu/pvr/tools/dbgdriv.h @@ -0,0 +1,183 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _DBGDRIV_ +#define _DBGDRIV_ + +#define BUFFER_SIZE (64 * PAGESIZE) + +#define DBGDRIV_VERSION 0x100 +#define MAX_PROCESSES 2 +#define BLOCK_USED 0x01 +#define BLOCK_LOCKED 0x02 +#define DBGDRIV_MONOBASE 0x000B0000 + +extern void *g_pvAPIMutex; + +void *DBGDrivCreateStream(char *pszName, + u32 ui32CapMode, + u32 ui32OutMode, + u32 ui32Flags, + u32 ui32Pages); +void DBGDrivDestroyStream(struct DBG_STREAM *psStream); +void *DBGDrivFindStream(char *pszName, + IMG_BOOL bResetStream); +u32 DBGDrivWriteString(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Level); +u32 DBGDrivReadString(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Limit); +u32 DBGDrivWrite(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level); +u32 DBGDrivWrite2(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level); +u32 DBGDrivRead(struct DBG_STREAM *psStream, + IMG_BOOL bReadInitBuffer, + u32 ui32OutBufferSize, + u8 *pui8OutBuf); +void DBGDrivSetCaptureMode(struct DBG_STREAM *psStream, + u32 ui32Mode, + u32 ui32Start, + u32 ui32Stop, + u32 ui32SampleRate); +void DBGDrivSetOutputMode(struct DBG_STREAM *psStream, + u32 ui32OutMode); +void DBGDrivSetDebugLevel(struct DBG_STREAM *psStream, + u32 ui32DebugLevel); +void DBGDrivSetFrame(struct DBG_STREAM *psStream, + u32 ui32Frame); +u32 DBGDrivGetFrame(struct DBG_STREAM *psStream); +void DBGDrivOverrideMode(struct DBG_STREAM *psStream, + u32 ui32Mode); +void DBGDrivDefaultMode(struct DBG_STREAM *psStream); +u32 DBGDrivGetServiceTable(void); +u32 DBGDrivWriteStringCM(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Level); +u32 DBGDrivWriteCM(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level); +void DBGDrivSetMarker(struct DBG_STREAM *psStream, + u32 ui32Marker); +u32 DBGDrivGetMarker(struct DBG_STREAM *psStream); +u32 DBGDrivIsLastCaptureFrame(struct DBG_STREAM *psStream); +u32 DBGDrivIsCaptureFrame(struct DBG_STREAM *psStream, + IMG_BOOL bCheckPreviousFrame); +u32 DBGDrivWriteLF(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level, + u32 ui32Flags); +u32 DBGDrivReadLF(struct DBG_STREAM *psStream, + u32 ui32OutBuffSize, + u8 *pui8OutBuf); +void DBGDrivStartInitPhase(struct DBG_STREAM *psStream); +void DBGDrivStopInitPhase(struct DBG_STREAM *psStream); +u32 DBGDrivGetStreamOffset(struct DBG_STREAM *psStream); +void DBGDrivSetStreamOffset(struct DBG_STREAM *psStream, u32 ui32StreamOffset); +void DBGDrivWaitForEvent(enum DBG_EVENT eEvent); + +void DestroyAllStreams(void); + +u32 AtoI(char *szIn); + +void HostMemSet(void *pvDest, u8 ui8Value, u32 ui32Size); +void HostMemCopy(void *pvDest, void *pvSrc, u32 ui32Size); +IMG_BOOL StreamValid(struct DBG_STREAM *psStream); +void Write(struct DBG_STREAM *psStream, u8 *pui8Data, + u32 ui32InBuffSize); +void MonoOut(char *pszString, IMG_BOOL bNewLine); + +void *ExtDBGDrivCreateStream(char *pszName, + u32 ui32CapMode, + u32 ui32OutMode, + u32 ui32Flags, + u32 ui32Size); +void ExtDBGDrivDestroyStream(struct DBG_STREAM *psStream); +void *ExtDBGDrivFindStream(char *pszName, + IMG_BOOL bResetStream); +u32 ExtDBGDrivWriteString(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Level); +u32 ExtDBGDrivReadString(struct DBG_STREAM *psStream, + char *pszString, + u32 ui32Limit); +u32 ExtDBGDrivWrite(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level); +u32 ExtDBGDrivRead(struct DBG_STREAM *psStream, + IMG_BOOL bReadInitBuffer, + u32 ui32OutBuffSize, + u8 *pui8OutBuf); +void ExtDBGDrivSetCaptureMode(struct DBG_STREAM *psStream, + u32 ui32Mode, + u32 ui32Start, + u32 ui32End, + u32 ui32SampleRate); +void ExtDBGDrivSetOutputMode(struct DBG_STREAM *psStream, + u32 ui32OutMode); +void ExtDBGDrivSetDebugLevel(struct DBG_STREAM *psStream, + u32 ui32DebugLevel); +void ExtDBGDrivSetFrame(struct DBG_STREAM *psStream, + u32 ui32Frame); +u32 ExtDBGDrivGetFrame(struct DBG_STREAM *psStream); +void ExtDBGDrivOverrideMode(struct DBG_STREAM *psStream, + u32 ui32Mode); +void ExtDBGDrivDefaultMode(struct DBG_STREAM *psStream); +u32 ExtDBGDrivWrite2(struct DBG_STREAM *psStream, u8 *pui8InBuf, + u32 ui32InBuffSize, u32 ui32Level); +u32 ExtDBGDrivWriteStringCM(struct DBG_STREAM *psStream, char *pszString, + u32 ui32Level); +u32 ExtDBGDrivWriteCM(struct DBG_STREAM *psStream, u8 *pui8InBuf, + u32 ui32InBuffSize, u32 ui32Level); +void ExtDBGDrivSetMarker(struct DBG_STREAM *psStream, u32 ui32Marker); +u32 ExtDBGDrivGetMarker(struct DBG_STREAM *psStream); +void ExtDBGDrivStartInitPhase(struct DBG_STREAM *psStream); +void ExtDBGDrivStopInitPhase(struct DBG_STREAM *psStream); +u32 ExtDBGDrivIsLastCaptureFrame(struct DBG_STREAM *psStream); +u32 ExtDBGDrivIsCaptureFrame(struct DBG_STREAM *psStream, + IMG_BOOL bCheckPreviousFrame); +u32 ExtDBGDrivWriteLF(struct DBG_STREAM *psStream, + u8 *pui8InBuf, + u32 ui32InBuffSize, + u32 ui32Level, + u32 ui32Flags); +u32 ExtDBGDrivReadLF(struct DBG_STREAM *psStream, + u32 ui32OutBuffSize, + u8 *pui8OutBuf); +u32 ExtDBGDrivGetStreamOffset(struct DBG_STREAM *psStream); +void ExtDBGDrivSetStreamOffset(struct DBG_STREAM *psStream, + u32 ui32StreamOffset); +void ExtDBGDrivWaitForEvent(enum DBG_EVENT eEvent); + +#endif diff --git a/drivers/gpu/pvr/tools/hostfunc.c b/drivers/gpu/pvr/tools/hostfunc.c new file mode 100644 index 00000000000..efc9f687ae4 --- /dev/null +++ b/drivers/gpu/pvr/tools/hostfunc.c @@ -0,0 +1,267 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/version.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <asm/page.h> +#include <linux/vmalloc.h> +#include <linux/mutex.h> +#include <linux/hardirq.h> + +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/jiffies.h> +#include <linux/delay.h> +#endif + +#include "img_types.h" +#include "pvr_debug.h" + +#include "dbgdrvif.h" +#include "hostfunc.h" + +#define PVR_STRING_TERMINATOR '\0' +#define PVR_IS_FILE_SEPARATOR(character) \ + (((character) == '\\') || ((character) == '/')) + +static u32 gPVRDebugLevel = DBGPRIV_WARNING; + +void PVRSRVDebugPrintf(u32 ui32DebugLevel, + const char *pszFileName, + u32 ui32Line, const char *pszFormat, ... + ) +{ + IMG_BOOL bTrace, bDebug; + char *pszLeafName; + + pszLeafName = (char *)strrchr(pszFileName, '\\'); + + if (pszLeafName) + pszFileName = pszLeafName; + + bTrace = gPVRDebugLevel & ui32DebugLevel & DBGPRIV_CALLTRACE; + bDebug = ((gPVRDebugLevel & DBGPRIV_ALLLEVELS) >= ui32DebugLevel); + + if (bTrace || bDebug) { + va_list vaArgs; + static char szBuffer[256]; + + va_start(vaArgs, pszFormat); + + if (bDebug) { + switch (ui32DebugLevel) { + case DBGPRIV_FATAL: + { + strcpy(szBuffer, "PVR_K:(Fatal): "); + break; + } + case DBGPRIV_ERROR: + { + strcpy(szBuffer, "PVR_K:(Error): "); + break; + } + case DBGPRIV_WARNING: + { + strcpy(szBuffer, "PVR_K:(Warning): "); + break; + } + case DBGPRIV_MESSAGE: + { + strcpy(szBuffer, "PVR_K:(Message): "); + break; + } + case DBGPRIV_VERBOSE: + { + strcpy(szBuffer, "PVR_K:(Verbose): "); + break; + } + default: + { + strcpy(szBuffer, + "PVR_K:(Unknown message level)"); + break; + } + } + } else { + strcpy(szBuffer, "PVR_K: "); + } + + vsprintf(&szBuffer[strlen(szBuffer)], pszFormat, vaArgs); + + if (!bTrace) + sprintf(&szBuffer[strlen(szBuffer)], " [%d, %s]", + (int)ui32Line, pszFileName); + + printk(KERN_INFO "%s\r\n", szBuffer); + + va_end(vaArgs); + } +} + +void HostMemSet(void *pvDest, u8 ui8Value, u32 ui32Size) +{ + memset(pvDest, (int)ui8Value, (size_t) ui32Size); +} + +void HostMemCopy(void *pvDst, void *pvSrc, u32 ui32Size) +{ + memcpy(pvDst, pvSrc, ui32Size); +} + +u32 HostReadRegistryDWORDFromString(char *pcKey, char *pcValueName, + u32 *pui32Data) +{ + + return 0; +} + +void *HostPageablePageAlloc(u32 ui32Pages) +{ + return (void *)vmalloc(ui32Pages * PAGE_SIZE); +} + +void HostPageablePageFree(void *pvBase) +{ + vfree(pvBase); +} + +void *HostNonPageablePageAlloc(u32 ui32Pages) +{ + return (void *)vmalloc(ui32Pages * PAGE_SIZE); +} + +void HostNonPageablePageFree(void *pvBase) +{ + vfree(pvBase); +} + +void *HostMapKrnBufIntoUser(void *pvKrnAddr, u32 ui32Size, + void **ppvMdl) +{ + + return NULL; +} + +void HostUnMapKrnBufFromUser(void *pvUserAddr, void *pvMdl, + void *pvProcess) +{ + +} + +void HostCreateRegDeclStreams(void) +{ + +} + +void *HostCreateMutex(void) +{ + struct mutex *psSem; + + psSem = kmalloc(sizeof(*psSem), GFP_KERNEL); + if (psSem) + mutex_init(psSem); + + return psSem; +} + +void HostAquireMutex(void *pvMutex) +{ + BUG_ON(in_interrupt()); + +#if defined(PVR_DEBUG_DBGDRV_DETECT_HOST_MUTEX_COLLISIONS) + if (mutex_trylock((struct mutex *)pvMutex)) { + printk(KERN_INFO "HostAquireMutex: Waiting for mutex\n"); + mutex_lock((struct mutex *)pvMutex); + } +#else + mutex_lock((struct mutex *)pvMutex); +#endif +} + +void HostReleaseMutex(void *pvMutex) +{ + mutex_unlock((struct mutex *)pvMutex); +} + +void HostDestroyMutex(void *pvMutex) +{ + kfree(pvMutex); +} + +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) + +#define EVENT_WAIT_TIMEOUT_MS 500 +#define EVENT_WAIT_TIMEOUT_JIFFIES (EVENT_WAIT_TIMEOUT_MS * HZ / 1000) + +static int iStreamData; +static wait_queue_head_t sStreamDataEvent; + +s32 HostCreateEventObjects(void) +{ + init_waitqueue_head(&sStreamDataEvent); + + return 0; +} + +void HostWaitForEvent(enum DBG_EVENT eEvent) +{ + switch (eEvent) { + case DBG_EVENT_STREAM_DATA: + + wait_event_interruptible_timeout(sStreamDataEvent, + iStreamData != 0, + EVENT_WAIT_TIMEOUT_JIFFIES); + iStreamData = 0; + break; + default: + + msleep_interruptible(EVENT_WAIT_TIMEOUT_MS); + break; + } +} + +void HostSignalEvent(enum DBG_EVENT eEvent) +{ + switch (eEvent) { + case DBG_EVENT_STREAM_DATA: + iStreamData = 1; + wake_up_interruptible(&sStreamDataEvent); + break; + default: + break; + } +} + +void HostDestroyEventObjects(void) +{ +} +#endif diff --git a/drivers/gpu/pvr/tools/hostfunc.h b/drivers/gpu/pvr/tools/hostfunc.h new file mode 100644 index 00000000000..64f88230e63 --- /dev/null +++ b/drivers/gpu/pvr/tools/hostfunc.h @@ -0,0 +1,58 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _HOSTFUNC_ +#define _HOSTFUNC_ + +#define HOST_PAGESIZE (4096) +#define DBG_MEMORY_INITIALIZER (0xe2) + +u32 HostReadRegistryDWORDFromString(char *pcKey, char *pcValueName, + u32 *pui32Data); + +void *HostPageablePageAlloc(u32 ui32Pages); +void HostPageablePageFree(void *pvBase); +void *HostNonPageablePageAlloc(u32 ui32Pages); +void HostNonPageablePageFree(void *pvBase); + +void *HostMapKrnBufIntoUser(void *pvKrnAddr, u32 ui32Size, void **ppvMdl); +void HostUnMapKrnBufFromUser(void *pvUserAddr, void *pvMdl, void *pvProcess); + +void HostCreateRegDeclStreams(void); + +void *HostCreateMutex(void); +void HostAquireMutex(void *pvMutex); +void HostReleaseMutex(void *pvMutex); +void HostDestroyMutex(void *pvMutex); + +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) +s32 HostCreateEventObjects(void); +void HostWaitForEvent(enum DBG_EVENT eEvent); +void HostSignalEvent(enum DBG_EVENT eEvent); +void HostDestroyEventObjects(void); +#endif + +#endif diff --git a/drivers/gpu/pvr/tools/hotkey.c b/drivers/gpu/pvr/tools/hotkey.c new file mode 100644 index 00000000000..b5a2eb86909 --- /dev/null +++ b/drivers/gpu/pvr/tools/hotkey.c @@ -0,0 +1,101 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include "img_types.h" +#include "pvr_debug.h" +#include "dbgdrvif.h" +#include "dbgdriv.h" +#include "hotkey.h" +#include "hostfunc.h" + +u32 g_ui32HotKeyFrame = 0xFFFFFFFF; +IMG_BOOL g_bHotKeyPressed = IMG_FALSE; +IMG_BOOL g_bHotKeyRegistered = IMG_FALSE; + +struct PRIVATEHOTKEYDATA g_PrivateHotKeyData; + +void ReadInHotKeys(void) +{ + g_PrivateHotKeyData.ui32ScanCode = 0x58; + g_PrivateHotKeyData.ui32ShiftState = 0x0; + + HostReadRegistryDWORDFromString("DEBUG\\Streams", "ui32ScanCode", + &g_PrivateHotKeyData.ui32ScanCode); + HostReadRegistryDWORDFromString("DEBUG\\Streams", "ui32ShiftState", + &g_PrivateHotKeyData.ui32ShiftState); +} + +void RegisterKeyPressed(u32 dwui32ScanCode, struct HOTKEYINFO *pInfo) +{ + struct DBG_STREAM *psStream; + + PVR_UNREFERENCED_PARAMETER(pInfo); + + if (dwui32ScanCode == g_PrivateHotKeyData.ui32ScanCode) { + PVR_DPF(PVR_DBG_MESSAGE, "PDUMP Hotkey pressed !\n"); + + psStream = (struct DBG_STREAM *) + g_PrivateHotKeyData.sHotKeyInfo.pvStream; + + if (!g_bHotKeyPressed) { + + g_ui32HotKeyFrame = psStream->ui32Current + 2; + + g_bHotKeyPressed = IMG_TRUE; + } + } +} + +void ActivateHotKeys(struct DBG_STREAM *psStream) +{ + + ReadInHotKeys(); + + if (!g_PrivateHotKeyData.sHotKeyInfo.hHotKey) { + if (g_PrivateHotKeyData.ui32ScanCode != 0) { + PVR_DPF(PVR_DBG_MESSAGE, + "Activate HotKey for PDUMP.\n"); + + g_PrivateHotKeyData.sHotKeyInfo.pvStream = psStream; + + DefineHotKey(g_PrivateHotKeyData.ui32ScanCode, + g_PrivateHotKeyData.ui32ShiftState, + &g_PrivateHotKeyData.sHotKeyInfo); + } else { + g_PrivateHotKeyData.sHotKeyInfo.hHotKey = 0; + } + } +} + +void DeactivateHotKeys(void) +{ + if (g_PrivateHotKeyData.sHotKeyInfo.hHotKey != 0) { + PVR_DPF(PVR_DBG_MESSAGE, "Deactivate HotKey.\n"); + + RemoveHotKey(g_PrivateHotKeyData.sHotKeyInfo.hHotKey); + g_PrivateHotKeyData.sHotKeyInfo.hHotKey = 0; + } +} diff --git a/drivers/gpu/pvr/tools/hotkey.h b/drivers/gpu/pvr/tools/hotkey.h new file mode 100644 index 00000000000..56c559fe3d4 --- /dev/null +++ b/drivers/gpu/pvr/tools/hotkey.h @@ -0,0 +1,60 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _HOTKEY_ +#define _HOTKEY_ + +struct HOTKEYINFO { + u8 ui8ScanCode; + u8 ui8Type; + u8 ui8Flag; + u8 ui8Filler1; + u32 ui32ShiftState; + u32 ui32HotKeyProc; + void *pvStream; + u32 hHotKey; +}; + +struct PRIVATEHOTKEYDATA { + u32 ui32ScanCode; + u32 ui32ShiftState; + struct HOTKEYINFO sHotKeyInfo; +}; + +extern u32 g_ui32HotKeyFrame; +extern IMG_BOOL g_bHotKeyPressed; +extern IMG_BOOL g_bHotKeyRegistered; + +void ReadInHotKeys(void); +void ActivateHotKeys(struct DBG_STREAM *psStream); +void DeactivateHotKeys(void); + +void RemoveHotKey(u32 hHotKey); +void DefineHotKey(u32 ui32ScanCode, u32 ui32ShiftState, + struct HOTKEYINFO *psInfo); +void RegisterKeyPressed(u32 ui32ScanCode, struct HOTKEYINFO *psInfo); + +#endif diff --git a/drivers/gpu/pvr/tools/ioctl.c b/drivers/gpu/pvr/tools/ioctl.c new file mode 100644 index 00000000000..ddba5278b67 --- /dev/null +++ b/drivers/gpu/pvr/tools/ioctl.c @@ -0,0 +1,399 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/uaccess.h> + +#include "img_types.h" +#include "dbgdrvif.h" +#include "dbgdriv.h" +#include "hotkey.h" + +u32 DBGDIOCDrivCreateStream(void *pvInBuffer, + void *pvOutBuffer) +{ + struct DBG_IN_CREATESTREAM *psIn; + void **ppvOut; + static char name[32]; + + psIn = (struct DBG_IN_CREATESTREAM *)pvInBuffer; + ppvOut = (void **)pvOutBuffer; + + + if (copy_from_user(name, psIn->pszName, 32) != 0) + return IMG_FALSE; + *ppvOut = + ExtDBGDrivCreateStream(name, psIn->ui32CapMode, psIn->ui32OutMode, + 0, psIn->ui32Pages); + + + return IMG_TRUE; +} + +u32 DBGDIOCDrivDestroyStream(void *pvInBuffer, + void *pvOutBuffer) +{ + u32 *pStream; + struct DBG_STREAM *psStream; + + pStream = (u32 *) pvInBuffer; + psStream = (struct DBG_STREAM *)*pStream; + + PVR_UNREFERENCED_PARAMETER(pvOutBuffer); + + ExtDBGDrivDestroyStream(psStream); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivGetStream(void *pvInBuffer, void *pvOutBuffer) +{ + struct DBG_IN_FINDSTREAM *psParams; + u32 *pui32Stream; + + psParams = (struct DBG_IN_FINDSTREAM *)pvInBuffer; + pui32Stream = (u32 *) pvOutBuffer; + + *pui32Stream = + (u32) ExtDBGDrivFindStream(psParams->pszName, + psParams->bResetStream); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivWriteString(void *pvInBuffer, void *pvOutBuffer) +{ + struct DBG_IN_WRITESTRING *psParams; + u32 *pui32OutLen; + + psParams = (struct DBG_IN_WRITESTRING *)pvInBuffer; + pui32OutLen = (u32 *) pvOutBuffer; + + *pui32OutLen = + ExtDBGDrivWriteString((struct DBG_STREAM *)psParams->pvStream, + psParams->pszString, psParams->ui32Level); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivWriteStringCM(void *pvInBuffer, + void *pvOutBuffer) +{ + struct DBG_IN_WRITESTRING *psParams; + u32 *pui32OutLen; + + psParams = (struct DBG_IN_WRITESTRING *)pvInBuffer; + pui32OutLen = (u32 *) pvOutBuffer; + + *pui32OutLen = + ExtDBGDrivWriteStringCM((struct DBG_STREAM *)psParams->pvStream, + psParams->pszString, psParams->ui32Level); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivReadString(void *pvInBuffer, void *pvOutBuffer) +{ + u32 *pui32OutLen; + struct DBG_IN_READSTRING *psParams; + + psParams = (struct DBG_IN_READSTRING *)pvInBuffer; + pui32OutLen = (u32 *) pvOutBuffer; + + *pui32OutLen = + ExtDBGDrivReadString(psParams->pvStream, psParams->pszString, + psParams->ui32StringLen); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivWrite(void *pvInBuffer, void *pvOutBuffer) +{ + u32 *pui32BytesCopied; + struct DBG_IN_WRITE *psInParams; + + psInParams = (struct DBG_IN_WRITE *)pvInBuffer; + pui32BytesCopied = (u32 *) pvOutBuffer; + + *pui32BytesCopied = + ExtDBGDrivWrite((struct DBG_STREAM *)psInParams->pvStream, + psInParams->pui8InBuffer, + psInParams->ui32TransferSize, + psInParams->ui32Level); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivWrite2(void *pvInBuffer, void *pvOutBuffer) +{ + u32 *pui32BytesCopied; + struct DBG_IN_WRITE *psInParams; + + psInParams = (struct DBG_IN_WRITE *)pvInBuffer; + pui32BytesCopied = (u32 *) pvOutBuffer; + + *pui32BytesCopied = + ExtDBGDrivWrite2((struct DBG_STREAM *)psInParams->pvStream, + psInParams->pui8InBuffer, + psInParams->ui32TransferSize, + psInParams->ui32Level); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivWriteCM(void *pvInBuffer, void *pvOutBuffer) +{ + u32 *pui32BytesCopied; + struct DBG_IN_WRITE *psInParams; + + psInParams = (struct DBG_IN_WRITE *)pvInBuffer; + pui32BytesCopied = (u32 *) pvOutBuffer; + + *pui32BytesCopied = + ExtDBGDrivWriteCM((struct DBG_STREAM *)psInParams->pvStream, + psInParams->pui8InBuffer, + psInParams->ui32TransferSize, + psInParams->ui32Level); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivRead(void *pvInBuffer, void *pvOutBuffer) +{ + u32 *pui32BytesCopied; + struct DBG_IN_READ *psInParams; + + psInParams = (struct DBG_IN_READ *)pvInBuffer; + pui32BytesCopied = (u32 *) pvOutBuffer; + + *pui32BytesCopied = + ExtDBGDrivRead((struct DBG_STREAM *)psInParams->pvStream, + psInParams->bReadInitBuffer, + psInParams->ui32OutBufferSize, + psInParams->pui8OutBuffer); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivSetCaptureMode(void *pvInBuffer, + void *pvOutBuffer) +{ + struct DBG_IN_SETDEBUGMODE *psParams; + + psParams = (struct DBG_IN_SETDEBUGMODE *)pvInBuffer; + PVR_UNREFERENCED_PARAMETER(pvOutBuffer); + + ExtDBGDrivSetCaptureMode((struct DBG_STREAM *)psParams->pvStream, + psParams->ui32Mode, + psParams->ui32Start, + psParams->ui32End, psParams->ui32SampleRate); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivSetOutMode(void *pvInBuffer, void *pvOutBuffer) +{ + struct DBG_IN_SETDEBUGOUTMODE *psParams; + + psParams = (struct DBG_IN_SETDEBUGOUTMODE *)pvInBuffer; + PVR_UNREFERENCED_PARAMETER(pvOutBuffer); + + ExtDBGDrivSetOutputMode((struct DBG_STREAM *)psParams->pvStream, + psParams->ui32Mode); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivSetDebugLevel(void *pvInBuffer, + void *pvOutBuffer) +{ + struct DBG_IN_SETDEBUGLEVEL *psParams; + + psParams = (struct DBG_IN_SETDEBUGLEVEL *)pvInBuffer; + PVR_UNREFERENCED_PARAMETER(pvOutBuffer); + + ExtDBGDrivSetDebugLevel((struct DBG_STREAM *)psParams->pvStream, + psParams->ui32Level); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivSetFrame(void *pvInBuffer, void *pvOutBuffer) +{ + struct DBG_IN_SETFRAME *psParams; + + psParams = (struct DBG_IN_SETFRAME *)pvInBuffer; + PVR_UNREFERENCED_PARAMETER(pvOutBuffer); + + ExtDBGDrivSetFrame((struct DBG_STREAM *)psParams->pvStream, + psParams->ui32Frame); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivGetFrame(void *pvInBuffer, void *pvOutBuffer) +{ + u32 *pStream; + struct DBG_STREAM *psStream; + u32 *pui32Current; + + pStream = (u32 *) pvInBuffer; + psStream = (struct DBG_STREAM *)*pStream; + pui32Current = (u32 *) pvOutBuffer; + + *pui32Current = ExtDBGDrivGetFrame(psStream); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivIsCaptureFrame(void *pvInBuffer, + void *pvOutBuffer) +{ + struct DBG_IN_ISCAPTUREFRAME *psParams; + u32 *pui32Current; + + psParams = (struct DBG_IN_ISCAPTUREFRAME *)pvInBuffer; + pui32Current = (u32 *) pvOutBuffer; + + *pui32Current = + ExtDBGDrivIsCaptureFrame((struct DBG_STREAM *)psParams->pvStream, + psParams->bCheckPreviousFrame); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivOverrideMode(void *pvInBuffer, + void *pvOutBuffer) +{ + struct DBG_IN_OVERRIDEMODE *psParams; + + psParams = (struct DBG_IN_OVERRIDEMODE *)pvInBuffer; + PVR_UNREFERENCED_PARAMETER(pvOutBuffer); + + ExtDBGDrivOverrideMode((struct DBG_STREAM *)psParams->pvStream, + psParams->ui32Mode); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivDefaultMode(void *pvInBuffer, void *pvOutBuffer) +{ + u32 *pStream; + struct DBG_STREAM *psStream; + + pStream = (u32 *) pvInBuffer; + psStream = (struct DBG_STREAM *)*pStream; + + PVR_UNREFERENCED_PARAMETER(pvOutBuffer); + + ExtDBGDrivDefaultMode(psStream); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivSetMarker(void *pvInBuffer, void *pvOutBuffer) +{ + struct DBG_IN_SETMARKER *psParams; + + psParams = (struct DBG_IN_SETMARKER *)pvInBuffer; + PVR_UNREFERENCED_PARAMETER(pvOutBuffer); + + ExtDBGDrivSetMarker((struct DBG_STREAM *)psParams->pvStream, + psParams->ui32Marker); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivGetMarker(void *pvInBuffer, void *pvOutBuffer) +{ + u32 *pStream; + struct DBG_STREAM *psStream; + u32 *pui32Current; + + pStream = (u32 *) pvInBuffer; + psStream = (struct DBG_STREAM *)*pStream; + pui32Current = (u32 *) pvOutBuffer; + + *pui32Current = ExtDBGDrivGetMarker(psStream); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivGetServiceTable(void *pvInBuffer, + void *pvOutBuffer) +{ + u32 *pui32Out; + + PVR_UNREFERENCED_PARAMETER(pvInBuffer); + pui32Out = (u32 *) pvOutBuffer; + + *pui32Out = DBGDrivGetServiceTable(); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivWriteLF(void *pvInBuffer, void *pvOutBuffer) +{ + struct DBG_IN_WRITE_LF *psInParams; + u32 *pui32BytesCopied; + + psInParams = (struct DBG_IN_WRITE_LF *)pvInBuffer; + pui32BytesCopied = (u32 *) pvOutBuffer; + + *pui32BytesCopied = ExtDBGDrivWriteLF(psInParams->pvStream, + psInParams->pui8InBuffer, + psInParams->ui32BufferSize, + psInParams->ui32Level, + psInParams->ui32Flags); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivReadLF(void *pvInBuffer, void *pvOutBuffer) +{ + u32 *pui32BytesCopied; + struct DBG_IN_READ *psInParams; + + psInParams = (struct DBG_IN_READ *)pvInBuffer; + pui32BytesCopied = (u32 *) pvOutBuffer; + + *pui32BytesCopied = + ExtDBGDrivReadLF((struct DBG_STREAM *)psInParams->pvStream, + psInParams->ui32OutBufferSize, + psInParams->pui8OutBuffer); + + return IMG_TRUE; +} + +u32 DBGDIOCDrivWaitForEvent(void *pvInBuffer, void *pvOutBuffer) +{ + enum DBG_EVENT eEvent = (enum DBG_EVENT)(*(u32 *) pvInBuffer); + + PVR_UNREFERENCED_PARAMETER(pvOutBuffer); + + ExtDBGDrivWaitForEvent(eEvent); + + return IMG_TRUE; +} diff --git a/drivers/gpu/pvr/tools/ioctl.h b/drivers/gpu/pvr/tools/ioctl.h new file mode 100644 index 00000000000..fcb1ff156eb --- /dev/null +++ b/drivers/gpu/pvr/tools/ioctl.h @@ -0,0 +1,81 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _IOCTL_ +#define _IOCTL_ + +u32 DBGDIOCDrivCreateStream(void *, void *); +u32 DBGDIOCDrivDestroyStream(void *, void *); +u32 DBGDIOCDrivGetStream(void *, void *); +u32 DBGDIOCDrivWriteString(void *, void *); +u32 DBGDIOCDrivReadString(void *, void *); +u32 DBGDIOCDrivWrite(void *, void *); +u32 DBGDIOCDrivWrite2(void *, void *); +u32 DBGDIOCDrivRead(void *, void *); +u32 DBGDIOCDrivSetCaptureMode(void *, void *); +u32 DBGDIOCDrivSetOutMode(void *, void *); +u32 DBGDIOCDrivSetDebugLevel(void *, void *); +u32 DBGDIOCDrivSetFrame(void *, void *); +u32 DBGDIOCDrivGetFrame(void *, void *); +u32 DBGDIOCDrivOverrideMode(void *, void *); +u32 DBGDIOCDrivDefaultMode(void *, void *); +u32 DBGDIOCDrivGetServiceTable(void *, void *); +u32 DBGDIOCDrivWriteStringCM(void *, void *); +u32 DBGDIOCDrivWriteCM(void *, void *); +u32 DBGDIOCDrivSetMarker(void *, void *); +u32 DBGDIOCDrivGetMarker(void *, void *); +u32 DBGDIOCDrivIsCaptureFrame(void *, void *); +u32 DBGDIOCDrivWriteLF(void *, void *); +u32 DBGDIOCDrivReadLF(void *, void *); +u32 DBGDIOCDrivWaitForEvent(void *, void *); + +u32(*g_DBGDrivProc[])(void *, void *) = { +DBGDIOCDrivCreateStream, + DBGDIOCDrivDestroyStream, + DBGDIOCDrivGetStream, + DBGDIOCDrivWriteString, + DBGDIOCDrivReadString, + DBGDIOCDrivWrite, + DBGDIOCDrivRead, + DBGDIOCDrivSetCaptureMode, + DBGDIOCDrivSetOutMode, + DBGDIOCDrivSetDebugLevel, + DBGDIOCDrivSetFrame, + DBGDIOCDrivGetFrame, + DBGDIOCDrivOverrideMode, + DBGDIOCDrivDefaultMode, + DBGDIOCDrivGetServiceTable, + DBGDIOCDrivWrite2, + DBGDIOCDrivWriteStringCM, + DBGDIOCDrivWriteCM, + DBGDIOCDrivSetMarker, + DBGDIOCDrivGetMarker, + DBGDIOCDrivIsCaptureFrame, + DBGDIOCDrivWriteLF, DBGDIOCDrivReadLF, DBGDIOCDrivWaitForEvent}; + +#define MAX_DBGVXD_W32_API (sizeof(g_DBGDrivProc)/sizeof(u32)) + +#endif diff --git a/drivers/gpu/pvr/tools/linuxsrv.h b/drivers/gpu/pvr/tools/linuxsrv.h new file mode 100644 index 00000000000..822ba4e3027 --- /dev/null +++ b/drivers/gpu/pvr/tools/linuxsrv.h @@ -0,0 +1,47 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef _LINUXSRV_H__ +#define _LINUXSRV_H__ + +struct IOCTL_PACKAGE { + u32 ui32Cmd; + u32 ui32Size; + void *pInBuffer; + u32 ui32InBufferSize; + void *pOutBuffer; + u32 ui32OutBufferSize; +}; + +u32 DeviceIoControl(u32 hDevice, + u32 ui32ControlCode, + void *pInBuffer, + u32 ui32InBufferSize, + void *pOutBuffer, + u32 ui32OutBufferSize, + u32 *pui32BytesReturned); + +#endif diff --git a/drivers/gpu/pvr/tools/main.c b/drivers/gpu/pvr/tools/main.c new file mode 100644 index 00000000000..5de15cc944b --- /dev/null +++ b/drivers/gpu/pvr/tools/main.c @@ -0,0 +1,197 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/kdev_t.h> +#include <linux/pci.h> +#include <linux/list.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/uaccess.h> + +#include "img_types.h" +#include "linuxsrv.h" +#include "ioctl.h" +#include "dbgdrvif.h" +#include "dbgdriv.h" +#include "hostfunc.h" +#include "pvr_debug.h" + +#define DRVNAME "dbgdrv" + +MODULE_AUTHOR("Imagination Technologies Ltd. <gpl-support@imgtec.com>"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE(DRVNAME); + +static int AssignedMajorNumber; + +static long dbgdrv_ioctl(struct file *, unsigned int, unsigned long); + +static int dbgdrv_open(struct inode unref__ * pInode, + struct file unref__ * pFile) +{ + return 0; +} + +static int dbgdrv_release(struct inode unref__ * pInode, + struct file unref__ * pFile) +{ + return 0; +} + +static int dbgdrv_mmap(struct file *pFile, struct vm_area_struct *ps_vma) +{ + return 0; +} + +static const struct file_operations dbgdrv_fops = { +owner: THIS_MODULE, +unlocked_ioctl : dbgdrv_ioctl, +open : dbgdrv_open, +release : dbgdrv_release, +mmap : dbgdrv_mmap, +}; + +void DBGDrvGetServiceTable(void **fn_table) +{ + *fn_table = &g_sDBGKMServices; + +} +EXPORT_SYMBOL(DBGDrvGetServiceTable); + +void cleanup_module(void) +{ + if (AssignedMajorNumber > 0) + unregister_chrdev(AssignedMajorNumber, DRVNAME); + +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) + HostDestroyEventObjects(); +#endif + + if (g_pvAPIMutex != NULL) + HostDestroyMutex(g_pvAPIMutex); + + return; +} + +int init_module(void) +{ + g_pvAPIMutex = HostCreateMutex(); + if (g_pvAPIMutex == NULL) { + cleanup_module(); + return -ENOMEM; + } +#if defined(SUPPORT_DBGDRV_EVENT_OBJECTS) + + (void)HostCreateEventObjects(); +#endif + + AssignedMajorNumber = + register_chrdev(AssignedMajorNumber, DRVNAME, &dbgdrv_fops); + + if (AssignedMajorNumber <= 0) { + PVR_DPF(PVR_DBG_ERROR, " unable to get major\n"); + cleanup_module(); + return -EBUSY; + } + + return 0; +} + +static long dbgdrv_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct IOCTL_PACKAGE *pIP = (struct IOCTL_PACKAGE *)arg; + + char *buffer, *in, *out; + + if ((pIP->ui32InBufferSize > (PAGE_SIZE >> 1)) + || (pIP->ui32OutBufferSize > (PAGE_SIZE >> 1))) { + PVR_DPF(PVR_DBG_ERROR, + "Sizes of the buffers are too large, cannot do ioctl\n"); + return -1; + } + + buffer = (char *)HostPageablePageAlloc(1); + if (!buffer) { + PVR_DPF(PVR_DBG_ERROR, + "Failed to allocate buffer, cannot do ioctl\n"); + return -EFAULT; + } + + in = buffer; + out = buffer + (PAGE_SIZE >> 1); + + if (copy_from_user(in, pIP->pInBuffer, pIP->ui32InBufferSize) != 0) + goto init_failed; + + cmd = ((pIP->ui32Cmd >> 2) & 0xFFF) - 0x801; + + if (pIP->ui32Cmd == DEBUG_SERVICE_READ) { + char *ui8Tmp; + u32 *pui32BytesCopied = (u32 *) out; + struct DBG_IN_READ *psReadInParams = (struct DBG_IN_READ *)in; + + ui8Tmp = vmalloc(psReadInParams->ui32OutBufferSize); + if (!ui8Tmp) + goto init_failed; + *pui32BytesCopied = ExtDBGDrivRead((struct DBG_STREAM *) + psReadInParams->pvStream, + psReadInParams->bReadInitBuffer, + psReadInParams->ui32OutBufferSize, ui8Tmp); + if (copy_to_user(psReadInParams->pui8OutBuffer, ui8Tmp, + *pui32BytesCopied) != 0) { + vfree(ui8Tmp); + goto init_failed; + } + vfree(ui8Tmp); + } else { + (g_DBGDrivProc[cmd]) (in, out); + } + + if (copy_to_user(pIP->pOutBuffer, out, pIP->ui32OutBufferSize) != 0) + goto init_failed; + + HostPageablePageFree((void *) buffer); + return 0; + +init_failed: + HostPageablePageFree((void *) buffer); + return -EFAULT; +} + +void RemoveHotKey(unsigned hHotKey) +{ + +} + +void DefineHotKey(unsigned ScanCode, unsigned ShiftState, void *pInfo) +{ + +} + diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 175f8f6ff88..1e02feb8463 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -23,6 +23,8 @@ source "drivers/gpu/drm/Kconfig" source "drivers/gpu/stub/Kconfig" +source "drivers/gpu/pvr/Kconfig" + config VGASTATE tristate default n diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 8ab6d43329b..d3eecdd00b3 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -201,6 +201,8 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane, int dss_init_overlay_managers(struct platform_device *pdev); void dss_uninit_overlay_managers(struct platform_device *pdev); int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); +int dss_mgr_notify_ovl(struct omap_overlay *ovl, + enum omap_dss_notify_event events); void dss_setup_partial_planes(struct omap_dss_device *dssdev, u16 *x, u16 *y, u16 *w, u16 *h, bool enlarge_update_area); diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 9aeea50e33f..7908b032e6d 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -25,6 +25,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/notifier.h> #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/jiffies.h> @@ -418,6 +419,8 @@ struct overlay_cache_data { u32 fifo_high; bool manual_update; + + enum omap_dss_notify_event requested_events; }; struct manager_cache_data { @@ -429,6 +432,8 @@ struct manager_cache_data { * VSYNC/EVSYNC */ bool shadow_dirty; + bool enabled; + u32 default_color; enum omap_dss_trans_key_type trans_key_type; @@ -447,8 +452,14 @@ struct manager_cache_data { /* enlarge the update area if the update area contains scaled * overlays */ bool enlarge_update_area; + + bool in_use; + + enum omap_dss_notify_event requested_events; }; +static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr); + static struct { spinlock_t lock; struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS]; @@ -457,7 +468,156 @@ static struct { bool irq_enabled; } dss_cache; +static ATOMIC_NOTIFIER_HEAD(dss_notifier_list); + +static int dss_notifier_call_chain(unsigned long val, void *v) +{ + return atomic_notifier_call_chain(&dss_notifier_list, val, v); +} + +/** + * Check from events which should be fired now. + * + * @return: list of events that should fire now. + */ +static enum omap_dss_notify_event dss_mgr_notify_check( + struct omap_overlay_manager *mgr, + struct manager_cache_data *mc, + enum omap_dss_notify_event events) +{ + if (mc->manual_update) { + if (mc->enabled && mc->in_use && mgr->info_dirty) + events &= ~OMAP_DSS_NOTIFY_GO_MGR; + + if (mc->enabled && mc->in_use) + events &= ~OMAP_DSS_NOTIFY_UPDATE_MGR; + } else { + if (mc->enabled && (mc->dirty || mc->shadow_dirty)) + events = OMAP_DSS_NOTIFY_NONE; + } + + return events; +} + +static enum omap_dss_notify_event dss_mgr_notify_check_ovl( + struct omap_overlay *ovl, + struct overlay_cache_data *oc, + struct manager_cache_data *mc, + enum omap_dss_notify_event events) +{ + if (mc->manual_update) { + if (mc->enabled && oc->enabled + && mc->in_use && ovl->info_dirty) + events &= ~OMAP_DSS_NOTIFY_GO_OVL; + + if (mc->enabled && oc->enabled && mc->in_use) + events &= ~OMAP_DSS_NOTIFY_UPDATE_OVL; + } else { + if (mc->enabled && oc->enabled + && (oc->dirty || oc->shadow_dirty)) + events = OMAP_DSS_NOTIFY_NONE; + } + + return events; +} + +static enum omap_dss_notify_event check_mgr_notify( + struct omap_overlay_manager *mgr) +{ + struct manager_cache_data *mc; + + if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC)) + return OMAP_DSS_NOTIFY_NONE; + + mc = &dss_cache.manager_cache[mgr->id]; + + if (mc->requested_events == OMAP_DSS_NOTIFY_NONE) + return OMAP_DSS_NOTIFY_NONE; + return dss_mgr_notify_check(mgr, mc, mc->requested_events); +} + +static enum omap_dss_notify_event check_ovl_notify( + struct omap_overlay *ovl) +{ + struct overlay_cache_data *oc; + struct manager_cache_data *mc; + + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) + return OMAP_DSS_NOTIFY_NONE; + + oc = &dss_cache.overlay_cache[ovl->id]; + + if (!ovl->manager) + return oc->requested_events; + + mc = &dss_cache.manager_cache[ovl->manager->id]; + + if (oc->requested_events == OMAP_DSS_NOTIFY_NONE) + return OMAP_DSS_NOTIFY_NONE; + + return dss_mgr_notify_check_ovl(ovl, oc, mc, oc->requested_events); +} + +static void dss_run_notifiers(void) +{ + struct overlay_cache_data *oc; + struct manager_cache_data *mc; + int i; + struct omap_overlay_manager *mgr; + struct omap_overlay *ovl; + enum omap_dss_notify_event events; + + list_for_each_entry(mgr, &manager_list, list) { + events = check_mgr_notify(mgr); + if (events == OMAP_DSS_NOTIFY_NONE) + continue; + + mc = &dss_cache.manager_cache[mgr->id]; + + mc->requested_events &= ~events; + + dss_notifier_call_chain(events, + (void *)(long)mgr->id); + } + + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + ovl = omap_dss_get_overlay(i); + + events = check_ovl_notify(ovl); + if (events == OMAP_DSS_NOTIFY_NONE) + continue; + + oc = &dss_cache.overlay_cache[ovl->id]; + + oc->requested_events &= ~events; + + dss_notifier_call_chain(events, + (void *)(long)ovl->id); + } +} + +void omap_dss_lock_cache(void) +{ + unsigned long flags; + spin_lock_irqsave(&dss_cache.lock, flags); + BUG_ON(dss_cache.manager_cache[0].in_use); + dss_cache.manager_cache[0].in_use = true; + spin_unlock_irqrestore(&dss_cache.lock, flags); +} +EXPORT_SYMBOL(omap_dss_lock_cache); + +void omap_dss_unlock_cache(void) +{ + unsigned long flags; + spin_lock_irqsave(&dss_cache.lock, flags); + BUG_ON(!dss_cache.manager_cache[0].in_use); + dss_cache.manager_cache[0].in_use = false; + dss_run_notifiers(); + spin_unlock_irqrestore(&dss_cache.lock, flags); + omap_dss_mgr_apply(omap_dss_get_overlay_manager(0)); +} +EXPORT_SYMBOL(omap_dss_unlock_cache); static int omap_dss_set_device(struct omap_overlay_manager *mgr, struct omap_dss_device *dssdev) @@ -527,153 +687,89 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); } -static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) -{ - unsigned long timeout = msecs_to_jiffies(500); - struct manager_cache_data *mc; - u32 irq; - int r; - int i; - struct omap_dss_device *dssdev = mgr->device; - - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC - || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { - irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - } else { - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { - enum omap_dss_update_mode mode; - mode = dssdev->driver->get_update_mode(dssdev); - if (mode != OMAP_DSS_UPDATE_AUTO) - return 0; - - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_FRAMEDONE - : DISPC_IRQ_FRAMEDONE2; - } else { - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_VSYNC - : DISPC_IRQ_VSYNC2; - } - } +struct dss_wait_notify_event { + enum omap_dss_notify_event event; + int id; + struct completion compl; + struct list_head list; +}; - mc = &dss_cache.manager_cache[mgr->id]; - i = 0; - while (1) { - unsigned long flags; - bool shadow_dirty, dirty; - - spin_lock_irqsave(&dss_cache.lock, flags); - dirty = mc->dirty; - shadow_dirty = mc->shadow_dirty; - spin_unlock_irqrestore(&dss_cache.lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } +static struct { + struct notifier_block nb; + spinlock_t lock; + struct list_head list; +} dss_wait_notify; - /* 4 iterations is the worst case: - * 1 - initial iteration, dirty = true (between VFP and VSYNC) - * 2 - first VSYNC, dirty = true - * 3 - dirty = false, shadow_dirty = true - * 4 - shadow_dirty = false */ - if (i++ == 3) { - DSSERR("mgr(%d)->wait_for_go() not finishing\n", - mgr->id); - r = 0; - break; - } +static int dss_wait_notify_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct dss_wait_notify_event *e; + unsigned long flags; - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; + spin_lock_irqsave(&dss_wait_notify.lock, flags); - if (r) { - DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); - break; - } + list_for_each_entry(e, &dss_wait_notify.list, list) { + if (!(event & e->event)) + continue; + if ((long)data != e->id) + continue; + complete(&e->compl); } - return r; + spin_unlock_irqrestore(&dss_wait_notify.lock, flags); + + return 0; } -int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) +static int dss_wait_notify_event(enum omap_dss_notify_event event, + int id) { unsigned long timeout = msecs_to_jiffies(500); - struct overlay_cache_data *oc; - struct omap_dss_device *dssdev; - u32 irq; + struct dss_wait_notify_event e = { + .event = event, + .id = id, + }; + unsigned long flags; int r; - int i; - if (!ovl->manager) - return 0; + init_completion(&e.compl); - dssdev = ovl->manager->device; + spin_lock_irqsave(&dss_wait_notify.lock, flags); + list_add_tail(&e.list, &dss_wait_notify.list); + spin_unlock_irqrestore(&dss_wait_notify.lock, flags); - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return 0; + r = omap_dss_request_notify(event, id); + if (r) + goto list_remove; - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC - || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { - irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - } else { - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { - enum omap_dss_update_mode mode; - mode = dssdev->driver->get_update_mode(dssdev); - if (mode != OMAP_DSS_UPDATE_AUTO) - return 0; - - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_FRAMEDONE - : DISPC_IRQ_FRAMEDONE2; - } else { - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_VSYNC - : DISPC_IRQ_VSYNC2; - } - } + r = wait_for_completion_interruptible_timeout(&e.compl, timeout); + if (!r) + r = -ETIMEDOUT; - oc = &dss_cache.overlay_cache[ovl->id]; - i = 0; - while (1) { - unsigned long flags; - bool shadow_dirty, dirty; - - spin_lock_irqsave(&dss_cache.lock, flags); - dirty = oc->dirty; - shadow_dirty = oc->shadow_dirty; - spin_unlock_irqrestore(&dss_cache.lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } + list_remove: + spin_lock_irqsave(&dss_wait_notify.lock, flags); + list_del(&e.list); + spin_unlock_irqrestore(&dss_wait_notify.lock, flags); - /* 4 iterations is the worst case: - * 1 - initial iteration, dirty = true (between VFP and VSYNC) - * 2 - first VSYNC, dirty = true - * 3 - dirty = false, shadow_dirty = true - * 4 - shadow_dirty = false */ - if (i++ == 3) { - DSSERR("ovl(%d)->wait_for_go() not finishing\n", - ovl->id); - r = 0; - break; - } + return r < 0 ? r : 0; +} - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; +static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) +{ + int r = dss_wait_notify_event(OMAP_DSS_NOTIFY_GO_MGR, mgr->id); - if (r) { - DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); - break; - } - } + if (r == -ETIMEDOUT) + DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); + + return r; +} + +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) +{ + int r = dss_wait_notify_event(OMAP_DSS_NOTIFY_GO_OVL, ovl->id); + + if (r == -ETIMEDOUT) + DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); return r; } @@ -1004,6 +1100,146 @@ static void make_even(u16 *x, u16 *w) *w = x2 - x1; } +static int dss_mgr_notify(struct omap_overlay_manager *mgr, + enum omap_dss_notify_event events) +{ + struct manager_cache_data *mc; + const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache); + unsigned long flags; + enum omap_dss_notify_event fire_events = OMAP_DSS_NOTIFY_NONE; + struct omap_dss_device *dssdev = mgr->device; + int r = 0; + + if (mgr->id >= num_mgrs) + return -EINVAL; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + dss_notifier_call_chain(events, + (void *)(long)mgr->id); + return 0; + } + + spin_lock_irqsave(&dss_cache.lock, flags); + + mc = &dss_cache.manager_cache[mgr->id]; + + if (!mc->manual_update && (events & OMAP_DSS_NOTIFY_UPDATE_MGR)) { + r = -EINVAL; + goto err_out; + } + + fire_events = dss_mgr_notify_check(mgr, mc, events); + + mc->requested_events |= events & ~fire_events; + +err_out: + spin_unlock_irqrestore(&dss_cache.lock, flags); + + if (fire_events != OMAP_DSS_NOTIFY_NONE) + dss_notifier_call_chain(fire_events, + (void *)(long)mgr->id); + + return r; +} + +int dss_mgr_notify_ovl(struct omap_overlay *ovl, + enum omap_dss_notify_event events) +{ + struct overlay_cache_data *oc; + struct manager_cache_data *mc; + const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache); + unsigned long flags; + enum omap_dss_notify_event fire_events = OMAP_DSS_NOTIFY_NONE; + struct omap_dss_device *dssdev; + int r = 0; + + if (ovl->id >= num_ovls) + return -EINVAL; + + if (!ovl->manager) { + dss_notifier_call_chain(events, + (void *)(long)ovl->id); + return 0; + } + + dssdev = ovl->manager->device; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + dss_notifier_call_chain(events, + (void *)(long)ovl->id); + return 0; + } + + spin_lock_irqsave(&dss_cache.lock, flags); + + oc = &dss_cache.overlay_cache[ovl->id]; + mc = &dss_cache.manager_cache[ovl->manager->id]; + + if (!mc->manual_update && (events & OMAP_DSS_NOTIFY_UPDATE_OVL)) { + r = -EINVAL; + goto err_out; + } + + fire_events = dss_mgr_notify_check_ovl(ovl, oc, mc, events); + + oc->requested_events |= events & ~fire_events; + +err_out: + spin_unlock_irqrestore(&dss_cache.lock, flags); + + if (fire_events != OMAP_DSS_NOTIFY_NONE) + dss_notifier_call_chain(fire_events, + (void *)(long)ovl->id); + + return r; +} + +int omap_dss_request_notify(enum omap_dss_notify_event events, + long value) +{ + int r; + struct omap_overlay_manager *mgr; + struct omap_overlay *ovl; + + if (events & ~(OMAP_DSS_NOTIFY_MASK_MGR | OMAP_DSS_NOTIFY_MASK_OVL)) + return -EINVAL; + + if (events & OMAP_DSS_NOTIFY_MASK_MGR) { + mgr = omap_dss_get_overlay_manager(value); + if (!mgr) + return -EINVAL; + if (!mgr->notify) + return -ENOSYS; + r = mgr->notify(mgr, events & OMAP_DSS_NOTIFY_MASK_MGR); + if (r) + return r; + } + if (events & OMAP_DSS_NOTIFY_MASK_OVL) { + ovl = omap_dss_get_overlay(value); + if (!ovl) + return -EINVAL; + if (!ovl->notify) + return -ENOSYS; + r = ovl->notify(ovl, events & OMAP_DSS_NOTIFY_MASK_OVL); + if (r) + return r; + } + return 0; +} +EXPORT_SYMBOL(omap_dss_request_notify); + +int omap_dss_register_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&dss_notifier_list, nb); +} +EXPORT_SYMBOL(omap_dss_register_notifier); + +int omap_dss_unregister_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&dss_notifier_list, nb); +} +EXPORT_SYMBOL(omap_dss_unregister_notifier); + /* Configure dispc for partial update. Return possibly modified update * area */ void dss_setup_partial_planes(struct omap_dss_device *dssdev, @@ -1178,11 +1414,12 @@ static void dss_apply_irq_handler(void *data, u32 mask) int i, r; bool mgr_busy[MAX_DSS_MANAGERS]; u32 irq_mask; + unsigned long flags; for (i = 0; i < num_mgrs; i++) mgr_busy[i] = dispc_go_busy(i); - spin_lock(&dss_cache.lock); + spin_lock_irqsave(&dss_cache.lock, flags); for (i = 0; i < num_ovls; ++i) { oc = &dss_cache.overlay_cache[i]; @@ -1220,7 +1457,8 @@ static void dss_apply_irq_handler(void *data, u32 mask) dss_cache.irq_enabled = false; end: - spin_unlock(&dss_cache.lock); + dss_run_notifiers(); + spin_unlock_irqrestore(&dss_cache.lock, flags); } static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) @@ -1248,6 +1486,12 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) continue; oc = &dss_cache.overlay_cache[ovl->id]; + if (ovl->manager) { + mc = &dss_cache.manager_cache[ovl->manager->id]; + + if (mc->in_use) + continue; + } if (!overlay_enabled(ovl)) { if (oc->enabled) { @@ -1319,6 +1563,9 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) mc = &dss_cache.manager_cache[mgr->id]; + if (mc->in_use) + continue; + if (mgr->device_changed) { mgr->device_changed = false; mgr->info_dirty = true; @@ -1377,6 +1624,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) oc = &dss_cache.overlay_cache[ovl->id]; + if (ovl->manager) { + mc = &dss_cache.manager_cache[ovl->manager->id]; + + if (mc->in_use) + continue; + } + if (!oc->enabled) continue; @@ -1469,13 +1723,29 @@ static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr, static int dss_mgr_enable(struct omap_overlay_manager *mgr) { + struct manager_cache_data *mc = &dss_cache.manager_cache[mgr->id]; + unsigned long flags; + + spin_lock_irqsave(&dss_cache.lock, flags); + mc->enabled = true; + spin_unlock_irqrestore(&dss_cache.lock, flags); + dispc_enable_channel(mgr->id, 1); return 0; } static int dss_mgr_disable(struct omap_overlay_manager *mgr) { + struct manager_cache_data *mc = &dss_cache.manager_cache[mgr->id]; + unsigned long flags; + dispc_enable_channel(mgr->id, 0); + + spin_lock_irqsave(&dss_cache.lock, flags); + mc->enabled = false; + dss_run_notifiers(); + spin_unlock_irqrestore(&dss_cache.lock, flags); + return 0; } @@ -1491,6 +1761,11 @@ int dss_init_overlay_managers(struct platform_device *pdev) spin_lock_init(&dss_cache.lock); + spin_lock_init(&dss_wait_notify.lock); + INIT_LIST_HEAD(&dss_wait_notify.list); + dss_wait_notify.nb.notifier_call = dss_wait_notify_callback; + omap_dss_register_notifier(&dss_wait_notify.nb); + INIT_LIST_HEAD(&manager_list); num_managers = 0; @@ -1522,6 +1797,7 @@ int dss_init_overlay_managers(struct platform_device *pdev) mgr->set_manager_info = &omap_dss_mgr_set_info; mgr->get_manager_info = &omap_dss_mgr_get_info; mgr->wait_for_go = &dss_mgr_wait_for_go; + mgr->notify = &dss_mgr_notify; mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; mgr->enable = &dss_mgr_enable; @@ -1596,6 +1872,8 @@ void dss_uninit_overlay_managers(struct platform_device *pdev) kfree(mgr); } + omap_dss_unregister_notifier(&dss_wait_notify.nb); + num_managers = 0; } diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 0f08025b1f0..fe53368019d 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -485,6 +485,12 @@ static int dss_ovl_wait_for_go(struct omap_overlay *ovl) return dss_mgr_wait_for_go_ovl(ovl); } +static int dss_ovl_notify(struct omap_overlay *ovl, + enum omap_dss_notify_event events) +{ + return dss_mgr_notify_ovl(ovl, events); +} + static int omap_dss_set_manager(struct omap_overlay *ovl, struct omap_overlay_manager *mgr) { @@ -631,6 +637,7 @@ void dss_init_overlays(struct platform_device *pdev) ovl->set_overlay_info = &dss_ovl_set_overlay_info; ovl->get_overlay_info = &dss_ovl_get_overlay_info; ovl->wait_for_go = &dss_ovl_wait_for_go; + ovl->notify = &dss_ovl_notify; ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); diff --git a/include/linux/pvr.h b/include/linux/pvr.h new file mode 100644 index 00000000000..49f64e00f84 --- /dev/null +++ b/include/linux/pvr.h @@ -0,0 +1,8 @@ +#ifndef __PVR_H +#define __PVR_H + +struct sgx_platform_data { + unsigned long fclock_max; +}; + +#endif diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 892b97f8e15..26b3b9a1e8b 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -22,6 +22,7 @@ #include <linux/kobject.h> #include <linux/device.h> #include <linux/platform_device.h> +#include <linux/notifier.h> #include <asm/atomic.h> #define DISPC_IRQ_FRAMEDONE (1 << 0) @@ -188,6 +189,48 @@ enum omap_dss_clk_source { OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, /* OMAP4: PLL2_CLK2 */ }; +/** + * Go event is triggered when all dss caches are clean (including shadow + * registers). + * + * This is used in xserver xv implementation to block writing to overlay until + * dss has completed reading same memory area. + * + * Example use in xv: + * If there is manual update triggered by gfx overlay first wait_for_go() + * doesn't block but wait_gfx() would block. + ** Frame 5 to first "buffer" + * wait_for_go() + * fill frame + * pan to first "buffer" + * update_window() for frame 1 + * request update notify + ** Frame 6 to second "buffer" (wait_gfx() would block here) + * wait_for_go() + * fill frame + * pan to second "buffer" + ** Frame 7 to first "buffer" + * wait_for_go() blocking + * First update completes + * wait_for_go() returns + * update notify arrives + * update_window() for frame 2 + * fill frame + * pan to third frame + * + * Update event is sent when manual update completes. Update event is not + * available for automatic update displays (returns -EINVAL). + */ +enum omap_dss_notify_event { + OMAP_DSS_NOTIFY_NONE = 0 << 0, + OMAP_DSS_NOTIFY_GO_MGR = 1 << 0, + OMAP_DSS_NOTIFY_UPDATE_MGR = 2 << 0, + OMAP_DSS_NOTIFY_MASK_MGR = 3 << 0, + OMAP_DSS_NOTIFY_GO_OVL = 1 << 2, + OMAP_DSS_NOTIFY_UPDATE_OVL = 2 << 2, + OMAP_DSS_NOTIFY_MASK_OVL = 3 << 2, +}; + /* RFBI */ struct rfbi_timings { @@ -349,6 +392,8 @@ struct omap_overlay { struct omap_overlay_info *info); int (*wait_for_go)(struct omap_overlay *ovl); + int (*notify)(struct omap_overlay *ovl, + enum omap_dss_notify_event events); }; struct omap_overlay_manager_info { @@ -392,6 +437,8 @@ struct omap_overlay_manager { int (*apply)(struct omap_overlay_manager *mgr); int (*wait_for_go)(struct omap_overlay_manager *mgr); + int (*notify)(struct omap_overlay_manager *mgr, + enum omap_dss_notify_event events); int (*wait_for_vsync)(struct omap_overlay_manager *mgr); int (*enable)(struct omap_overlay_manager *mgr); @@ -584,10 +631,18 @@ struct omap_overlay_manager *omap_dss_get_overlay_manager(int num); int omap_dss_get_num_overlays(void); struct omap_overlay *omap_dss_get_overlay(int num); +void omap_dss_lock_cache(void); +void omap_dss_unlock_cache(void); + void omapdss_default_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres); int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev); +int omap_dss_register_notifier(struct notifier_block *nb); +int omap_dss_unregister_notifier(struct notifier_block *nb); + +int omap_dss_request_notify(enum omap_dss_notify_event event, long value); + typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask); int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask); diff --git a/include/video/sgx-util.h b/include/video/sgx-util.h new file mode 100644 index 00000000000..4a5bd7ff50a --- /dev/null +++ b/include/video/sgx-util.h @@ -0,0 +1,64 @@ +/* + * SGX utility functions + * + * Copyright (C) 2010 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SGX_UTIL_H +#define __SGX_UTIL_H + +#include <linux/kernel.h> + +#define OMAPLFB_PAGE_SIZE 4096 + +/* Greatest common divisor */ +static unsigned long gcd(unsigned long a, unsigned long b) +{ + unsigned long r; + + if (a < b) { + r = a; + a = b; + b = r; + } + + while ((r = a % b) != 0) { + a = b; + b = r; + } + + return b; +} + +/* + * Workout the smallest size that is aligned to both 4K (for the SGX) + * and line length (for the fbdev driver). + */ +static unsigned int sgx_buffer_align(unsigned stride, unsigned size) +{ + unsigned lcm; + + if (!stride || !size) + return 0; + + lcm = stride * OMAPLFB_PAGE_SIZE / gcd(stride, + OMAPLFB_PAGE_SIZE); + + return roundup(size, lcm); +} + +#endif /* __SGX_UTIL_H */ |