From c54fa69dd2d8a63f01430546cc9e8c6e83e6fd6a Mon Sep 17 00:00:00 2001 From: Klaus Kurzmann Date: Sun, 3 Oct 2010 15:59:58 +0200 Subject: linux-2.6.35: add meego patches for nokia900 Signed-off-by: Klaus Kurzmann --- recipes/linux/linux-2.6.35/nokia900/defconfig | 2237 + .../nokia900/inconsistent-mmc-fix-2.6.35.patch | 94 + ...tooth-Support-for-n900-bluetooth-hardware.patch | 2279 + ...2.6-Earpiece-and-headset-support-for-N900.patch | 577 + .../nokia900/linux-2.6-Hacks-for-Nokia-N900.patch | 651 + .../linux-2.6-SGX-PVR-driver-for-N900.patch | 45789 +++ ...fd-twl4030-Driver-for-twl4030-madc-module.patch | 759 + ...l4030-Driver-for-twl4030-madc-module.patch~HEAD | 759 + ...030-Driver-for-twl4030-madc-module.patch~HEAD_0 | 759 + .../nokia900/linux-2.6-n900-modem-support.patch | 7773 + .../nokia900/linux-2.6-omap3isp-rx51.patch | 33781 ++ .../nokia900/linux-2.6-usb-bt-autosuspend.patch | 13 + ...b-musb-ignore-spurious-SESSREQ-interrupts.patch | 42 + .../nokia900/linux-2.6-usb-uvc-autosuspend.patch | 19 + .../linux-2.6.29-dont-wait-for-mouse.patch | 47 + .../linux-2.6.33-ahci-alpm-accounting.patch | 300 + .../nokia900/linux-2.6.33-vfs-tracepoints.patch | 116 + ...inux-2.6.35-aava-firmware-workaround-wifi.patch | 66 + .../linux-2.6.35-aava-firmware-workaround.patch | 39 + .../nokia900/linux-2.6.35-ac-2010-08-24.patch | 301256 ++++++++++++++++++ .../nokia900/linux-2.6.35-ac-pending.patch | 26 + .../linux-2.6.35-ac-revert-mmc-hacks.patch | 403 + .../nokia900/linux-2.6.35-dont-skew-the-tick.patch | 33 + .../linux-2.6.35-make-gma600-work-on-IA.patch | 148 + .../nokia900/linux-2.6.35-mrst-rtc.patch | 28 + .../linux-2.6.35-rc4-annotate-device-pm.patch | 224 + .../nokia900/linux-2.6.35-slab-timer.patch | 38 + .../linux-2.6.35-stable-cherry-picks.patch | 4289 + ...hone-TV-out-and-basic-jack-detection-supp.patch | 810 + ....6.36-Introduce-and-enable-tsc2005-driver.patch | 912 + .../nokia900/linux-2.6.36-battery.patch | 87 + .../nokia900/linux-2.6.36-battery2.patch | 33 + ...fix-unprotected-acess-to-task-credentials.patch | 98 + ...latform-support-for-lis3lv02d-acceleromet.patch | 140 + ...map-rx51-Platform-support-for-tsl2563-ALS.patch | 52 + .../linux-2.6.36-powertop-timer-tracing.patch | 64 + .../nokia900/linux-2.6.36-tidspbridge.patch | 51086 +++ ...MODULE_ALIAS-macro-at-correct-postion-for.patch | 43 + ....36-wl1251-fix-trigger-scan-timeout-usage.patch | 37 + .../linux-2.6.37-EEM-support-for-g_nokia.patch | 86 + ...37-omap-rx51-add-support-for-USB-chargers.patch | 34 + ...rx51-Platform-support-for-lp5523-led-chip.patch | 127 + ...pply-add-isp1704-charger-detection-driver.patch | 413 + ...7-power_supply-add-types-for-USB-chargers.patch | 47 + recipes/linux/linux_2.6.35.bb | 91 + 45 files changed, 456705 insertions(+) create mode 100644 recipes/linux/linux-2.6.35/nokia900/defconfig create mode 100644 recipes/linux/linux-2.6.35/nokia900/inconsistent-mmc-fix-2.6.35.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-Bluetooth-Support-for-n900-bluetooth-hardware.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-Earpiece-and-headset-support-for-N900.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-Hacks-for-Nokia-N900.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-SGX-PVR-driver-for-N900.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-mfd-twl4030-Driver-for-twl4030-madc-module.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-mfd-twl4030-Driver-for-twl4030-madc-module.patch~HEAD create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-mfd-twl4030-Driver-for-twl4030-madc-module.patch~HEAD_0 create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-n900-modem-support.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-omap3isp-rx51.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-usb-bt-autosuspend.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-usb-musb-ignore-spurious-SESSREQ-interrupts.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6-usb-uvc-autosuspend.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.29-dont-wait-for-mouse.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.33-ahci-alpm-accounting.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.33-vfs-tracepoints.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-aava-firmware-workaround-wifi.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-aava-firmware-workaround.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-ac-2010-08-24.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-ac-pending.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-ac-revert-mmc-hacks.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-dont-skew-the-tick.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-make-gma600-work-on-IA.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-mrst-rtc.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-rc4-annotate-device-pm.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-slab-timer.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.35-stable-cherry-picks.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-FM-TX-headphone-TV-out-and-basic-jack-detection-supp.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-Introduce-and-enable-tsc2005-driver.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-battery.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-battery2.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-fix-unprotected-acess-to-task-credentials.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-omap-rx51-Platform-support-for-lis3lv02d-acceleromet.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-omap-rx51-Platform-support-for-tsl2563-ALS.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-powertop-timer-tracing.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-tidspbridge.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-wl1251-Use-MODULE_ALIAS-macro-at-correct-postion-for.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.36-wl1251-fix-trigger-scan-timeout-usage.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.37-EEM-support-for-g_nokia.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.37-omap-rx51-add-support-for-USB-chargers.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.37-omap3-rx51-Platform-support-for-lp5523-led-chip.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.37-power_supply-add-isp1704-charger-detection-driver.patch create mode 100644 recipes/linux/linux-2.6.35/nokia900/linux-2.6.37-power_supply-add-types-for-USB-chargers.patch (limited to 'recipes/linux') diff --git a/recipes/linux/linux-2.6.35/nokia900/defconfig b/recipes/linux/linux-2.6.35/nokia900/defconfig new file mode 100644 index 0000000000..2f1903d283 --- /dev/null +++ b/recipes/linux/linux-2.6.35/nokia900/defconfig @@ -0,0 +1,2237 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.35.3 +# Sat Oct 2 13:00:43 2010 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_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_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_LZO is not set +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_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TINY_RCU is not set +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_CGROUPS is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES 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_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_EXTRA_PASS=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_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 is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +# CONFIG_SLOW_WORK 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 is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_DEADLINE is not set +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_AAEC2000 is not set +# 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_STMP3XXX 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_L7200 is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI 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_NS9XXX is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_NUC93X 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_S5P6440 is not set +# CONFIG_ARCH_S5P6442 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X 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 + +# +# TI OMAP Implementations +# +CONFIG_ARCH_OMAP_OTG=y +# CONFIG_ARCH_OMAP1 is not set +CONFIG_ARCH_OMAP2PLUS=y +# CONFIG_ARCH_OMAP2 is not set +CONFIG_ARCH_OMAP3=y +# CONFIG_ARCH_OMAP4 is not set + +# +# OMAP Feature Selections +# +CONFIG_OMAP_RESET_CLOCKS=y +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_MCBSP=y +CONFIG_OMAP_MBOX_FWK=m +# CONFIG_OMAP_MPU_TIMER 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_ARCH_OMAP3430=y +CONFIG_OMAP_PACKAGE_CBB=y + +# +# OMAP Board Type +# +# CONFIG_MACH_OMAP3_BEAGLE is not set +# CONFIG_MACH_DEVKIT8000 is not set +# CONFIG_MACH_OMAP_LDP is not set +# CONFIG_MACH_OVERO is not set +# CONFIG_MACH_OMAP3EVM is not set +# CONFIG_MACH_OMAP3517EVM is not set +# CONFIG_MACH_OMAP3_PANDORA is not set +# CONFIG_MACH_OMAP3_TOUCHBOOK is not set +# CONFIG_MACH_OMAP_3430SDP is not set +CONFIG_MACH_NOKIA_RX51=y +# CONFIG_MACH_OMAP_ZOOM2 is not set +# CONFIG_MACH_OMAP_ZOOM3 is not set +# CONFIG_MACH_CM_T35 is not set +# CONFIG_MACH_IGEP0020 is not set +# CONFIG_MACH_SBC3530 is not set +# CONFIG_MACH_OMAP_3630SDP is not set +# CONFIG_OMAP3_EMU is not set +# CONFIG_OMAP3_SDRC_AC_TIMING is not set + +# +# Processor Type +# +CONFIG_CPU_32v6K=y +CONFIG_CPU_V7=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_HAS_TLS_REG=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +CONFIG_COMMON_CLKDEV=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_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_HZ=128 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# 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_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/mmcblk0p1 rootwait console=tty0 console=ttyS2,115200n8 omapfb.vram=0:2M,1:2M,2:2M mtdoops.mtddev=2 nosplash" +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y + +# +# CPU Power Management +# +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Power management options +# +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_ADVANCED_DEBUG=y +# CONFIG_PM_VERBOSE is not set +CONFIG_CAN_PM_TRACE=y +CONFIG_PM_SLEEP=y +# CONFIG_PM_SLEEP_ADVANCED_DEBUG is not set +CONFIG_SUSPEND_NVS=y +CONFIG_SUSPEND=y +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_SUSPEND_FREEZER=y +# CONFIG_APM_EMULATION is not set +# CONFIG_PM_RUNTIME is not set +CONFIG_PM_OPS=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_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=m +CONFIG_INET_TCP_DIAG=m +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_TCP_MD5SIG=y +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER 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=y +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_L2CAP_EXT_FEATURES=y +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_BT_HCIH4P=m +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=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 is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +CONFIG_MAC80211_RC_PID=y +# CONFIG_MAC80211_RC_MINSTREL is not set +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_LEDS is not set +# CONFIG_MAC80211_DEBUGFS is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_LEDS=y +CONFIG_RFKILL_INPUT=y +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_DEVTMPFS is not set +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 is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# 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=y +CONFIG_MTD_OOPS=y + +# +# 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 is not set +CONFIG_MTD_ONENAND=y +# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set +# 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 + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set + +# +# UBI debugging options +# +# 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=m +CONFIG_BLK_DEV_CRYPTOLOOP=m + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# 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=4096 +# 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_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29015 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_BH1770GLC is not set +# CONFIG_C2PORT is not set +CONFIG_CMT=m + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=m +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=m +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=m +# 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_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m +# CONFIG_VETH is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +# CONFIG_AX88796 is not set +CONFIG_SMC91X=m +# CONFIG_TI_DAVINCI_EMAC 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 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_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +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 is not set +# CONFIG_P54_COMMON is not set +# CONFIG_RT2X00 is not set +CONFIG_WL12XX=m +CONFIG_WL1251=m +CONFIG_WL1251_SPI=m +# CONFIG_WL1251_SDIO is not set +# CONFIG_WL1271 is not set +# CONFIG_ZD1211RW 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 is not set +CONFIG_USB_HSO=m +# CONFIG_USB_CDC_PHONET is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_WAN is not set +# 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=m +CONFIG_INPUT_POLLDEV=m +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +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_ATKBD is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=m +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_TC35894XBG 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_TWL4030=y +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_AD7879 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_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_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 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=m +CONFIG_INPUT_TWL4030_VIBRA=m +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO 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 is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# 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_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=m +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# 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_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_MRST is not set +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_OMAP=y +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# 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_BITBANG is not set +# CONFIG_SPI_GPIO is not set +CONFIG_SPI_OMAP24XX=y +# 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 +CONFIG_HSI=y + +# +# HSI controllers +# +CONFIG_OMAP_SSI=m +CONFIG_OMAP_SSI_CONFIG=y + +# +# HSI clients +# +CONFIG_SSI_PROTOCOL=m +CONFIG_HSI_CHAR=m +CONFIG_HSI_CMT_SPEECH=m + +# +# PPS support +# +# CONFIG_PPS is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_IT8761E is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X 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 + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=m +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2782 is not set +CONFIG_BATTERY_BQ27x00=y +# CONFIG_BATTERY_MAX17040 is not set +CONFIG_CHARGER_ISP1704=m +CONFIG_HWMON=m +# 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_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_IT87 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_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX1619 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_SENSORS_SHT15 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 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_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_LIS3_SPI is not set +CONFIG_SENSORS_LIS3_I2C=m +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_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_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_TPS65010 is not set +# CONFIG_TPS6507X is not set +CONFIG_TWL4030_CORE=y +# CONFIG_TWL4030_POWER is not set +CONFIG_TWL4030_CODEC=y +# CONFIG_MFD_TC35892 is not set +CONFIG_TWL4030_MADC=y +# 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_WM8400 is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13783 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_AB8500_CORE is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# 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_TWL4030=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +CONFIG_MEDIA_SUPPORT=m + +# +# Multimedia core support +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L2_COMMON=m +# CONFIG_VIDEO_ALLOW_V4L1 is not set +# CONFIG_VIDEO_V4L1_COMPAT is not set +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=m + +# +# Multimedia drivers +# +CONFIG_IR_CORE=m +CONFIG_VIDEO_IR=m +# CONFIG_RC_MAP is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_IMON is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=m +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +CONFIG_MEDIA_TUNER_MC44S803=m +CONFIG_VIDEO_V4L2=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_CONTIG=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +# CONFIG_VIDEO_IR_I2C is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TDA9875 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set + +# +# RDS decoders +# +# CONFIG_VIDEO_SAA6588 is not set + +# +# Video decoders +# +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_VPX3220 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_CX25840 is not set + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_AK881X is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +CONFIG_VIDEO_OMAP2_VOUT=m +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_V4L_USB_DRIVERS is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +CONFIG_PVR=m +CONFIG_PVR_RELEASE_N900=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 is not set +# 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_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_FB_OMAP_BOOTLOADER_INIT=y +CONFIG_OMAP2_VRAM=y +CONFIG_OMAP2_VRFB=y +CONFIG_OMAP2_DSS=y +CONFIG_OMAP2_VRAM_SIZE=2 +# 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 is not set +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_FB_OMAP2=y +# CONFIG_FB_OMAP2_DEBUG_SUPPORT is not set +CONFIG_FB_OMAP2_NUM_FBS=3 + +# +# OMAP2/3 Display Device Drivers +# +# CONFIG_PANEL_GENERIC is not set +# CONFIG_PANEL_SHARP_LS037V7DW01 is not set +# CONFIG_PANEL_SHARP_LQ043T1DG01 is not set +# CONFIG_PANEL_TOPPOLY_TDO35S is not set +# CONFIG_PANEL_TPO_TD043MTEA1 is not set +CONFIG_PANEL_ACX565AKM=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set + +# +# Display device support +# +CONFIG_DISPLAY_SUPPORT=y + +# +# Display hardware drivers +# + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# 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 is not set +# CONFIG_SND_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 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_USB is not set +CONFIG_SND_SOC=y +CONFIG_SND_OMAP_SOC=y +CONFIG_SND_OMAP_SOC_MCBSP=y +CONFIG_SND_OMAP_SOC_RX51=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_TLV320AIC3X=y +CONFIG_SND_SOC_TPA6130A2=y +# CONFIG_SOUND_PRIME is not set +# CONFIG_HID_SUPPORT is not set +CONFIG_HID=m +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 is not set +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_OTG=y +CONFIG_USB_OTG_WHITELIST=y +CONFIG_USB_OTG_BLACKLIST_HUB=y +CONFIG_USB_MON=m +# 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_SOC=y + +# +# OMAP 343x high speed USB support +# +# 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 is not set +CONFIG_USB_INVENTRA_DMA=y +# CONFIG_USB_TI_CPPI_DMA is not set +# CONFIG_USB_MUSB_DEBUG is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# 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=m +# CONFIG_USB_STORAGE_DEBUG 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_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 is not set +# CONFIG_USB_ISIGHTFW is not set +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA25X is not set +# CONFIG_USB_GADGET_R8A66597 is not set +# CONFIG_USB_GADGET_PXA27X is not set +# CONFIG_USB_GADGET_S3C_HSOTG is not set +# CONFIG_USB_GADGET_IMX is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_QE is not set +# CONFIG_USB_GADGET_CI13XXX is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LANGWELL is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_ETH_EEM=n +# 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_NOKIA=m +CONFIG_USB_G_NOKIA_EEM=y +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_WEBCAM 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_NOP_USB_XCEIV is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_OMAP is not set +CONFIG_MMC_OMAP_HS=y +# CONFIG_MMC_SPI is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m + +# +# LED drivers +# +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_LP3944 is not set +CONFIG_LEDS_LP5523=m +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +CONFIG_LEDS_TRIGGER_GPIO=m +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +# 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_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 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_TWL4030=m +# 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 + +# +# SPI RTC drivers +# +# 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=y +# CONFIG_STAGING_EXCLUDE_BUILD is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_USB_IP_COMMON is not set +# CONFIG_W35UND is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_OTUS is not set +# CONFIG_RT2870 is not set +# CONFIG_COMEDI is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_TRANZPORT is not set +# CONFIG_POHMELFS is not set +# CONFIG_LINE6_USB is not set +# CONFIG_SPECTRA is not set +# CONFIG_VT6656 is not set +# CONFIG_FB_UDL is not set + +# +# RAR Register Driver +# +CONFIG_IIO=m +# CONFIG_IIO_RING_BUFFER is not set +# CONFIG_IIO_TRIGGER is not set + +# +# Accelerometers +# +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_KXSD9 is not set +# CONFIG_LIS3L02DQ is not set + +# +# Analog to digital convertors +# +# CONFIG_MAX1363 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16260 is not set + +# +# Inertial measurement units +# +# CONFIG_ADIS16300 is not set +# CONFIG_ADIS16350 is not set +# CONFIG_ADIS16400 is not set + +# +# Light sensors +# +CONFIG_SENSORS_TSL2563=m + +# +# Triggers - standalone +# +# CONFIG_RAMZSWAP is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_FB_SM7XX is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_ST_BT is not set +# CONFIG_ADIS16255 is not set +# CONFIG_MFLD_SENSORS is not set + +# +# Intel CE Media Processor +# +# CONFIG_X86_INTEL_CE is not set +# CONFIG_VIDEO_MRSTCI is not set +# CONFIG_N_IFX_MUX is not set +CONFIG_TIDSPBRIDGE=m +CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE=0x600000 +# CONFIG_TIDSPBRIDGE_DEBUG is not set +CONFIG_TIDSPBRIDGE_RECOVERY=y +# CONFIG_TIDSPBRIDGE_CACHE_LINE_CHECK is not set +CONFIG_TIDSPBRIDGE_WDT3=y +CONFIG_TIDSPBRIDGE_WDT_TIMEOUT=5 +# CONFIG_TIDSPBRIDGE_NTFY_PWRERR is not set +CONFIG_TIDSPBRIDGE_BACKTRACE=y + +# +# 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 is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=y +CONFIG_BTRFS_FS_POSIX_ACL=y +# CONFIG_NILFS2_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +CONFIG_GENERIC_ACL=y + +# +# 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=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +# 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=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_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 is not set +CONFIG_UBIFS_FS=m +# 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_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# 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="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +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_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DETECT_SOFTLOCKUP is not set +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_SCHED_DEBUG=y +CONFIG_SCHEDSTATS=y +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# 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_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_DETECTOR 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_LKDTM is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_PAGE_POISONING is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_DYNAMIC_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_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_OC_ETM is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO 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_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MANAGER_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_TEST=m + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_SEQIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CTR=m +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=m + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_VMAC=m + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_GHASH=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +# 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=y +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_ZLIB=y +CONFIG_CRYPTO_LZO=m + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_OMAP_SHAM=m +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/recipes/linux/linux-2.6.35/nokia900/inconsistent-mmc-fix-2.6.35.patch b/recipes/linux/linux-2.6.35/nokia900/inconsistent-mmc-fix-2.6.35.patch new file mode 100644 index 0000000000..12ade34e7e --- /dev/null +++ b/recipes/linux/linux-2.6.35/nokia900/inconsistent-mmc-fix-2.6.35.patch @@ -0,0 +1,94 @@ +Index: linux-2.6.35/arch/arm/mach-omap2/board-rx51-peripherals.c +=================================================================== +--- linux-2.6.35.orig/arch/arm/mach-omap2/board-rx51-peripherals.c 2010-09-19 11:01:36.480370002 +0200 ++++ linux-2.6.35/arch/arm/mach-omap2/board-rx51-peripherals.c 2010-09-19 11:02:56.730370000 +0200 +@@ -475,6 +475,7 @@ + static struct omap2_hsmmc_info mmc[] __initdata = { + { + .name = "external", ++ .mmcblk_devidx = 1, + .mmc = 1, + .wires = 4, + .cover_only = true, +@@ -484,6 +485,7 @@ + }, + { + .name = "internal", ++ .mmcblk_devidx = 0, + .mmc = 2, + .wires = 8, /* See also rx51_mmc2_remux */ + .gpio_cd = -EINVAL, +Index: linux-2.6.35/arch/arm/mach-omap2/hsmmc.c +=================================================================== +--- linux-2.6.35.orig/arch/arm/mach-omap2/hsmmc.c 2010-09-19 11:01:13.140370002 +0200 ++++ linux-2.6.35/arch/arm/mach-omap2/hsmmc.c 2010-09-19 11:03:48.490370007 +0200 +@@ -257,6 +257,7 @@ + snprintf(hc->name, ARRAY_SIZE(hc->name), + "mmc%islot%i", c->mmc, 1); + mmc->slots[0].name = hc->name; ++ mmc->slots[0].mmcblk_devidx = c->mmcblk_devidx; + mmc->nr_slots = 1; + mmc->slots[0].wires = c->wires; + mmc->slots[0].internal_clock = !c->ext_clock; +Index: linux-2.6.35/arch/arm/mach-omap2/hsmmc.h +=================================================================== +--- linux-2.6.35.orig/arch/arm/mach-omap2/hsmmc.h 2010-09-19 11:01:13.150370002 +0200 ++++ linux-2.6.35/arch/arm/mach-omap2/hsmmc.h 2010-09-19 11:04:09.070370002 +0200 +@@ -21,6 +21,7 @@ + char *name; /* or NULL for default */ + struct device *dev; /* returned: pointer to mmc adapter */ + int ocr_mask; /* temporary HACK */ ++ int mmcblk_devidx; /* preferred mmcblkX device index */ + /* Remux (pad configuation) when powering on/off */ + void (*remux)(struct device *dev, int slot, int power_on); + }; +Index: linux-2.6.35/arch/arm/plat-omap/include/plat/mmc.h +=================================================================== +--- linux-2.6.35.orig/arch/arm/plat-omap/include/plat/mmc.h 2010-09-19 11:04:43.480369999 +0200 ++++ linux-2.6.35/arch/arm/plat-omap/include/plat/mmc.h 2010-09-19 11:05:06.150370000 +0200 +@@ -132,6 +132,7 @@ + int (*get_cover_state)(struct device *dev, int slot); + + const char *name; ++ int mmcblk_devidx; /* preferred mmcblkX index for this slot */ + u32 ocr_mask; + + /* Card detection IRQs */ +Index: linux-2.6.35/drivers/mmc/card/block.c +=================================================================== +--- linux-2.6.35.orig/drivers/mmc/card/block.c 2010-09-19 11:05:25.060370002 +0200 ++++ linux-2.6.35/drivers/mmc/card/block.c 2010-09-19 11:07:06.980369995 +0200 +@@ -482,7 +482,7 @@ + struct mmc_blk_data *md; + int devidx, ret; + +- devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); ++ devidx = find_next_zero_bit(dev_use, MMC_NUM_MINORS, card->host->mmcblk_devidx); + if (devidx >= MMC_NUM_MINORS) + return ERR_PTR(-ENOSPC); + __set_bit(devidx, dev_use); +Index: linux-2.6.35/drivers/mmc/host/omap_hsmmc.c +=================================================================== +--- linux-2.6.35.orig/drivers/mmc/host/omap_hsmmc.c 2010-09-19 11:07:22.040370005 +0200 ++++ linux-2.6.35/drivers/mmc/host/omap_hsmmc.c 2010-09-19 11:08:05.310369999 +0200 +@@ -2157,6 +2157,7 @@ + } + + mmc->ocr_avail = mmc_slot(host).ocr_mask; ++ mmc->mmcblk_devidx = mmc_slot(host).mmcblk_devidx; + + /* Request IRQ for card detect */ + if ((mmc_slot(host).card_detect_irq)) { +Index: linux-2.6.35/include/linux/mmc/host.h +=================================================================== +--- linux-2.6.35.orig/include/linux/mmc/host.h 2010-09-19 11:09:55.410370002 +0200 ++++ linux-2.6.35/include/linux/mmc/host.h 2010-09-19 11:10:17.200370002 +0200 +@@ -210,7 +210,7 @@ + #endif + + struct dentry *debugfs_root; +- ++ unsigned int mmcblk_devidx; /* preferred mmc block device index (mmcblkX) */ + struct mutex *port_mutex; + + unsigned long private[0] ____cacheline_aligned; diff --git a/recipes/linux/linux-2.6.35/nokia900/linux-2.6-Bluetooth-Support-for-n900-bluetooth-hardware.patch b/recipes/linux/linux-2.6.35/nokia900/linux-2.6-Bluetooth-Support-for-n900-bluetooth-hardware.patch new file mode 100644 index 0000000000..ceccd11117 --- /dev/null +++ b/recipes/linux/linux-2.6.35/nokia900/linux-2.6-Bluetooth-Support-for-n900-bluetooth-hardware.patch @@ -0,0 +1,2279 @@ +From cd320710da1ab5b340bff78311fa492f9ff9b9c6 Mon Sep 17 00:00:00 2001 +From: Ville Tervo +Date: Fri, 9 Apr 2010 11:56:16 +0300 +Subject: [PATCH 04/11] Bluetooth: Support for n900 bluetooth hardware + +Adds support for N900 bluetooth hardware + +Signed-off-by: Ville Tervo +--- + arch/arm/mach-omap2/board-rx51-peripherals.c | 73 + + drivers/bluetooth/Kconfig | 11 + drivers/bluetooth/Makefile | 2 + drivers/bluetooth/hci_h4p/Makefile | 7 + drivers/bluetooth/hci_h4p/core.c | 1038 +++++++++++++++++++++++++++ + drivers/bluetooth/hci_h4p/fw-bcm.c | 144 +++ + drivers/bluetooth/hci_h4p/fw-csr.c | 141 +++ + drivers/bluetooth/hci_h4p/fw-ti1273.c | 113 ++ + drivers/bluetooth/hci_h4p/fw.c | 166 ++++ + drivers/bluetooth/hci_h4p/hci_h4p.h | 231 ++++++ + drivers/bluetooth/hci_h4p/uart.c | 203 +++++ + include/linux/bluetooth/hci_h4p.h | 41 + + 12 files changed, 2170 insertions(+) + create mode 100644 drivers/bluetooth/hci_h4p/Makefile + create mode 100644 drivers/bluetooth/hci_h4p/core.c + create mode 100644 drivers/bluetooth/hci_h4p/fw-bcm.c + create mode 100644 drivers/bluetooth/hci_h4p/fw-csr.c + create mode 100644 drivers/bluetooth/hci_h4p/fw-ti1273.c + create mode 100644 drivers/bluetooth/hci_h4p/fw.c + create mode 100644 drivers/bluetooth/hci_h4p/hci_h4p.h + create mode 100644 drivers/bluetooth/hci_h4p/uart.c + create mode 100644 include/linux/bluetooth/hci_h4p.h + +--- a/arch/arm/mach-omap2/board-rx51-peripherals.c ++++ b/arch/arm/mach-omap2/board-rx51-peripherals.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -33,6 +34,7 @@ + #include + #include + #include ++#include + + #include "mux.h" + #include "hsmmc.h" +@@ -46,6 +48,10 @@ + #define RX51_TSC2005_RESET_GPIO 104 + #define RX51_TSC2005_IRQ_GPIO 100 + ++#define RX51_HCI_H4P_RESET_GPIO 91 ++#define RX51_HCI_H4P_HOSTWU_GPIO 101 ++#define RX51_HCI_H4P_BTWU_GPIO 37 ++ + /* list all spi devices here */ + enum { + RX51_SPI_WL1251, +@@ -928,6 +934,72 @@ + */ + } + ++static void rx51_hci_h4p_set_power(bool enable) ++{ ++ gpio_set_value(RX51_HCI_H4P_RESET_GPIO, enable); ++} ++ ++static void rx51_hci_h4p_set_bt_wu(bool enable) ++{ ++ gpio_set_value(RX51_HCI_H4P_BTWU_GPIO, enable); ++} ++ ++static bool rx51_hci_h4p_get_host_wu(void) ++{ ++ return gpio_get_value(RX51_HCI_H4P_HOSTWU_GPIO); ++} ++ ++struct hci_h4p_platform_data bt_plat_data = { ++ .uart_irq = INT_24XX_UART2_IRQ, ++ .host_wu = rx51_hci_h4p_get_host_wu, ++ .bt_wu = rx51_hci_h4p_set_bt_wu, ++ .reset = rx51_hci_h4p_set_power, ++ .host_wu_gpio = RX51_HCI_H4P_HOSTWU_GPIO, ++}; ++ ++static struct platform_device rx51_bt_device = { ++ .name = "hci_h4p", ++ .id = -1, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = (void *)&bt_plat_data, ++ } ++}; ++ ++void __init rx51_bt_init(void) ++{ ++ int err; ++ ++ err = gpio_request(RX51_HCI_H4P_RESET_GPIO, "bt_reset"); ++ if (err < 0) ++ return; ++ ++ err = gpio_request(RX51_HCI_H4P_BTWU_GPIO, "bt_wakeup"); ++ if (err < 0) ++ goto fail; ++ ++ err = gpio_request(RX51_HCI_H4P_HOSTWU_GPIO, "host_wakeup"); ++ if (err < 0) ++ goto fail2; ++ ++ gpio_direction_output(RX51_HCI_H4P_RESET_GPIO, 0); ++ gpio_direction_output(RX51_HCI_H4P_BTWU_GPIO, 0); ++ gpio_direction_input(RX51_HCI_H4P_HOSTWU_GPIO); ++ ++ bt_plat_data.uart_base = ioremap(OMAP3_UART2_BASE, SZ_2K); ++ ++ err = platform_device_register(&rx51_bt_device); ++ if (!err) ++ return; ++ ++ gpio_free(RX51_HCI_H4P_HOSTWU_GPIO); ++fail2: ++ gpio_free(RX51_HCI_H4P_BTWU_GPIO); ++fail: ++ gpio_free(RX51_HCI_H4P_RESET_GPIO); ++ printk(KERN_ERR "Bluetooth device registration failed\n"); ++} ++ + void __init rx51_peripherals_init(void) + { + rx51_i2c_init(); +@@ -936,6 +1008,7 @@ + rx51_add_gpio_keys(); + rx51_init_wl1251(); + rx51_init_tsc2005(); ++ rx51_bt_init(); + spi_register_board_info(rx51_peripherals_spi_board_info, + ARRAY_SIZE(rx51_peripherals_spi_board_info)); + omap2_hsmmc_init(mmc); +--- a/drivers/bluetooth/Kconfig ++++ b/drivers/bluetooth/Kconfig +@@ -207,4 +207,15 @@ + Say Y here to compile support for "Atheros firmware download driver" + into the kernel or say M to compile it as module (ath3k). + ++config BT_HCIH4P ++ tristate "HCI driver with Nokia H4 extensions" ++ depends on BT ++ select FW_LOADER ++ help ++ Bluetooth HCI driver with H4 extensions. This driver provides ++ support for H4+ Bluetooth chip with vendor-specific H4 extensions. ++ ++ Say Y here to compile support for h4 extended devices into the kernel ++ or say M to compile it as module (hci_h4p). ++ + endmenu +--- a/drivers/bluetooth/Makefile ++++ b/drivers/bluetooth/Makefile +@@ -27,3 +27,5 @@ + hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o + hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o + hci_uart-objs := $(hci_uart-y) ++ ++obj-$(CONFIG_BT_HCIH4P) += hci_h4p/ +--- /dev/null ++++ b/drivers/bluetooth/hci_h4p/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for the Linux Bluetooth HCI device drivers. ++# ++ ++obj-$(CONFIG_BT_HCIH4P) += hci_h4p.o ++ ++hci_h4p-objs := core.o fw.o uart.o fw-csr.o fw-bcm.o fw-ti1273.o +--- /dev/null ++++ b/drivers/bluetooth/hci_h4p/core.c +@@ -0,0 +1,1038 @@ ++/* ++ * This file is part of hci_h4p bluetooth driver ++ * ++ * Copyright (C) 2005-2010 Nokia Corporation. ++ * ++ * Contact: Ville Tervo ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "hci_h4p.h" ++ ++static void hci_h4p_set_clk(struct hci_h4p_info *info, int *clock, int enable) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&info->clocks_lock, flags); ++ if (enable && !*clock) { ++ NBT_DBG_POWER("Enabling %p\n", clock); ++ clk_enable(info->uart_fclk); ++ clk_enable(info->uart_iclk); ++ if (atomic_read(&info->clk_users) == 0) ++ hci_h4p_restore_regs(info); ++ atomic_inc(&info->clk_users); ++ } ++ ++ if (!enable && *clock) { ++ NBT_DBG_POWER("Disabling %p\n", clock); ++ if (atomic_dec_and_test(&info->clk_users)) ++ hci_h4p_store_regs(info); ++ clk_disable(info->uart_fclk); ++ clk_disable(info->uart_iclk); ++ } ++ ++ *clock = enable; ++ spin_unlock_irqrestore(&info->clocks_lock, flags); ++} ++ ++/* Power management functions */ ++void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable) ++{ ++ u8 v; ++ ++ return; ++ ++ v = hci_h4p_inb(info, UART_OMAP_SYSC); ++ v &= ~(UART_OMAP_SYSC_IDLEMASK); ++ ++ if (enable) ++ v |= UART_OMAP_SYSC_SMART_IDLE; ++ else ++ v |= UART_OMAP_SYSC_NO_IDLE; ++ ++ hci_h4p_outb(info, UART_OMAP_SYSC, v); ++} ++ ++static void hci_h4p_disable_tx(struct hci_h4p_info *info) ++{ ++ NBT_DBG_POWER("\n"); ++ ++ if (!info->pm_enabled) ++ return; ++ ++ hci_h4p_smart_idle(info, 1); ++ ++ info->bt_wakeup(0); ++ hci_h4p_set_clk(info, &info->tx_clocks_en, 0); ++ info->tx_enabled = 0; ++} ++ ++void hci_h4p_enable_tx(struct hci_h4p_info *info) ++{ ++ NBT_DBG_POWER("\n"); ++ ++ if (!info->pm_enabled) ++ return; ++ ++ hci_h4p_set_clk(info, &info->tx_clocks_en, 1); ++ info->tx_enabled = 1; ++ hci_h4p_smart_idle(info, 0); ++ info->bt_wakeup(1); ++ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | ++ UART_IER_THRI); ++} ++ ++static void hci_h4p_disable_rx(struct hci_h4p_info *info) ++{ ++ if (!info->pm_enabled) ++ return; ++ ++ info->rx_enabled = 0; ++ ++ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) { ++ NBT_DBG("data ready postpone autorts"); ++ return; ++ } ++ ++ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) { ++ NBT_DBG("trasmitter not empty postpone autorts"); ++ return; ++ } ++ ++ hci_h4p_set_rts(info, info->rx_enabled); ++ __hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS); ++ info->autorts = 0; ++ hci_h4p_set_clk(info, &info->rx_clocks_en, 0); ++} ++ ++static void hci_h4p_enable_rx(struct hci_h4p_info *info) ++{ ++ if (!info->pm_enabled) ++ return; ++ ++ hci_h4p_set_clk(info, &info->rx_clocks_en, 1); ++ info->rx_enabled = 1; ++ ++ hci_h4p_set_rts(info, 1); ++ ++ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) { ++ NBT_DBG("trasmitter not empty postpone autorts"); ++ return; ++ } ++ ++ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) { ++ NBT_DBG("data ready postpone autorts"); ++ return; ++ } ++ ++ __hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS); ++ info->autorts = 1; ++} ++ ++/* Negotiation functions */ ++int hci_h4p_send_alive_packet(struct hci_h4p_info *info) ++{ ++ struct hci_h4p_alive_hdr *alive_hdr; ++ struct hci_h4p_alive_msg *alive_cmd; ++ struct sk_buff *skb; ++ unsigned long flags; ++ ++ NBT_DBG("Sending alive packet\n"); ++ ++ skb = bt_skb_alloc(HCI_H4P_ALIVE_HDR_SIZE + HCI_H4P_ALIVE_MSG_SIZE, GFP_ATOMIC); ++ if (!skb) ++ return -ENOMEM; ++ ++ alive_hdr = (void *) skb_put(skb, HCI_H4P_ALIVE_HDR_SIZE); ++ alive_hdr->dlen = HCI_H4P_ALIVE_MSG_SIZE; ++ alive_cmd = (void *) skb_put(skb, HCI_H4P_ALIVE_MSG_SIZE); ++ alive_cmd->message_id = HCI_H4P_ALIVE_IND_REQ; ++ alive_cmd->unused = 0x00; ++ *skb_push(skb, 1) = H4_ALIVE_PKT; ++ ++ skb_queue_tail(&info->txq, skb); ++ spin_lock_irqsave(&info->lock, flags); ++ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | ++ UART_IER_THRI); ++ spin_unlock_irqrestore(&info->lock, flags); ++ ++ NBT_DBG("Alive packet sent\n"); ++ ++ return 0; ++} ++ ++static void hci_h4p_alive_packet(struct hci_h4p_info *info, struct sk_buff *skb) ++{ ++ struct hci_h4p_alive_hdr *alive_hdr = (void *) skb->data; ++ struct hci_h4p_alive_msg *alive_evt; ++ ++ if (alive_hdr->dlen > skb->len) { ++ info->init_error = -EPROTO; ++ complete(&info->init_completion); ++ return; ++ } ++ ++ alive_evt = (void *) skb_pull(skb, HCI_H4P_ALIVE_HDR_SIZE); ++ ++ NBT_DBG("Received alive packet\n"); ++ if (alive_evt->message_id != HCI_H4P_ALIVE_IND_RESP) { ++ dev_err(info->dev, "Could not negotiate hci_h4p settings\n"); ++ info->init_error = -EINVAL; ++ } ++ ++ complete(&info->init_completion); ++ kfree_skb(skb); ++} ++ ++static int hci_h4p_send_negotiation(struct hci_h4p_info *info) ++{ ++ struct hci_h4p_init_cmd *init_cmd; ++ struct hci_h4p_init_hdr *init_hdr; ++ struct sk_buff *skb; ++ unsigned long flags; ++ int err; ++ ++ NBT_DBG("Sending negotiation..\n"); ++ ++ skb = bt_skb_alloc(HCI_H4P_INIT_HDR_SIZE + HCI_H4P_INIT_CMD_SIZE, GFP_KERNEL); ++ if (!skb) ++ return -ENOMEM; ++ ++ init_hdr = (void *)skb_put(skb, HCI_H4P_INIT_HDR_SIZE); ++ init_hdr->dlen = HCI_H4P_INIT_CMD_SIZE; ++ init_cmd = (void *)skb_put(skb, HCI_H4P_INIT_CMD_SIZE); ++ init_cmd->ack = 0x00; ++ init_cmd->baudrate = cpu_to_le16(0x01a1); ++ init_cmd->unused = cpu_to_le16(0x0000); ++ init_cmd->mode = HCI_H4P_MODE; ++ init_cmd->sys_clk = cpu_to_le16(0x9600); ++ init_cmd->unused2 = cpu_to_le16(0x0000); ++ *skb_push(skb, 1) = H4_NEG_PKT; ++ ++ hci_h4p_change_speed(info, INIT_SPEED); ++ ++ hci_h4p_set_rts(info, 1); ++ info->init_error = 0; ++ init_completion(&info->init_completion); ++ skb_queue_tail(&info->txq, skb); ++ spin_lock_irqsave(&info->lock, flags); ++ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | ++ UART_IER_THRI); ++ spin_unlock_irqrestore(&info->lock, flags); ++ ++ if (!wait_for_completion_interruptible_timeout(&info->init_completion, ++ msecs_to_jiffies(1000))) ++ return -ETIMEDOUT; ++ ++ if (info->init_error < 0) ++ return info->init_error; ++ ++ /* Change to operational settings */ ++ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS); ++ hci_h4p_set_rts(info, 0); ++ hci_h4p_change_speed(info, MAX_BAUD_RATE); ++ ++ err = hci_h4p_wait_for_cts(info, 1, 100); ++ if (err < 0) ++ return err; ++ ++ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS); ++ init_completion(&info->init_completion); ++ err = hci_h4p_send_alive_packet(info); ++ ++ if (err < 0) ++ return err; ++ ++ if (!wait_for_completion_interruptible_timeout(&info->init_completion, ++ msecs_to_jiffies(1000))) ++ return -ETIMEDOUT; ++ ++ if (info->init_error < 0) ++ return info->init_error; ++ ++ NBT_DBG("Negotiation succesful\n"); ++ return 0; ++} ++ ++static void hci_h4p_negotiation_packet(struct hci_h4p_info *info, ++ struct sk_buff *skb) ++{ ++ struct hci_h4p_init_hdr *init_hdr = (void *) skb->data; ++ struct hci_h4p_init_evt *init_evt; ++ ++ if (init_hdr->dlen > skb->len) { ++ kfree_skb(skb); ++ info->init_error = -EPROTO; ++ complete(&info->init_completion); ++ return; ++ } ++ ++ init_evt = (void *)skb_pull(skb, HCI_H4P_INIT_HDR_SIZE); ++ ++ if (init_evt->ack != HCI_H4P_ACK) { ++ dev_err(info->dev, "Could not negotiate hci_h4p settings\n"); ++ info->init_error = -EINVAL; ++ } ++ ++ info->man_id = init_evt->man_id; ++ info->ver_id = init_evt->ver_id; ++ ++ complete(&info->init_completion); ++ kfree_skb(skb); ++} ++ ++/* H4 packet handling functions */ ++static int hci_h4p_get_hdr_len(struct hci_h4p_info *info, u8 pkt_type) ++{ ++ long retval; ++ ++ switch (pkt_type) { ++ case H4_EVT_PKT: ++ retval = HCI_EVENT_HDR_SIZE; ++ break; ++ case H4_ACL_PKT: ++ retval = HCI_ACL_HDR_SIZE; ++ break; ++ case H4_SCO_PKT: ++ retval = HCI_SCO_HDR_SIZE; ++ break; ++ case H4_NEG_PKT: ++ retval = HCI_H4P_INIT_HDR_SIZE; ++ break; ++ case H4_ALIVE_PKT: ++ retval = HCI_H4P_ALIVE_HDR_SIZE; ++ break; ++ case H4_RADIO_PKT: ++ retval = H4_RADIO_HDR_SIZE; ++ break; ++ default: ++ dev_err(info->dev, "Unknown H4 packet type 0x%.2x\n", pkt_type); ++ retval = -1; ++ break; ++ } ++ ++ return retval; ++} ++ ++static unsigned int hci_h4p_get_data_len(struct hci_h4p_info *info, ++ struct sk_buff *skb) ++{ ++ long retval = -1; ++ struct hci_event_hdr *evt_hdr; ++ struct hci_acl_hdr *acl_hdr; ++ struct hci_sco_hdr *sco_hdr; ++ struct hci_h4p_radio_hdr *radio_hdr; ++ struct hci_h4p_init_hdr *init_hdr; ++ struct hci_h4p_alive_hdr *alive_hdr; ++ ++ switch (bt_cb(skb)->pkt_type) { ++ case H4_EVT_PKT: ++ evt_hdr = (struct hci_event_hdr *)skb->data; ++ retval = evt_hdr->plen; ++ break; ++ case H4_ACL_PKT: ++ acl_hdr = (struct hci_acl_hdr *)skb->data; ++ retval = le16_to_cpu(acl_hdr->dlen); ++ break; ++ case H4_SCO_PKT: ++ sco_hdr = (struct hci_sco_hdr *)skb->data; ++ retval = sco_hdr->dlen; ++ break; ++ case H4_RADIO_PKT: ++ radio_hdr = (struct hci_h4p_radio_hdr *)skb->data; ++ retval = radio_hdr->dlen; ++ break; ++ case H4_NEG_PKT: ++ init_hdr = (struct hci_h4p_init_hdr *)skb->data; ++ retval = init_hdr->dlen; ++ break; ++ case H4_ALIVE_PKT: ++ alive_hdr = (struct hci_h4p_alive_hdr *)skb->data; ++ retval = alive_hdr->dlen; ++ break; ++ } ++ ++ return retval; ++} ++ ++static inline void hci_h4p_recv_frame(struct hci_h4p_info *info, ++ struct sk_buff *skb) ++{ ++ ++ if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) { ++ NBT_DBG("fw_event\n"); ++ if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) { ++ hci_h4p_negotiation_packet(info, info->rx_skb); ++ return; ++ } ++ if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) { ++ hci_h4p_alive_packet(info, info->rx_skb); ++ return; ++ } ++ hci_h4p_parse_fw_event(info, skb); ++ } else { ++ hci_recv_frame(skb); ++ NBT_DBG("Frame sent to upper layer\n"); ++ } ++} ++ ++static inline void hci_h4p_handle_byte(struct hci_h4p_info *info, u8 byte) ++{ ++ switch (info->rx_state) { ++ case WAIT_FOR_PKT_TYPE: ++ bt_cb(info->rx_skb)->pkt_type = byte; ++ info->rx_count = hci_h4p_get_hdr_len(info, byte); ++ if (info->rx_count < 0) { ++ info->hdev->stat.err_rx++; ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ } else { ++ info->rx_state = WAIT_FOR_HEADER; ++ } ++ break; ++ case WAIT_FOR_HEADER: ++ info->rx_count--; ++ *skb_put(info->rx_skb, 1) = byte; ++ if (info->rx_count != 0) ++ break; ++ ++ info->rx_count = hci_h4p_get_data_len(info, ++ info->rx_skb); ++ if (info->rx_count > skb_tailroom(info->rx_skb)) { ++ dev_err(info->dev, "Too long frame.\n"); ++ info->garbage_bytes = info->rx_count - ++ skb_tailroom(info->rx_skb); ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ } ++ info->rx_state = WAIT_FOR_DATA; ++ break; ++ case WAIT_FOR_DATA: ++ info->rx_count--; ++ *skb_put(info->rx_skb, 1) = byte; ++ break; ++ default: ++ WARN_ON(1); ++ break; ++ } ++ ++ if (info->rx_count == 0) { ++ /* H4+ devices should allways send word aligned ++ * packets */ ++ if (!(info->rx_skb->len % 2)) ++ info->garbage_bytes++; ++ hci_h4p_recv_frame(info, info->rx_skb); ++ info->rx_skb = NULL; ++ } ++} ++ ++static void hci_h4p_rx(unsigned long data) ++{ ++ u8 byte; ++ struct hci_h4p_info *info = (struct hci_h4p_info *)data; ++ ++ NBT_DBG("rx woke up\n"); ++ ++ while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) { ++ byte = hci_h4p_inb(info, UART_RX); ++ if (info->garbage_bytes) { ++ info->garbage_bytes--; ++ continue; ++ } ++ if (info->rx_skb == NULL) { ++ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, ++ GFP_ATOMIC); ++ if (!info->rx_skb) { ++ dev_err(info->dev, ++ "No memory for new packet\n"); ++ return; ++ } ++ info->rx_state = WAIT_FOR_PKT_TYPE; ++ info->rx_skb->dev = (void *)info->hdev; ++ } ++ info->hdev->stat.byte_rx++; ++ NBT_DBG_TRANSFER_NF("0x%.2x ", byte); ++ hci_h4p_handle_byte(info, byte); ++ } ++ ++ if (info->rx_enabled == info->autorts) ++ return; ++ ++ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) ++ return; ++ ++ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) ++ return; ++ ++ hci_h4p_set_rts(info, info->rx_enabled); ++ __hci_h4p_set_auto_ctsrts(info, info->rx_enabled, UART_EFR_RTS); ++ info->autorts = info->rx_enabled; ++ ++ /* Flush posted write to avoid spurious interrupts */ ++ hci_h4p_inb(info, UART_OMAP_SCR); ++ hci_h4p_set_clk(info, &info->rx_clocks_en, 0); ++} ++ ++static void hci_h4p_tx(unsigned long data) ++{ ++ unsigned int sent = 0; ++ struct sk_buff *skb; ++ struct hci_h4p_info *info = (struct hci_h4p_info *)data; ++ ++ NBT_DBG("tx woke up\n"); ++ NBT_DBG_TRANSFER("data "); ++ ++ if (info->autorts != info->rx_enabled) { ++ NBT_DBG("rts unbalanced.. autorts %d rx_enabled %d", info->autorts, info->rx_enabled); ++ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT && ++ !(hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)) { ++ __hci_h4p_set_auto_ctsrts(info, info->rx_enabled, ++ UART_EFR_RTS); ++ info->autorts = info->rx_enabled; ++ hci_h4p_set_rts(info, info->rx_enabled); ++ hci_h4p_set_clk(info, &info->rx_clocks_en, ++ info->rx_enabled); ++ NBT_DBG("transmitter empty. setinng into balance\n"); ++ } else { ++ hci_h4p_outb(info, UART_OMAP_SCR, ++ hci_h4p_inb(info, UART_OMAP_SCR) | ++ UART_OMAP_SCR_EMPTY_THR); ++ NBT_DBG("transmitter/receiver was not empty waiting for next irq\n"); ++ hci_h4p_set_rts(info, 1); ++ goto finish_tx; ++ } ++ } ++ ++ skb = skb_dequeue(&info->txq); ++ if (!skb) { ++ /* No data in buffer */ ++ NBT_DBG("skb ready\n"); ++ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) { ++ hci_h4p_outb(info, UART_IER, ++ hci_h4p_inb(info, UART_IER) & ++ ~UART_IER_THRI); ++ hci_h4p_inb(info, UART_OMAP_SCR); ++ hci_h4p_disable_tx(info); ++ NBT_DBG("transmitter was empty. cleaning up\n"); ++ return; ++ } ++ hci_h4p_outb(info, UART_OMAP_SCR, ++ hci_h4p_inb(info, UART_OMAP_SCR) | ++ UART_OMAP_SCR_EMPTY_THR); ++ NBT_DBG("transmitter was not empty waiting for next irq\n"); ++ goto finish_tx; ++ } ++ ++ /* Copy data to tx fifo */ ++ while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) && ++ (sent < skb->len)) { ++ NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]); ++ hci_h4p_outb(info, UART_TX, skb->data[sent]); ++ sent++; ++ } ++ ++ info->hdev->stat.byte_tx += sent; ++ if (skb->len == sent) { ++ kfree_skb(skb); ++ } else { ++ skb_pull(skb, sent); ++ skb_queue_head(&info->txq, skb); ++ } ++ ++ hci_h4p_outb(info, UART_OMAP_SCR, hci_h4p_inb(info, UART_OMAP_SCR) & ++ ~UART_OMAP_SCR_EMPTY_THR); ++ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | ++ UART_IER_THRI); ++ ++finish_tx: ++ /* Flush posted write to avoid spurious interrupts */ ++ hci_h4p_inb(info, UART_OMAP_SCR); ++ ++} ++ ++static irqreturn_t hci_h4p_interrupt(int irq, void *data) ++{ ++ struct hci_h4p_info *info = (struct hci_h4p_info *)data; ++ u8 iir, msr; ++ int ret; ++ ++ ret = IRQ_NONE; ++ ++ iir = hci_h4p_inb(info, UART_IIR); ++ if (iir & UART_IIR_NO_INT) ++ return IRQ_HANDLED; ++ ++ NBT_DBG("In interrupt handler iir 0x%.2x\n", iir); ++ ++ iir &= UART_IIR_ID; ++ ++ if (iir == UART_IIR_MSI) { ++ msr = hci_h4p_inb(info, UART_MSR); ++ ret = IRQ_HANDLED; ++ } ++ if (iir == UART_IIR_RLSI) { ++ hci_h4p_inb(info, UART_RX); ++ hci_h4p_inb(info, UART_LSR); ++ ret = IRQ_HANDLED; ++ } ++ ++ if (iir == UART_IIR_RDI) { ++ hci_h4p_rx((unsigned long)data); ++ ret = IRQ_HANDLED; ++ } ++ ++ if (iir == UART_IIR_THRI) { ++ hci_h4p_tx((unsigned long)data); ++ ret = IRQ_HANDLED; ++ } ++ ++ return ret; ++} ++ ++static irqreturn_t hci_h4p_wakeup_interrupt(int irq, void *dev_inst) ++{ ++ struct hci_h4p_info *info = dev_inst; ++ int should_wakeup; ++ struct hci_dev *hdev; ++ ++ if (!info->hdev) ++ return IRQ_HANDLED; ++ ++ hdev = info->hdev; ++ ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return IRQ_HANDLED; ++ ++ should_wakeup = info->host_wakeup(); ++ NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup); ++ ++ /* Check if wee have missed some interrupts */ ++ if (info->rx_enabled == should_wakeup) ++ return IRQ_HANDLED; ++ ++ if (should_wakeup) ++ hci_h4p_enable_rx(info); ++ else ++ hci_h4p_disable_rx(info); ++ ++ return IRQ_HANDLED; ++} ++ ++static int hci_h4p_reset(struct hci_h4p_info *info) ++{ ++ int err; ++ ++ err = hci_h4p_reset_uart(info); ++ if (err < 0) { ++ dev_err(info->dev, "Uart reset failed\n"); ++ return err; ++ } ++ hci_h4p_init_uart(info); ++ hci_h4p_set_rts(info, 0); ++ ++ info->reset(0); ++ info->bt_wakeup(1); ++ msleep(10); ++ info->reset(1); ++ ++ err = hci_h4p_wait_for_cts(info, 1, 100); ++ if (err < 0) { ++ dev_err(info->dev, "No cts from bt chip\n"); ++ return err; ++ } ++ ++ hci_h4p_set_rts(info, 1); ++ ++ return 0; ++} ++ ++/* hci callback functions */ ++static int hci_h4p_hci_flush(struct hci_dev *hdev) ++{ ++ struct hci_h4p_info *info; ++ info = hdev->driver_data; ++ ++ skb_queue_purge(&info->txq); ++ ++ return 0; ++} ++ ++static int hci_h4p_hci_open(struct hci_dev *hdev) ++{ ++ struct hci_h4p_info *info; ++ int err; ++ struct sk_buff_head fw_queue; ++ unsigned long flags; ++ ++ info = hdev->driver_data; ++ ++ if (test_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ ++ info->rx_enabled = 1; ++ info->rx_state = WAIT_FOR_PKT_TYPE; ++ info->rx_count = 0; ++ info->garbage_bytes = 0; ++ info->rx_skb = NULL; ++ info->pm_enabled = 0; ++ init_completion(&info->fw_completion); ++ hci_h4p_set_clk(info, &info->tx_clocks_en, 1); ++ hci_h4p_set_clk(info, &info->rx_clocks_en, 1); ++ skb_queue_head_init(&fw_queue); ++ ++ err = hci_h4p_reset(info); ++ if (err < 0) ++ goto err_clean; ++ ++ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS); ++ info->autorts = 1; ++ err = hci_h4p_send_negotiation(info); ++ if (err < 0) ++ goto err_clean; ++ ++ skb_queue_head_init(&fw_queue); ++ err = hci_h4p_read_fw(info, &fw_queue); ++ if (err < 0) { ++ dev_err(info->dev, "Cannot read firmware\n"); ++ return err; ++ } ++ ++ /* FW image contains also unneeded negoation and alive msgs */ ++ skb_dequeue(&fw_queue); ++ skb_dequeue(&fw_queue); ++ ++ err = hci_h4p_send_fw(info, &fw_queue); ++ if (err < 0) { ++ dev_err(info->dev, "Sending firmware failed.\n"); ++ goto err_clean; ++ } ++ ++ info->pm_enabled = 1; ++ ++ spin_lock_irqsave(&info->lock, flags); ++ info->rx_enabled = info->host_wakeup(); ++ hci_h4p_set_clk(info, &info->rx_clocks_en, info->rx_enabled); ++ spin_unlock_irqrestore(&info->lock, flags); ++ ++ hci_h4p_set_clk(info, &info->tx_clocks_en, 0); ++ ++ set_bit(HCI_RUNNING, &hdev->flags); ++ ++ NBT_DBG("hci up and running\n"); ++ return 0; ++ ++err_clean: ++ hci_h4p_hci_flush(hdev); ++ hci_h4p_reset_uart(info); ++ hci_h4p_set_clk(info, &info->tx_clocks_en, 0); ++ hci_h4p_set_clk(info, &info->rx_clocks_en, 0); ++ info->reset(0); ++ info->bt_wakeup(0); ++ skb_queue_purge(&fw_queue); ++ kfree_skb(info->rx_skb); ++ ++ return err; ++} ++ ++static int hci_h4p_hci_close(struct hci_dev *hdev) ++{ ++ struct hci_h4p_info *info = hdev->driver_data; ++ ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ ++ hci_h4p_hci_flush(hdev); ++ hci_h4p_set_clk(info, &info->tx_clocks_en, 1); ++ hci_h4p_set_clk(info, &info->rx_clocks_en, 1); ++ hci_h4p_reset_uart(info); ++ hci_h4p_set_clk(info, &info->tx_clocks_en, 0); ++ hci_h4p_set_clk(info, &info->rx_clocks_en, 0); ++ info->reset(0); ++ info->bt_wakeup(0); ++ kfree_skb(info->rx_skb); ++ ++ return 0; ++} ++ ++static void hci_h4p_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++static int hci_h4p_hci_send_frame(struct sk_buff *skb) ++{ ++ struct hci_h4p_info *info; ++ struct hci_dev *hdev = (struct hci_dev *)skb->dev; ++ int err = 0; ++ unsigned long flags; ++ ++ if (!hdev) { ++ printk(KERN_WARNING "hci_h4p: Frame for unknown device\n"); ++ return -ENODEV; ++ } ++ ++ NBT_DBG("dev %p, skb %p\n", hdev, skb); ++ ++ info = hdev->driver_data; ++ ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) { ++ dev_warn(info->dev, "Frame for non-running device\n"); ++ return -EIO; ++ } ++ ++ switch (bt_cb(skb)->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ } ++ ++ /* Push frame type to skb */ ++ *skb_push(skb, 1) = (bt_cb(skb)->pkt_type); ++ /* We should allways send word aligned data to h4+ devices */ ++ if (skb->len % 2) { ++ err = skb_pad(skb, 1); ++ if (!err) ++ *skb_put(skb, 1) = 0x00; ++ } ++ if (err) ++ return err; ++ ++ spin_lock_irqsave(&info->lock, flags); ++ skb_queue_tail(&info->txq, skb); ++ hci_h4p_enable_tx(info); ++ spin_unlock_irqrestore(&info->lock, flags); ++ ++ return 0; ++} ++ ++static int hci_h4p_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, ++ unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++static int hci_h4p_register_hdev(struct hci_h4p_info *info) ++{ ++ struct hci_dev *hdev; ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = hci_alloc_dev(); ++ if (!hdev) { ++ dev_err(info->dev, "Can't allocate memory for device\n"); ++ return -ENOMEM; ++ } ++ info->hdev = hdev; ++ ++ hdev->bus = HCI_UART; ++ hdev->driver_data = info; ++ ++ hdev->open = hci_h4p_hci_open; ++ hdev->close = hci_h4p_hci_close; ++ hdev->flush = hci_h4p_hci_flush; ++ hdev->send = hci_h4p_hci_send_frame; ++ hdev->destruct = hci_h4p_hci_destruct; ++ hdev->ioctl = hci_h4p_hci_ioctl; ++ set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); ++ ++ hdev->owner = THIS_MODULE; ++ ++ if (hci_register_dev(hdev) < 0) { ++ dev_err(info->dev, "hci_register failed %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int hci_h4p_probe(struct platform_device *pdev) ++{ ++ struct hci_h4p_platform_data *bt_plat_data; ++ struct hci_h4p_info *info; ++ int err; ++ ++ dev_info(&pdev->dev, "Registering HCI H4P device\n"); ++ info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ info->dev = &pdev->dev; ++ info->pm_enabled = 0; ++ info->tx_enabled = 1; ++ info->rx_enabled = 1; ++ info->garbage_bytes = 0; ++ info->tx_clocks_en = 0; ++ info->rx_clocks_en = 0; ++ spin_lock_init(&info->lock); ++ spin_lock_init(&info->clocks_lock); ++ skb_queue_head_init(&info->txq); ++ ++ if (pdev->dev.platform_data == NULL) { ++ dev_err(&pdev->dev, "Could not get Bluetooth config data\n"); ++ kfree(info); ++ return -ENODATA; ++ } ++ ++ bt_plat_data = pdev->dev.platform_data; ++ info->chip_type = 3; ++ info->bt_wakeup = bt_plat_data->bt_wu; ++ info->host_wakeup = bt_plat_data->host_wu; ++ info->reset = bt_plat_data->reset; ++ info->uart_base = bt_plat_data->uart_base; ++ info->host_wakeup_gpio = bt_plat_data->host_wu_gpio; ++ ++ NBT_DBG("RESET gpio: %p\n", info->reset); ++ NBT_DBG("BTWU gpio: %p\n", info->bt_wakeup); ++ NBT_DBG("HOSTWU gpio: %p\n", info->host_wakeup); ++ ++ info->irq = bt_plat_data->uart_irq; ++ err = request_irq(info->irq, hci_h4p_interrupt, IRQF_DISABLED | IRQF_SHARED, ++ "hci_h4p", info); ++ if (err < 0) { ++ dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", info->irq); ++ goto cleanup; ++ } ++ ++ err = request_irq(gpio_to_irq(info->host_wakeup_gpio), ++ hci_h4p_wakeup_interrupt, IRQF_TRIGGER_FALLING | ++ IRQF_TRIGGER_RISING | IRQF_DISABLED, ++ "hci_h4p_wkup", info); ++ if (err < 0) { ++ dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n", ++ gpio_to_irq(info->host_wakeup_gpio)); ++ free_irq(info->irq, info); ++ goto cleanup; ++ } ++ ++ err = set_irq_wake(gpio_to_irq(info->host_wakeup_gpio), 1); ++ if (err < 0) { ++ dev_err(info->dev, "hci_h4p: unable to set wakeup for IRQ %d\n", ++ gpio_to_irq(info->host_wakeup_gpio)); ++ free_irq(info->irq, info); ++ free_irq(gpio_to_irq(info->host_wakeup_gpio), info); ++ goto cleanup; ++ } ++ ++ hci_h4p_set_clk(info, &info->tx_clocks_en, 1); ++ err = hci_h4p_reset_uart(info); ++ if (err < 0) ++ goto cleanup_irq; ++ hci_h4p_init_uart(info); ++ hci_h4p_set_rts(info, 0); ++ err = hci_h4p_reset(info); ++ hci_h4p_reset_uart(info); ++ if (err < 0) ++ goto cleanup_irq; ++ info->reset(0); ++ hci_h4p_set_clk(info, &info->tx_clocks_en, 0); ++ ++ platform_set_drvdata(pdev, info); ++ ++ if (hci_h4p_register_hdev(info) < 0) { ++ dev_err(info->dev, "failed to register hci_h4p hci device\n"); ++ goto cleanup_irq; ++ } ++ ++ return 0; ++ ++cleanup_irq: ++ free_irq(info->irq, (void *)info); ++ free_irq(gpio_to_irq(info->host_wakeup_gpio), info); ++cleanup: ++ info->reset(0); ++ kfree(info); ++ return err; ++ ++} ++ ++static int hci_h4p_remove(struct platform_device *pdev) ++{ ++ struct hci_h4p_info *info; ++ ++ info = platform_get_drvdata(pdev); ++ ++ hci_h4p_hci_close(info->hdev); ++ free_irq(gpio_to_irq(info->host_wakeup_gpio), info); ++ hci_unregister_dev(info->hdev); ++ hci_free_dev(info->hdev); ++ free_irq(info->irq, (void *) info); ++ kfree(info); ++ ++ return 0; ++} ++ ++static struct platform_driver hci_h4p_driver = { ++ .probe = hci_h4p_probe, ++ .remove = hci_h4p_remove, ++ .driver = { ++ .name = "hci_h4p", ++ }, ++}; ++ ++static int __init hci_h4p_init(void) ++{ ++ int err = 0; ++ ++ /* Register the driver with LDM */ ++ err = platform_driver_register(&hci_h4p_driver); ++ if (err < 0) ++ printk(KERN_WARNING "failed to register hci_h4p driver\n"); ++ ++ return err; ++} ++ ++static void __exit hci_h4p_exit(void) ++{ ++ platform_driver_unregister(&hci_h4p_driver); ++} ++ ++module_init(hci_h4p_init); ++module_exit(hci_h4p_exit); ++ ++MODULE_ALIAS("platform:hci_h4p"); ++MODULE_DESCRIPTION("h4 driver with nokia extensions"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Ville Tervo"); +--- /dev/null ++++ b/drivers/bluetooth/hci_h4p/fw-bcm.c +@@ -0,0 +1,144 @@ ++/* ++ * This file is part of hci_h4p bluetooth driver ++ * ++ * Copyright (C) 2005-2008 Nokia Corporation. ++ * ++ * Contact: Ville Tervo ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "hci_h4p.h" ++ ++static struct sk_buff_head *fw_q; ++ ++static int inject_bdaddr(struct hci_h4p_info *info, struct sk_buff *skb) ++{ ++ unsigned int offset; ++ ++ if (skb->len < 10) { ++ dev_info(info->dev, "Valid bluetooth address not found.\n"); ++ return -ENODATA; ++ } ++ ++ offset = 4; ++ skb->data[offset + 5] = 0x00; ++ skb->data[offset + 4] = 0x11; ++ skb->data[offset + 3] = 0x22; ++ skb->data[offset + 2] = 0x33; ++ skb->data[offset + 1] = 0x44; ++ skb->data[offset + 0] = 0x55; ++ ++ return 0; ++} ++ ++void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb) ++{ ++ struct sk_buff *fw_skb; ++ int err; ++ unsigned long flags; ++ ++ if (skb->data[5] != 0x00) { ++ dev_err(info->dev, "Firmware sending command failed 0x%.2x\n", ++ skb->data[5]); ++ info->fw_error = -EPROTO; ++ } ++ ++ kfree_skb(skb); ++ ++ fw_skb = skb_dequeue(fw_q); ++ if (fw_skb == NULL || info->fw_error) { ++ complete(&info->fw_completion); ++ return; ++ } ++ ++ if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc) { ++ NBT_DBG_FW("Injecting bluetooth address\n"); ++ err = inject_bdaddr(info, fw_skb); ++ if (err < 0) { ++ kfree_skb(fw_skb); ++ info->fw_error = err; ++ complete(&info->fw_completion); ++ return; ++ } ++ } ++ ++ skb_queue_tail(&info->txq, fw_skb); ++ spin_lock_irqsave(&info->lock, flags); ++ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | ++ UART_IER_THRI); ++ spin_unlock_irqrestore(&info->lock, flags); ++} ++ ++ ++int hci_h4p_bcm_send_fw(struct hci_h4p_info *info, ++ struct sk_buff_head *fw_queue) ++{ ++ struct sk_buff *skb; ++ unsigned long flags, time; ++ ++ info->fw_error = 0; ++ ++ NBT_DBG_FW("Sending firmware\n"); ++ ++ time = jiffies; ++ ++ fw_q = fw_queue; ++ skb = skb_dequeue(fw_queue); ++ if (!skb) ++ return -ENODATA; ++ ++ NBT_DBG_FW("Sending commands\n"); ++ ++ /* ++ * Disable smart-idle as UART TX interrupts ++ * are not wake-up capable ++ */ ++ hci_h4p_smart_idle(info, 0); ++ ++ /* Check if this is bd_address packet */ ++ init_completion(&info->fw_completion); ++ skb_queue_tail(&info->txq, skb); ++ spin_lock_irqsave(&info->lock, flags); ++ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | ++ UART_IER_THRI); ++ spin_unlock_irqrestore(&info->lock, flags); ++ ++ if (!wait_for_completion_timeout(&info->fw_completion, ++ msecs_to_jiffies(2000))) { ++ dev_err(info->dev, "No reply to fw command\n"); ++ return -ETIMEDOUT; ++ } ++ ++ if (info->fw_error) { ++ dev_err(info->dev, "FW error\n"); ++ return -EPROTO; ++ } ++ ++ NBT_DBG_FW("Firmware sent in %d msecs\n", ++ jiffies_to_msecs(jiffies-time)); ++ ++ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS); ++ hci_h4p_set_rts(info, 0); ++ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE); ++ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS); ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/bluetooth/hci_h4p/fw-csr.c +@@ -0,0 +1,141 @@ ++/* ++ * This file is part of hci_h4p bluetooth driver ++ * ++ * Copyright (C) 2005-2008 Nokia Corporation. ++ * ++ * Contact: Ville Tervo ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "hci_h4p.h" ++ ++void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb) ++{ ++ /* Check if this is fw packet */ ++ if (skb->data[0] != 0xff) { ++ hci_recv_frame(skb); ++ return; ++ } ++ ++ if (skb->data[11] || skb->data[12]) { ++ dev_err(info->dev, "Firmware sending command failed\n"); ++ info->fw_error = -EPROTO; ++ } ++ ++ kfree_skb(skb); ++ complete(&info->fw_completion); ++} ++ ++int hci_h4p_bc4_send_fw(struct hci_h4p_info *info, ++ struct sk_buff_head *fw_queue) ++{ ++ struct sk_buff *skb; ++ unsigned int offset; ++ int retries, count; ++ unsigned long flags; ++ struct hci_h4p_bluetooth_config *config; ++ ++ info->fw_error = 0; ++ ++ NBT_DBG_FW("Sending firmware\n"); ++ skb = skb_dequeue(fw_queue); ++ ++ if (!skb) ++ return -ENOMSG; ++ ++ config = info->dev->platform_data; ++ if (!config) { ++ kfree_skb(skb); ++ return -ENODEV; ++ } ++ ++ /* Check if this is bd_address packet */ ++ if (skb->data[15] == 0x01 && skb->data[16] == 0x00) { ++ offset = 21; ++ skb->data[offset + 1] = 0x00; ++ skb->data[offset + 5] = 0x00; ++ skb->data[offset + 7] = 0x00; ++ skb->data[offset + 6] = 0x01; ++ skb->data[offset + 4] = 0x22; ++ skb->data[offset + 0] = 0x66; ++ skb->data[offset + 3] = 0x77; ++ skb->data[offset + 2] = 0x33; ++ } ++ ++ for (count = 1; ; count++) { ++ NBT_DBG_FW("Sending firmware command %d\n", count); ++ init_completion(&info->fw_completion); ++ skb_queue_tail(&info->txq, skb); ++ spin_lock_irqsave(&info->lock, flags); ++ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | ++ UART_IER_THRI); ++ spin_unlock_irqrestore(&info->lock, flags); ++ ++ skb = skb_dequeue(fw_queue); ++ if (!skb) ++ break; ++ ++ if (!wait_for_completion_timeout(&info->fw_completion, ++ msecs_to_jiffies(1000))) { ++ dev_err(info->dev, "No reply to fw command\n"); ++ return -ETIMEDOUT; ++ } ++ ++ if (info->fw_error) { ++ dev_err(info->dev, "FW error\n"); ++ return -EPROTO; ++ } ++ }; ++ ++ /* Wait for chip warm reset */ ++ retries = 100; ++ while ((!skb_queue_empty(&info->txq) || ++ !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) && ++ retries--) { ++ msleep(10); ++ } ++ if (!retries) { ++ dev_err(info->dev, "Transmitter not empty\n"); ++ return -ETIMEDOUT; ++ } ++ ++ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE); ++ ++ if (hci_h4p_wait_for_cts(info, 1, 100)) { ++ dev_err(info->dev, "cts didn't deassert after final speed\n"); ++ return -ETIMEDOUT; ++ } ++ ++ retries = 100; ++ do { ++ init_completion(&info->init_completion); ++ hci_h4p_send_alive_packet(info); ++ retries--; ++ } while (!wait_for_completion_timeout(&info->init_completion, 100) && ++ retries > 0); ++ ++ if (!retries) { ++ dev_err(info->dev, "No alive reply after speed change\n"); ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/bluetooth/hci_h4p/fw-ti1273.c +@@ -0,0 +1,113 @@ ++/* ++ * This file is part of hci_h4p bluetooth driver ++ * ++ * Copyright (C) 2009 Nokia Corporation. ++ * ++ * Contact: Ville Tervo ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "hci_h4p.h" ++ ++static struct sk_buff_head *fw_q; ++ ++void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info, ++ struct sk_buff *skb) ++{ ++ struct sk_buff *fw_skb; ++ unsigned long flags; ++ ++ if (skb->data[5] != 0x00) { ++ dev_err(info->dev, "Firmware sending command failed 0x%.2x\n", ++ skb->data[5]); ++ info->fw_error = -EPROTO; ++ } ++ ++ kfree_skb(skb); ++ ++ fw_skb = skb_dequeue(fw_q); ++ if (fw_skb == NULL || info->fw_error) { ++ complete(&info->fw_completion); ++ return; ++ } ++ ++ hci_h4p_enable_tx(info); ++ skb_queue_tail(&info->txq, fw_skb); ++ spin_lock_irqsave(&info->lock, flags); ++ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | ++ UART_IER_THRI); ++ spin_unlock_irqrestore(&info->lock, flags); ++} ++ ++ ++int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info, ++ struct sk_buff_head *fw_queue) ++{ ++ struct sk_buff *skb; ++ unsigned long flags, time; ++ ++ info->fw_error = 0; ++ ++ NBT_DBG_FW("Sending firmware\n"); ++ ++ time = jiffies; ++ ++ fw_q = fw_queue; ++ skb = skb_dequeue(fw_queue); ++ if (!skb) ++ return -ENODATA; ++ ++ NBT_DBG_FW("Sending commands\n"); ++ /* Check if this is bd_address packet */ ++ init_completion(&info->fw_completion); ++ hci_h4p_enable_tx(info); ++ skb_queue_tail(&info->txq, skb); ++ spin_lock_irqsave(&info->lock, flags); ++ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | ++ UART_IER_THRI); ++ spin_unlock_irqrestore(&info->lock, flags); ++ ++ if (!wait_for_completion_timeout(&info->fw_completion, ++ msecs_to_jiffies(40000))) { ++ dev_err(info->dev, "No reply to fw command\n"); ++ return -ETIMEDOUT; ++ } ++ ++ if (info->fw_error) { ++ dev_err(info->dev, "FW error\n"); ++ return -EPROTO; ++ } ++ ++ NBT_DBG_FW("Firmware sent in %d msecs\n", ++ jiffies_to_msecs(jiffies-time)); ++ ++ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS); ++ hci_h4p_set_rts(info, 0); ++ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE); ++ if (hci_h4p_wait_for_cts(info, 1, 100)) { ++ dev_err(info->dev, ++ "cts didn't go down after final speed change\n"); ++ return -ETIMEDOUT; ++ } ++ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS); ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/bluetooth/hci_h4p/fw.c +@@ -0,0 +1,166 @@ ++/* ++ * This file is part of hci_h4p bluetooth driver ++ * ++ * Copyright (C) 2005, 2006 Nokia Corporation. ++ * ++ * Contact: Ville Tervo ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "hci_h4p.h" ++ ++static int fw_pos; ++ ++/* Firmware handling */ ++static int hci_h4p_open_firmware(struct hci_h4p_info *info, ++ const struct firmware **fw_entry) ++{ ++ int err; ++ ++ fw_pos = 0; ++ NBT_DBG_FW("Opening %d/%d firmware\n", info->man_id, info->ver_id); ++ switch (info->man_id) { ++ case BT_CHIP_TI: ++ err = request_firmware(fw_entry, "ti1273.bin", info->dev); ++ break; ++ case BT_CHIP_CSR: ++ err = request_firmware(fw_entry, "bc4fw.bin", info->dev); ++ break; ++ case BT_CHIP_BCM: ++ err = request_firmware(fw_entry, "bcmfw.bin", info->dev); ++ break; ++ default: ++ dev_err(info->dev, "Invalid chip type %d\n", info->man_id); ++ *fw_entry = NULL; ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static void hci_h4p_close_firmware(const struct firmware *fw_entry) ++{ ++ release_firmware(fw_entry); ++} ++ ++/* Read fw. Return length of the command. If no more commands in ++ * fw 0 is returned. In error case return value is negative. ++ */ ++static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb, ++ const struct firmware *fw_entry, gfp_t how) ++{ ++ unsigned int cmd_len; ++ ++ if (fw_pos >= fw_entry->size) ++ return 0; ++ ++ if (fw_pos + 2 > fw_entry->size) { ++ dev_err(info->dev, "Corrupted firmware image 1\n"); ++ return -EMSGSIZE; ++ } ++ ++ cmd_len = fw_entry->data[fw_pos++]; ++ cmd_len += fw_entry->data[fw_pos++] << 8; ++ if (cmd_len == 0) ++ return 0; ++ ++ if (fw_pos + cmd_len > fw_entry->size) { ++ dev_err(info->dev, "Corrupted firmware image 2\n"); ++ return -EMSGSIZE; ++ } ++ ++ *skb = bt_skb_alloc(cmd_len, how); ++ if (!*skb) { ++ dev_err(info->dev, "Cannot reserve memory for buffer\n"); ++ return -ENOMEM; ++ } ++ memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len); ++ ++ fw_pos += cmd_len; ++ ++ return (*skb)->len; ++} ++ ++int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue) ++{ ++ const struct firmware *fw_entry = NULL; ++ struct sk_buff *skb = NULL; ++ int err; ++ ++ err = hci_h4p_open_firmware(info, &fw_entry); ++ if (err < 0 || !fw_entry) ++ goto err_clean; ++ ++ while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) { ++ if (err < 0 || !skb) ++ goto err_clean; ++ ++ skb_queue_tail(fw_queue, skb); ++ } ++ ++err_clean: ++ hci_h4p_close_firmware(fw_entry); ++ return err; ++} ++ ++int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue) ++{ ++ int err; ++ ++ switch (info->man_id) { ++ case BT_CHIP_CSR: ++ err = hci_h4p_bc4_send_fw(info, fw_queue); ++ break; ++ case BT_CHIP_TI: ++ err = hci_h4p_ti1273_send_fw(info, fw_queue); ++ break; ++ case BT_CHIP_BCM: ++ err = hci_h4p_bcm_send_fw(info, fw_queue); ++ break; ++ default: ++ dev_err(info->dev, "Don't know how to send firmware\n"); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb) ++{ ++ switch (info->man_id) { ++ case BT_CHIP_CSR: ++ hci_h4p_bc4_parse_fw_event(info, skb); ++ break; ++ case BT_CHIP_TI: ++ hci_h4p_ti1273_parse_fw_event(info, skb); ++ break; ++ case BT_CHIP_BCM: ++ hci_h4p_bcm_parse_fw_event(info, skb); ++ break; ++ default: ++ dev_err(info->dev, "Don't know how to parse fw event\n"); ++ info->fw_error = -EINVAL; ++ } ++ ++ return; ++} +--- /dev/null ++++ b/drivers/bluetooth/hci_h4p/hci_h4p.h +@@ -0,0 +1,231 @@ ++/* ++ * This file is part of hci_h4p bluetooth driver ++ * ++ * Copyright (C) 2005-2010 Nokia Corporation. ++ * ++ * Contact: Ville Tervo ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H ++#define __DRIVERS_BLUETOOTH_HCI_H4P_H ++ ++#define BT_CHIP_CSR 0x02 ++#define BT_CHIP_TI 0x30 ++#define BT_CHIP_BCM 0x04 ++ ++#define UART_SYSC_OMAP_RESET 0x03 ++#define UART_SYSS_RESETDONE 0x01 ++#define UART_OMAP_SCR_EMPTY_THR 0x08 ++#define UART_OMAP_SCR_WAKEUP 0x10 ++#define UART_OMAP_SSR_WAKEUP 0x02 ++#define UART_OMAP_SSR_TXFULL 0x01 ++ ++#define UART_OMAP_SYSC_IDLEMODE 0x03 ++#define UART_OMAP_SYSC_IDLEMASK (3 << UART_OMAP_SYSC_IDLEMODE) ++ ++#define UART_OMAP_SYSC_FORCE_IDLE (0 << UART_OMAP_SYSC_IDLEMODE) ++#define UART_OMAP_SYSC_NO_IDLE (1 << UART_OMAP_SYSC_IDLEMODE) ++#define UART_OMAP_SYSC_SMART_IDLE (2 << UART_OMAP_SYSC_IDLEMODE) ++ ++#define NBT_DBG(fmt, arg...) \ ++ pr_debug("%s: " fmt "" , __func__ , ## arg) ++ ++#define NBT_DBG_FW(fmt, arg...) \ ++ pr_debug("%s: " fmt "" , __func__ , ## arg) ++ ++#define NBT_DBG_POWER(fmt, arg...) \ ++ pr_debug("%s: " fmt "" , __func__ , ## arg) ++ ++#define NBT_DBG_TRANSFER(fmt, arg...) \ ++ pr_debug("%s: " fmt "" , __func__ , ## arg) ++ ++#define NBT_DBG_TRANSFER_NF(fmt, arg...) \ ++ pr_debug(fmt "" , ## arg) ++ ++#define NBT_DBG_DMA(fmt, arg...) \ ++ pr_debug("%s: " fmt "" , __func__ , ## arg) ++ ++struct hci_h4p_info { ++ struct hci_dev *hdev; ++ spinlock_t lock; ++ ++ void __iomem *uart_base; ++ unsigned long uart_phys_base; ++ int irq; ++ struct device *dev; ++ u8 chip_type; ++ void (*bt_wakeup)(bool enable); ++ bool (*host_wakeup)(void); ++ void (*reset)(bool enable); ++ int host_wakeup_gpio; ++ int man_id; ++ int ver_id; ++ ++ struct sk_buff_head fw_queue; ++ struct completion init_completion; ++ struct completion fw_completion; ++ int fw_error; ++ int init_error; ++ ++ struct sk_buff_head txq; ++ ++ struct sk_buff *rx_skb; ++ long rx_count; ++ unsigned long rx_state; ++ unsigned long garbage_bytes; ++ ++ int pm_enabled; ++ int tx_enabled; ++ int autorts; ++ int rx_enabled; ++ ++ int tx_clocks_en; ++ int rx_clocks_en; ++ spinlock_t clocks_lock; ++ struct clk *uart_iclk; ++ struct clk *uart_fclk; ++ atomic_t clk_users; ++ u16 dll; ++ u16 dlh; ++ u16 ier; ++ u16 mdr1; ++ u16 efr; ++}; ++ ++struct hci_h4p_radio_hdr { ++ __u8 evt; ++ __u8 dlen; ++} __attribute__ ((packed)); ++ ++ ++struct hci_h4p_init_hdr { ++ __u8 dlen; ++} __attribute__ ((packed)); ++#define HCI_H4P_INIT_HDR_SIZE 1 ++ ++struct hci_h4p_init_cmd { ++ __u8 ack; ++ __u16 baudrate; ++ __u16 unused; ++ __u8 mode; ++ __u16 sys_clk; ++ __u16 unused2; ++} __attribute__ ((packed)); ++#define HCI_H4P_INIT_CMD_SIZE 10 ++ ++struct hci_h4p_init_evt { ++ __u8 ack; ++ __u16 baudrate; ++ __u16 unused; ++ __u8 mode; ++ __u16 sys_clk; ++ __u16 unused2; ++ __u8 man_id; ++ __u8 ver_id; ++} __attribute__ ((packed)); ++#define HCI_H4P_INIT_EVT_SIZE 12 ++ ++struct hci_h4p_alive_hdr { ++ __u8 dlen; ++} __attribute__ ((packed)); ++#define HCI_H4P_ALIVE_HDR_SIZE 1 ++ ++struct hci_h4p_alive_msg { ++ __u8 message_id; ++ __u8 unused; ++} __attribute__ ((packed)); ++#define HCI_H4P_ALIVE_MSG_SIZE 2 ++ ++#define MAX_BAUD_RATE 921600 ++#define BC4_MAX_BAUD_RATE 3692300 ++#define UART_CLOCK 48000000 ++#define BT_INIT_DIVIDER 320 ++#define BT_BAUDRATE_DIVIDER 384000000 ++#define BT_SYSCLK_DIV 1000 ++#define INIT_SPEED 120000 ++ ++#define HCI_H4P_MODE 0x4c ++ ++#define HCI_H4P_ACK 0x20 ++#define HCI_H4P_NACK 0x40 ++#define HCI_H4P_ALIVE_IND_REQ 0x55 ++#define HCI_H4P_ALIVE_IND_RESP 0xCC ++ ++#define H4_TYPE_SIZE 1 ++#define H4_RADIO_HDR_SIZE 2 ++ ++/* H4+ packet types */ ++#define H4_CMD_PKT 0x01 ++#define H4_ACL_PKT 0x02 ++#define H4_SCO_PKT 0x03 ++#define H4_EVT_PKT 0x04 ++#define H4_NEG_PKT 0x06 ++#define H4_ALIVE_PKT 0x07 ++#define H4_RADIO_PKT 0x08 ++ ++/* TX states */ ++#define WAIT_FOR_PKT_TYPE 1 ++#define WAIT_FOR_HEADER 2 ++#define WAIT_FOR_DATA 3 ++ ++struct hci_fw_event { ++ struct hci_event_hdr hev; ++ struct hci_ev_cmd_complete cmd; ++ u8 status; ++} __attribute__ ((packed)); ++ ++int hci_h4p_send_alive_packet(struct hci_h4p_info *info); ++ ++void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, ++ struct sk_buff *skb); ++int hci_h4p_bcm_send_fw(struct hci_h4p_info *info, ++ struct sk_buff_head *fw_queue); ++ ++void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, ++ struct sk_buff *skb); ++int hci_h4p_bc4_send_fw(struct hci_h4p_info *info, ++ struct sk_buff_head *fw_queue); ++ ++void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info, ++ struct sk_buff *skb); ++int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info, ++ struct sk_buff_head *fw_queue); ++ ++int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue); ++int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue); ++void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb); ++ ++void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val); ++u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset); ++void hci_h4p_set_rts(struct hci_h4p_info *info, int active); ++int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms); ++void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which); ++void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which); ++void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed); ++int hci_h4p_reset_uart(struct hci_h4p_info *info); ++void hci_h4p_init_uart(struct hci_h4p_info *info); ++void hci_h4p_enable_tx(struct hci_h4p_info *info); ++void hci_h4p_store_regs(struct hci_h4p_info *info); ++void hci_h4p_restore_regs(struct hci_h4p_info *info); ++void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable); ++ ++#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */ +--- /dev/null ++++ b/drivers/bluetooth/hci_h4p/uart.c +@@ -0,0 +1,203 @@ ++/* ++ * This file is part of hci_h4p bluetooth driver ++ * ++ * Copyright (C) 2005, 2006 Nokia Corporation. ++ * ++ * Contact: Ville Tervo ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "hci_h4p.h" ++ ++inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val) ++{ ++ __raw_writeb(val, info->uart_base + (offset << 2)); ++} ++ ++inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset) ++{ ++ return __raw_readb(info->uart_base + (offset << 2)); ++} ++ ++void hci_h4p_set_rts(struct hci_h4p_info *info, int active) ++{ ++ u8 b; ++ ++ b = hci_h4p_inb(info, UART_MCR); ++ if (active) ++ b |= UART_MCR_RTS; ++ else ++ b &= ~UART_MCR_RTS; ++ hci_h4p_outb(info, UART_MCR, b); ++} ++ ++int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, ++ int timeout_ms) ++{ ++ unsigned long timeout; ++ int state; ++ ++ timeout = jiffies + msecs_to_jiffies(timeout_ms); ++ for (;;) { ++ state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS; ++ if (active) { ++ if (state) ++ return 0; ++ } else { ++ if (!state) ++ return 0; ++ } ++ if (time_after(jiffies, timeout)) ++ return -ETIMEDOUT; ++ msleep(1); ++ } ++} ++ ++void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which) ++{ ++ u8 lcr, b; ++ ++ lcr = hci_h4p_inb(info, UART_LCR); ++ hci_h4p_outb(info, UART_LCR, 0xbf); ++ b = hci_h4p_inb(info, UART_EFR); ++ if (on) ++ b |= which; ++ else ++ b &= ~which; ++ hci_h4p_outb(info, UART_EFR, b); ++ hci_h4p_outb(info, UART_LCR, lcr); ++} ++ ++void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&info->lock, flags); ++ __hci_h4p_set_auto_ctsrts(info, on, which); ++ spin_unlock_irqrestore(&info->lock, flags); ++} ++ ++void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed) ++{ ++ unsigned int divisor; ++ u8 lcr, mdr1; ++ ++ NBT_DBG("Setting speed %lu\n", speed); ++ ++ if (speed >= 460800) { ++ divisor = UART_CLOCK / 13 / speed; ++ mdr1 = 3; ++ } else { ++ divisor = UART_CLOCK / 16 / speed; ++ mdr1 = 0; ++ } ++ ++ /* Make sure UART mode is disabled */ ++ hci_h4p_outb(info, UART_OMAP_MDR1, 7); ++ ++ lcr = hci_h4p_inb(info, UART_LCR); ++ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB); /* Set DLAB */ ++ hci_h4p_outb(info, UART_DLL, divisor & 0xff); /* Set speed */ ++ hci_h4p_outb(info, UART_DLM, divisor >> 8); ++ hci_h4p_outb(info, UART_LCR, lcr); ++ ++ /* Make sure UART mode is enabled */ ++ hci_h4p_outb(info, UART_OMAP_MDR1, mdr1); ++} ++ ++int hci_h4p_reset_uart(struct hci_h4p_info *info) ++{ ++ int count = 0; ++ ++ /* Reset the UART */ ++ hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET); ++ while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) { ++ if (count++ > 100) { ++ dev_err(info->dev, "hci_h4p: UART reset timeout\n"); ++ return -ENODEV; ++ } ++ udelay(1); ++ } ++ ++ return 0; ++} ++ ++ ++void hci_h4p_store_regs(struct hci_h4p_info *info) ++{ ++ u16 lcr = 0; ++ ++ lcr = hci_h4p_inb(info, UART_LCR); ++ hci_h4p_outb(info, UART_LCR, 0xBF); ++ info->dll = hci_h4p_inb(info, UART_DLL); ++ info->dlh = hci_h4p_inb(info, UART_DLM); ++ info->efr = hci_h4p_inb(info, UART_EFR); ++ hci_h4p_outb(info, UART_LCR, lcr); ++ info->mdr1 = hci_h4p_inb(info, UART_OMAP_MDR1); ++ info->ier = hci_h4p_inb(info, UART_IER); ++} ++ ++void hci_h4p_restore_regs(struct hci_h4p_info *info) ++{ ++ u16 lcr = 0; ++ ++ hci_h4p_init_uart(info); ++ ++ hci_h4p_outb(info, UART_OMAP_MDR1, 7); ++ lcr = hci_h4p_inb(info, UART_LCR); ++ hci_h4p_outb(info, UART_LCR, 0xBF); ++ hci_h4p_outb(info, UART_DLL, info->dll); /* Set speed */ ++ hci_h4p_outb(info, UART_DLM, info->dlh); ++ hci_h4p_outb(info, UART_EFR, info->efr); ++ hci_h4p_outb(info, UART_LCR, lcr); ++ hci_h4p_outb(info, UART_OMAP_MDR1, info->mdr1); ++ hci_h4p_outb(info, UART_IER, info->ier); ++} ++ ++void hci_h4p_init_uart(struct hci_h4p_info *info) ++{ ++ u8 mcr, efr; ++ ++ /* Enable and setup FIFO */ ++ hci_h4p_outb(info, UART_OMAP_MDR1, 0x00); ++ ++ hci_h4p_outb(info, UART_LCR, 0xbf); ++ efr = hci_h4p_inb(info, UART_EFR); ++ hci_h4p_outb(info, UART_EFR, UART_EFR_ECB); ++ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB); ++ mcr = hci_h4p_inb(info, UART_MCR); ++ hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR); ++ hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | ++ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | ++ (3 << 6) | (0 << 4)); ++ hci_h4p_outb(info, UART_LCR, 0xbf); ++ hci_h4p_outb(info, UART_TI752_TLR, 0xed); ++ hci_h4p_outb(info, UART_TI752_TCR, 0xef); ++ hci_h4p_outb(info, UART_EFR, efr); ++ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB); ++ hci_h4p_outb(info, UART_MCR, 0x00); ++ hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8); ++ hci_h4p_outb(info, UART_IER, UART_IER_RDI | UART_IER_RLSI); ++ hci_h4p_outb(info, UART_OMAP_WER, 0xff); ++ hci_h4p_outb(info, UART_OMAP_SYSC, (0 << 0) | (1 << 2) | (1 << 3)); ++} +--- /dev/null ++++ b/include/linux/bluetooth/hci_h4p.h +@@ -0,0 +1,41 @@ ++/* ++ * This file is part of hci_h4p bluetooth driver ++ * ++ * Copyright (C) 2010 Nokia Corporation. ++ * ++ * Contact: Roger Quadros ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ */ ++ ++ ++/** ++ * struct hci_h4p_platform data - hci_h4p Platform data structure ++ * @uart_base: UART base address ++ * @uart_irq: UART Interrupt number ++ * @host_wu: Function hook determine if Host should wakeup or not. ++ * @bt_wu: Function hook to enable/disable Bluetooth transmission ++ * @reset: Function hook to set/clear reset conditiona ++ * @host_wu_gpio: Gpio used to wakeup host ++ */ ++struct hci_h4p_platform_data { ++ void *uart_base; ++ unsigned int uart_irq; ++ bool (*host_wu)(void); ++ void (*bt_wu)(bool); ++ void (*reset)(bool); ++ unsigned int host_wu_gpio; ++}; diff --git a/recipes/linux/linux-2.6.35/nokia900/linux-2.6-Earpiece-and-headset-support-for-N900.patch b/recipes/linux/linux-2.6.35/nokia900/linux-2.6-Earpiece-and-headset-support-for-N900.patch new file mode 100644 index 0000000000..6603785746 --- /dev/null +++ b/recipes/linux/linux-2.6.35/nokia900/linux-2.6-Earpiece-and-headset-support-for-N900.patch @@ -0,0 +1,577 @@ +From 3a00b962f5d60f67b0c447a47ed173d8826ffa0b Mon Sep 17 00:00:00 2001 +From: Jarkko Nikula +Date: Tue, 29 Jun 2010 14:44:50 +0300 +Subject: [PATCH 09/11] Earpiece and headset support for N900 + +This patch is combination of following patches: + +1. ASoC: RX-51: Add aic34b_dummy driver only for the RX-51 + +Only purpose of this dummy driver is to support a few audio connections +on Nokia RX-51/N900 HW. Currently ASoC framework supports only single audio +codec per card. The RX-51 has two of them since the TLV320AIC34 audio codec +used in RX-51 integrates basically two TLV320AIC33 codecs into a same chip. +These instances are called as AIC34A and AIC34B. The AIC34A is used as an +audio codec and the AIC34B is used kind of audio amplifier and mic bias +driver. + +Ideally features of this driver are supported by the tlv320aic3x codec +driver but as only single instance of it can exist currently, this driver +registers needed features as additional controls and widgets for the card. + +This driver should vanish as soon as the ASoC multi-component framework +maturises and gets integrated into mainline. + +Signed-off-by: Jarkko Nikula + +2. omap: rx51: Add second instance of the TLV320AIC34 codec + +TLV320AIC34 integrates basically two TLV320AIC33 audio codecs. The AIC34A +is found from I2C address 0x18 and AIC34B from 0x19. + +Signed-off-by: Jarkko Nikula + +3. ASoC: RX-51: Add support for earpiece + +Earpiece is connected to HPL pins of the second TLV320AIC34 codec instance. +Audio routings between AIC34A, AIC34B and earpiece is following + + AIC34A MONO_LOUT -> AIC34B LINE2R -> AIC34B HPL -> earpiece + +Add support for this routing by using the aic34b_dummy driver. + +As the aic34b_dummy should vanish after the ASoC multi-component is ready, +also this patch must be edited by modifying the audio_map accordingly. + +Signed-off-by: Jarkko Nikula + +4. ASoC: RX-51: Add mic input to AV jack + +Mic input is connected to LINE1L of the AIC34A via ECI_SW2 (name took from +the Maemo 2.6.28 kernel sources) switch. This patch adds the headset feature +to AV jack. Headset is combination of headphone stereo output with mic +input. + +This patch doesn't drive the mic bias so signal will be too weak to be +usable. The mic bias feature will be introduced by another patch. + +Signed-off-by: Jarkko Nikula + +5. SoC: RX-51: Add route for AIC34B generated mic bias + +This patch adds support for headset mic bias by using a feature provided +by the aic34b_dummy driver. + +As the aic34b_dummy should vanish after the ASoC multi-component is ready, +also this patch must be edited by modifying the audio_map accordingly. + +Signed-off-by: Jarkko Nikula +--- + arch/arm/mach-omap2/board-rx51-peripherals.c | 3 + + sound/soc/omap/Makefile | 2 +- + sound/soc/omap/aic34b_dummy.c | 260 ++++++++++++++++++++++++++ + sound/soc/omap/aic34b_dummy.h | 29 +++ + sound/soc/omap/rx51.c | 62 ++++++- + 5 files changed, 353 insertions(+), 3 deletions(-) + create mode 100644 sound/soc/omap/aic34b_dummy.c + create mode 100644 sound/soc/omap/aic34b_dummy.h + +diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c +index 0aab1a0..0d98752 100644 +--- a/arch/arm/mach-omap2/board-rx51-peripherals.c ++++ b/arch/arm/mach-omap2/board-rx51-peripherals.c +@@ -853,6 +853,9 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = { + I2C_BOARD_INFO("tlv320aic3x", 0x18), + .platform_data = &rx51_aic3x_data, + }, ++ { ++ I2C_BOARD_INFO("aic34b_dummy", 0x19), ++ }, + #if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE) + { + I2C_BOARD_INFO("tsl2563", 0x29), +diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile +index ba9fc65..0a7374f 100644 +--- a/sound/soc/omap/Makefile ++++ b/sound/soc/omap/Makefile +@@ -24,7 +24,7 @@ snd-soc-zoom2-objs := zoom2.o + snd-soc-igep0020-objs := igep0020.o + + obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o +-obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o ++obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o aic34b_dummy.o + obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o + obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o + obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o +diff --git a/sound/soc/omap/aic34b_dummy.c b/sound/soc/omap/aic34b_dummy.c +new file mode 100644 +index 0000000..bace5fc +--- /dev/null ++++ b/sound/soc/omap/aic34b_dummy.c +@@ -0,0 +1,260 @@ ++/* ++ * aic34b_dummy.c -- Dummy driver for AIC34 block B parts used in Nokia RX51 ++ * ++ * Purpose for this driver is to cover few audio connections on Nokia RX51 HW ++ * which are connected into block B of TLV320AIC34 dual codec. ++ * ++ * Copyright (C) 2008 Nokia Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ * TODO: ++ * - Get rid of this driver, at least when ASoC multi-component is merged into ++ * mainline. ++ * This driver is hacked only for Nokia RX51 HW. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/tlv320aic3x.h" ++ ++struct i2c_client *aic34b_client; ++ ++static int aic34b_read(struct i2c_client *client, unsigned int reg) ++{ ++ int val; ++ ++ val = i2c_smbus_read_byte_data(client, reg); ++ ++ return val; ++} ++ ++static int aic34b_write(struct i2c_client *client, unsigned int reg, ++ u8 value) ++{ ++ u8 data[2]; ++ ++ data[0] = reg & 0xff; ++ data[1] = value & 0xff; ++ ++ return (i2c_master_send(client, data, 2) == 2) ? 0 : -EIO; ++} ++ ++static int aic34b_get_volsw(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct soc_mixer_control *mc = ++ (struct soc_mixer_control *)kcontrol->private_value; ++ unsigned int reg = mc->reg; ++ unsigned int shift = mc->shift; ++ int max = mc->max; ++ unsigned int mask = (1 << fls(max)) - 1; ++ unsigned int invert = mc->invert; ++ int val; ++ ++ if (aic34b_client == NULL) ++ return 0; ++ ++ val = (aic34b_read(aic34b_client, reg) >> shift) & mask; ++ if (invert) ++ val = max - val; ++ ucontrol->value.integer.value[0] = val; ++ ++ return 0; ++} ++ ++static int aic34b_put_volsw(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct soc_mixer_control *mc = ++ (struct soc_mixer_control *)kcontrol->private_value; ++ unsigned int reg = mc->reg; ++ unsigned int shift = mc->shift; ++ int max = mc->max; ++ unsigned int mask = (1 << fls(max)) - 1; ++ unsigned int invert = mc->invert; ++ unsigned int val = (ucontrol->value.integer.value[0] & mask); ++ int val_reg; ++ ++ if (aic34b_client == NULL) ++ return 0; ++ ++ if (invert) ++ val = max - val; ++ ++ val_reg = aic34b_read(aic34b_client, reg); ++ if (((val_reg >> shift) & mask) == val) { ++ return 0; ++ } ++ ++ val_reg &= ~(mask << shift); ++ val_reg |= val << shift; ++ aic34b_write(aic34b_client, reg, val_reg); ++ ++ return 1; ++} ++ ++static int aic34b_bypass_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ int val; ++ ++ if (aic34b_client == NULL) ++ return 0; ++ ++ switch (event) { ++ case SND_SOC_DAPM_POST_PMU: ++ /* Connect LINE2R to RADC in differential mode and 0 dB gain */ ++ aic34b_write(aic34b_client, LINE2R_2_RADC_CTRL, 0x80); ++ /* Unmute Right ADC-PGA */ ++ aic34b_write(aic34b_client, RADC_VOL, 0x00); ++ /* Right PGA -> HPLOUT */ ++ val = aic34b_read(aic34b_client, PGAR_2_HPLOUT_VOL); ++ aic34b_write(aic34b_client, PGAR_2_HPLOUT_VOL, val | 0x80); ++ /* Unmute HPLOUT with 1 dB gain */ ++ aic34b_write(aic34b_client, HPLOUT_CTRL, 0x19); ++ /* Unmute HPLCOM with 1 dB gain */ ++ aic34b_write(aic34b_client, HPLCOM_CTRL, 0x19); ++ break; ++ case SND_SOC_DAPM_POST_PMD: ++ /* Disconnect LINE2R from RADC */ ++ aic34b_write(aic34b_client, LINE2R_2_RADC_CTRL, 0xF8); ++ /* Mute Right ADC-PGA */ ++ aic34b_write(aic34b_client, RADC_VOL, 0x80); ++ /* Detach Right PGA from HPLOUT */ ++ val = aic34b_read(aic34b_client, PGAR_2_HPLOUT_VOL); ++ aic34b_write(aic34b_client, PGAR_2_HPLOUT_VOL, val & 0x7f); ++ /* Power down HPLOUT */ ++ aic34b_write(aic34b_client, HPLOUT_CTRL, 0x06); ++ /* Power down HPLCOM */ ++ aic34b_write(aic34b_client, HPLCOM_CTRL, 0x06); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int aic34b_mic_bias_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ if (aic34b_client == NULL) ++ return 0; ++ ++ switch (event) { ++ case SND_SOC_DAPM_POST_PMU: ++ aic34b_write(aic34b_client, MICBIAS_CTRL, 2 << 6); ++ break; ++ case SND_SOC_DAPM_POST_PMD: ++ aic34b_write(aic34b_client, MICBIAS_CTRL, 0); ++ break; ++ } ++ ++ return 0; ++} ++ ++static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1); ++ ++static const struct snd_kcontrol_new aic34b_snd_controls[] = { ++ SOC_SINGLE_EXT_TLV("34B HPL PGAR Bypass Playback Volume", ++ PGAR_2_HPLOUT_VOL, 0, 118, 1, ++ aic34b_get_volsw, aic34b_put_volsw, ++ output_stage_tlv), ++}; ++ ++static const struct snd_soc_dapm_widget aic34b_dapm_widgets[] = { ++ SND_SOC_DAPM_PGA_E("34B LINE2R HPL Bypass", SND_SOC_NOPM, ++ 0, 0, NULL, 0, aic34b_bypass_event, ++ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), ++ SND_SOC_DAPM_MICBIAS_E("34B Mic Bias 2.5V", SND_SOC_NOPM, ++ 0, 0, aic34b_mic_bias_event, ++ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), ++ ++ SND_SOC_DAPM_OUTPUT("34B_HPLOUT"), ++ SND_SOC_DAPM_OUTPUT("34B_HPLCOM"), ++ SND_SOC_DAPM_INPUT("34B_LINE2R"), ++}; ++ ++static const struct snd_soc_dapm_route audio_map[] = { ++ {"34B LINE2R HPL Bypass", NULL, "34B_LINE2R"}, ++ {"34B_HPLOUT", NULL, "34B LINE2R HPL Bypass"}, ++ {"34B_HPLCOM", NULL, "34B LINE2R HPL Bypass"}, ++}; ++ ++int aic34b_add_controls(struct snd_soc_codec *codec) ++{ ++ snd_soc_dapm_new_controls(codec, aic34b_dapm_widgets, ++ ARRAY_SIZE(aic34b_dapm_widgets)); ++ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); ++ return snd_soc_add_controls(codec, aic34b_snd_controls, ++ ARRAY_SIZE(aic34b_snd_controls)); ++} ++EXPORT_SYMBOL_GPL(aic34b_add_controls); ++ ++static int aic34b_dummy_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ if (aic34b_read(client, AIC3X_PLL_PROGA_REG) != 0x10) { ++ /* Chip not present */ ++ return -ENODEV; ++ } ++ aic34b_client = client; ++ ++ return 0; ++} ++ ++static int aic34b_dummy_remove(struct i2c_client *client) ++{ ++ aic34b_client = NULL; ++ ++ return 0; ++} ++ ++static const struct i2c_device_id aic34b_dummy_id[] = { ++ { "aic34b_dummy", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, aic34b_dummy_id); ++ ++static struct i2c_driver aic34b_dummy_driver = { ++ .driver = { ++ .name = "aic34b_dummy" ++ }, ++ .probe = aic34b_dummy_probe, ++ .remove = aic34b_dummy_remove, ++ .id_table = aic34b_dummy_id, ++}; ++ ++static int __init aic34b_dummy_init(void) ++{ ++ return i2c_add_driver(&aic34b_dummy_driver); ++} ++ ++static void __exit aic34b_dummy_exit(void) ++{ ++ i2c_del_driver(&aic34b_dummy_driver); ++} ++ ++MODULE_AUTHOR(); ++MODULE_DESCRIPTION("Dummy driver for AIC34 block B parts used on Nokia RX51"); ++MODULE_LICENSE("GPL"); ++ ++module_init(aic34b_dummy_init); ++module_exit(aic34b_dummy_exit); +diff --git a/sound/soc/omap/aic34b_dummy.h b/sound/soc/omap/aic34b_dummy.h +new file mode 100644 +index 0000000..d37588a +--- /dev/null ++++ b/sound/soc/omap/aic34b_dummy.h +@@ -0,0 +1,29 @@ ++/* ++ * aic34b_dummy.h ++ * ++ * Copyright (C) 2008 Nokia Corporation ++ * ++ * Contact: Jarkko Nikula ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef __AIC34B_DUMMY__ ++#define __AIC34B_DUMMY__ ++ ++int aic34b_add_controls(struct snd_soc_codec *codec); ++ ++#endif +diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c +index 9b536da..5171428 100644 +--- a/sound/soc/omap/rx51.c ++++ b/sound/soc/omap/rx51.c +@@ -38,9 +38,11 @@ + #include "omap-pcm.h" + #include "../codecs/tlv320aic3x.h" + #include "../codecs/tpa6130a2.h" ++#include "aic34b_dummy.h" + + #define RX51_TVOUT_SEL_GPIO 40 + #define RX51_JACK_DETECT_GPIO 177 ++#define RX51_ECI_SW2_GPIO 182 + /* + * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This + * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c +@@ -51,18 +53,22 @@ enum { + RX51_JACK_DISABLED, + RX51_JACK_TVOUT, /* tv-out with stereo audio */ + RX51_JACK_HP, /* stereo output, no mic */ ++ RX51_JACK_HS, /* stereo output with mic input */ + }; + + static int rx51_spk_func; + static int rx51_dmic_func; + static int rx51_jack_func; + static int rx51_fmtx_func; ++static int rx51_ear_func; + + static void rx51_ext_control(struct snd_soc_codec *codec) + { +- int hp = 0; ++ int hp = 0, mic = 0; + + switch (rx51_jack_func) { ++ case RX51_JACK_HS: ++ mic = 1; + case RX51_JACK_TVOUT: + case RX51_JACK_HP: + hp = 1; +@@ -85,6 +91,14 @@ static void rx51_ext_control(struct snd_soc_codec *codec) + snd_soc_dapm_enable_pin(codec, "FM Transmitter"); + else + snd_soc_dapm_disable_pin(codec, "FM Transmitter"); ++ if (rx51_ear_func) ++ snd_soc_dapm_enable_pin(codec, "Earpiece"); ++ else ++ snd_soc_dapm_disable_pin(codec, "Earpiece"); ++ if (mic) ++ snd_soc_dapm_enable_pin(codec, "Mic Jack"); ++ else ++ snd_soc_dapm_disable_pin(codec, "Mic Jack"); + + gpio_set_value(RX51_TVOUT_SEL_GPIO, + rx51_jack_func == RX51_JACK_TVOUT); +@@ -238,6 +252,28 @@ static int rx51_set_fmtx(struct snd_kcontrol *kcontrol, + return 1; + } + ++static int rx51_get_ear(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ ucontrol->value.integer.value[0] = rx51_ear_func; ++ ++ return 0; ++} ++ ++static int rx51_set_ear(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); ++ ++ if (rx51_ear_func == ucontrol->value.integer.value[0]) ++ return 0; ++ ++ rx51_ear_func = ucontrol->value.integer.value[0]; ++ rx51_ext_control(codec); ++ ++ return 1; ++} ++ + static struct snd_soc_jack rx51_av_jack; + + static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = { +@@ -255,6 +291,8 @@ static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { + SND_SOC_DAPM_MIC("DMic", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("FM Transmitter", NULL), ++ SND_SOC_DAPM_SPK("Earpiece", NULL), ++ SND_SOC_DAPM_MIC("Mic Jack", NULL), + }; + + static const struct snd_soc_dapm_route audio_map[] = { +@@ -271,18 +309,27 @@ static const struct snd_soc_dapm_route audio_map[] = { + + {"FM Transmitter", NULL, "LLOUT"}, + {"FM Transmitter", NULL, "RLOUT"}, ++ ++ {"34B_LINE2R", NULL, "MONO_LOUT"}, ++ {"Earpiece", NULL, "34B_HPLOUT"}, ++ {"Earpiece", NULL, "34B_HPLCOM"}, ++ ++ {"LINE1L", NULL, "34B Mic Bias 2.5V"}, ++ {"34B Mic Bias 2.5V", NULL, "Mic Jack"} + }; + + static const char *spk_function[] = {"Off", "On"}; + static const char *input_function[] = {"ADC", "Digital Mic"}; +-static const char *jack_function[] = {"Off", "TV-OUT", "Headphone"}; ++static const char *jack_function[] = {"Off", "TV-OUT", "Headphone", "Headset"}; + static const char *fmtx_function[] = {"Off", "On"}; ++static const char *ear_function[] = {"Off", "On"}; + + static const struct soc_enum rx51_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fmtx_function), fmtx_function), ++ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ear_function), ear_function), + }; + + static const struct snd_kcontrol_new aic34_rx51_controls[] = { +@@ -294,6 +341,8 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = { + rx51_get_jack, rx51_set_jack), + SOC_ENUM_EXT("FMTX Function", rx51_enum[3], + rx51_get_fmtx, rx51_set_fmtx), ++ SOC_ENUM_EXT("Earpiece Function", rx51_enum[4], ++ rx51_get_ear, rx51_set_ear), + }; + + static int rx51_aic34_init(struct snd_soc_codec *codec) +@@ -319,6 +368,8 @@ static int rx51_aic34_init(struct snd_soc_codec *codec) + tpa6130a2_add_controls(codec); + snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42); + ++ aic34b_add_controls(codec); ++ + /* Set up RX-51 specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + +@@ -382,6 +433,10 @@ static int __init rx51_soc_init(void) + if (err) + goto err_gpio_tvout_sel; + gpio_direction_output(RX51_TVOUT_SEL_GPIO, 0); ++ err = gpio_request(RX51_ECI_SW2_GPIO, "eci_sw2"); ++ if (err) ++ goto err_gpio_eci_sw2; ++ gpio_direction_output(RX51_ECI_SW2_GPIO, 1); + + rx51_snd_device = platform_device_alloc("soc-audio", -1); + if (!rx51_snd_device) { +@@ -401,6 +456,8 @@ static int __init rx51_soc_init(void) + err2: + platform_device_put(rx51_snd_device); + err1: ++ gpio_free(RX51_ECI_SW2_GPIO); ++err_gpio_eci_sw2: + gpio_free(RX51_TVOUT_SEL_GPIO); + err_gpio_tvout_sel: + +@@ -413,6 +470,7 @@ static void __exit rx51_soc_exit(void) + rx51_av_jack_gpios); + + platform_device_unregister(rx51_snd_device); ++ gpio_free(RX51_ECI_SW2_GPIO); + gpio_free(RX51_TVOUT_SEL_GPIO); + } + +-- +1.7.0.4 + diff --git a/recipes/linux/linux-2.6.35/nokia900/linux-2.6-Hacks-for-Nokia-N900.patch b/recipes/linux/linux-2.6.35/nokia900/linux-2.6-Hacks-for-Nokia-N900.patch new file mode 100644 index 0000000000..d23b486a67 --- /dev/null +++ b/recipes/linux/linux-2.6.35/nokia900/linux-2.6-Hacks-for-Nokia-N900.patch @@ -0,0 +1,651 @@ +From df0b24d1e5fcb0a409debf3f9f1fcfd32f6cb2e8 Mon Sep 17 00:00:00 2001 +From: Felipe Balbi +Date: Mon, 4 Jan 2010 15:05:37 +0200 +Subject: [PATCH 01/11] Hacks for Nokia N900 + +This patch is combination of following hacks: + +1. usb: musb: add mA and charger sysfs entries + + This is the same mA entry and charger entry used in Fremantle program. + We are adding it as __deprecated because it will change and this is + done just for us to be able to test USB charging funtionality. + + One difference from Fremantle is that we now issue + sysfs_notify() when that value changes. + + Signed-off-by: Felipe Balbi + Signed-off-by: Ameya Palande + +2. usb: musb: add suspend sysfs entry + + This patch is combination of following patches: + 1. usb: musb: suspend notification only when needed + 2. usb: musb: Notify sysfs on suspend + 3. usb: musb: fix build with MUSB Host only mode + + Signed-off-by: Niilo Minkkinen + Signed-off-by: Heikki Krogerus + Signed-off-by: Felipe Balbi + Signed-off-by: Roger Quadros + Signed-off-by: Jouni Hogander + Signed-off-by: Ameya Palande + +3. usb: otg: add detect_charger field to otg_transceiver + + Then we can allow musb to kick charger detection on transceiver. + This is added as __deprecated because it only exists to mimic + the behavior we had in Fremantle. + + Signed-off-by: Felipe Balbi + +4. OMAP2/3 clock: implement clock rate/parent change notifiers + + Patch-Mainline: Not sure + + This patch allows core code and driver code to register for + notification when a clock's rate or parent changes. These are useful + because drivers don't have exclusive control over a clock's rate: + power management code (e.g., CPUFreq) may cause rate changes across + large parts of the clock tree. + + There are three notifier messages: + + 1. a pre-change notifier, called before the change; + + 2. a post-change notifier, called after the change; and + + 3. an abort notifier, called if the change fails for any reason after + the pre-change notifier callbacks have run. + + Since the implementation uses a blocking notifier, notifier code may + block waiting for devices to quiesce; but long delays here will reduce + the effectiveness of DVFS. Since notifier callbacks are called with + clocks_mutex held, callback code must not re-enter the clock framework. + + Pre-change notifiers are passed the current clock rate and the + post-change notifiers the new clock rate. The notifiers are called even + if the clock rate is the same before and after the change. This is + because reprogramming a clock's parent or rate may briefly disrupt the + clock. + + There are likely to be few users of these notifiers, compared to the + total number of clocks. So, rather than storing one notifier per + struct clk, notifiers are stored in a separate, dynamically allocated + list, effectively trading execution speed (in terms of a sequential + scan of the notifier list) for memory savings. The implementation is + completely hidden from the callbacks and can be easily changed. + + Until prototypes for these functions are made available in + include/linux/clk.h, drivers should pass function pointers to + clk_notifier_register() and clk_notifier_unregister() via their + platform_data struct. + + This patch is a collaboration between Tero Kristo + and Paul Walmsley and several + others. Hiroshi Doyu tracked down and fixed a + bug where blocking_notifier_chain_*() were called while interrupts + were disabled. Nishanth Menon found and fixed a bug in + the clk_notifier_unregister() path, where a list_del() was missing. + And thanks to Jouni Hogander for comments + and review during the evolution of these patches. + + Signed-off-by: Paul Walmsley + Signed-off-by: Tero Kristo + +5. PM: export missing symbols + + Patch-Mainline: never as this is a temporary hack + + Needed by the PVR driver. + + This patch is combined version of the following patches + + 1. PM: export clk_notifier_{register/unregister} + 2. PM: export omap_pm_set_min_bus_tput + + Signed-off-by: Imre Deak + Signed-off-by: Roger Quadros +--- + arch/arm/plat-omap/clock.c | 208 +++++++++++++++++++++++++++++++ + arch/arm/plat-omap/include/plat/clock.h | 63 +++++++++- + arch/arm/plat-omap/omap-pm-noop.c | 1 + + drivers/usb/musb/musb_core.c | 47 +++++++- + drivers/usb/musb/musb_core.h | 2 + + drivers/usb/musb/musb_gadget.c | 9 ++ + include/linux/usb/otg.h | 11 ++ + 7 files changed, 339 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c +index 7190cbd..f17e433 100644 +--- a/arch/arm/plat-omap/clock.c ++++ b/arch/arm/plat-omap/clock.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #include + +@@ -29,6 +30,78 @@ static DEFINE_MUTEX(clocks_mutex); + static DEFINE_SPINLOCK(clockfw_lock); + + static struct clk_functions *arch_clock; ++static LIST_HEAD(clk_notifier_list); ++ ++/* ++ * _clk_free_notifier_chain - safely remove struct clk_notifier ++ * @cn: struct clk_notifier * ++ * ++ * Removes the struct clk_notifier @cn from the clk_notifier_list and ++ * frees it. ++ */ ++static void _clk_free_notifier_chain(struct clk_notifier *cn) ++{ ++ list_del(&cn->node); ++ kfree(cn); ++} ++ ++/* ++ * omap_clk_notify - call clk notifier chain ++ * @clk: struct clk * that is changing rate ++ * @msg: clk notifier type (i.e., CLK_POST_RATE_CHANGE; see mach/clock.h) ++ * @old_rate: old rate ++ * @new_rate: new rate ++ * ++ * Triggers a notifier call chain on the post-clk-rate-change notifier ++ * for clock 'clk'. Passes a pointer to the struct clk and the ++ * previous and current rates to the notifier callback. Intended to be ++ * called by internal clock code only. No return value. ++ */ ++static void omap_clk_notify(struct clk *clk, unsigned long msg) ++{ ++ struct clk_notifier *cn; ++ struct clk_notifier_data cnd; ++ ++ cnd.clk = clk; ++ cnd.rate = clk->rate; ++ ++ list_for_each_entry(cn, &clk_notifier_list, node) { ++ if (cn->clk == clk) { ++ blocking_notifier_call_chain(&cn->notifier_head, msg, ++ &cnd); ++ break; ++ } ++ } ++} ++ ++/* ++ * omap_clk_notify_downstream - trigger clock change notifications ++ * @clk: struct clk * to start the notifications with ++ * @msg: notifier msg - see "Clk notifier callback types" in mach/clock.h ++ * ++ * Call clock change notifiers on clocks starting with @clk and including ++ * all of @clk's downstream children clocks. Returns NOTIFY_DONE. ++ */ ++static int omap_clk_notify_downstream(struct clk *clk, unsigned long msg) ++{ ++ struct clk *child; ++ int ret; ++ ++ if (!clk->notifier_count) ++ return NOTIFY_DONE; ++ ++ omap_clk_notify(clk, msg); ++ ++ if (list_empty(&clk->children)) ++ return NOTIFY_DONE; ++ ++ list_for_each_entry(child, &clk->children, sibling) { ++ ret = omap_clk_notify_downstream(child, msg); ++ if (ret) ++ break; ++ } ++ return ret; ++} + + /* + * Standard clock functions defined in include/linux/clk.h +@@ -115,10 +188,16 @@ int clk_set_rate(struct clk *clk, unsigned long rate) + { + unsigned long flags; + int ret = -EINVAL; ++ int msg; + + if (clk == NULL || IS_ERR(clk)) + return ret; + ++ mutex_lock(&clocks_mutex); ++ ++ if (clk->notifier_count) ++ omap_clk_notify_downstream(clk, CLK_PRE_RATE_CHANGE); ++ + spin_lock_irqsave(&clockfw_lock, flags); + if (arch_clock->clk_set_rate) + ret = arch_clock->clk_set_rate(clk, rate); +@@ -129,6 +208,12 @@ int clk_set_rate(struct clk *clk, unsigned long rate) + } + spin_unlock_irqrestore(&clockfw_lock, flags); + ++ msg = (ret) ? CLK_ABORT_RATE_CHANGE : CLK_POST_RATE_CHANGE; ++ ++ omap_clk_notify_downstream(clk, msg); ++ ++ mutex_unlock(&clocks_mutex); ++ + return ret; + } + EXPORT_SYMBOL(clk_set_rate); +@@ -137,10 +222,16 @@ int clk_set_parent(struct clk *clk, struct clk *parent) + { + unsigned long flags; + int ret = -EINVAL; ++ int msg; + + if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent)) + return ret; + ++ mutex_lock(&clocks_mutex); ++ ++ if (clk->notifier_count) ++ omap_clk_notify_downstream(clk, CLK_PRE_RATE_CHANGE); ++ + spin_lock_irqsave(&clockfw_lock, flags); + if (clk->usecount == 0) { + if (arch_clock->clk_set_parent) +@@ -154,6 +245,12 @@ int clk_set_parent(struct clk *clk, struct clk *parent) + ret = -EBUSY; + spin_unlock_irqrestore(&clockfw_lock, flags); + ++ msg = (ret) ? CLK_ABORT_RATE_CHANGE : CLK_POST_RATE_CHANGE; ++ ++ omap_clk_notify_downstream(clk, msg); ++ ++ mutex_unlock(&clocks_mutex); ++ + return ret; + } + EXPORT_SYMBOL(clk_set_parent); +@@ -384,9 +481,120 @@ void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) + } + #endif + ++/* Clk notifier implementation */ ++ ++/* ++ * clk_notifier_register - add a clock parameter change notifier ++ * @clk: struct clk * to watch ++ * @nb: struct notifier_block * with callback info ++ * ++ * Request notification for changes to the clock 'clk'. This uses a ++ * blocking notifier. Callback code must not call into the clock ++ * framework, as clocks_mutex is held. Pre-notifier callbacks will be ++ * passed the previous and new rate of the clock. ++ * ++ * clk_notifier_register() must be called from process ++ * context. Returns -EINVAL if called with null arguments, -ENOMEM ++ * upon allocation failure; otherwise, passes along the return value ++ * of blocking_notifier_chain_register(). ++ */ ++int clk_notifier_register(struct clk *clk, struct notifier_block *nb) ++{ ++ struct clk_notifier *cn = NULL, *cn_new = NULL; ++ int r; ++ struct clk *clkp; ++ ++ if (!clk || !nb) ++ return -EINVAL; ++ ++ mutex_lock(&clocks_mutex); ++ ++ list_for_each_entry(cn, &clk_notifier_list, node) ++ if (cn->clk == clk) ++ break; ++ ++ if (cn->clk != clk) { ++ cn_new = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL); ++ if (!cn_new) { ++ r = -ENOMEM; ++ goto cnr_out; ++ }; ++ ++ cn_new->clk = clk; ++ BLOCKING_INIT_NOTIFIER_HEAD(&cn_new->notifier_head); ++ ++ list_add(&cn_new->node, &clk_notifier_list); ++ cn = cn_new; ++ } ++ ++ r = blocking_notifier_chain_register(&cn->notifier_head, nb); ++ if (!IS_ERR_VALUE(r)) { ++ clkp = clk; ++ do { ++ clkp->notifier_count++; ++ } while ((clkp = clkp->parent)); ++ } else { ++ if (cn_new) ++ _clk_free_notifier_chain(cn); ++ } ++ ++cnr_out: ++ mutex_unlock(&clocks_mutex); ++ ++ return r; ++} ++EXPORT_SYMBOL(clk_notifier_register); ++ + /* ++ * clk_notifier_unregister - remove a clock change notifier ++ * @clk: struct clk * ++ * @nb: struct notifier_block * with callback info + * ++ * Request no further notification for changes to clock 'clk'. ++ * Returns -EINVAL if called with null arguments; otherwise, passes ++ * along the return value of blocking_notifier_chain_unregister(). + */ ++int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) ++{ ++ struct clk_notifier *cn = NULL; ++ struct clk *clkp; ++ int r = -EINVAL; ++ ++ if (!clk || !nb) ++ return -EINVAL; ++ ++ mutex_lock(&clocks_mutex); ++ ++ list_for_each_entry(cn, &clk_notifier_list, node) ++ if (cn->clk == clk) ++ break; ++ ++ if (cn->clk != clk) { ++ r = -ENOENT; ++ goto cnu_out; ++ }; ++ ++ r = blocking_notifier_chain_unregister(&cn->notifier_head, nb); ++ if (!IS_ERR_VALUE(r)) { ++ clkp = clk; ++ do { ++ clkp->notifier_count--; ++ } while ((clkp = clkp->parent)); ++ } ++ ++ /* ++ * XXX ugh, layering violation. There should be some ++ * support in the notifier code for this. ++ */ ++ if (!cn->notifier_head.head) ++ _clk_free_notifier_chain(cn); ++ ++cnu_out: ++ mutex_unlock(&clocks_mutex); ++ ++ return r; ++} ++EXPORT_SYMBOL(clk_notifier_unregister); + + #ifdef CONFIG_OMAP_RESET_CLOCKS + /* +diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h +index dfc472c..2f584c8 100644 +--- a/arch/arm/plat-omap/include/plat/clock.h ++++ b/arch/arm/plat-omap/include/plat/clock.h +@@ -15,6 +15,8 @@ + + #include + ++#include ++ + struct module; + struct clk; + struct clockdomain; +@@ -116,6 +118,37 @@ struct dpll_data { + + #endif + ++/* ++ * struct clk_notifier - associate a clk with a notifier ++ * @clk: struct clk * to associate the notifier with ++ * @notifier_head: a blocking_notifier_head for this clk ++ * @node: linked list pointers ++ * ++ * A list of struct clk_notifier is maintained by the notifier code. ++ * An entry is created whenever code registers the first notifier on a ++ * particular @clk. Future notifiers on that @clk are added to the ++ * @notifier_head. ++ */ ++struct clk_notifier { ++ struct clk *clk; ++ struct blocking_notifier_head notifier_head; ++ struct list_head node; ++}; ++ ++/* ++ * struct clk_notifier_data - rate data to pass to the notifier callback ++ * @clk: struct clk * being changed ++ * @rate: current rate of this clock ++ * ++ * This struct is passed as parameter to the clock notifier callbacks when ++ * a clock is changed. Current rate of the clock is passed along with the ++ * call in pre-notifier, and the new rate in post-notifier. ++ */ ++struct clk_notifier_data { ++ struct clk *clk; ++ unsigned long rate; ++}; ++ + struct clk { + struct list_head node; + const struct clkops *ops; +@@ -129,6 +162,7 @@ struct clk { + int (*set_rate)(struct clk *, unsigned long); + long (*round_rate)(struct clk *, unsigned long); + void (*init)(struct clk *); ++ u16 notifier_count; + __u8 enable_bit; + __s8 usecount; + u8 fixed_div; +@@ -178,6 +212,8 @@ extern void recalculate_root_clocks(void); + extern unsigned long followparent_recalc(struct clk *clk); + extern void clk_enable_init_clocks(void); + unsigned long omap_fixed_divisor_recalc(struct clk *clk); ++extern int clk_notifier_register(struct clk *clk, struct notifier_block *nb); ++extern int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); + #ifdef CONFIG_CPU_FREQ + extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table); + extern void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); +@@ -204,7 +240,32 @@ extern struct clk dummy_ck; + #define RATE_IN_4430 (1 << 5) + + #define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X) +- + #define RATE_IN_3430ES2PLUS (RATE_IN_3430ES2 | RATE_IN_36XX) + ++/* ++ * Clk notifier callback types ++ * ++ * Since the notifier is called with interrupts disabled, any actions ++ * taken by callbacks must be extremely fast and lightweight. ++ * ++ * CLK_PRE_RATE_CHANGE - called immediately before the clock rate is ++ * changed. Drivers must immediately terminate any operations that ++ * will be affected by the rate change. Callbacks must always ++ * return NOTIFY_DONE. ++ * ++ * CLK_ABORT_RATE_CHANGE: called if the rate change failed for some ++ * reason after CLK_PRE_RATE_CHANGE. In this case, all registered ++ * notifiers on the clock will be called with ++ * CLK_ABORT_RATE_CHANGE. Callbacks must always return ++ * NOTIFY_DONE. ++ * ++ * CLK_POST_RATE_CHANGE - called after the clock rate change has ++ * successfully completed. Callbacks must always return ++ * NOTIFY_DONE. ++ * ++ */ ++#define CLK_PRE_RATE_CHANGE 1 ++#define CLK_ABORT_RATE_CHANGE 2 ++#define CLK_POST_RATE_CHANGE 3 ++ + #endif +diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c +index 186bca8..9418f56 100644 +--- a/arch/arm/plat-omap/omap-pm-noop.c ++++ b/arch/arm/plat-omap/omap-pm-noop.c +@@ -84,6 +84,7 @@ void omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r) + * TI CDP code can call constraint_set here on the VDD2 OPP. + */ + } ++EXPORT_SYMBOL(omap_pm_set_min_bus_tput); + + void omap_pm_set_max_dev_wakeup_lat(struct device *dev, long t) + { +diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c +index 3b795c5..9504484 100644 +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -1789,8 +1789,38 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) + } + static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store); + ++static ssize_t ++musb_ma_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct musb *musb = dev_to_musb(dev); ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", musb->power_draw); ++} ++static DEVICE_ATTR(mA, 0444, musb_ma_show, NULL); ++ ++static ssize_t ++musb_charger_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct musb *musb = dev_to_musb(dev); ++ int charger; ++ ++ charger = otg_detect_charger(musb->xceiv); ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", charger); ++} ++static DEVICE_ATTR(charger, 0444, musb_charger_show, NULL); ++ + #ifdef CONFIG_USB_GADGET_MUSB_HDRC + ++static ssize_t ++musb_suspend_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct musb *musb = dev_to_musb(dev); ++ ++ return sprintf(buf, "%d\n", musb->is_suspended); ++} ++static DEVICE_ATTR(suspend, 0444, musb_suspend_show, NULL); ++ + /* Gadget drivers can't know that a host is connected so they might want + * to start SRP, but users can. This allows userspace to trigger SRP. + */ +@@ -1819,7 +1849,10 @@ static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store); + static struct attribute *musb_attributes[] = { + &dev_attr_mode.attr, + &dev_attr_vbus.attr, ++ &dev_attr_mA.attr, ++ &dev_attr_charger.attr, + #ifdef CONFIG_USB_GADGET_MUSB_HDRC ++ &dev_attr_suspend.attr, + &dev_attr_srp.attr, + #endif + NULL +@@ -1835,12 +1868,24 @@ static const struct attribute_group musb_attr_group = { + static void musb_irq_work(struct work_struct *data) + { + struct musb *musb = container_of(data, struct musb, irq_work); +- static int old_state; ++ static int old_state, old_suspend; ++ static int old_power_draw; + + if (musb->xceiv->state != old_state) { + old_state = musb->xceiv->state; + sysfs_notify(&musb->controller->kobj, NULL, "mode"); + } ++ ++ if (musb->power_draw != old_power_draw) { ++ old_power_draw = musb->power_draw; ++ sysfs_notify(&musb->controller->kobj, NULL, "mA"); ++ } ++#ifdef CONFIG_USB_GADGET_MUSB_HDRC ++ if (old_suspend != musb->is_suspended) { ++ old_suspend = musb->is_suspended; ++ sysfs_notify(&musb->controller->kobj, NULL, "suspend"); ++ } ++#endif + } + + /* -------------------------------------------------------------------------- +diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h +index 91d6779..52e4b6a 100644 +--- a/drivers/usb/musb/musb_core.h ++++ b/drivers/usb/musb/musb_core.h +@@ -401,6 +401,8 @@ struct musb { + + u8 min_power; /* vbus for periph, in mA/2 */ + ++ unsigned power_draw __deprecated; /* current power drawn, gadget only */ ++ + bool is_host; + + int a_wait_bcon; /* VBUS timeout in msecs */ +diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c +index 6fca870..ca10aef 100644 +--- a/drivers/usb/musb/musb_gadget.c ++++ b/drivers/usb/musb/musb_gadget.c +@@ -1521,8 +1521,17 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) + { + struct musb *musb = gadget_to_musb(gadget); + ++ /* REVISIT we shouldn't need to be passing ++ * this kind of value to userland. We have ++ * now the blocking notifier for transceivers ++ * which could very well handle this ++ */ ++ musb->power_draw = mA; ++ schedule_work(&musb->irq_work); ++ + if (!musb->xceiv->set_power) + return -EOPNOTSUPP; ++ + return otg_set_power(musb->xceiv, mA); + } + +diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h +index f8302d0..685943f 100644 +--- a/include/linux/usb/otg.h ++++ b/include/linux/usb/otg.h +@@ -117,6 +117,8 @@ struct otg_transceiver { + /* start or continue HNP role switch */ + int (*start_hnp)(struct otg_transceiver *otg); + ++ /* detect a charger */ ++ int (*detect_charger)(struct otg_transceiver *otg) __deprecated; + }; + + +@@ -226,6 +228,15 @@ otg_start_srp(struct otg_transceiver *otg) + return otg->start_srp(otg); + } + ++static inline int ++otg_detect_charger(struct otg_transceiver *otg) ++{ ++ if (otg->detect_charger) ++ return otg->detect_charger(otg); ++ ++ return 0; ++} ++ + /* notifiers */ + static inline int + otg_register_notifier(struct otg_transceiver *otg, struct notifier_block *nb) +-- +1.7.0.4 + diff --git a/recipes/linux/linux-2.6.35/nokia900/linux-2.6-SGX-PVR-driver-for-N900.patch b/recipes/linux/linux-2.6.35/nokia900/linux-2.6-SGX-PVR-driver-for-N900.patch new file mode 100644 index 0000000000..599fa02c3b --- /dev/null +++ b/recipes/linux/linux-2.6.35/nokia900/linux-2.6-SGX-PVR-driver-for-N900.patch @@ -0,0 +1,45789 @@ +From 63e4a840772ffd345209792ff8e742218111d2c8 Mon Sep 17 00:00:00 2001 +From: Roger Quadros +Date: Tue, 6 Apr 2010 16:35:41 +0300 +Subject: [PATCH 03/11] SGX PVR driver for N900 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch is combination of following patches: + +1. gpu: pvr: Add PVR GPU driver + +Patch-Mainline: not sure +Add the SGX PVR driver. + +Signed-off-by: Imre Deak +Signed-off-by: Felipe Balbi +Signed-off-by: Topi Pohjolainen +Signed-off-by: Ville Syrjälä +Signed-off-by: Mark Underwood +Signed-off-by: Phil Carmody +Signed-off-by: Tomi Valkeinen +Signed-off-by: Sami Kyöstilä +Signed-off-by: Mark Riding +Signed-off-by: Janusz Sobczak +Signed-off-by: Roger Quadros + +2. gpu: pvr: compilation fixes for kernel > 2.6.33 + +Signed-off-by: Ameya Palande +--- + drivers/gpu/Makefile | 2 +- + drivers/gpu/pvr/COPYING | 351 +++ + drivers/gpu/pvr/Kconfig | 46 + + drivers/gpu/pvr/Makefile | 43 + + drivers/gpu/pvr/README | 27 + + drivers/gpu/pvr/bridged_pvr_bridge.c | 3341 +++++++++++++++++++++++++ + drivers/gpu/pvr/bridged_pvr_bridge.h | 157 ++ + drivers/gpu/pvr/bridged_sgx_bridge.c | 1813 ++++++++++++++ + drivers/gpu/pvr/bridged_sgx_bridge.h | 167 ++ + drivers/gpu/pvr/bridged_support.c | 77 + + drivers/gpu/pvr/bridged_support.h | 35 + + drivers/gpu/pvr/buffer_manager.c | 1486 +++++++++++ + drivers/gpu/pvr/buffer_manager.h | 169 ++ + drivers/gpu/pvr/bufferclass_example.c | 266 ++ + drivers/gpu/pvr/bufferclass_example.h | 104 + + drivers/gpu/pvr/bufferclass_example_linux.c | 202 ++ + drivers/gpu/pvr/bufferclass_example_linux.h | 46 + + drivers/gpu/pvr/bufferclass_example_private.c | 194 ++ + drivers/gpu/pvr/bufferclass_example_private.h | 33 + + drivers/gpu/pvr/dbgdrvif.h | 318 +++ + drivers/gpu/pvr/device.h | 186 ++ + drivers/gpu/pvr/deviceclass.c | 1522 +++++++++++ + drivers/gpu/pvr/devicemem.c | 1150 +++++++++ + drivers/gpu/pvr/env_data.h | 57 + + drivers/gpu/pvr/env_perproc.h | 51 + + drivers/gpu/pvr/event.c | 270 ++ + drivers/gpu/pvr/event.h | 35 + + drivers/gpu/pvr/handle.c | 1443 +++++++++++ + drivers/gpu/pvr/handle.h | 150 ++ + drivers/gpu/pvr/hash.c | 382 +++ + drivers/gpu/pvr/hash.h | 51 + + drivers/gpu/pvr/img_defs.h | 46 + + drivers/gpu/pvr/img_types.h | 69 + + drivers/gpu/pvr/ioctldef.h | 93 + + drivers/gpu/pvr/kernelbuffer.h | 55 + + drivers/gpu/pvr/kerneldisplay.h | 104 + + drivers/gpu/pvr/lock.h | 31 + + drivers/gpu/pvr/mem.c | 130 + + drivers/gpu/pvr/mm.c | 1501 +++++++++++ + drivers/gpu/pvr/mm.h | 267 ++ + drivers/gpu/pvr/mmap.c | 922 +++++++ + drivers/gpu/pvr/mmap.h | 74 + + drivers/gpu/pvr/mmu.c | 1442 +++++++++++ + drivers/gpu/pvr/mmu.h | 85 + + drivers/gpu/pvr/module.c | 304 +++ + drivers/gpu/pvr/mutex.h | 36 + + drivers/gpu/pvr/mutils.h | 37 + + drivers/gpu/pvr/ocpdefs.h | 294 +++ + drivers/gpu/pvr/oemfuncs.h | 41 + + drivers/gpu/pvr/omaplfb.h | 140 + + drivers/gpu/pvr/omaplfb_displayclass.c | 852 +++++++ + drivers/gpu/pvr/omaplfb_linux.c | 168 ++ + drivers/gpu/pvr/osfunc.c | 1585 ++++++++++++ + drivers/gpu/pvr/osfunc.h | 232 ++ + drivers/gpu/pvr/osperproc.c | 84 + + drivers/gpu/pvr/osperproc.h | 36 + + drivers/gpu/pvr/pb.c | 419 ++++ + drivers/gpu/pvr/pdump.c | 1271 ++++++++++ + drivers/gpu/pvr/pdump_common.c | 237 ++ + drivers/gpu/pvr/pdump_km.h | 268 ++ + drivers/gpu/pvr/pdumpdefs.h | 92 + + drivers/gpu/pvr/perproc.c | 266 ++ + drivers/gpu/pvr/perproc.h | 79 + + drivers/gpu/pvr/power.c | 628 +++++ + drivers/gpu/pvr/power.h | 104 + + drivers/gpu/pvr/private_data.h | 35 + + drivers/gpu/pvr/proc.c | 421 ++++ + drivers/gpu/pvr/proc.h | 54 + + drivers/gpu/pvr/pvr_bridge.h | 1107 ++++++++ + drivers/gpu/pvr/pvr_bridge_k.c | 191 ++ + drivers/gpu/pvr/pvr_bridge_km.h | 190 ++ + drivers/gpu/pvr/pvr_debug.c | 353 +++ + drivers/gpu/pvr/pvr_debug.h | 110 + + drivers/gpu/pvr/pvrconfig.h | 36 + + drivers/gpu/pvr/pvrmmap.h | 36 + + drivers/gpu/pvr/pvrmodule.h | 31 + + drivers/gpu/pvr/pvrsrv.c | 906 +++++++ + drivers/gpu/pvr/pvrversion.h | 37 + + drivers/gpu/pvr/queue.c | 828 ++++++ + drivers/gpu/pvr/queue.h | 81 + + drivers/gpu/pvr/ra.c | 1163 +++++++++ + drivers/gpu/pvr/ra.h | 107 + + drivers/gpu/pvr/resman.c | 540 ++++ + drivers/gpu/pvr/resman.h | 92 + + drivers/gpu/pvr/services.h | 237 ++ + drivers/gpu/pvr/services_headers.h | 42 + + drivers/gpu/pvr/servicesext.h | 435 ++++ + drivers/gpu/pvr/servicesint.h | 173 ++ + drivers/gpu/pvr/sgx530defs.h | 471 ++++ + drivers/gpu/pvr/sgx_bridge.h | 388 +++ + drivers/gpu/pvr/sgx_bridge_km.h | 109 + + drivers/gpu/pvr/sgx_options.h | 178 ++ + drivers/gpu/pvr/sgxapi_km.h | 237 ++ + drivers/gpu/pvr/sgxconfig.h | 75 + + drivers/gpu/pvr/sgxcoretypes.h | 41 + + drivers/gpu/pvr/sgxdefs.h | 38 + + drivers/gpu/pvr/sgxerrata.h | 34 + + drivers/gpu/pvr/sgxfeaturedefs.h | 40 + + drivers/gpu/pvr/sgxinfo.h | 338 +++ + drivers/gpu/pvr/sgxinfokm.h | 262 ++ + drivers/gpu/pvr/sgxinit.c | 1622 ++++++++++++ + drivers/gpu/pvr/sgxkick.c | 504 ++++ + drivers/gpu/pvr/sgxmmu.h | 57 + + drivers/gpu/pvr/sgxpower.c | 398 +++ + drivers/gpu/pvr/sgxreset.c | 223 ++ + drivers/gpu/pvr/sgxscript.h | 65 + + drivers/gpu/pvr/sgxtransfer.c | 290 +++ + drivers/gpu/pvr/sgxutils.c | 750 ++++++ + drivers/gpu/pvr/sgxutils.h | 77 + + drivers/gpu/pvr/srvkm.h | 50 + + drivers/gpu/pvr/syscommon.h | 179 ++ + drivers/gpu/pvr/sysconfig.c | 818 ++++++ + drivers/gpu/pvr/sysconfig.h | 53 + + drivers/gpu/pvr/sysinfo.h | 94 + + drivers/gpu/pvr/syslocal.h | 98 + + drivers/gpu/pvr/sysutils.c | 719 ++++++ + drivers/gpu/pvr/tools/Makefile | 29 + + drivers/gpu/pvr/tools/dbgdriv.c | 1652 ++++++++++++ + drivers/gpu/pvr/tools/dbgdriv.h | 183 ++ + drivers/gpu/pvr/tools/hostfunc.c | 267 ++ + drivers/gpu/pvr/tools/hostfunc.h | 58 + + drivers/gpu/pvr/tools/hotkey.c | 101 + + drivers/gpu/pvr/tools/hotkey.h | 60 + + drivers/gpu/pvr/tools/ioctl.c | 399 +++ + drivers/gpu/pvr/tools/ioctl.h | 81 + + drivers/gpu/pvr/tools/linuxsrv.h | 47 + + drivers/gpu/pvr/tools/main.c | 197 ++ + drivers/video/Kconfig | 2 + + include/video/sgx-util.h | 64 + + 129 files changed, 44718 insertions(+), 1 deletions(-) + create mode 100644 drivers/gpu/pvr/COPYING + create mode 100644 drivers/gpu/pvr/Kconfig + create mode 100644 drivers/gpu/pvr/Makefile + create mode 100644 drivers/gpu/pvr/README + create mode 100644 drivers/gpu/pvr/bridged_pvr_bridge.c + create mode 100644 drivers/gpu/pvr/bridged_pvr_bridge.h + create mode 100644 drivers/gpu/pvr/bridged_sgx_bridge.c + create mode 100644 drivers/gpu/pvr/bridged_sgx_bridge.h + create mode 100644 drivers/gpu/pvr/bridged_support.c + create mode 100644 drivers/gpu/pvr/bridged_support.h + create mode 100644 drivers/gpu/pvr/buffer_manager.c + create mode 100644 drivers/gpu/pvr/buffer_manager.h + create mode 100644 drivers/gpu/pvr/bufferclass_example.c + create mode 100644 drivers/gpu/pvr/bufferclass_example.h + create mode 100644 drivers/gpu/pvr/bufferclass_example_linux.c + create mode 100644 drivers/gpu/pvr/bufferclass_example_linux.h + create mode 100644 drivers/gpu/pvr/bufferclass_example_private.c + create mode 100644 drivers/gpu/pvr/bufferclass_example_private.h + create mode 100644 drivers/gpu/pvr/dbgdrvif.h + create mode 100644 drivers/gpu/pvr/device.h + create mode 100644 drivers/gpu/pvr/deviceclass.c + create mode 100644 drivers/gpu/pvr/devicemem.c + create mode 100644 drivers/gpu/pvr/env_data.h + create mode 100644 drivers/gpu/pvr/env_perproc.h + create mode 100644 drivers/gpu/pvr/event.c + create mode 100644 drivers/gpu/pvr/event.h + create mode 100644 drivers/gpu/pvr/handle.c + create mode 100644 drivers/gpu/pvr/handle.h + create mode 100644 drivers/gpu/pvr/hash.c + create mode 100644 drivers/gpu/pvr/hash.h + create mode 100644 drivers/gpu/pvr/img_defs.h + create mode 100644 drivers/gpu/pvr/img_types.h + create mode 100644 drivers/gpu/pvr/ioctldef.h + create mode 100644 drivers/gpu/pvr/kernelbuffer.h + create mode 100644 drivers/gpu/pvr/kerneldisplay.h + create mode 100644 drivers/gpu/pvr/lock.h + create mode 100644 drivers/gpu/pvr/mem.c + create mode 100644 drivers/gpu/pvr/mm.c + create mode 100644 drivers/gpu/pvr/mm.h + create mode 100644 drivers/gpu/pvr/mmap.c + create mode 100644 drivers/gpu/pvr/mmap.h + create mode 100644 drivers/gpu/pvr/mmu.c + create mode 100644 drivers/gpu/pvr/mmu.h + create mode 100644 drivers/gpu/pvr/module.c + create mode 100644 drivers/gpu/pvr/mutex.h + create mode 100644 drivers/gpu/pvr/mutils.h + create mode 100644 drivers/gpu/pvr/ocpdefs.h + create mode 100644 drivers/gpu/pvr/oemfuncs.h + create mode 100644 drivers/gpu/pvr/omaplfb.h + create mode 100644 drivers/gpu/pvr/omaplfb_displayclass.c + create mode 100644 drivers/gpu/pvr/omaplfb_linux.c + create mode 100644 drivers/gpu/pvr/osfunc.c + create mode 100644 drivers/gpu/pvr/osfunc.h + create mode 100644 drivers/gpu/pvr/osperproc.c + create mode 100644 drivers/gpu/pvr/osperproc.h + create mode 100644 drivers/gpu/pvr/pb.c + create mode 100644 drivers/gpu/pvr/pdump.c + create mode 100644 drivers/gpu/pvr/pdump_common.c + create mode 100644 drivers/gpu/pvr/pdump_km.h + create mode 100644 drivers/gpu/pvr/pdumpdefs.h + create mode 100644 drivers/gpu/pvr/perproc.c + create mode 100644 drivers/gpu/pvr/perproc.h + create mode 100644 drivers/gpu/pvr/power.c + create mode 100644 drivers/gpu/pvr/power.h + create mode 100644 drivers/gpu/pvr/private_data.h + create mode 100644 drivers/gpu/pvr/proc.c + create mode 100644 drivers/gpu/pvr/proc.h + create mode 100644 drivers/gpu/pvr/pvr_bridge.h + create mode 100644 drivers/gpu/pvr/pvr_bridge_k.c + create mode 100644 drivers/gpu/pvr/pvr_bridge_km.h + create mode 100644 drivers/gpu/pvr/pvr_debug.c + create mode 100644 drivers/gpu/pvr/pvr_debug.h + create mode 100644 drivers/gpu/pvr/pvrconfig.h + create mode 100644 drivers/gpu/pvr/pvrmmap.h + create mode 100644 drivers/gpu/pvr/pvrmodule.h + create mode 100644 drivers/gpu/pvr/pvrsrv.c + create mode 100644 drivers/gpu/pvr/pvrversion.h + create mode 100644 drivers/gpu/pvr/queue.c + create mode 100644 drivers/gpu/pvr/queue.h + create mode 100644 drivers/gpu/pvr/ra.c + create mode 100644 drivers/gpu/pvr/ra.h + create mode 100644 drivers/gpu/pvr/resman.c + create mode 100644 drivers/gpu/pvr/resman.h + create mode 100644 drivers/gpu/pvr/services.h + create mode 100644 drivers/gpu/pvr/services_headers.h + create mode 100644 drivers/gpu/pvr/servicesext.h + create mode 100644 drivers/gpu/pvr/servicesint.h + create mode 100644 drivers/gpu/pvr/sgx530defs.h + create mode 100644 drivers/gpu/pvr/sgx_bridge.h + create mode 100644 drivers/gpu/pvr/sgx_bridge_km.h + create mode 100644 drivers/gpu/pvr/sgx_options.h + create mode 100644 drivers/gpu/pvr/sgxapi_km.h + create mode 100644 drivers/gpu/pvr/sgxconfig.h + create mode 100644 drivers/gpu/pvr/sgxcoretypes.h + create mode 100644 drivers/gpu/pvr/sgxdefs.h + create mode 100644 drivers/gpu/pvr/sgxerrata.h + create mode 100644 drivers/gpu/pvr/sgxfeaturedefs.h + create mode 100644 drivers/gpu/pvr/sgxinfo.h + create mode 100644 drivers/gpu/pvr/sgxinfokm.h + create mode 100644 drivers/gpu/pvr/sgxinit.c + create mode 100644 drivers/gpu/pvr/sgxkick.c + create mode 100644 drivers/gpu/pvr/sgxmmu.h + create mode 100644 drivers/gpu/pvr/sgxpower.c + create mode 100644 drivers/gpu/pvr/sgxreset.c + create mode 100644 drivers/gpu/pvr/sgxscript.h + create mode 100644 drivers/gpu/pvr/sgxtransfer.c + create mode 100644 drivers/gpu/pvr/sgxutils.c + create mode 100644 drivers/gpu/pvr/sgxutils.h + create mode 100644 drivers/gpu/pvr/srvkm.h + create mode 100644 drivers/gpu/pvr/syscommon.h + create mode 100644 drivers/gpu/pvr/sysconfig.c + create mode 100644 drivers/gpu/pvr/sysconfig.h + create mode 100644 drivers/gpu/pvr/sysinfo.h + create mode 100644 drivers/gpu/pvr/syslocal.h + create mode 100644 drivers/gpu/pvr/sysutils.c + create mode 100644 drivers/gpu/pvr/tools/Makefile + create mode 100644 drivers/gpu/pvr/tools/dbgdriv.c + create mode 100644 drivers/gpu/pvr/tools/dbgdriv.h + create mode 100644 drivers/gpu/pvr/tools/hostfunc.c + create mode 100644 drivers/gpu/pvr/tools/hostfunc.h + create mode 100644 drivers/gpu/pvr/tools/hotkey.c + create mode 100644 drivers/gpu/pvr/tools/hotkey.h + create mode 100644 drivers/gpu/pvr/tools/ioctl.c + create mode 100644 drivers/gpu/pvr/tools/ioctl.h + create mode 100644 drivers/gpu/pvr/tools/linuxsrv.h + create mode 100644 drivers/gpu/pvr/tools/main.c + create mode 100644 include/video/sgx-util.h + +diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile +index 30879df..21f750f 100644 +--- a/drivers/gpu/Makefile ++++ b/drivers/gpu/Makefile +@@ -1 +1 @@ +-obj-y += drm/ vga/ ++obj-y += drm/ vga/ pvr/ +diff --git a/drivers/gpu/pvr/COPYING b/drivers/gpu/pvr/COPYING +new file mode 100644 +index 0000000..80dd76b +--- /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. ++ ++ ++ Copyright (C) 19yy ++ ++ 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. ++ ++ , 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 0000000..2021d31 +--- /dev/null ++++ b/drivers/gpu/pvr/Kconfig +@@ -0,0 +1,46 @@ ++menuconfig PVR ++ tristate "PowerVR Services" ++ depends on OMAP2_DSS ++ ++if PVR ++ ++choice ++ prompt "Build type" ++ default PVR_RELEASE_N900 ++config PVR_RELEASE_N900 ++ bool "Release" ++config PVR_DEBUG ++ bool "Debug" ++config PVR_TIMING ++ bool "Timing" ++endchoice ++ ++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 0000000..81db9be +--- /dev/null ++++ b/drivers/gpu/pvr/Makefile +@@ -0,0 +1,43 @@ ++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 ++ ++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 0000000..7da0e62 +--- /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. ++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 0000000..fa1a371 +--- /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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++ ++#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 ++#include /* for cache flush */ ++#include ++#include ++ ++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' : ++ '?'); ++ return 0; ++ } ++ ++ 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_NONE, ++ 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(DEBUG) ++ 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(DEBUG) ++ 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(u32 cmd, void *in, void *out, ++ 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, 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(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 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(bid, in, out, 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 0000000..7249802 +--- /dev/null ++++ b/drivers/gpu/pvr/bridged_pvr_bridge.h +@@ -0,0 +1,157 @@ ++/********************************************************************** ++ * ++ * 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. ++ * 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(DEBUG) ++#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 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 0000000..adbd436 +--- /dev/null ++++ b/drivers/gpu/pvr/bridged_sgx_bridge.c +@@ -0,0 +1,1813 @@ ++/********************************************************************** ++ * ++ * 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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++ ++#include ++ ++#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" ++ ++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; ++} ++ ++int SGXDoKickBW(u32 ui32BridgeID, ++ struct PVRSRV_BRIDGE_IN_DOKICK *psDoKickIN, ++ struct PVRSRV_BRIDGE_RETURN *psRetOUT, ++ struct PVRSRV_PER_PROCESS_DATA *psPerProc) ++{ ++ void *hDevCookieInt; ++ u32 i; ++ ++ PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_DOKICK); ++ ++ 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 > SGX_MAX_3D_STATUS_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); ++ ++ 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(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; ++ ++ 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; ++ ++ 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; ++ ++ psRetOUT->eError = ++ SGX2DQueryBlitsCompleteKM(psDevInfo, ++ (struct PVRSRV_KERNEL_SYNC_INFO *) ++ pvSyncInfo, ++ ps2DQueryBltsCompleteIN-> ++ bWaitForComplete); ++ ++ 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 0000000..3867dc4 +--- /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. ++ * 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, ++ 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(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 0000000..499a3df +--- /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. ++ * 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 0000000..96b8643 +--- /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. ++ * 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 0000000..7d633dc +--- /dev/null ++++ b/drivers/gpu/pvr/buffer_manager.c +@@ -0,0 +1,1486 @@ ++/********************************************************************** ++ * ++ * 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. ++ * 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" ++ ++#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 && (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) ++ return NULL; ++ ++ 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; ++ ++ PVR_DPF(PVR_DBG_MESSAGE, "BM_DestroyHeap"); ++ ++ if (psBMHeap) { ++ struct BM_HEAP **ppsBMHeap; ++ ++ 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); ++ } ++ } else { ++ PVR_DPF(PVR_DBG_ERROR, "BM_DestroyHeap: invalid heap handle"); ++ } ++} ++ ++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 && (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; ++} +diff --git a/drivers/gpu/pvr/buffer_manager.h b/drivers/gpu/pvr/buffer_manager.h +new file mode 100644 +index 0000000..45de4d0 +--- /dev/null ++++ b/drivers/gpu/pvr/buffer_manager.h +@@ -0,0 +1,169 @@ ++/********************************************************************** ++ * ++ * 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. ++ * 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); ++ ++#endif +diff --git a/drivers/gpu/pvr/bufferclass_example.c b/drivers/gpu/pvr/bufferclass_example.c +new file mode 100644 +index 0000000..4f7a8ea +--- /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. ++ * 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 0000000..c9dd094 +--- /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. ++ * 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 0000000..bfb6ab6 +--- /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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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(DEBUG) ++ 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 0000000..8e17fdf +--- /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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#ifndef __BC_EXAMPLE_LINUX_H__ ++#define __BC_EXAMPLE_LINUX_H__ ++ ++#include ++ ++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 0000000..360524e +--- /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. ++ * 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 0000000..527c782 +--- /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. ++ * 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 0000000..d8ace97 +--- /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. ++ * 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 0000000..a5240c4 +--- /dev/null ++++ b/drivers/gpu/pvr/device.h +@@ -0,0 +1,186 @@ ++/********************************************************************** ++ * ++ * 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. ++ * 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 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 0000000..6fde440 +--- /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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++#include ++ ++#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(KERNEL_ID, 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(KERNEL_ID, 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 0000000..6cbcf2c +--- /dev/null ++++ b/drivers/gpu/pvr/devicemem.c +@@ -0,0 +1,1150 @@ ++/********************************************************************** ++ * ++ * 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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++ ++#include "services_headers.h" ++#include "buffer_manager.h" ++#include "pdump_km.h" ++#include "pvr_bridge_km.h" ++ ++#include ++ ++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 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) ++ eError = PVRSRVFreeSyncInfoKM(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 = PVRSRVAllocSyncInfoKM(hDevCookie, ++ hDevMemContext, ++ &psMemInfo->psKernelSyncInfo); ++ 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: ++ if (psMemInfo) { ++ FreeDeviceMem(psMemInfo); ++ ++ psMemInfo = NULL; ++ } ++ ++ErrorExitPhase3: ++ if (psMemInfo) { ++ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ++ sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo, ++ NULL); ++ } ++ ++ErrorExitPhase2: ++ if (psIntSysPAddr) ++ 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 0000000..7317a51 +--- /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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#ifndef _ENV_DATA_ ++#define _ENV_DATA_ ++ ++#include ++#include ++#include ++ ++#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 0000000..7f092f6 +--- /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. ++ * 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 0000000..e538100 +--- /dev/null ++++ b/drivers/gpu/pvr/event.c +@@ -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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "mutex.h" ++#include "lock.h" ++#include "event.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(DEBUG) ++ 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(DEBUG) ++ 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(DEBUG) ++ 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(DEBUG) ++ 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; ++ ++ mutex_unlock(&gPVRSRVLock); ++ ++ ui32TimeOutJiffies = ++ (u32) schedule_timeout((s32) ui32TimeOutJiffies); ++ ++ mutex_lock(&gPVRSRVLock); ++#if defined(DEBUG) ++ 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 0000000..54de808 +--- /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. ++ * 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 0000000..77e28fc +--- /dev/null ++++ b/drivers/gpu/pvr/handle.c +@@ -0,0 +1,1443 @@ ++/********************************************************************** ++ * ++ * 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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++ ++#include "services_headers.h" ++#include "handle.h" ++ ++#ifdef DEBUG ++#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 DEBUG ++ { ++ IMG_BOOL bIsEmpty2; ++ ++ bIsEmpty2 = (IMG_BOOL) (psList->ui32Prev == ui32Index); ++ PVR_ASSERT(bIsEmpty == bIsEmpty2); ++ } ++#endif ++ ++ return bIsEmpty; ++} ++ ++#ifdef 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 (ui32CopySize != 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 DEBUG ++ 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 0000000..668e5d8 +--- /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. ++ * 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 0000000..318d9dd +--- /dev/null ++++ b/drivers/gpu/pvr/hash.c +@@ -0,0 +1,382 @@ ++/********************************************************************** ++ * ++ * 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. ++ * 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); ++ ++ OSAllocMem(PVRSRV_PAGEABLE_SELECT, ++ sizeof(struct BUCKET *) * uNewSize, ++ (void **) &ppNewTable, NULL); ++ if (ppNewTable == NULL) ++ 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; ++ ++ OSAllocMem(PVRSRV_PAGEABLE_SELECT, ++ sizeof(struct BUCKET *) * pHash->uSize, ++ (void **) &pHash->ppBucketTable, NULL); ++ ++ if (pHash->ppBucketTable == NULL) { ++ 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 0000000..d0319ad +--- /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. ++ * 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 0000000..b0a25c2 +--- /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. ++ * 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 0000000..c52ba6c +--- /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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#ifndef __IMG_TYPES_H__ ++#define __IMG_TYPES_H__ ++ ++#include ++ ++#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 0000000..36a1684 +--- /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. ++ * 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 0000000..da69d7e +--- /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. ++ * 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 0000000..c601906 +--- /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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#if !defined(__KERNELDISPLAY_H__) ++#define __KERNELDISPLAY_H__ ++ ++#include ++ ++#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/lock.h b/drivers/gpu/pvr/lock.h +new file mode 100644 +index 0000000..c3b6ff3 +--- /dev/null ++++ b/drivers/gpu/pvr/lock.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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++#ifndef __LOCK_H__ ++#define __LOCK_H__ ++ ++extern struct mutex gPVRSRVLock; ++ ++#endif +diff --git a/drivers/gpu/pvr/mem.c b/drivers/gpu/pvr/mem.c +new file mode 100644 +index 0000000..6375cad +--- /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. ++ * 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 0000000..29bdd93 +--- /dev/null ++++ b/drivers/gpu/pvr/mm.c +@@ -0,0 +1,1501 @@ ++/********************************************************************** ++ * ++ * 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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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" ++#include "mutex.h" ++#include "lock.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 0000000..9484363 +--- /dev/null ++++ b/drivers/gpu/pvr/mm.h +@@ -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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#ifndef __IMG_LINUX_MM_H__ ++#define __IMG_LINUX_MM_H__ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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); ++ ++#if defined(LINUX_MEM_AREAS_DEBUG) ++void LinuxMemAreaRegister(struct LinuxMemArea *psLinuxMemArea); ++#else ++#define LinuxMemAreaRegister(X) ++#endif ++ ++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(DEBUG) || 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 0000000..7b3b784 +--- /dev/null ++++ b/drivers/gpu/pvr/mmap.c +@@ -0,0 +1,922 @@ ++/********************************************************************** ++ * ++ * 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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 "mutex.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 FIRST_PHYSICAL_PFN 0 ++#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 >= FIRST_PHYSICAL_PFN && 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(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(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 0000000..3ab55ff +--- /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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#if !defined(__MMAP_H__) ++#define __MMAP_H__ ++ ++#include ++#include ++ ++#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 0000000..3219cb1 +--- /dev/null ++++ b/drivers/gpu/pvr/mmu.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. ++ * 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) { ++ OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ++ sizeof(struct MMU_PT_INFO), ++ (void **) &ppsPTInfoList[i], NULL); ++ if (ppsPTInfoList[i] == NULL) { ++ 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; ++ } ++ ++ OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ++ sizeof(struct MMU_CONTEXT), (void **) &psMMUContext, NULL); ++ if (psMMUContext == NULL) { ++ 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; ++ } ++ ++ OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ++ sizeof(struct MMU_HEAP), (void **)&pMMUHeap, NULL); ++ if (pMMUHeap == NULL) { ++ 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; ++ } ++ ++ if (pui8MemBlock) { ++ sMemBlockCpuPAddr = OSMapLinToCPUPhys(pui8MemBlock); ++ } else { ++ ++ sMemBlockCpuPAddr = ++ OSMemHandleToCpuPAddr(hOSMemHandle, 0); ++ } ++ } 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); ++ } ++} ++ +diff --git a/drivers/gpu/pvr/mmu.h b/drivers/gpu/pvr/mmu.h +new file mode 100644 +index 0000000..85d939e +--- /dev/null ++++ b/drivers/gpu/pvr/mmu.h +@@ -0,0 +1,85 @@ ++/********************************************************************** ++ * ++ * 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. ++ * 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); ++ ++#endif +diff --git a/drivers/gpu/pvr/module.c b/drivers/gpu/pvr/module.c +new file mode 100644 +index 0000000..a38dcf3 +--- /dev/null ++++ b/drivers/gpu/pvr/module.c +@@ -0,0 +1,304 @@ ++/********************************************************************** ++ * ++ * 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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 "mutex.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 "lock.h" ++ ++#define DRVNAME "pvrsrvkm" ++ ++#ifdef DEBUG ++static int debug = DBGPRIV_WARNING; ++#include ++module_param(debug, int, 0); ++#endif ++ ++struct mutex gPVRSRVLock; ++ ++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; ++ ++ mutex_lock(&gPVRSRVLock); ++ ++ 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; ++ ++ ret = 0; ++err_unlock: ++ mutex_unlock(&gPVRSRVLock); ++ return ret; ++} ++ ++static int pvr_release(struct inode unref__ * inode, struct file *filp) ++{ ++ struct PVRSRV_FILE_PRIVATE_DATA *priv; ++ ++ mutex_lock(&gPVRSRVLock); ++ ++ priv = filp->private_data; ++ ++ PVRSRVProcessDisconnect(priv->ui32OpenPID); ++ ++ OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, ++ sizeof(*priv), ++ priv, priv->hBlockAlloc); ++ ++ mutex_unlock(&gPVRSRVLock); ++ return 0; ++} ++ ++static const struct file_operations pvr_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = PVRSRV_BridgeDispatchKM, ++ .open = pvr_open, ++ .release = pvr_release, ++ .mmap = PVRMMap, ++}; ++ ++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 void pvr_dev_release(struct device *pdev) ++{ ++ PVR_DPF(PVR_DBG_WARNING, "pvr_dev_release(pdev=%p)", pdev); ++} ++ ++static struct platform_device pvr_device = { ++ .name = DRVNAME, ++ .id = -1, ++ .dev = { ++ .release = pvr_dev_release ++ } ++}; ++ ++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() != 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"); ++ ++ mutex_init(&gPVRSRVLock); ++ ++#ifdef DEBUG ++ 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; ++ ++ error = platform_device_register(&pvr_device); ++ if (error) ++ goto err5; ++ ++ return 0; ++ ++err5: ++ platform_driver_unregister(&pvr_driver); ++err4: ++ PVRMMapCleanup(); ++ LinuxBridgeDeInit(); ++err3: ++ LinuxMMCleanup(); ++err2: ++ RemoveProcEntries(); ++err1: ++ pr_err("%s: failed (%d)\n", __func__, error); ++ ++ return error; ++} ++ ++static void __exit pvr_cleanup(void) ++{ ++ struct SYS_DATA *sysdata; ++ ++ PVR_TRACE("pvr_cleanup"); ++ ++ SysAcquireData(&sysdata); ++ ++ platform_device_unregister(&pvr_device); ++ 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/mutex.h b/drivers/gpu/pvr/mutex.h +new file mode 100644 +index 0000000..cbd963a +--- /dev/null ++++ b/drivers/gpu/pvr/mutex.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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#ifndef __INCLUDED_LINUX_MUTEX_H_ ++#define __INCLUDED_LINUX_MUTEX_H_ ++ ++#include ++ ++#include ++ ++extern struct mutex gPVRSRVLock; ++ ++#endif +diff --git a/drivers/gpu/pvr/mutils.h b/drivers/gpu/pvr/mutils.h +new file mode 100644 +index 0000000..47279ec +--- /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. ++ * 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 0000000..12c3b36 +--- /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 0000000..a957a21 +--- /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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#if !defined(__OEMFUNCS_H__) ++#define __OEMFUNCS_H__ ++ ++#include ++ ++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 0000000..fe4b2bb +--- /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. ++ * 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 DEBUG ++#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 0000000..a3bcc96 +--- /dev/null ++++ b/drivers/gpu/pvr/omaplfb_displayclass.c +@@ -0,0 +1,852 @@ ++/********************************************************************** ++ * ++ * 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. ++ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include