From dba153e51695d71eec91123468c9ca9ddc97b9dc Mon Sep 17 00:00:00 2001 From: Koen Kooi Date: Mon, 8 Dec 2008 16:39:00 +0100 Subject: linux-omap 2.6.27: add pvr patch from http://repository.maemo.org/pool/maemo5.0/free/k/kernel/kernel_2.6.27-20084805r03.diff.gz * this also needs a patch to dispc.{c,h}, which needs a bit more work * once the dispc patch is in drivers/gpu/Makefile can add drm-tungsten and pvr to obj-y --- .../linux/linux-omap-2.6.27/beagleboard/defconfig | 70 +- packages/linux/linux-omap-2.6.27/pvr/pvr-add.patch | 155094 ++++++++++++++++++ packages/linux/linux-omap_2.6.27.bb | 13 +- 3 files changed, 155133 insertions(+), 44 deletions(-) create mode 100644 packages/linux/linux-omap-2.6.27/pvr/pvr-add.patch (limited to 'packages/linux') diff --git a/packages/linux/linux-omap-2.6.27/beagleboard/defconfig b/packages/linux/linux-omap-2.6.27/beagleboard/defconfig index ed2acaafff..31b322007a 100644 --- a/packages/linux/linux-omap-2.6.27/beagleboard/defconfig +++ b/packages/linux/linux-omap-2.6.27/beagleboard/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.27-omap1 -# Sun Dec 7 16:18:46 2008 +# Mon Dec 8 16:15:28 2008 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -50,13 +50,13 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_CGROUPS=y # CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_NS is not set CONFIG_CGROUP_DEVICE=y -CONFIG_GROUP_SCHED=n +CONFIG_GROUP_SCHED=y CONFIG_FAIR_GROUP_SCHED=y # CONFIG_RT_GROUP_SCHED is not set -# CONFIG_USER_SCHED is not set +CONFIG_USER_SCHED=y # CONFIG_CGROUP_SCHED is not set -CONFIG_VZ_FAIRSCHED=y # CONFIG_CGROUP_CPUACCT is not set # CONFIG_RESOURCE_COUNTERS is not set CONFIG_SYSFS_DEPRECATED=y @@ -91,8 +91,9 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y -CONFIG_SLAB=y -# CONFIG_SLUB is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y # CONFIG_SLOB is not set CONFIG_PROFILING=y # CONFIG_MARKERS is not set @@ -109,7 +110,6 @@ CONFIG_HAVE_KRETPROBES=y CONFIG_HAVE_CLK=y CONFIG_PROC_PAGE_MONITOR=y CONFIG_HAVE_GENERIC_DMA_COHERENT=y -CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -363,7 +363,6 @@ CONFIG_NET=y # # Networking options # -CONFIG_NET_NS=y CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y @@ -1261,6 +1260,30 @@ CONFIG_DVB_ISL6421=m # # Graphics support # +CONFIG_PVR=m +CONFIG_PVR_TRANSFER_QUEUE=y +CONFIG_PVR_SUPPORT_SRVINIT=y +CONFIG_PVR_SUPPORT_SECURE_HANDLES=y +CONFIG_PVR_SERVICES4=y +CONFIG_PVR_SGXCORE_530=y +CONFIG_PVR_SGX_CORE_REV_103=y +CONFIG_PVR_PVR2D_ALT_2DHW=y +CONFIG_PVR_SYSTEM_OMAP3430=y +# CONFIG_PVR_SYSTEM_NO_HARDWARE is not set +# CONFIG_PVR_BUFFERCLASS_EXAMPLE is not set +CONFIG_PVR_USE_PTHREADS=y +CONFIG_PVR_SUPPORT_SGX_EVENT_OBJECT=y +CONFIG_PVR_SYS_USING_INTERRUPTS=y +CONFIG_PVR_SUPPORT_HW_RECOVERY=y +CONFIG_PVR_SUPPORT_ACTIVE_POWER_MANAGEMENT=y +CONFIG_PVR_BUILD_RELEASE=y +# CONFIG_PVR_BUILD_DEBUG is not set +# CONFIG_PVR_BUILD_TIMING is not set +CONFIG_PVR_SUPPORT_SGX1=y +# CONFIG_DRM_VER_ORIG is not set +CONFIG_DRM_VER_TUNGSTEN=y +CONFIG_DRM_TUNGSTEN=y +CONFIG_DRM_TUNGSTEN_PVR2D=m # CONFIG_VGASTATE is not set # CONFIG_VIDEO_OUTPUT_CONTROL is not set CONFIG_FB=y @@ -1698,13 +1721,8 @@ CONFIG_INOTIFY_USER=y CONFIG_QUOTA=y # CONFIG_QUOTA_NETLINK_INTERFACE is not set CONFIG_PRINT_QUOTA_WARNING=y -CONFIG_QUOTA_COMPAT=y # CONFIG_QFMT_V1 is not set CONFIG_QFMT_V2=y -CONFIG_SIM_FS=m -CONFIG_VZ_QUOTA=m -# CONFIG_VZ_QUOTA_UNLOAD is not set -CONFIG_VZ_QUOTA_UGID=y CONFIG_QUOTACTL=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set @@ -1870,7 +1888,6 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set -CONFIG_SYSRQ_DEBUG=y CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SHIRQ is not set CONFIG_DETECT_SOFTLOCKUP=y @@ -1880,7 +1897,6 @@ CONFIG_SCHED_DEBUG=y CONFIG_SCHEDSTATS=y CONFIG_TIMER_STATS=y # CONFIG_DEBUG_OBJECTS is not set -# CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set @@ -1922,6 +1938,7 @@ CONFIG_HAVE_ARCH_KGDB=y # Security options # # CONFIG_KEYS is not set +# CONFIG_SECURITY is not set # CONFIG_SECURITY_FILE_CAPABILITIES is not set CONFIG_XOR_BLOCKS=m CONFIG_ASYNC_CORE=m @@ -2032,26 +2049,3 @@ CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y - -# -# OpenVZ -# -CONFIG_VE=y -CONFIG_VE_CALLS=m -CONFIG_VZ_GENCALLS=y -CONFIG_VE_NETDEV=m -CONFIG_VE_ETHDEV=m -CONFIG_VZ_DEV=m -CONFIG_VZ_WDOG=m -CONFIG_VZ_CHECKPOINT=n - -# -# User resources -# -CONFIG_BEANCOUNTERS=y -CONFIG_BC_RSS_ACCOUNTING=y -CONFIG_BC_IO_ACCOUNTING=y -CONFIG_BC_IO_SCHED=y -CONFIG_BC_SWAP_ACCOUNTING=y -CONFIG_BC_PROC=y -# CONFIG_BC_DEBUG is not set diff --git a/packages/linux/linux-omap-2.6.27/pvr/pvr-add.patch b/packages/linux/linux-omap-2.6.27/pvr/pvr-add.patch new file mode 100644 index 0000000000..9ff89fee3d --- /dev/null +++ b/packages/linux/linux-omap-2.6.27/pvr/pvr-add.patch @@ -0,0 +1,155094 @@ +diff -Nurd git/drivers/gpu/drm-tungsten/ati_pcigart.c git-nokia/drivers/gpu/drm-tungsten/ati_pcigart.c +--- kernel-2.6.27.orig/drivers/video/Kconfig ++++ kernel-2.6.27/drivers/video/Kconfig +@@ -7,7 +7,7 @@ + + source "drivers/char/agp/Kconfig" + +-source "drivers/gpu/drm/Kconfig" ++source "drivers/gpu/Kconfig" + + config VGASTATE + tristate +--- git/drivers/gpu/drm-tungsten/ati_pcigart.c 1970-01-01 01:00:00.000000000 +0100 ++++ git-nokia/drivers/gpu/drm-tungsten/ati_pcigart.c 2008-12-08 14:52:52.000000000 +0100 +@@ -0,0 +1,199 @@ ++/** ++ * \file ati_pcigart.c ++ * ATI PCI GART support ++ * ++ * \author Gareth Hughes ++ */ ++ ++/* ++ * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com ++ * ++ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include "drmP.h" ++ ++# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ ++# define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1)) ++ ++#define ATI_PCIE_WRITE 0x4 ++#define ATI_PCIE_READ 0x8 ++ ++static __inline__ void gart_insert_page_into_table(struct drm_ati_pcigart_info *gart_info, dma_addr_t addr, u32 *pci_gart) ++{ ++ u32 page_base; ++ ++ page_base = (u32)addr & ATI_PCIGART_PAGE_MASK; ++ switch(gart_info->gart_reg_if) { ++ case DRM_ATI_GART_IGP: ++ page_base |= (upper_32_bits(addr) & 0xff) << 4; ++ page_base |= 0xc; ++ break; ++ case DRM_ATI_GART_PCIE: ++ page_base >>= 8; ++ page_base |= (upper_32_bits(addr) & 0xff) << 24; ++ page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE; ++ break; ++ default: ++ case DRM_ATI_GART_PCI: ++ break; ++ } ++ *pci_gart = cpu_to_le32(page_base); ++} ++ ++static int drm_ati_alloc_pcigart_table(struct drm_device *dev, ++ struct drm_ati_pcigart_info *gart_info) ++{ ++ gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size, ++ PAGE_SIZE, ++ gart_info->table_mask); ++ if (gart_info->table_handle == NULL) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void drm_ati_free_pcigart_table(struct drm_device *dev, ++ struct drm_ati_pcigart_info *gart_info) ++{ ++ drm_pci_free(dev, gart_info->table_handle); ++ gart_info->table_handle = NULL; ++} ++ ++int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) ++{ ++ struct drm_sg_mem *entry = dev->sg; ++ unsigned long pages; ++ int i; ++ int max_pages; ++ ++ /* we need to support large memory configurations */ ++ if (!entry) { ++ DRM_ERROR("no scatter/gather memory!\n"); ++ return 0; ++ } ++ ++ if (gart_info->bus_addr) { ++ ++ max_pages = (gart_info->table_size / sizeof(u32)); ++ pages = (entry->pages <= max_pages) ++ ? entry->pages : max_pages; ++ ++ for (i = 0; i < pages; i++) { ++ if (!entry->busaddr[i]) ++ break; ++ pci_unmap_page(dev->pdev, entry->busaddr[i], ++ PAGE_SIZE, PCI_DMA_TODEVICE); ++ } ++ ++ if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) ++ gart_info->bus_addr = 0; ++ } ++ ++ ++ if (gart_info->gart_table_location == DRM_ATI_GART_MAIN ++ && gart_info->table_handle) { ++ ++ drm_ati_free_pcigart_table(dev, gart_info); ++ } ++ ++ return 1; ++} ++EXPORT_SYMBOL(drm_ati_pcigart_cleanup); ++ ++int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) ++{ ++ struct drm_sg_mem *entry = dev->sg; ++ void *address = NULL; ++ unsigned long pages; ++ u32 *pci_gart; ++ dma_addr_t bus_address = 0; ++ int i, j, ret = 0; ++ int max_pages; ++ dma_addr_t entry_addr; ++ ++ if (!entry) { ++ DRM_ERROR("no scatter/gather memory!\n"); ++ goto done; ++ } ++ ++ if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { ++ DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); ++ ++ ret = drm_ati_alloc_pcigart_table(dev, gart_info); ++ if (ret) { ++ DRM_ERROR("cannot allocate PCI GART page!\n"); ++ goto done; ++ } ++ ++ address = gart_info->table_handle->vaddr; ++ bus_address = gart_info->table_handle->busaddr; ++ } else { ++ address = gart_info->addr; ++ bus_address = gart_info->bus_addr; ++ DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n", ++ bus_address, (unsigned long)address); ++ } ++ ++ pci_gart = (u32 *) address; ++ ++ max_pages = (gart_info->table_size / sizeof(u32)); ++ pages = (entry->pages <= max_pages) ++ ? entry->pages : max_pages; ++ ++ memset(pci_gart, 0, max_pages * sizeof(u32)); ++ ++ for (i = 0; i < pages; i++) { ++ /* we need to support large memory configurations */ ++ entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i], ++ 0, PAGE_SIZE, PCI_DMA_TODEVICE); ++ if (entry->busaddr[i] == 0) { ++ DRM_ERROR("unable to map PCIGART pages!\n"); ++ drm_ati_pcigart_cleanup(dev, gart_info); ++ address = NULL; ++ bus_address = 0; ++ goto done; ++ } ++ ++ entry_addr = entry->busaddr[i]; ++ for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { ++ gart_insert_page_into_table(gart_info, entry_addr, pci_gart); ++ pci_gart++; ++ entry_addr += ATI_PCIGART_PAGE_SIZE; ++ } ++ } ++ ++ ret = 1; ++ ++#if defined(__i386__) || defined(__x86_64__) ++ wbinvd(); ++#else ++ mb(); ++#endif ++ ++ done: ++ gart_info->addr = address; ++ gart_info->bus_addr = bus_address; ++ return ret; ++} ++EXPORT_SYMBOL(drm_ati_pcigart_init); +diff -Nurd git/drivers/gpu/drm-tungsten/drm_agpsupport.c git-nokia/drivers/gpu/drm-tungsten/drm_agpsupport.c +--- git/drivers/gpu/drm-tungsten/drm_agpsupport.c 1970-01-01 01:00:00.000000000 +0100 ++++ git-nokia/drivers/gpu/drm-tungsten/drm_agpsupport.c 2008-12-08 14:52:52.000000000 +0100 +@@ -0,0 +1,715 @@ ++/** ++ * \file drm_agpsupport.c ++ * DRM support for AGP/GART backend ++ * ++ * \author Rickard E. (Rik) Faith ++ * \author Gareth Hughes ++ */ ++ ++/* ++ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. ++ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include "drmP.h" ++#include ++ ++#if __OS_HAS_AGP ++ ++/** ++ * Get AGP information. ++ * ++ * \param inode device inode. ++ * \param file_priv DRM file private. ++ * \param cmd command. ++ * \param arg pointer to a (output) drm_agp_info structure. ++ * \return zero on success or a negative number on failure. ++ * ++ * Verifies the AGP device has been initialized and acquired and fills in the ++ * drm_agp_info structure with the information in drm_agp_head::agp_info. ++ */ ++int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info) ++{ ++ DRM_AGP_KERN *kern; ++ ++ if (!dev->agp || !dev->agp->acquired) ++ return -EINVAL; ++ ++ kern = &dev->agp->agp_info; ++ info->agp_version_major = kern->version.major; ++ info->agp_version_minor = kern->version.minor; ++ info->mode = kern->mode; ++ info->aperture_base = kern->aper_base; ++ info->aperture_size = kern->aper_size * 1024 * 1024; ++ info->memory_allowed = kern->max_memory << PAGE_SHIFT; ++ info->memory_used = kern->current_memory << PAGE_SHIFT; ++ info->id_vendor = kern->device->vendor; ++ info->id_device = kern->device->device; ++ ++ return 0; ++} ++EXPORT_SYMBOL(drm_agp_info); ++ ++int drm_agp_info_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_agp_info *info = data; ++ int err; ++ ++ err = drm_agp_info(dev, info); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++/** ++ * Acquire the AGP device. ++ * ++ * \param dev DRM device that is to acquire AGP. ++ * \return zero on success or a negative number on failure. ++ * ++ * Verifies the AGP device hasn't been acquired before and calls ++ * \c agp_backend_acquire. ++ */ ++int drm_agp_acquire(struct drm_device * dev) ++{ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) ++ int retcode; ++#endif ++ ++ if (!dev->agp) ++ return -ENODEV; ++ if (dev->agp->acquired) ++ return -EBUSY; ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) ++ if ((retcode = agp_backend_acquire())) ++ return retcode; ++#else ++ if (!(dev->agp->bridge = agp_backend_acquire(dev->pdev))) ++ return -ENODEV; ++#endif ++ ++ dev->agp->acquired = 1; ++ return 0; ++} ++EXPORT_SYMBOL(drm_agp_acquire); ++ ++/** ++ * Acquire the AGP device (ioctl). ++ * ++ * \param inode device inode. ++ * \param file_priv DRM file private. ++ * \param cmd command. ++ * \param arg user argument. ++ * \return zero on success or a negative number on failure. ++ * ++ * Verifies the AGP device hasn't been acquired before and calls ++ * \c agp_backend_acquire. ++ */ ++int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ return drm_agp_acquire((struct drm_device *) file_priv->minor->dev); ++} ++ ++/** ++ * Release the AGP device. ++ * ++ * \param dev DRM device that is to release AGP. ++ * \return zero on success or a negative number on failure. ++ * ++ * Verifies the AGP device has been acquired and calls \c agp_backend_release. ++ */ ++int drm_agp_release(struct drm_device *dev) ++{ ++ if (!dev->agp || !dev->agp->acquired) ++ return -EINVAL; ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) ++ agp_backend_release(); ++#else ++ agp_backend_release(dev->agp->bridge); ++#endif ++ dev->agp->acquired = 0; ++ return 0; ++ ++} ++EXPORT_SYMBOL(drm_agp_release); ++ ++int drm_agp_release_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ return drm_agp_release(dev); ++} ++ ++/** ++ * Enable the AGP bus. ++ * ++ * \param dev DRM device that has previously acquired AGP. ++ * \param mode Requested AGP mode. ++ * \return zero on success or a negative number on failure. ++ * ++ * Verifies the AGP device has been acquired but not enabled, and calls ++ * \c agp_enable. ++ */ ++int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode) ++{ ++ if (!dev->agp || !dev->agp->acquired) ++ return -EINVAL; ++ ++ dev->agp->mode = mode.mode; ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) ++ agp_enable(mode.mode); ++#else ++ agp_enable(dev->agp->bridge, mode.mode); ++#endif ++ dev->agp->enabled = 1; ++ return 0; ++} ++EXPORT_SYMBOL(drm_agp_enable); ++ ++int drm_agp_enable_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_agp_mode *mode = data; ++ ++ return drm_agp_enable(dev, *mode); ++} ++ ++/** ++ * Allocate AGP memory. ++ * ++ * \param inode device inode. ++ * \param file_priv file private pointer. ++ * \param cmd command. ++ * \param arg pointer to a drm_agp_buffer structure. ++ * \return zero on success or a negative number on failure. ++ * ++ * Verifies the AGP device is present and has been acquired, allocates the ++ * memory via alloc_agp() and creates a drm_agp_mem entry for it. ++ */ ++int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) ++{ ++ struct drm_agp_mem *entry; ++ DRM_AGP_MEM *memory; ++ unsigned long pages; ++ u32 type; ++ ++ if (!dev->agp || !dev->agp->acquired) ++ return -EINVAL; ++ if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS))) ++ return -ENOMEM; ++ ++ memset(entry, 0, sizeof(*entry)); ++ ++ pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; ++ type = (u32) request->type; ++ if (!(memory = drm_alloc_agp(dev, pages, type))) { ++ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); ++ return -ENOMEM; ++ } ++ ++ entry->handle = (unsigned long)memory->key + 1; ++ entry->memory = memory; ++ entry->bound = 0; ++ entry->pages = pages; ++ list_add(&entry->head, &dev->agp->memory); ++ ++ request->handle = entry->handle; ++ request->physical = memory->physical; ++ ++ return 0; ++} ++EXPORT_SYMBOL(drm_agp_alloc); ++ ++ ++int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_agp_buffer *request = data; ++ ++ return drm_agp_alloc(dev, request); ++} ++ ++/** ++ * Search for the AGP memory entry associated with a handle. ++ * ++ * \param dev DRM device structure. ++ * \param handle AGP memory handle. ++ * \return pointer to the drm_agp_mem structure associated with \p handle. ++ * ++ * Walks through drm_agp_head::memory until finding a matching handle. ++ */ ++static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev, ++ unsigned long handle) ++{ ++ struct drm_agp_mem *entry; ++ ++ list_for_each_entry(entry, &dev->agp->memory, head) { ++ if (entry->handle == handle) ++ return entry; ++ } ++ return NULL; ++} ++ ++/** ++ * Unbind AGP memory from the GATT (ioctl). ++ * ++ * \param inode device inode. ++ * \param file_priv DRM file private. ++ * \param cmd command. ++ * \param arg pointer to a drm_agp_binding structure. ++ * \return zero on success or a negative number on failure. ++ * ++ * Verifies the AGP device is present and acquired, looks-up the AGP memory ++ * entry and passes it to the unbind_agp() function. ++ */ ++int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) ++{ ++ struct drm_agp_mem *entry; ++ int ret; ++ ++ if (!dev->agp || !dev->agp->acquired) ++ return -EINVAL; ++ if (!(entry = drm_agp_lookup_entry(dev, request->handle))) ++ return -EINVAL; ++ if (!entry->bound) ++ return -EINVAL; ++ ret = drm_unbind_agp(entry->memory); ++ if (ret == 0) ++ entry->bound = 0; ++ return ret; ++} ++EXPORT_SYMBOL(drm_agp_unbind); ++ ++ ++int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_agp_binding *request = data; ++ ++ return drm_agp_unbind(dev, request); ++} ++ ++ ++/** ++ * Bind AGP memory into the GATT (ioctl) ++ * ++ * \param inode device inode. ++ * \param file_priv DRM file private. ++ * \param cmd command. ++ * \param arg pointer to a drm_agp_binding structure. ++ * \return zero on success or a negative number on failure. ++ * ++ * Verifies the AGP device is present and has been acquired and that no memory ++ * is currently bound into the GATT. Looks-up the AGP memory entry and passes ++ * it to bind_agp() function. ++ */ ++int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) ++{ ++ struct drm_agp_mem *entry; ++ int retcode; ++ int page; ++ ++ if (!dev->agp || !dev->agp->acquired) ++ return -EINVAL; ++ if (!(entry = drm_agp_lookup_entry(dev, request->handle))) ++ return -EINVAL; ++ if (entry->bound) ++ return -EINVAL; ++ page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE; ++ if ((retcode = drm_bind_agp(entry->memory, page))) ++ return retcode; ++ entry->bound = dev->agp->base + (page << PAGE_SHIFT); ++ DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", ++ dev->agp->base, entry->bound); ++ return 0; ++} ++EXPORT_SYMBOL(drm_agp_bind); ++ ++ ++int drm_agp_bind_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_agp_binding *request = data; ++ ++ return drm_agp_bind(dev, request); ++} ++ ++ ++/** ++ * Free AGP memory (ioctl). ++ * ++ * \param inode device inode. ++ * \param file_priv DRM file private. ++ * \param cmd command. ++ * \param arg pointer to a drm_agp_buffer structure. ++ * \return zero on success or a negative number on failure. ++ * ++ * Verifies the AGP device is present and has been acquired and looks up the ++ * AGP memory entry. If the memory it's currently bound, unbind it via ++ * unbind_agp(). Frees it via free_agp() as well as the entry itself ++ * and unlinks from the doubly linked list it's inserted in. ++ */ ++int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) ++{ ++ struct drm_agp_mem *entry; ++ ++ if (!dev->agp || !dev->agp->acquired) ++ return -EINVAL; ++ if (!(entry = drm_agp_lookup_entry(dev, request->handle))) ++ return -EINVAL; ++ if (entry->bound) ++ drm_unbind_agp(entry->memory); ++ ++ list_del(&entry->head); ++ ++ drm_free_agp(entry->memory, entry->pages); ++ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); ++ return 0; ++} ++EXPORT_SYMBOL(drm_agp_free); ++ ++ ++ ++int drm_agp_free_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_agp_buffer *request = data; ++ ++ return drm_agp_free(dev, request); ++} ++ ++ ++/** ++ * Initialize the AGP resources. ++ * ++ * \return pointer to a drm_agp_head structure. ++ * ++ * Gets the drm_agp_t structure which is made available by the agpgart module ++ * via the inter_module_* functions. Creates and initializes a drm_agp_head ++ * structure. ++ */ ++struct drm_agp_head *drm_agp_init(struct drm_device *dev) ++{ ++ struct drm_agp_head *head = NULL; ++ ++ if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS))) ++ return NULL; ++ memset((void *)head, 0, sizeof(*head)); ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) ++ agp_copy_info(&head->agp_info); ++#else ++ head->bridge = agp_find_bridge(dev->pdev); ++ if (!head->bridge) { ++ if (!(head->bridge = agp_backend_acquire(dev->pdev))) { ++ drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); ++ return NULL; ++ } ++ agp_copy_info(head->bridge, &head->agp_info); ++ agp_backend_release(head->bridge); ++ } else { ++ agp_copy_info(head->bridge, &head->agp_info); ++ } ++#endif ++ if (head->agp_info.chipset == NOT_SUPPORTED) { ++ drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); ++ return NULL; ++ } ++ INIT_LIST_HEAD(&head->memory); ++ head->cant_use_aperture = head->agp_info.cant_use_aperture; ++ head->page_mask = head->agp_info.page_mask; ++ head->base = head->agp_info.aper_base; ++ return head; ++} ++ ++/** Calls agp_allocate_memory() */ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) ++DRM_AGP_MEM *drm_agp_allocate_memory(size_t pages, u32 type) ++{ ++ return agp_allocate_memory(pages, type); ++} ++#else ++DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, ++ size_t pages, u32 type) ++{ ++ return agp_allocate_memory(bridge, pages, type); ++} ++#endif ++ ++/** Calls agp_free_memory() */ ++int drm_agp_free_memory(DRM_AGP_MEM * handle) ++{ ++ if (!handle) ++ return 0; ++ agp_free_memory(handle); ++ return 1; ++} ++ ++/** Calls agp_bind_memory() */ ++int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start) ++{ ++ if (!handle) ++ return -EINVAL; ++ return agp_bind_memory(handle, start); ++} ++EXPORT_SYMBOL(drm_agp_bind_memory); ++ ++/** Calls agp_unbind_memory() */ ++int drm_agp_unbind_memory(DRM_AGP_MEM * handle) ++{ ++ if (!handle) ++ return -EINVAL; ++ return agp_unbind_memory(handle); ++} ++ ++/** ++ * Binds a collection of pages into AGP memory at the given offset, returning ++ * the AGP memory structure containing them. ++ * ++ * No reference is held on the pages during this time -- it is up to the ++ * caller to handle that. ++ */ ++DRM_AGP_MEM * ++drm_agp_bind_pages(struct drm_device *dev, ++ struct page **pages, ++ unsigned long num_pages, ++ uint32_t gtt_offset) ++{ ++ DRM_AGP_MEM *mem; ++ int ret, i; ++ ++ DRM_DEBUG("drm_agp_populate_ttm\n"); ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) ++ mem = drm_agp_allocate_memory(num_pages, AGP_USER_MEMORY); ++#else ++ mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages, ++ AGP_USER_MEMORY); ++#endif ++ if (mem == NULL) { ++ DRM_ERROR("Failed to allocate memory for %ld pages\n", ++ num_pages); ++ return NULL; ++ } ++ ++ for (i = 0; i < num_pages; i++) ++ mem->memory[i] = phys_to_gart(page_to_phys(pages[i])); ++ mem->page_count = num_pages; ++ ++ mem->is_flushed = true; ++ ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE); ++ if (ret != 0) { ++ DRM_ERROR("Failed to bind AGP memory: %d\n", ret); ++ agp_free_memory(mem); ++ return NULL; ++ } ++ ++ return mem; ++} ++EXPORT_SYMBOL(drm_agp_bind_pages); ++ ++/* ++ * AGP ttm backend interface. ++ */ ++ ++#ifndef AGP_USER_TYPES ++#define AGP_USER_TYPES (1 << 16) ++#define AGP_USER_MEMORY (AGP_USER_TYPES) ++#define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1) ++#endif ++#define AGP_REQUIRED_MAJOR 0 ++#define AGP_REQUIRED_MINOR 102 ++ ++static int drm_agp_needs_unbind_cache_adjust(struct drm_ttm_backend *backend) ++{ ++ return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); ++} ++ ++ ++static int drm_agp_populate(struct drm_ttm_backend *backend, ++ unsigned long num_pages, struct page **pages, ++ struct page *dummy_read_page) ++{ ++ struct drm_agp_ttm_backend *agp_be = ++ container_of(backend, struct drm_agp_ttm_backend, backend); ++ struct page **cur_page, **last_page = pages + num_pages; ++ DRM_AGP_MEM *mem; ++ int dummy_page_count = 0; ++ ++ if (drm_alloc_memctl(num_pages * sizeof(void *))) ++ return -1; ++ ++ DRM_DEBUG("drm_agp_populate_ttm\n"); ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) ++ mem = drm_agp_allocate_memory(num_pages, AGP_USER_MEMORY); ++#else ++ mem = drm_agp_allocate_memory(agp_be->bridge, num_pages, AGP_USER_MEMORY); ++#endif ++ if (!mem) { ++ drm_free_memctl(num_pages * sizeof(void *)); ++ return -1; ++ } ++ ++ DRM_DEBUG("Current page count is %ld\n", (long) mem->page_count); ++ mem->page_count = 0; ++ for (cur_page = pages; cur_page < last_page; ++cur_page) { ++ struct page *page = *cur_page; ++ if (!page) { ++ page = dummy_read_page; ++ ++dummy_page_count; ++ } ++ mem->memory[mem->page_count++] = phys_to_gart(page_to_phys(page)); ++ } ++ if (dummy_page_count) ++ DRM_DEBUG("Mapped %d dummy pages\n", dummy_page_count); ++ agp_be->mem = mem; ++ return 0; ++} ++ ++static int drm_agp_bind_ttm(struct drm_ttm_backend *backend, ++ struct drm_bo_mem_reg *bo_mem) ++{ ++ struct drm_agp_ttm_backend *agp_be = ++ container_of(backend, struct drm_agp_ttm_backend, backend); ++ DRM_AGP_MEM *mem = agp_be->mem; ++ int ret; ++ int snooped = (bo_mem->flags & DRM_BO_FLAG_CACHED) && !(bo_mem->flags & DRM_BO_FLAG_CACHED_MAPPED); ++ ++ DRM_DEBUG("drm_agp_bind_ttm\n"); ++ mem->is_flushed = true; ++ mem->type = AGP_USER_MEMORY; ++ /* CACHED MAPPED implies not snooped memory */ ++ if (snooped) ++ mem->type = AGP_USER_CACHED_MEMORY; ++ ++ ret = drm_agp_bind_memory(mem, bo_mem->mm_node->start); ++ if (ret) ++ DRM_ERROR("AGP Bind memory failed\n"); ++ ++ DRM_FLAG_MASKED(backend->flags, (bo_mem->flags & DRM_BO_FLAG_CACHED) ? ++ DRM_BE_FLAG_BOUND_CACHED : 0, ++ DRM_BE_FLAG_BOUND_CACHED); ++ return ret; ++} ++ ++static int drm_agp_unbind_ttm(struct drm_ttm_backend *backend) ++{ ++ struct drm_agp_ttm_backend *agp_be = ++ container_of(backend, struct drm_agp_ttm_backend, backend); ++ ++ DRM_DEBUG("drm_agp_unbind_ttm\n"); ++ if (agp_be->mem->is_bound) ++ return drm_agp_unbind_memory(agp_be->mem); ++ else ++ return 0; ++} ++ ++static void drm_agp_clear_ttm(struct drm_ttm_backend *backend) ++{ ++ struct drm_agp_ttm_backend *agp_be = ++ container_of(backend, struct drm_agp_ttm_backend, backend); ++ DRM_AGP_MEM *mem = agp_be->mem; ++ ++ DRM_DEBUG("drm_agp_clear_ttm\n"); ++ if (mem) { ++ unsigned long num_pages = mem->page_count; ++ backend->func->unbind(backend); ++ agp_free_memory(mem); ++ drm_free_memctl(num_pages * sizeof(void *)); ++ } ++ agp_be->mem = NULL; ++} ++ ++static void drm_agp_destroy_ttm(struct drm_ttm_backend *backend) ++{ ++ struct drm_agp_ttm_backend *agp_be; ++ ++ if (backend) { ++ DRM_DEBUG("drm_agp_destroy_ttm\n"); ++ agp_be = container_of(backend, struct drm_agp_ttm_backend, backend); ++ if (agp_be) { ++ if (agp_be->mem) ++ backend->func->clear(backend); ++ drm_ctl_free(agp_be, sizeof(*agp_be), DRM_MEM_TTM); ++ } ++ } ++} ++ ++static struct drm_ttm_backend_func agp_ttm_backend = { ++ .needs_ub_cache_adjust = drm_agp_needs_unbind_cache_adjust, ++ .populate = drm_agp_populate, ++ .clear = drm_agp_clear_ttm, ++ .bind = drm_agp_bind_ttm, ++ .unbind = drm_agp_unbind_ttm, ++ .destroy = drm_agp_destroy_ttm, ++}; ++ ++struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev) ++{ ++ ++ struct drm_agp_ttm_backend *agp_be; ++ struct agp_kern_info *info; ++ ++ if (!dev->agp) { ++ DRM_ERROR("AGP is not initialized.\n"); ++ return NULL; ++ } ++ info = &dev->agp->agp_info; ++ ++ if (info->version.major != AGP_REQUIRED_MAJOR || ++ info->version.minor < AGP_REQUIRED_MINOR) { ++ DRM_ERROR("Wrong agpgart version %d.%d\n" ++ "\tYou need at least version %d.%d.\n", ++ info->version.major, ++ info->version.minor, ++ AGP_REQUIRED_MAJOR, ++ AGP_REQUIRED_MINOR); ++ return NULL; ++ } ++ ++ ++ agp_be = drm_ctl_calloc(1, sizeof(*agp_be), DRM_MEM_TTM); ++ if (!agp_be) ++ return NULL; ++ ++ agp_be->mem = NULL; ++ ++ agp_be->bridge = dev->agp->bridge; ++ agp_be->populated = false; ++ agp_be->backend.func = &agp_ttm_backend; ++ agp_be->backend.dev = dev; ++ ++ return &agp_be->backend; ++} ++EXPORT_SYMBOL(drm_agp_init_ttm); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) ++void drm_agp_chipset_flush(struct drm_device *dev) ++{ ++ agp_flush_chipset(dev->agp->bridge); ++} ++EXPORT_SYMBOL(drm_agp_chipset_flush); ++#endif ++ ++#endif /* __OS_HAS_AGP */ +diff -Nurd git/drivers/gpu/drm-tungsten/drm_auth.c git-nokia/drivers/gpu/drm-tungsten/drm_auth.c +--- git/drivers/gpu/drm-tungsten/drm_auth.c 1970-01-01 01:00:00.000000000 +0100 ++++ git-nokia/drivers/gpu/drm-tungsten/drm_auth.c 2008-12-08 14:52:52.000000000 +0100 +@@ -0,0 +1,189 @@ ++/** ++ * \file drm_auth.c ++ * IOCTLs for authentication ++ * ++ * \author Rickard E. (Rik) Faith ++ * \author Gareth Hughes ++ */ ++ ++/* ++ * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com ++ * ++ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. ++ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include "drmP.h" ++ ++/** ++ * Find the file with the given magic number. ++ * ++ * \param dev DRM device. ++ * \param magic magic number. ++ * ++ * Searches in drm_device::magiclist within all files with the same hash key ++ * the one with matching magic number, while holding the drm_device::struct_mutex ++ * lock. ++ */ ++static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic) ++{ ++ struct drm_file *retval = NULL; ++ struct drm_magic_entry *pt; ++ struct drm_hash_item *hash; ++ ++ mutex_lock(&dev->struct_mutex); ++ if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { ++ pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); ++ retval = pt->priv; ++ } ++ mutex_unlock(&dev->struct_mutex); ++ return retval; ++} ++ ++/** ++ * Adds a magic number. ++ * ++ * \param dev DRM device. ++ * \param priv file private data. ++ * \param magic magic number. ++ * ++ * Creates a drm_magic_entry structure and appends to the linked list ++ * associated the magic number hash key in drm_device::magiclist, while holding ++ * the drm_device::struct_mutex lock. ++ */ ++static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, ++ drm_magic_t magic) ++{ ++ struct drm_magic_entry *entry; ++ ++ DRM_DEBUG("%d\n", magic); ++ ++ entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); ++ if (!entry) ++ return -ENOMEM; ++ memset(entry, 0, sizeof(*entry)); ++ entry->priv = priv; ++ entry->hash_item.key = (unsigned long)magic; ++ mutex_lock(&dev->struct_mutex); ++ drm_ht_insert_item(&dev->magiclist, &entry->hash_item); ++ list_add_tail(&entry->head, &dev->magicfree); ++ mutex_unlock(&dev->struct_mutex); ++ ++ return 0; ++} ++ ++/** ++ * Remove a magic number. ++ * ++ * \param dev DRM device. ++ * \param magic magic number. ++ * ++ * Searches and unlinks the entry in drm_device::magiclist with the magic ++ * number hash key, while holding the drm_device::struct_mutex lock. ++ */ ++static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic) ++{ ++ struct drm_magic_entry *pt; ++ struct drm_hash_item *hash; ++ ++ DRM_DEBUG("%d\n", magic); ++ ++ mutex_lock(&dev->struct_mutex); ++ if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { ++ mutex_unlock(&dev->struct_mutex); ++ return -EINVAL; ++ } ++ pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); ++ drm_ht_remove_item(&dev->magiclist, hash); ++ list_del(&pt->head); ++ mutex_unlock(&dev->struct_mutex); ++ ++ drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); ++ ++ return 0; ++} ++ ++/** ++ * Get a unique magic number (ioctl). ++ * ++ * \param inode device inode. ++ * \param file_priv DRM file private. ++ * \param cmd command. ++ * \param arg pointer to a resulting drm_auth structure. ++ * \return zero on success, or a negative number on failure. ++ * ++ * If there is a magic number in drm_file::magic then use it, otherwise ++ * searches an unique non-zero magic number and add it associating it with \p ++ * file_priv. ++ */ ++int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) ++{ ++ static drm_magic_t sequence = 0; ++ static DEFINE_SPINLOCK(lock); ++ struct drm_auth *auth = data; ++ ++ /* Find unique magic */ ++ if (file_priv->magic) { ++ auth->magic = file_priv->magic; ++ } else { ++ do { ++ spin_lock(&lock); ++ if (!sequence) ++ ++sequence; /* reserve 0 */ ++ auth->magic = sequence++; ++ spin_unlock(&lock); ++ } while (drm_find_file(dev, auth->magic)); ++ file_priv->magic = auth->magic; ++ drm_add_magic(dev, file_priv, auth->magic); ++ } ++ ++ DRM_DEBUG("%u\n", auth->magic); ++ ++ return 0; ++} ++ ++/** ++ * Authenticate with a magic. ++ * ++ * \param inode device inode. ++ * \param file_priv DRM file private. ++ * \param cmd command. ++ * \param arg pointer to a drm_auth structure. ++ * \return zero if authentication successed, or a negative number otherwise. ++ * ++ * Checks if \p file_priv is associated with the magic number passed in \arg. ++ */ ++int drm_authmagic(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_auth *auth = data; ++ struct drm_file *file; ++ ++ DRM_DEBUG("%u\n", auth->magic); ++ if ((file = drm_find_file(dev, auth->magic))) { ++ file->authenticated = 1; ++ drm_remove_magic(dev, auth->magic); ++ return 0; ++ } ++ return -EINVAL; ++} +diff -Nurd git/drivers/gpu/drm-tungsten/drm_bo.c git-nokia/drivers/gpu/drm-tungsten/drm_bo.c +--- git/drivers/gpu/drm-tungsten/drm_bo.c 1970-01-01 01:00:00.000000000 +0100 ++++ git-nokia/drivers/gpu/drm-tungsten/drm_bo.c 2008-12-08 14:52:52.000000000 +0100 +@@ -0,0 +1,2796 @@ ++/************************************************************************** ++ * ++ * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sub license, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ++ * USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ **************************************************************************/ ++/* ++ * Authors: Thomas Hellström ++ */ ++ ++#include "drmP.h" ++ ++/* ++ * Locking may look a bit complicated but isn't really: ++ * ++ * The buffer usage atomic_t needs to be protected by dev->struct_mutex ++ * when there is a chance that it can be zero before or after the operation. ++ * ++ * dev->struct_mutex also protects all lists and list heads, ++ * Hash tables and hash heads. ++ * ++ * bo->mutex protects the buffer object itself excluding the usage field. ++ * bo->mutex does also protect the buffer list heads, so to manipulate those, ++ * we need both the bo->mutex and the dev->struct_mutex. ++ * ++ * Locking order is bo->mutex, dev->struct_mutex. Therefore list traversal ++ * is a bit complicated. When dev->struct_mutex is released to grab bo->mutex, ++ * the list traversal will, in general, need to be restarted. ++ * ++ */ ++ ++static void drm_bo_destroy_locked(struct drm_buffer_object *bo); ++static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo); ++static void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo); ++static void drm_bo_unmap_virtual(struct drm_buffer_object *bo); ++ ++static inline uint64_t drm_bo_type_flags(unsigned type) ++{ ++ return (1ULL << (24 + type)); ++} ++ ++/* ++ * bo locked. dev->struct_mutex locked. ++ */ ++ ++void drm_bo_add_to_pinned_lru(struct drm_buffer_object *bo) ++{ ++ struct drm_mem_type_manager *man; ++ ++ DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); ++ DRM_ASSERT_LOCKED(&bo->mutex); ++ ++ man = &bo->dev->bm.man[bo->pinned_mem_type]; ++ list_add_tail(&bo->pinned_lru, &man->pinned); ++} ++ ++void drm_bo_add_to_lru(struct drm_buffer_object *bo) ++{ ++ struct drm_mem_type_manager *man; ++ ++ DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); ++ ++ if (!(bo->mem.proposed_flags & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT)) ++ || bo->mem.mem_type != bo->pinned_mem_type) { ++ man = &bo->dev->bm.man[bo->mem.mem_type]; ++ list_add_tail(&bo->lru, &man->lru); ++ } else { ++ INIT_LIST_HEAD(&bo->lru); ++ } ++} ++ ++static int drm_bo_vm_pre_move(struct drm_buffer_object *bo, int old_is_pci) ++{ ++#ifdef DRM_ODD_MM_COMPAT ++ int ret; ++ ++ if (!bo->map_list.map) ++ return 0; ++ ++ ret = drm_bo_lock_kmm(bo); ++ if (ret) ++ return ret; ++ drm_bo_unmap_virtual(bo); ++ if (old_is_pci) ++ drm_bo_finish_unmap(bo); ++#else ++ if (!bo->map_list.map) ++ return 0; ++ ++ drm_bo_unmap_virtual(bo); ++#endif ++ return 0; ++} ++ ++static void drm_bo_vm_post_move(struct drm_buffer_object *bo) ++{ ++#ifdef DRM_ODD_MM_COMPAT ++ int ret; ++ ++ if (!bo->map_list.map) ++ return; ++ ++ ret = drm_bo_remap_bound(bo); ++ if (ret) { ++ DRM_ERROR("Failed to remap a bound buffer object.\n" ++ "\tThis might cause a sigbus later.\n"); ++ } ++ drm_bo_unlock_kmm(bo); ++#endif ++} ++ ++/* ++ * Call bo->mutex locked. ++ */ ++ ++static int drm_bo_add_ttm(struct drm_buffer_object *bo) ++{ ++ struct drm_device *dev = bo->dev; ++ int ret = 0; ++ uint32_t page_flags = 0; ++ ++ DRM_ASSERT_LOCKED(&bo->mutex); ++ bo->ttm = NULL; ++ ++ if (bo->mem.proposed_flags & DRM_BO_FLAG_WRITE) ++ page_flags |= DRM_TTM_PAGE_WRITE; ++ ++ switch (bo->type) { ++ case drm_bo_type_device: ++ case drm_bo_type_kernel: ++ bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, ++ page_flags, dev->bm.dummy_read_page); ++ if (!bo->ttm) ++ ret = -ENOMEM; ++ break; ++ case drm_bo_type_user: ++ bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, ++ page_flags | DRM_TTM_PAGE_USER, ++ dev->bm.dummy_read_page); ++ if (!bo->ttm) ++ ret = -ENOMEM; ++ ++ ret = drm_ttm_set_user(bo->ttm, current, ++ bo->buffer_start, ++ bo->num_pages); ++ if (ret) ++ return ret; ++ ++ break; ++ default: ++ DRM_ERROR("Illegal buffer object type\n"); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int drm_bo_handle_move_mem(struct drm_buffer_object *bo, ++ struct drm_bo_mem_reg *mem, ++ int evict, int no_wait) ++{ ++ struct drm_device *dev = bo->dev; ++ struct drm_buffer_manager *bm = &dev->bm; ++ int old_is_pci = drm_mem_reg_is_pci(dev, &bo->mem); ++ int new_is_pci = drm_mem_reg_is_pci(dev, mem); ++ struct drm_mem_type_manager *old_man = &bm->man[bo->mem.mem_type]; ++ struct drm_mem_type_manager *new_man = &bm->man[mem->mem_type]; ++ int ret = 0; ++ ++ if (old_is_pci || new_is_pci || ++ ((mem->flags ^ bo->mem.flags) & DRM_BO_FLAG_CACHED)) ++ ret = drm_bo_vm_pre_move(bo, old_is_pci); ++ if (ret) ++ return ret; ++ ++ /* ++ * Create and bind a ttm if required. ++ */ ++ ++ if (!(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (bo->ttm == NULL)) { ++ ret = drm_bo_add_ttm(bo); ++ if (ret) ++ goto out_err; ++ ++ if (mem->mem_type != DRM_BO_MEM_LOCAL) { ++ ret = drm_ttm_bind(bo->ttm, mem); ++ if (ret) ++ goto out_err; ++ } ++ ++ if (bo->mem.mem_type == DRM_BO_MEM_LOCAL) { ++ ++ struct drm_bo_mem_reg *old_mem = &bo->mem; ++ uint64_t save_flags = old_mem->flags; ++ uint64_t save_proposed_flags = old_mem->proposed_flags; ++ ++ *old_mem = *mem; ++ mem->mm_node = NULL; ++ old_mem->proposed_flags = save_proposed_flags; ++ DRM_FLAG_MASKED(save_flags, mem->flags, ++ DRM_BO_MASK_MEMTYPE); ++ goto moved; ++ } ++ ++ } ++ ++ if (!(old_man->flags & _DRM_FLAG_MEMTYPE_FIXED) && ++ !(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED)) ++ ret = drm_bo_move_ttm(bo, evict, no_wait, mem); ++ else if (dev->driver->bo_driver->move) ++ ret = dev->driver->bo_driver->move(bo, evict, no_wait, mem); ++ else ++ ret = drm_bo_move_memcpy(bo, evict, no_wait, mem); ++ ++ if (ret) ++ goto out_err; ++ ++moved: ++ if (old_is_pci || new_is_pci) ++ drm_bo_vm_post_move(bo); ++ ++ if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { ++ ret = ++ dev->driver->bo_driver->invalidate_caches(dev, ++ bo->mem.flags); ++ if (ret) ++ DRM_ERROR("Can not flush read caches\n"); ++ } ++ ++ DRM_FLAG_MASKED(bo->priv_flags, ++ (evict) ? _DRM_BO_FLAG_EVICTED : 0, ++ _DRM_BO_FLAG_EVICTED); ++ ++ if (bo->mem.mm_node) ++ bo->offset = (bo->mem.mm_node->start << PAGE_SHIFT) + ++ bm->man[bo->mem.mem_type].gpu_offset; ++ ++ ++ return 0; ++ ++out_err: ++ if (old_is_pci || new_is_pci) ++ drm_bo_vm_post_move(bo); ++ ++ new_man = &bm->man[bo->mem.mem_type]; ++ if ((new_man->flags & _DRM_FLAG_MEMTYPE_FIXED) && bo->ttm) { ++ drm_ttm_unbind(bo->ttm); ++ drm_ttm_destroy(bo->ttm); ++ bo->ttm = NULL; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Call bo->mutex locked. ++ * Returns -EBUSY if the buffer is currently rendered to or from. 0 otherwise. ++ */ ++ ++static int drm_bo_busy(struct drm_buffer_object *bo, int check_unfenced) ++{ ++ struct drm_fence_object *fence = bo->fence; ++ ++ if (check_unfenced && (bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) ++ return -EBUSY; ++ ++ if (fence) { ++ if (drm_fence_object_signaled(fence, bo->fence_type)) { ++ drm_fence_usage_deref_unlocked(&bo->fence); ++ return 0; ++ } ++ drm_fence_object_flush(fence, DRM_FENCE_TYPE_EXE); ++ if (drm_fence_object_signaled(fence, bo->fence_type)) { ++ drm_fence_usage_deref_unlocked(&bo->fence); ++ return 0; ++ } ++ return -EBUSY; ++ } ++ return 0; ++} ++ ++static int drm_bo_check_unfenced(struct drm_buffer_object *bo) ++{ ++ int ret; ++ ++ mutex_lock(&bo->mutex); ++ ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); ++ mutex_unlock(&bo->mutex); ++ return ret; ++} ++ ++ ++/* ++ * Call bo->mutex locked. ++ * Wait until the buffer is idle. ++ */ ++ ++int drm_bo_wait(struct drm_buffer_object *bo, int lazy, int interruptible, ++ int no_wait, int check_unfenced) ++{ ++ int ret; ++ ++ DRM_ASSERT_LOCKED(&bo->mutex); ++ while(unlikely(drm_bo_busy(bo, check_unfenced))) { ++ if (no_wait) ++ return -EBUSY; ++ ++ if (check_unfenced && (bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) { ++ mutex_unlock(&bo->mutex); ++ wait_event(bo->event_queue, !drm_bo_check_unfenced(bo)); ++ mutex_lock(&bo->mutex); ++ bo->priv_flags |= _DRM_BO_FLAG_UNLOCKED; ++ } ++ ++ if (bo->fence) { ++ struct drm_fence_object *fence; ++ uint32_t fence_type = bo->fence_type; ++ ++ drm_fence_reference_unlocked(&fence, bo->fence); ++ mutex_unlock(&bo->mutex); ++ ++ ret = drm_fence_object_wait(fence, lazy, !interruptible, ++ fence_type); ++ ++ drm_fence_usage_deref_unlocked(&fence); ++ mutex_lock(&bo->mutex); ++ bo->priv_flags |= _DRM_BO_FLAG_UNLOCKED; ++ if (ret) ++ return ret; ++ } ++ ++ } ++ return 0; ++} ++EXPORT_SYMBOL(drm_bo_wait); ++ ++static int drm_bo_expire_fence(struct drm_buffer_object *bo, int allow_errors) ++{ ++ struct drm_device *dev = bo->dev; ++ struct drm_buffer_manager *bm = &dev->bm; ++ ++ if (bo->fence) { ++ if (bm->nice_mode) { ++ unsigned long _end = jiffies + 3 * DRM_HZ; ++ int ret; ++ do { ++ ret = drm_bo_wait(bo, 0, 0, 0, 0); ++ if (ret && allow_errors) ++ return ret; ++ ++ } while (ret && !time_after_eq(jiffies, _end)); ++ ++ if (bo->fence) { ++ bm->nice_mode = 0; ++ DRM_ERROR("Detected GPU lockup or " ++ "fence driver was taken down. " ++ "Evicting buffer.\n"); ++ } ++ } ++ if (bo->fence) ++ drm_fence_usage_deref_unlocked(&bo->fence); ++ } ++ return 0; ++} ++ ++/* ++ * Call dev->struct_mutex locked. ++ * Attempts to remove all private references to a buffer by expiring its ++ * fence object and removing from lru lists and memory managers. ++ */ ++ ++static void drm_bo_cleanup_refs(struct drm_buffer_object *bo, int remove_all) ++{ ++ struct drm_device *dev = bo->dev; ++ struct drm_buffer_manager *bm = &dev->bm; ++ ++ DRM_ASSERT_LOCKED(&dev->struct_mutex); ++ ++ atomic_inc(&bo->usage); ++ mutex_unlock(&dev->struct_mutex); ++ mutex_lock(&bo->mutex); ++ ++ DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); ++ ++ if (bo->fence && drm_fence_object_signaled(bo->fence, ++ bo->fence_type)) ++ drm_fence_usage_deref_unlocked(&bo->fence); ++ ++ if (bo->fence && remove_all) ++ (void)drm_bo_expire_fence(bo, 0); ++ ++ mutex_lock(&dev->struct_mutex); ++ ++ if (!atomic_dec_and_test(&bo->usage)) ++ goto out; ++ ++ if (!bo->fence) { ++ list_del_init(&bo->lru); ++ if (bo->mem.mm_node) { ++ drm_mm_put_block(bo->mem.mm_node); ++ if (bo->pinned_node == bo->mem.mm_node) ++ bo->pinned_node = NULL; ++ bo->mem.mm_node = NULL; ++ } ++ list_del_init(&bo->pinned_lru); ++ if (bo->pinned_node) { ++ drm_mm_put_block(bo->pinned_node); ++ bo->pinned_node = NULL; ++ } ++ list_del_init(&bo->ddestroy); ++ mutex_unlock(&bo->mutex); ++ drm_bo_destroy_locked(bo); ++ return; ++ } ++ ++ if (list_empty(&bo->ddestroy)) { ++ drm_fence_object_flush(bo->fence, bo->fence_type); ++ list_add_tail(&bo->ddestroy, &bm->ddestroy); ++ schedule_delayed_work(&bm->wq, ++ ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); ++ } ++ ++out: ++ mutex_unlock(&bo->mutex); ++ return; ++} ++ ++/* ++ * Verify that refcount is 0 and that there are no internal references ++ * to the buffer object. Then destroy it. ++ */ ++ ++static void drm_bo_destroy_locked(struct drm_buffer_object *bo) ++{ ++ struct drm_device *dev = bo->dev; ++ struct drm_buffer_manager *bm = &dev->bm; ++ ++ DRM_ASSERT_LOCKED(&dev->struct_mutex); ++ ++ if (list_empty(&bo->lru) && bo->mem.mm_node == NULL && ++ list_empty(&bo->pinned_lru) && bo->pinned_node == NULL && ++ list_empty(&bo->ddestroy) && atomic_read(&bo->usage) == 0) { ++ if (bo->fence != NULL) { ++ DRM_ERROR("Fence was non-zero.\n"); ++ drm_bo_cleanup_refs(bo, 0); ++ return; ++ } ++ ++#ifdef DRM_ODD_MM_COMPAT ++ BUG_ON(!list_empty(&bo->vma_list)); ++ BUG_ON(!list_empty(&bo->p_mm_list)); ++#endif ++ ++ if (bo->ttm) { ++ drm_ttm_unbind(bo->ttm); ++ drm_ttm_destroy(bo->ttm); ++ bo->ttm = NULL; ++ } ++ ++ atomic_dec(&bm->count); ++ ++ drm_ctl_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); ++ ++ return; ++ } ++ ++ /* ++ * Some stuff is still trying to reference the buffer object. ++ * Get rid of those references. ++ */ ++ ++ drm_bo_cleanup_refs(bo, 0); ++ ++ return; ++} ++ ++/* ++ * Call dev->struct_mutex locked. ++ */ ++ ++static void drm_bo_delayed_delete(struct drm_device *dev, int remove_all) ++{ ++ struct drm_buffer_manager *bm = &dev->bm; ++ ++ struct drm_buffer_object *entry, *nentry; ++ struct list_head *list, *next; ++ ++ list_for_each_safe(list, next, &bm->ddestroy) { ++ entry = list_entry(list, struct drm_buffer_object, ddestroy); ++ ++ nentry = NULL; ++ if (next != &bm->ddestroy) { ++ nentry = list_entry(next, struct drm_buffer_object, ++ ddestroy); ++ atomic_inc(&nentry->usage); ++ } ++ ++ drm_bo_cleanup_refs(entry, remove_all); ++ ++ if (nentry) ++ atomic_dec(&nentry->usage); ++ } ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++static void drm_bo_delayed_workqueue(void *data) ++#else ++static void drm_bo_delayed_workqueue(struct work_struct *work) ++#endif ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ struct drm_device *dev = (struct drm_device *) data; ++ struct drm_buffer_manager *bm = &dev->bm; ++#else ++ struct drm_buffer_manager *bm = ++ container_of(work, struct drm_buffer_manager, wq.work); ++ struct drm_device *dev = container_of(bm, struct drm_device, bm); ++#endif ++ ++ DRM_DEBUG("Delayed delete Worker\n"); ++ ++ mutex_lock(&dev->struct_mutex); ++ if (!bm->initialized) { ++ mutex_unlock(&dev->struct_mutex); ++ return; ++ } ++ drm_bo_delayed_delete(dev, 0); ++ if (bm->initialized && !list_empty(&bm->ddestroy)) { ++ schedule_delayed_work(&bm->wq, ++ ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); ++ } ++ mutex_unlock(&dev->struct_mutex); ++} ++ ++void drm_bo_usage_deref_locked(struct drm_buffer_object **bo) ++{ ++ struct drm_buffer_object *tmp_bo = *bo; ++ bo = NULL; ++ ++ DRM_ASSERT_LOCKED(&tmp_bo->dev->struct_mutex); ++ ++ if (atomic_dec_and_test(&tmp_bo->usage)) ++ drm_bo_destroy_locked(tmp_bo); ++} ++EXPORT_SYMBOL(drm_bo_usage_deref_locked); ++ ++static void drm_bo_base_deref_locked(struct drm_file *file_priv, ++ struct drm_user_object *uo) ++{ ++ struct drm_buffer_object *bo = ++ drm_user_object_entry(uo, struct drm_buffer_object, base); ++ ++ DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); ++ ++ drm_bo_takedown_vm_locked(bo); ++ drm_bo_usage_deref_locked(&bo); ++} ++ ++void drm_bo_usage_deref_unlocked(struct drm_buffer_object **bo) ++{ ++ struct drm_buffer_object *tmp_bo = *bo; ++ struct drm_device *dev = tmp_bo->dev; ++ ++ *bo = NULL; ++ if (atomic_dec_and_test(&tmp_bo->usage)) { ++ mutex_lock(&dev->struct_mutex); ++ if (atomic_read(&tmp_bo->usage) == 0) ++ drm_bo_destroy_locked(tmp_bo); ++ mutex_unlock(&dev->struct_mutex); ++ } ++} ++EXPORT_SYMBOL(drm_bo_usage_deref_unlocked); ++ ++void drm_putback_buffer_objects(struct drm_device *dev) ++{ ++ struct drm_buffer_manager *bm = &dev->bm; ++ struct list_head *list = &bm->unfenced; ++ struct drm_buffer_object *entry, *next; ++ ++ mutex_lock(&dev->struct_mutex); ++ list_for_each_entry_safe(entry, next, list, lru) { ++ atomic_inc(&entry->usage); ++ mutex_unlock(&dev->struct_mutex); ++ ++ mutex_lock(&entry->mutex); ++ BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); ++ mutex_lock(&dev->struct_mutex); ++ ++ list_del_init(&entry->lru); ++ DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); ++ wake_up_all(&entry->event_queue); ++ ++ /* ++ * FIXME: Might want to put back on head of list ++ * instead of tail here. ++ */ ++ ++ drm_bo_add_to_lru(entry); ++ mutex_unlock(&entry->mutex); ++ drm_bo_usage_deref_locked(&entry); ++ } ++ mutex_unlock(&dev->struct_mutex); ++} ++EXPORT_SYMBOL(drm_putback_buffer_objects); ++ ++ ++/* ++ * Note. The caller has to register (if applicable) ++ * and deregister fence object usage. ++ */ ++ ++int drm_fence_buffer_objects(struct drm_device *dev, ++ struct list_head *list, ++ uint32_t fence_flags, ++ struct drm_fence_object *fence, ++ struct drm_fence_object **used_fence) ++{ ++ struct drm_buffer_manager *bm = &dev->bm; ++ struct drm_buffer_object *entry; ++ uint32_t fence_type = 0; ++ uint32_t fence_class = ~0; ++ int count = 0; ++ int ret = 0; ++ struct list_head *l; ++ ++ mutex_lock(&dev->struct_mutex); ++ ++ if (!list) ++ list = &bm->unfenced; ++ ++ if (fence) ++ fence_class = fence->fence_class; ++ ++ list_for_each_entry(entry, list, lru) { ++ BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); ++ fence_type |= entry->new_fence_type; ++ if (fence_class == ~0) ++ fence_class = entry->new_fence_class; ++ else if (entry->new_fence_class != fence_class) { ++ DRM_ERROR("Unmatching fence classes on unfenced list: " ++ "%d and %d.\n", ++ fence_class, ++ entry->new_fence_class); ++ ret = -EINVAL; ++ goto out; ++ } ++ count++; ++ } ++ ++ if (!count) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (fence) { ++ if ((fence_type & fence->type) != fence_type || ++ (fence->fence_class != fence_class)) { ++ DRM_ERROR("Given fence doesn't match buffers " ++ "on unfenced list.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ } else { ++ mutex_unlock(&dev->struct_mutex); ++ ret = drm_fence_object_create(dev, fence_class, fence_type, ++ fence_flags | DRM_FENCE_FLAG_EMIT, ++ &fence); ++ mutex_lock(&dev->struct_mutex); ++ if (ret) ++ goto out; ++ } ++ ++ count = 0; ++ l = list->next; ++ while (l != list) { ++ prefetch(l->next); ++ entry = list_entry(l, struct drm_buffer_object, lru); ++ atomic_inc(&entry->usage); ++ mutex_unlock(&dev->struct_mutex); ++ mutex_lock(&entry->mutex); ++ mutex_lock(&dev->struct_mutex); ++ list_del_init(l); ++ if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { ++ count++; ++ if (entry->fence) ++ drm_fence_usage_deref_locked(&entry->fence); ++ entry->fence = drm_fence_reference_locked(fence); ++ entry->fence_class = entry->new_fence_class; ++ entry->fence_type = entry->new_fence_type; ++ DRM_FLAG_MASKED(entry->priv_flags, 0, ++ _DRM_BO_FLAG_UNFENCED); ++ wake_up_all(&entry->event_queue); ++ drm_bo_add_to_lru(entry); ++ } ++ mutex_unlock(&entry->mutex); ++ drm_bo_usage_deref_locked(&entry); ++ l = list->next; ++ } ++ DRM_DEBUG("Fenced %d buffers\n", count); ++out: ++ mutex_unlock(&dev->struct_mutex); ++ *used_fence = fence; ++ return ret; ++} ++EXPORT_SYMBOL(drm_fence_buffer_objects); ++ ++/* ++ * bo->mutex locked ++ */ ++ ++static int drm_bo_evict(struct drm_buffer_object *bo, unsigned mem_type, ++ int no_wait) ++{ ++ int ret = 0; ++ struct drm_device *dev = bo->dev; ++ struct drm_bo_mem_reg evict_mem; ++ ++ /* ++ * Someone might have modified the buffer before we took the ++ * buffer mutex. ++ */ ++ ++ do { ++ bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; ++ ++ if (unlikely(bo->mem.flags & ++ (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT))) ++ goto out_unlock; ++ if (unlikely(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) ++ goto out_unlock; ++ if (unlikely(bo->mem.mem_type != mem_type)) ++ goto out_unlock; ++ ret = drm_bo_wait(bo, 0, 1, no_wait, 0); ++ if (ret) ++ goto out_unlock; ++ ++ } while(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); ++ ++ evict_mem = bo->mem; ++ evict_mem.mm_node = NULL; ++ ++ evict_mem = bo->mem; ++ evict_mem.proposed_flags = dev->driver->bo_driver->evict_flags(bo); ++ ++ mutex_lock(&dev->struct_mutex); ++ list_del_init(&bo->lru); ++ mutex_unlock(&dev->struct_mutex); ++ ++ ret = drm_bo_mem_space(bo, &evict_mem, no_wait); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ DRM_ERROR("Failed to find memory space for " ++ "buffer 0x%p eviction.\n", bo); ++ goto out; ++ } ++ ++ ret = drm_bo_handle_move_mem(bo, &evict_mem, 1, no_wait); ++ ++ if (ret) { ++ if (ret != -EAGAIN) ++ DRM_ERROR("Buffer eviction failed\n"); ++ goto out; ++ } ++ ++ DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, ++ _DRM_BO_FLAG_EVICTED); ++ ++out: ++ mutex_lock(&dev->struct_mutex); ++ if (evict_mem.mm_node) { ++ if (evict_mem.mm_node != bo->pinned_node) ++ drm_mm_put_block(evict_mem.mm_node); ++ evict_mem.mm_node = NULL; ++ } ++ drm_bo_add_to_lru(bo); ++ BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); ++out_unlock: ++ mutex_unlock(&dev->struct_mutex); ++ ++ return ret; ++} ++ ++/** ++ * Repeatedly evict memory from the LRU for @mem_type until we create enough ++ * space, or we've evicted everything and there isn't enough space. ++ */ ++static int drm_bo_mem_force_space(struct drm_device *dev, ++ struct drm_bo_mem_reg *mem, ++ uint32_t mem_type, int no_wait) ++{ ++ struct drm_mm_node *node; ++ struct drm_buffer_manager *bm = &dev->bm; ++ struct drm_buffer_object *entry; ++ struct drm_mem_type_manager *man = &bm->man[mem_type]; ++ struct list_head *lru; ++ unsigned long num_pages = mem->num_pages; ++ int ret; ++ ++ mutex_lock(&dev->struct_mutex); ++ do { ++ node = drm_mm_search_free(&man->manager, num_pages, ++ mem->page_alignment, 1); ++ if (node) ++ break; ++ ++ lru = &man->lru; ++ if (lru->next == lru) ++ break; ++ ++ entry = list_entry(lru->next, struct drm_buffer_object, lru); ++ atomic_inc(&entry->usage); ++ mutex_unlock(&dev->struct_mutex); ++ mutex_lock(&entry->mutex); ++ ret = drm_bo_evict(entry, mem_type, no_wait); ++ mutex_unlock(&entry->mutex); ++ drm_bo_usage_deref_unlocked(&entry); ++ if (ret) ++ return ret; ++ mutex_lock(&dev->struct_mutex); ++ } while (1); ++ ++ if (!node) { ++ mutex_unlock(&dev->struct_mutex); ++ return -ENOMEM; ++ } ++ ++ node = drm_mm_get_block(node, num_pages, mem->page_alignment); ++ if (unlikely(!node)) { ++ mutex_unlock(&dev->struct_mutex); ++ return -ENOMEM; ++ } ++ ++ mutex_unlock(&dev->struct_mutex); ++ mem->mm_node = node; ++ mem->mem_type = mem_type; ++ return 0; ++} ++ ++static int drm_bo_mt_compatible(struct drm_mem_type_manager *man, ++ int disallow_fixed, ++ uint32_t mem_type, ++ uint64_t mask, uint32_t *res_mask) ++{ ++ uint64_t cur_flags = drm_bo_type_flags(mem_type); ++ uint64_t flag_diff; ++ ++ if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && disallow_fixed) ++ return 0; ++ if (man->flags & _DRM_FLAG_MEMTYPE_CACHED) ++ cur_flags |= DRM_BO_FLAG_CACHED; ++ if (man->flags & _DRM_FLAG_MEMTYPE_MAPPABLE) ++ cur_flags |= DRM_BO_FLAG_MAPPABLE; ++ if (man->flags & _DRM_FLAG_MEMTYPE_CSELECT) ++ DRM_FLAG_MASKED(cur_flags, mask, DRM_BO_FLAG_CACHED); ++ ++ if ((cur_flags & mask & DRM_BO_MASK_MEM) == 0) ++ return 0; ++ ++ if (mem_type == DRM_BO_MEM_LOCAL) { ++ *res_mask = cur_flags; ++ return 1; ++ } ++ ++ flag_diff = (mask ^ cur_flags); ++ if (flag_diff & DRM_BO_FLAG_CACHED_MAPPED) ++ cur_flags |= DRM_BO_FLAG_CACHED_MAPPED; ++ ++ if ((flag_diff & DRM_BO_FLAG_CACHED) && ++ (!(mask & DRM_BO_FLAG_CACHED) || ++ (mask & DRM_BO_FLAG_FORCE_CACHING))) ++ return 0; ++ ++ if ((flag_diff & DRM_BO_FLAG_MAPPABLE) && ++ ((mask & DRM_BO_FLAG_MAPPABLE) || ++ (mask & DRM_BO_FLAG_FORCE_MAPPABLE))) ++ return 0; ++ ++ *res_mask = cur_flags; ++ return 1; ++} ++ ++/** ++ * Creates space for memory region @mem according to its type. ++ * ++ * This function first searches for free space in compatible memory types in ++ * the priority order defined by the driver. If free space isn't found, then ++ * drm_bo_mem_force_space is attempted in priority order to evict and find ++ * space. ++ */ ++int drm_bo_mem_space(struct drm_buffer_object *bo, ++ struct drm_bo_mem_reg *mem, int no_wait) ++{ ++ struct drm_device *dev = bo->dev; ++ struct drm_buffer_manager *bm = &dev->bm; ++ struct drm_mem_type_manager *man; ++ ++ uint32_t num_prios = dev->driver->bo_driver->num_mem_type_prio; ++ const uint32_t *prios = dev->driver->bo_driver->mem_type_prio; ++ uint32_t i; ++ uint32_t mem_type = DRM_BO_MEM_LOCAL; ++ uint32_t cur_flags; ++ int type_found = 0; ++ int type_ok = 0; ++ int has_eagain = 0; ++ struct drm_mm_node *node = NULL; ++ int ret; ++ ++ mem->mm_node = NULL; ++ for (i = 0; i < num_prios; ++i) { ++ mem_type = prios[i]; ++ man = &bm->man[mem_type]; ++ ++ type_ok = drm_bo_mt_compatible(man, ++ bo->type == drm_bo_type_user, ++ mem_type, mem->proposed_flags, ++ &cur_flags); ++ ++ if (!type_ok) ++ continue; ++ ++ if (mem_type == DRM_BO_MEM_LOCAL) ++ break; ++ ++ if ((mem_type == bo->pinned_mem_type) && ++ (bo->pinned_node != NULL)) { ++ node = bo->pinned_node; ++ break; ++ } ++ ++ mutex_lock(&dev->struct_mutex); ++ if (man->has_type && man->use_type) { ++ type_found = 1; ++ node = drm_mm_search_free(&man->manager, mem->num_pages, ++ mem->page_alignment, 1); ++ if (node) ++ node = drm_mm_get_block(node, mem->num_pages, ++ mem->page_alignment); ++ } ++ mutex_unlock(&dev->struct_mutex); ++ if (node) ++ break; ++ } ++ ++ if ((type_ok && (mem_type == DRM_BO_MEM_LOCAL)) || node) { ++ mem->mm_node = node; ++ mem->mem_type = mem_type; ++ mem->flags = cur_flags; ++ return 0; ++ } ++ ++ if (!type_found) ++ return -EINVAL; ++ ++ num_prios = dev->driver->bo_driver->num_mem_busy_prio; ++ prios = dev->driver->bo_driver->mem_busy_prio; ++ ++ for (i = 0; i < num_prios; ++i) { ++ mem_type = prios[i]; ++ man = &bm->man[mem_type]; ++ ++ if (!man->has_type) ++ continue; ++ ++ if (!drm_bo_mt_compatible(man, ++ bo->type == drm_bo_type_user, ++ mem_type, ++ mem->proposed_flags, ++ &cur_flags)) ++ continue; ++ ++ ret =