[intel] Quirk away MSI support on 945G/GM.
[platform/upstream/libdrm.git] / linux-core / xgi_fb.c
index 67fdfe1..3f50fe8 100644 (file)
-\r
-/****************************************************************************\r
- * Copyright (C) 2003-2006 by XGI Technology, Taiwan.                  \r
- *                                                                                                                                                     *\r
- * All Rights Reserved.                                                                                                                *\r
- *                                                                                                                                                     *\r
- * Permission is hereby granted, free of charge, to any person obtaining\r
- * a copy of this software and associated documentation files (the     \r
- * "Software"), to deal in the Software without restriction, including \r
- * without limitation on the rights to use, copy, modify, merge,       \r
- * publish, distribute, sublicense, and/or sell copies of the Software,        \r
- * and to permit persons to whom the Software is furnished to do so,   \r
- * subject to the following conditions:                                        \r
- *                                                                                                                                                     *\r
- * The above copyright notice and this permission notice (including the        \r
- * next paragraph) shall be included in all copies or substantial      \r
- * portions of the Software.                                           \r
- *                                                                                                                                                     *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,     \r
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  \r
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND               \r
- * NON-INFRINGEMENT.  IN NO EVENT SHALL XGI AND/OR                     \r
- * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,          \r
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,          \r
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER                       \r
- * DEALINGS IN THE SOFTWARE.                                                                                           \r
- ***************************************************************************/\r
-\r
-#include "xgi_types.h"\r
-#include "xgi_linux.h"\r
-#include "xgi_drv.h"\r
-#include "xgi_fb.h"\r
-\r
-#define XGI_FB_HEAP_START 0x1000000\r
-\r
-static xgi_mem_heap_t   *xgi_fb_heap;\r
-static kmem_cache_t     *xgi_fb_cache_block = NULL;\r
-extern struct list_head xgi_mempid_list;\r
-\r
-static xgi_mem_block_t *xgi_mem_new_node(void);\r
-static xgi_mem_block_t *xgi_mem_alloc(xgi_info_t *info, unsigned long size);\r
-static xgi_mem_block_t *xgi_mem_free(xgi_info_t *info, unsigned long offset);\r
-\r
-void xgi_fb_alloc(xgi_info_t *info,\r
-                  xgi_mem_req_t *req,\r
-                  xgi_mem_alloc_t *alloc)\r
-{\r
-    xgi_mem_block_t *block;\r
-    xgi_mem_pid_t *mempid_block;\r
-\r
-    if (req->is_front)\r
-    {\r
-        alloc->location = LOCAL;\r
-        alloc->bus_addr = info->fb.base;\r
-        alloc->hw_addr  = 0;\r
-        XGI_INFO("Video RAM allocation on front buffer successfully! \n");\r
-    }\r
-    else\r
-    {\r
-        xgi_down(info->fb_sem);\r
-        block = xgi_mem_alloc(info, req->size);\r
-        xgi_up(info->fb_sem);\r
-\r
-        if (block == NULL)\r
-        {\r
-            alloc->location = LOCAL;\r
-            alloc->size     = 0;\r
-            alloc->bus_addr = 0;\r
-            alloc->hw_addr  = 0;\r
-            XGI_ERROR("Video RAM allocation failed\n");\r
-        }\r
-        else\r
-        {\r
-            XGI_INFO("Video RAM allocation succeeded: 0x%p\n",\r
-                    (char *) block->offset);\r
-            alloc->location = LOCAL;\r
-            alloc->size     = block->size;\r
-            alloc->bus_addr = info->fb.base + block->offset;\r
-            alloc->hw_addr  = block->offset;\r
-\r
-            /* manage mempid */\r
-            mempid_block = kmalloc(sizeof(xgi_mem_pid_t), GFP_KERNEL);\r
-            mempid_block->location = LOCAL;\r
-            mempid_block->bus_addr = alloc->bus_addr;\r
-            mempid_block->pid = alloc->pid;\r
-\r
-            if (!mempid_block)\r
-                XGI_ERROR("mempid_block alloc failed\n");\r
-\r
-            XGI_INFO("Memory ProcessID add one fb block pid:%ld successfully! \n", mempid_block->pid);\r
-            list_add(&mempid_block->list, &xgi_mempid_list);\r
-        }\r
-    }\r
-}\r
-\r
-void xgi_fb_free(xgi_info_t *info, unsigned long bus_addr)\r
-{\r
-    xgi_mem_block_t     *block;\r
-    unsigned long       offset = bus_addr - info->fb.base;\r
-    xgi_mem_pid_t       *mempid_block;\r
-    xgi_mem_pid_t       *mempid_freeblock = NULL;\r
-    struct list_head    *mempid_list;\r
-\r
-    if (offset < 0)\r
-    {\r
-        XGI_INFO("free onscreen frame buffer successfully !\n");\r
-    }\r
-    else\r
-    {\r
-        xgi_down(info->fb_sem);\r
-        block = xgi_mem_free(info, offset);\r
-        xgi_up(info->fb_sem);\r
-\r
-        if (block == NULL)\r
-        {\r
-            XGI_ERROR("xgi_mem_free() failed at base 0x%lx\n", offset);\r
-        }\r
-\r
-        /* manage mempid */\r
-        mempid_list = xgi_mempid_list.next;\r
-        while (mempid_list != &xgi_mempid_list)\r
-        {\r
-            mempid_block = list_entry(mempid_list, struct xgi_mem_pid_s, list);\r
-            if (mempid_block->location == LOCAL && mempid_block->bus_addr == bus_addr)\r
-            {\r
-                mempid_freeblock = mempid_block;\r
-                break;\r
-            }\r
-            mempid_list = mempid_list->next;\r
-        }\r
-        if (mempid_freeblock)\r
-        {\r
-            list_del(&mempid_freeblock->list);\r
-            XGI_INFO("Memory ProcessID delete one fb block pid:%ld successfully! \n", mempid_freeblock->pid);\r
-            kfree(mempid_freeblock);\r
-        }\r
-    }\r
-}\r
-\r
-int xgi_fb_heap_init(xgi_info_t *info)\r
-{\r
-    xgi_mem_block_t *block;\r
-\r
-    xgi_fb_heap = kmalloc(sizeof(xgi_mem_heap_t), GFP_KERNEL);\r
-    if (!xgi_fb_heap)\r
-    {\r
-        XGI_ERROR("xgi_fb_heap alloc failed\n");\r
-        return 0;\r
-    }\r
-\r
-    INIT_LIST_HEAD(&xgi_fb_heap->free_list);\r
-    INIT_LIST_HEAD(&xgi_fb_heap->used_list);\r
-    INIT_LIST_HEAD(&xgi_fb_heap->sort_list);\r
-\r
-    xgi_fb_cache_block = kmem_cache_create("xgi_fb_block", sizeof(xgi_mem_block_t),\r
-                                           0, SLAB_HWCACHE_ALIGN, NULL, NULL);\r
-\r
-    if (NULL == xgi_fb_cache_block)\r
-    {\r
-         XGI_ERROR("Fail to creat xgi_fb_block\n");\r
-         goto fail1;\r
-    }\r
-\r
-    block = (xgi_mem_block_t *)kmem_cache_alloc(xgi_fb_cache_block, GFP_KERNEL);\r
-    if (!block)\r
-    {\r
-        XGI_ERROR("kmem_cache_alloc failed\n");\r
-        goto fail2;\r
-    }\r
-\r
-    block->offset = XGI_FB_HEAP_START;\r
-    block->size   = info->fb.size - XGI_FB_HEAP_START;\r
-\r
-    list_add(&block->list, &xgi_fb_heap->free_list);\r
-\r
-    xgi_fb_heap->max_freesize = info->fb.size - XGI_FB_HEAP_START;\r
-\r
-    XGI_INFO("fb start offset: 0x%lx, memory size : 0x%lx\n", block->offset, block->size);\r
-    XGI_INFO("xgi_fb_heap->max_freesize: 0x%lx \n", xgi_fb_heap->max_freesize);\r
-\r
-    return 1;\r
-\r
-fail2:\r
-    if (xgi_fb_cache_block)\r
-    {\r
-        kmem_cache_destroy(xgi_fb_cache_block);\r
-        xgi_fb_cache_block = NULL;\r
-    }\r
-fail1:\r
-    if(xgi_fb_heap)\r
-    {\r
-        kfree(xgi_fb_heap);\r
-        xgi_fb_heap = NULL;\r
-    }\r
-    return 0;\r
-}\r
-\r
-void xgi_fb_heap_cleanup(xgi_info_t *info)\r
-{\r
-    struct list_head    *free_list, *temp;\r
-    xgi_mem_block_t     *block;\r
-    int                 i;\r
-\r
-    if (xgi_fb_heap)\r
-    {\r
-        free_list = &xgi_fb_heap->free_list;\r
-        for (i = 0; i < 3; i++, free_list++)\r
-        {\r
-            temp = free_list->next;\r
-            while (temp != free_list)\r
-            {\r
-                block = list_entry(temp, struct xgi_mem_block_s, list);\r
-                temp = temp->next;\r
-\r
-                XGI_INFO("No. %d block->offset: 0x%lx block->size: 0x%lx \n",\r
-                          i, block->offset, block->size);\r
-                //XGI_INFO("No. %d free block: 0x%p \n", i, block);\r
-                kmem_cache_free(xgi_fb_cache_block, block);\r
-                block = NULL;\r
-            }\r
-        }\r
-        XGI_INFO("xgi_fb_heap: 0x%p \n", xgi_fb_heap);\r
-        kfree(xgi_fb_heap);\r
-        xgi_fb_heap = NULL;\r
-    }\r
-\r
-    if (xgi_fb_cache_block)\r
-    {\r
-        kmem_cache_destroy(xgi_fb_cache_block);\r
-        xgi_fb_cache_block = NULL;\r
-    }\r
-}\r
-\r
-static xgi_mem_block_t * xgi_mem_new_node(void)\r
-{\r
-    xgi_mem_block_t *block;\r
-\r
-    block = (xgi_mem_block_t *)kmem_cache_alloc(xgi_fb_cache_block, GFP_KERNEL);\r
-    if (!block)\r
-    {\r
-        XGI_ERROR("kmem_cache_alloc failed\n");\r
-        return NULL;\r
-    }\r
-\r
-    return block;\r
-}\r
-\r
-#if 0\r
-static void xgi_mem_insert_node_after(xgi_mem_list_t *list,\r
-                                      xgi_mem_block_t *current,\r
-                                      xgi_mem_block_t *block);\r
-static void xgi_mem_insert_node_before(xgi_mem_list_t *list,\r
-                                       xgi_mem_block_t *current,\r
-                                       xgi_mem_block_t *block);\r
-static void xgi_mem_insert_node_head(xgi_mem_list_t *list,\r
-                                     xgi_mem_block_t *block);\r
-static void xgi_mem_insert_node_tail(xgi_mem_list_t *list,\r
-                                     xgi_mem_block_t *block);\r
-static void xgi_mem_delete_node(xgi_mem_list_t *list,\r
-                                xgi_mem_block_t *block);\r
-/*\r
- *  insert node:block after node:current\r
- */\r
-static void xgi_mem_insert_node_after(xgi_mem_list_t *list,\r
-                                      xgi_mem_block_t *current,\r
-                                      xgi_mem_block_t *block)\r
-{\r
-    block->prev = current;\r
-    block->next = current->next;\r
-    current->next = block;\r
-\r
-    if (current == list->tail)\r
-    {\r
-        list->tail = block;\r
-    }\r
-    else\r
-    {\r
-        block->next->prev = block;\r
-    }\r
-}\r
-\r
-/*\r
- *  insert node:block before node:current\r
- */\r
-static void xgi_mem_insert_node_before(xgi_mem_list_t *list,\r
-                                       xgi_mem_block_t *current,\r
-                                       xgi_mem_block_t *block)\r
-{\r
-    block->prev = current->prev;\r
-    block->next = current;\r
-    current->prev = block;\r
-    if (current == list->head)\r
-    {\r
-        list->head = block;\r
-    }\r
-    else\r
-    {\r
-        block->prev->next = block;\r
-    }\r
-}\r
-void xgi_mem_insert_node_head(xgi_mem_list_t *list,\r
-                              xgi_mem_block_t *block)\r
-{\r
-    block->next = list->head;\r
-    block->prev = NULL;\r
-\r
-    if (NULL == list->head)\r
-    {\r
-        list->tail = block;\r
-    }\r
-    else\r
-    {\r
-        list->head->prev = block;\r
-    }\r
-    list->head = block;\r
-}\r
-\r
-static void xgi_mem_insert_node_tail(xgi_mem_list_t *list,\r
-                                     xgi_mem_block_t *block)\r
-\r
-{\r
-    block->next = NULL;\r
-    block->prev = list->tail;\r
-    if (NULL == list->tail)\r
-    {\r
-        list->head = block;\r
-    }\r
-    else\r
-    {\r
-        list->tail->next = block;\r
-    }\r
-    list->tail = block;\r
-}\r
-\r
-static void xgi_mem_delete_node(xgi_mem_list_t *list,\r
-                         xgi_mem_block_t *block)\r
-{\r
-    if (block == list->head)\r
-    {\r
-        list->head = block->next;\r
-    }\r
-    if (block == list->tail)\r
-    {\r
-        list->tail = block->prev;\r
-    }\r
-\r
-    if (block->prev)\r
-    {\r
-        block->prev->next = block->next;\r
-    }\r
-    if (block->next)\r
-    {\r
-        block->next->prev = block->prev;\r
-    }\r
-\r
-    block->next = block->prev = NULL;\r
-}\r
-#endif\r
-static xgi_mem_block_t *xgi_mem_alloc(xgi_info_t *info, unsigned long originalSize)\r
-{\r
-    struct list_head    *free_list;\r
-    xgi_mem_block_t     *block, *free_block, *used_block;\r
-\r
-    unsigned long       size = (originalSize + PAGE_SIZE - 1) & PAGE_MASK;\r
-\r
-    XGI_INFO("Original 0x%lx bytes requested, really 0x%lx allocated\n", originalSize, size);\r
-\r
-    if (size == 0)\r
-    {\r
-        XGI_ERROR("size == 0\n");\r
-        return (NULL);\r
-    }\r
-    XGI_INFO("max_freesize: 0x%lx \n", xgi_fb_heap->max_freesize);\r
-    if (size > xgi_fb_heap->max_freesize)\r
-    {\r
-        XGI_ERROR("size: 0x%lx is bigger than frame buffer total free size: 0x%lx !\n",\r
-                  size, xgi_fb_heap->max_freesize);\r
-        return (NULL);\r
-    }\r
-\r
-    free_list = xgi_fb_heap->free_list.next;\r
-\r
-    while (free_list != &xgi_fb_heap->free_list)\r
-    {\r
-        XGI_INFO("free_list: 0x%px \n", free_list);\r
-        block = list_entry(free_list, struct xgi_mem_block_s, list);\r
-        if (size <= block->size)\r
-        {\r
-            break;\r
-        }\r
-        free_list = free_list->next;\r
-    }\r
-\r
-    if (free_list == &xgi_fb_heap->free_list)\r
-    {\r
-        XGI_ERROR("Can't allocate %ldk size from frame buffer memory !\n", size/1024);\r
-        return (NULL);\r
-    }\r
-\r
-    free_block = block;\r
-    XGI_INFO("alloc size: 0x%lx from offset: 0x%lx size: 0x%lx \n",\r
-              size, free_block->offset, free_block->size);\r
-\r
-    if (size == free_block->size)\r
-    {\r
-        used_block = free_block;\r
-        XGI_INFO("size == free_block->size: free_block = 0x%p\n", free_block);\r
-        list_del(&free_block->list);\r
-    }\r
-    else\r
-    {\r
-        used_block = xgi_mem_new_node();\r
-\r
-        if (used_block == NULL)  return (NULL);\r
-\r
-        if (used_block == free_block)\r
-        {\r
-            XGI_ERROR("used_block == free_block = 0x%p\n", used_block);\r
-        }\r
-\r
-        used_block->offset = free_block->offset;\r
-        used_block->size = size;\r
-\r
-        free_block->offset += size;\r
-        free_block->size -= size;\r
-    }\r
-\r
-    xgi_fb_heap->max_freesize -= size;\r
-\r
-    list_add(&used_block->list, &xgi_fb_heap->used_list);\r
-\r
-    return (used_block);\r
-}\r
-\r
-static xgi_mem_block_t *xgi_mem_free(xgi_info_t *info, unsigned long offset)\r
-{\r
-    struct list_head    *free_list, *used_list;\r
-    xgi_mem_block_t     *used_block = NULL, *block = NULL;\r
-    xgi_mem_block_t     *prev, *next;\r
-\r
-    unsigned long       upper;\r
-    unsigned long       lower;\r
-\r
-    used_list = xgi_fb_heap->used_list.next;\r
-    while (used_list != &xgi_fb_heap->used_list)\r
-    {\r
-        block = list_entry(used_list, struct xgi_mem_block_s, list);\r
-        if (block->offset == offset)\r
-        {\r
-            break;\r
-        }\r
-        used_list = used_list->next;\r
-    }\r
-\r
-    if (used_list == &xgi_fb_heap->used_list)\r
-    {\r
-        XGI_ERROR("can't find block: 0x%lx to free!\n", offset);\r
-        return (NULL);\r
-    }\r
-\r
-    used_block = block;\r
-    XGI_INFO("used_block: 0x%p, offset = 0x%lx, size = 0x%lx\n",\r
-              used_block, used_block->offset, used_block->size);\r
-\r
-    xgi_fb_heap->max_freesize += used_block->size;\r
-\r
-    prev = next = NULL;\r
-    upper = used_block->offset + used_block->size;\r
-    lower = used_block->offset;\r
-\r
-    free_list = xgi_fb_heap->free_list.next;\r
-    while (free_list != &xgi_fb_heap->free_list)\r
-    {\r
-        block = list_entry(free_list, struct xgi_mem_block_s, list);\r
-\r
-        if (block->offset == upper)\r
-        {\r
-            next = block;\r
-        }\r
-        else if ((block->offset + block->size) == lower)\r
-        {\r
-            prev = block;\r
-        }\r
-        free_list = free_list->next;\r
-    }\r
-\r
-    XGI_INFO("next = 0x%p, prev = 0x%p\n", next, prev);\r
-    list_del(&used_block->list);\r
-\r
-    if (prev && next)\r
-    {\r
-        prev->size += (used_block->size + next->size);\r
-        list_del(&next->list);\r
-        XGI_INFO("free node 0x%p\n", next);\r
-        kmem_cache_free(xgi_fb_cache_block, next);\r
-        kmem_cache_free(xgi_fb_cache_block, used_block);\r
-\r
-        next = NULL;\r
-        used_block = NULL;\r
-        return (prev);\r
-    }\r
-\r
-    if (prev)\r
-    {\r
-        prev->size += used_block->size;\r
-        XGI_INFO("free node 0x%p\n", used_block);\r
-        kmem_cache_free(xgi_fb_cache_block, used_block);\r
-        used_block = NULL;\r
-        return (prev);\r
-    }\r
-\r
-    if (next)\r
-    {\r
-        next->size += used_block->size;\r
-        next->offset = used_block->offset;\r
-        XGI_INFO("free node 0x%p\n", used_block);\r
-        kmem_cache_free(xgi_fb_cache_block, used_block);\r
-        used_block = NULL;\r
-        return (next);\r
-    }\r
-\r
-    list_add(&used_block->list, &xgi_fb_heap->free_list);\r
-    XGI_INFO("Recycled free node %p, offset = 0x%lx, size = 0x%lx\n",\r
-              used_block, used_block->offset, used_block->size);\r
-\r
-    return (used_block);\r
-}\r
-\r
+/****************************************************************************
+ * Copyright (C) 2003-2006 by XGI Technology, Taiwan.
+ *
+ * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * XGI 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 "xgi_drv.h"
+
+#define XGI_FB_HEAP_START 0x1000000
+
+int xgi_alloc(struct xgi_info * info, struct xgi_mem_alloc * alloc,
+             struct drm_file * filp)
+{
+       struct drm_memblock_item *block;
+       const char *const mem_name = (alloc->location == XGI_MEMLOC_LOCAL)
+               ? "on-card" : "GART";
+
+
+       if ((alloc->location != XGI_MEMLOC_LOCAL)
+           && (alloc->location != XGI_MEMLOC_NON_LOCAL)) {
+               DRM_ERROR("Invalid memory pool (0x%08x) specified.\n",
+                         alloc->location);
+               return -EINVAL;
+       }
+
+       if ((alloc->location == XGI_MEMLOC_LOCAL)
+           ? !info->fb_heap_initialized : !info->pcie_heap_initialized) {
+               DRM_ERROR("Attempt to allocate from uninitialized memory "
+                         "pool (0x%08x).\n", alloc->location);
+               return -EINVAL;
+       }
+
+       mutex_lock(&info->dev->struct_mutex);
+       block = drm_sman_alloc(&info->sman, alloc->location, alloc->size,
+                              0, (unsigned long) filp);
+       mutex_unlock(&info->dev->struct_mutex);
+
+       if (block == NULL) {
+               alloc->size = 0;
+               DRM_ERROR("%s memory allocation failed\n", mem_name);
+               return -ENOMEM;
+       } else {
+               alloc->offset = (*block->mm->offset)(block->mm,
+                                                    block->mm_info);
+               alloc->hw_addr = alloc->offset;
+               alloc->index = block->user_hash.key;
+
+               if (block->user_hash.key != (unsigned long) alloc->index) {
+                       DRM_ERROR("%s truncated handle %lx for pool %d "
+                                 "offset %x\n",
+                                 __func__, block->user_hash.key,
+                                 alloc->location, alloc->offset);
+               }
+
+               if (alloc->location == XGI_MEMLOC_NON_LOCAL) {
+                       alloc->hw_addr += info->pcie.base;
+               }
+
+               DRM_DEBUG("%s memory allocation succeeded: 0x%x\n",
+                         mem_name, alloc->offset);
+       }
+
+       return 0;
+}
+
+
+int xgi_alloc_ioctl(struct drm_device * dev, void * data,
+                   struct drm_file * filp)
+{
+       struct xgi_info *info = dev->dev_private;
+
+       return xgi_alloc(info, (struct xgi_mem_alloc *) data, filp);
+}
+
+
+int xgi_free(struct xgi_info * info, unsigned long index,
+            struct drm_file * filp)
+{
+       int err;
+
+       mutex_lock(&info->dev->struct_mutex);
+       err = drm_sman_free_key(&info->sman, index);
+       mutex_unlock(&info->dev->struct_mutex);
+
+       return err;
+}
+
+
+int xgi_free_ioctl(struct drm_device * dev, void * data,
+                  struct drm_file * filp)
+{
+       struct xgi_info *info = dev->dev_private;
+
+       return xgi_free(info, *(unsigned long *) data, filp);
+}
+
+
+int xgi_fb_heap_init(struct xgi_info * info)
+{
+       int err;
+
+       mutex_lock(&info->dev->struct_mutex);
+       err = drm_sman_set_range(&info->sman, XGI_MEMLOC_LOCAL,
+                                XGI_FB_HEAP_START,
+                                info->fb.size - XGI_FB_HEAP_START);
+       mutex_unlock(&info->dev->struct_mutex);
+
+       info->fb_heap_initialized = (err == 0);
+       return err;
+}