1829150b0SGordon Ross /*
247dc10d7SGordon Ross * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
347dc10d7SGordon Ross */
447dc10d7SGordon Ross
547dc10d7SGordon Ross /*
647dc10d7SGordon Ross * Copyright (c) 2009, 2013, Intel Corporation.
7829150b0SGordon Ross * All Rights Reserved.
8829150b0SGordon Ross *
9829150b0SGordon Ross * Permission is hereby granted, free of charge, to any person obtaining a
10829150b0SGordon Ross * copy of this software and associated documentation files (the "Software"),
11829150b0SGordon Ross * to deal in the Software without restriction, including without limitation
12829150b0SGordon Ross * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13829150b0SGordon Ross * and/or sell copies of the Software, and to permit persons to whom the
14829150b0SGordon Ross * Software is furnished to do so, subject to the following conditions:
15829150b0SGordon Ross *
16829150b0SGordon Ross * The above copyright notice and this permission notice (including the next
17829150b0SGordon Ross * paragraph) shall be included in all copies or substantial portions of the
18829150b0SGordon Ross * Software.
19829150b0SGordon Ross *
20829150b0SGordon Ross * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21829150b0SGordon Ross * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22829150b0SGordon Ross * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23829150b0SGordon Ross * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24829150b0SGordon Ross * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25829150b0SGordon Ross * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26829150b0SGordon Ross * IN THE SOFTWARE.
27829150b0SGordon Ross *
28829150b0SGordon Ross * Authors:
29829150b0SGordon Ross * Eric Anholt <eric@anholt.net>
30829150b0SGordon Ross *
31829150b0SGordon Ross */
32829150b0SGordon Ross
33829150b0SGordon Ross #include "drmP.h"
3447dc10d7SGordon Ross #include <vm/seg_kmem.h>
35829150b0SGordon Ross
3647dc10d7SGordon Ross /** @file drm_gem.c
37829150b0SGordon Ross *
38829150b0SGordon Ross * This file provides some of the base ioctls and library routines for
39829150b0SGordon Ross * the graphics memory manager implemented by each device driver.
40829150b0SGordon Ross *
41829150b0SGordon Ross * Because various devices have different requirements in terms of
42829150b0SGordon Ross * synchronization and migration strategies, implementing that is left up to
43829150b0SGordon Ross * the driver, and all that the general API provides should be generic --
44829150b0SGordon Ross * allocating objects, reading/writing data with the cpu, freeing objects.
45829150b0SGordon Ross * Even there, platform-dependent optimizations for reading/writing data with
46829150b0SGordon Ross * the CPU mean we'll likely hook those out to driver-specific calls. However,
47829150b0SGordon Ross * the DRI2 implementation wants to have at least allocate/mmap be generic.
48829150b0SGordon Ross *
49829150b0SGordon Ross * The goal was to have swap-backed object allocation managed through
50829150b0SGordon Ross * struct file. However, file descriptors as handles to a struct file have
51829150b0SGordon Ross * two major failings:
52829150b0SGordon Ross * - Process limits prevent more than 1024 or so being used at a time by
53829150b0SGordon Ross * default.
54829150b0SGordon Ross * - Inability to allocate high fds will aggravate the X Server's select()
55829150b0SGordon Ross * handling, and likely that of many GL client applications as well.
56829150b0SGordon Ross *
5747dc10d7SGordon Ross * This led to a plan of using our own integer IDs (called handles, following
58829150b0SGordon Ross * DRM terminology) to mimic fds, and implement the fd syscalls we need as
59829150b0SGordon Ross * ioctls. The objects themselves will still include the struct file so
60829150b0SGordon Ross * that we can transition to fds if the required kernel infrastructure shows
61829150b0SGordon Ross * up at a later date, and as our interface with shmfs for memory allocation.
62829150b0SGordon Ross */
63829150b0SGordon Ross
6447dc10d7SGordon Ross /*
6547dc10d7SGordon Ross * We make up offsets for buffer objects so we can recognize them at
6647dc10d7SGordon Ross * mmap time.
6747dc10d7SGordon Ross */
6847dc10d7SGordon Ross #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
6947dc10d7SGordon Ross #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
70829150b0SGordon Ross
7147dc10d7SGordon Ross int drm_use_mem_pool = 0;
7247dc10d7SGordon Ross /* memory pool is used for all platforms now */
7347dc10d7SGordon Ross #define HAS_MEM_POOL(gen) ((gen > 30) && (drm_use_mem_pool))
74829150b0SGordon Ross
7547dc10d7SGordon Ross /**
7647dc10d7SGordon Ross * Initialize the GEM device fields
7747dc10d7SGordon Ross */
78829150b0SGordon Ross
79829150b0SGordon Ross int
drm_gem_init(struct drm_device * dev)8047dc10d7SGordon Ross drm_gem_init(struct drm_device *dev)
81829150b0SGordon Ross {
82829150b0SGordon Ross
8347dc10d7SGordon Ross spin_lock_init(&dev->object_name_lock);
8447dc10d7SGordon Ross idr_list_init(&dev->object_name_idr);
85829150b0SGordon Ross
8647dc10d7SGordon Ross gfxp_mempool_init();
87829150b0SGordon Ross
8847dc10d7SGordon Ross return 0;
89829150b0SGordon Ross }
90829150b0SGordon Ross
91829150b0SGordon Ross void
9247dc10d7SGordon Ross /* LINTED */
drm_gem_destroy(struct drm_device * dev)9347dc10d7SGordon Ross drm_gem_destroy(struct drm_device *dev)
94829150b0SGordon Ross {
95829150b0SGordon Ross }
96829150b0SGordon Ross
9747dc10d7SGordon Ross static void
drm_gem_object_free_internal(struct drm_gem_object * obj,int gen)9847dc10d7SGordon Ross drm_gem_object_free_internal(struct drm_gem_object *obj, int gen)
99829150b0SGordon Ross {
10047dc10d7SGordon Ross if (obj->pfnarray != NULL)
10147dc10d7SGordon Ross kmem_free(obj->pfnarray, btopr(obj->real_size) * sizeof (pfn_t));
10247dc10d7SGordon Ross if (HAS_MEM_POOL(gen)) {
10347dc10d7SGordon Ross gfxp_free_mempool(&obj->mempool_cookie, obj->kaddr, obj->real_size);
10447dc10d7SGordon Ross } else {
10547dc10d7SGordon Ross (void) ddi_dma_unbind_handle(obj->dma_hdl);
10647dc10d7SGordon Ross ddi_dma_mem_free(&obj->acc_hdl);
10747dc10d7SGordon Ross ddi_dma_free_handle(&obj->dma_hdl);
10847dc10d7SGordon Ross }
10947dc10d7SGordon Ross obj->kaddr = NULL;
110829150b0SGordon Ross }
111829150b0SGordon Ross
11247dc10d7SGordon Ross static ddi_dma_attr_t old_dma_attr = {
11347dc10d7SGordon Ross DMA_ATTR_V0,
11434389f68SGordon Ross 0, /* dma_attr_addr_lo */
11547dc10d7SGordon Ross 0xffffffffU, /* dma_attr_addr_hi */
11647dc10d7SGordon Ross 0xffffffffU, /* dma_attr_count_max */
11747dc10d7SGordon Ross 4096, /* dma_attr_align */
11847dc10d7SGordon Ross 0x1fffU, /* dma_attr_burstsizes */
11947dc10d7SGordon Ross 1, /* dma_attr_minxfer */
12047dc10d7SGordon Ross 0xffffffffU, /* dma_attr_maxxfer */
12147dc10d7SGordon Ross 0xffffffffU, /* dma_attr_seg */
12247dc10d7SGordon Ross 1, /* dma_attr_sgllen, variable */
12347dc10d7SGordon Ross 4, /* dma_attr_granular */
12447dc10d7SGordon Ross DDI_DMA_FLAGERR, /* dma_attr_flags */
12547dc10d7SGordon Ross };
12647dc10d7SGordon Ross
12747dc10d7SGordon Ross static ddi_device_acc_attr_t old_acc_attr = {
12847dc10d7SGordon Ross DDI_DEVICE_ATTR_V0,
12947dc10d7SGordon Ross DDI_NEVERSWAP_ACC,
13047dc10d7SGordon Ross DDI_MERGING_OK_ACC,
13147dc10d7SGordon Ross DDI_FLAGERR_ACC
13247dc10d7SGordon Ross };
133829150b0SGordon Ross
13447dc10d7SGordon Ross static int
drm_gem_object_alloc_internal_normal(struct drm_device * dev,struct drm_gem_object * obj,size_t size,int flag)13547dc10d7SGordon Ross drm_gem_object_alloc_internal_normal(struct drm_device *dev, struct drm_gem_object *obj,
13647dc10d7SGordon Ross size_t size, int flag)
137829150b0SGordon Ross {
138829150b0SGordon Ross ddi_dma_cookie_t cookie;
139829150b0SGordon Ross uint_t cookie_cnt;
140829150b0SGordon Ross pgcnt_t real_pgcnt, pgcnt = btopr(size);
14147dc10d7SGordon Ross uint64_t paddr, cookie_end;
142829150b0SGordon Ross int i, n;
14347dc10d7SGordon Ross int (*cb)(caddr_t);
14447dc10d7SGordon Ross ddi_device_acc_attr_t *acc_attr;
14547dc10d7SGordon Ross ddi_dma_attr_t* dma_attr;
14647dc10d7SGordon Ross uint_t mode_flag;
147829150b0SGordon Ross
14847dc10d7SGordon Ross acc_attr = &old_acc_attr;
14947dc10d7SGordon Ross dma_attr = &old_dma_attr;
15047dc10d7SGordon Ross mode_flag = IOMEM_DATA_UC_WR_COMBINE;
151829150b0SGordon Ross
15247dc10d7SGordon Ross cb = (flag == 0) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
15347dc10d7SGordon Ross dma_attr->dma_attr_sgllen = (int)pgcnt;
154829150b0SGordon Ross
15547dc10d7SGordon Ross if (ddi_dma_alloc_handle(dev->devinfo, dma_attr,
15647dc10d7SGordon Ross cb, NULL, &obj->dma_hdl)) {
15747dc10d7SGordon Ross DRM_ERROR("ddi_dma_alloc_handle failed");
158829150b0SGordon Ross goto err1;
159829150b0SGordon Ross }
16047dc10d7SGordon Ross if (ddi_dma_mem_alloc(obj->dma_hdl, ptob(pgcnt), acc_attr,
16147dc10d7SGordon Ross mode_flag, cb, NULL,
162829150b0SGordon Ross &obj->kaddr, &obj->real_size, &obj->acc_hdl)) {
16347dc10d7SGordon Ross DRM_ERROR("ddi_dma_mem_alloc failed");
164829150b0SGordon Ross goto err2;
165829150b0SGordon Ross }
166829150b0SGordon Ross if (ddi_dma_addr_bind_handle(obj->dma_hdl, NULL,
167829150b0SGordon Ross obj->kaddr, obj->real_size, DDI_DMA_RDWR,
16847dc10d7SGordon Ross cb, NULL, &cookie, &cookie_cnt)
169829150b0SGordon Ross != DDI_DMA_MAPPED) {
17047dc10d7SGordon Ross DRM_ERROR("ddi_dma_addr_bind_handle failed");
171829150b0SGordon Ross goto err3;
172829150b0SGordon Ross }
173829150b0SGordon Ross
174829150b0SGordon Ross real_pgcnt = btopr(obj->real_size);
175829150b0SGordon Ross
176829150b0SGordon Ross obj->pfnarray = kmem_zalloc(real_pgcnt * sizeof (pfn_t), KM_NOSLEEP);
177829150b0SGordon Ross if (obj->pfnarray == NULL) {
17847dc10d7SGordon Ross DRM_DEBUG("pfnarray == NULL");
179829150b0SGordon Ross goto err4;
180829150b0SGordon Ross }
18147dc10d7SGordon Ross
182829150b0SGordon Ross for (n = 0, i = 1; ; i++) {
18347dc10d7SGordon Ross for (paddr = cookie.dmac_laddress,
18447dc10d7SGordon Ross cookie_end = cookie.dmac_laddress + cookie.dmac_size;
185829150b0SGordon Ross paddr < cookie_end;
186829150b0SGordon Ross paddr += PAGESIZE) {
187829150b0SGordon Ross obj->pfnarray[n++] = btop(paddr);
188829150b0SGordon Ross if (n >= real_pgcnt)
18947dc10d7SGordon Ross return (0);
190829150b0SGordon Ross }
191829150b0SGordon Ross if (i >= cookie_cnt)
192829150b0SGordon Ross break;
193829150b0SGordon Ross ddi_dma_nextcookie(obj->dma_hdl, &cookie);
194829150b0SGordon Ross }
195829150b0SGordon Ross
19647dc10d7SGordon Ross err4:
19747dc10d7SGordon Ross (void) ddi_dma_unbind_handle(obj->dma_hdl);
19847dc10d7SGordon Ross err3:
19947dc10d7SGordon Ross ddi_dma_mem_free(&obj->acc_hdl);
20047dc10d7SGordon Ross err2:
20147dc10d7SGordon Ross ddi_dma_free_handle(&obj->dma_hdl);
20247dc10d7SGordon Ross err1:
20347dc10d7SGordon Ross return (-1);
20447dc10d7SGordon Ross
20547dc10d7SGordon Ross }
20647dc10d7SGordon Ross
20747dc10d7SGordon Ross /* Alloc GEM object by memory pool */
20847dc10d7SGordon Ross static int
drm_gem_object_alloc_internal_mempool(struct drm_gem_object * obj,size_t size,int flag)20947dc10d7SGordon Ross drm_gem_object_alloc_internal_mempool(struct drm_gem_object *obj,
21047dc10d7SGordon Ross size_t size, int flag)
21147dc10d7SGordon Ross {
21247dc10d7SGordon Ross int ret;
21347dc10d7SGordon Ross pgcnt_t pgcnt = btopr(size);
21447dc10d7SGordon Ross
21547dc10d7SGordon Ross obj->pfnarray = kmem_zalloc(pgcnt * sizeof (pfn_t), KM_NOSLEEP);
21647dc10d7SGordon Ross if (obj->pfnarray == NULL) {
21747dc10d7SGordon Ross DRM_ERROR("Failed to allocate pfnarray ");
21847dc10d7SGordon Ross return (-1);
21947dc10d7SGordon Ross }
22047dc10d7SGordon Ross
22147dc10d7SGordon Ross ret = gfxp_alloc_from_mempool(&obj->mempool_cookie, &obj->kaddr,
22247dc10d7SGordon Ross obj->pfnarray, pgcnt, flag);
22347dc10d7SGordon Ross if (ret) {
22447dc10d7SGordon Ross DRM_ERROR("Failed to alloc pages from memory pool");
22547dc10d7SGordon Ross kmem_free(obj->pfnarray, pgcnt * sizeof (pfn_t));
22647dc10d7SGordon Ross return (-1);
22747dc10d7SGordon Ross }
22847dc10d7SGordon Ross
22947dc10d7SGordon Ross obj->real_size = size;
23047dc10d7SGordon Ross return (0);
23147dc10d7SGordon Ross }
23247dc10d7SGordon Ross
23347dc10d7SGordon Ross static int
drm_gem_object_internal(struct drm_device * dev,struct drm_gem_object * obj,size_t size,int gen)23447dc10d7SGordon Ross drm_gem_object_internal(struct drm_device *dev, struct drm_gem_object *obj,
23547dc10d7SGordon Ross size_t size, int gen)
23647dc10d7SGordon Ross {
23747dc10d7SGordon Ross pfn_t tmp_pfn;
23847dc10d7SGordon Ross int ret, num = 0;
23947dc10d7SGordon Ross
24047dc10d7SGordon Ross alloc_again:
24147dc10d7SGordon Ross if (HAS_MEM_POOL(gen)) {
24247dc10d7SGordon Ross uint32_t mode;
24347dc10d7SGordon Ross if (gen >= 60)
24447dc10d7SGordon Ross mode = GFXP_MEMORY_CACHED;
24547dc10d7SGordon Ross else
24647dc10d7SGordon Ross mode = GFXP_MEMORY_WRITECOMBINED;
24747dc10d7SGordon Ross ret = drm_gem_object_alloc_internal_mempool(obj, size, mode);
24847dc10d7SGordon Ross if (ret)
24947dc10d7SGordon Ross return (-1);
25047dc10d7SGordon Ross } else {
25147dc10d7SGordon Ross ret = drm_gem_object_alloc_internal_normal(dev, obj, size, 0);
25247dc10d7SGordon Ross if (ret)
25347dc10d7SGordon Ross return (-1);
25447dc10d7SGordon Ross }
25547dc10d7SGordon Ross tmp_pfn = hat_getpfnum(kas.a_hat, obj->kaddr);
25647dc10d7SGordon Ross if (tmp_pfn != obj->pfnarray[0]) {
25747dc10d7SGordon Ross DRM_ERROR("obj %p map incorrect 0x%lx != 0x%lx",
25847dc10d7SGordon Ross (void *)obj, tmp_pfn, obj->pfnarray[0]);
25947dc10d7SGordon Ross drm_gem_object_free_internal(obj, gen);
26047dc10d7SGordon Ross udelay(150);
26147dc10d7SGordon Ross
26247dc10d7SGordon Ross if (num++ < 5)
26347dc10d7SGordon Ross goto alloc_again;
26447dc10d7SGordon Ross else
26547dc10d7SGordon Ross return (-1);
26647dc10d7SGordon Ross }
26747dc10d7SGordon Ross
26847dc10d7SGordon Ross return (0);
26947dc10d7SGordon Ross }
27047dc10d7SGordon Ross /*
27147dc10d7SGordon Ross * Initialize an already allocate GEM object of the specified size with
27247dc10d7SGordon Ross * shmfs backing store.
27347dc10d7SGordon Ross */
27447dc10d7SGordon Ross int
drm_gem_object_init(struct drm_device * dev,struct drm_gem_object * obj,size_t size,int gen)27547dc10d7SGordon Ross drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj,
27647dc10d7SGordon Ross size_t size, int gen)
27747dc10d7SGordon Ross {
27847dc10d7SGordon Ross drm_local_map_t *map;
27947dc10d7SGordon Ross int ret;
28047dc10d7SGordon Ross
28147dc10d7SGordon Ross if (size == 0) {
28247dc10d7SGordon Ross DRM_DEBUG("size == 0");
28347dc10d7SGordon Ross return (-1);
28447dc10d7SGordon Ross }
28547dc10d7SGordon Ross
28647dc10d7SGordon Ross obj->dev = dev;
28747dc10d7SGordon Ross obj->size = size;
28847dc10d7SGordon Ross
28947dc10d7SGordon Ross ret = drm_gem_object_internal(dev, obj, size, gen);
29047dc10d7SGordon Ross if (ret)
29147dc10d7SGordon Ross return (-1);
29247dc10d7SGordon Ross
293829150b0SGordon Ross map = drm_alloc(sizeof (struct drm_local_map), DRM_MEM_MAPS);
294829150b0SGordon Ross if (map == NULL) {
29547dc10d7SGordon Ross DRM_DEBUG("map == NULL");
296829150b0SGordon Ross goto err5;
297829150b0SGordon Ross }
298829150b0SGordon Ross
299829150b0SGordon Ross map->handle = obj;
300829150b0SGordon Ross map->offset = (uintptr_t)map->handle;
301829150b0SGordon Ross map->offset &= 0xffffffffUL;
302829150b0SGordon Ross map->size = obj->real_size;
30347dc10d7SGordon Ross map->type = _DRM_GEM;
30447dc10d7SGordon Ross map->callback = 0;
305829150b0SGordon Ross map->flags = _DRM_WRITE_COMBINING | _DRM_REMOVABLE;
30647dc10d7SGordon Ross map->umem_cookie =
307829150b0SGordon Ross gfxp_umem_cookie_init(obj->kaddr, obj->real_size);
30847dc10d7SGordon Ross if (map->umem_cookie == NULL) {
30947dc10d7SGordon Ross DRM_DEBUG("umem_cookie == NULL");
310829150b0SGordon Ross goto err6;
311829150b0SGordon Ross }
312829150b0SGordon Ross
31347dc10d7SGordon Ross obj->maplist.map = map;
31447dc10d7SGordon Ross if (drm_map_handle(dev, &obj->maplist)) {
31547dc10d7SGordon Ross DRM_DEBUG("drm_map_handle failed");
316829150b0SGordon Ross goto err7;
317829150b0SGordon Ross }
318829150b0SGordon Ross
31947dc10d7SGordon Ross kref_init(&obj->refcount);
32047dc10d7SGordon Ross atomic_set(&obj->handle_count, 0);
32147dc10d7SGordon Ross
32247dc10d7SGordon Ross if (MDB_TRACK_ENABLE) {
32347dc10d7SGordon Ross INIT_LIST_HEAD(&obj->track_list);
32447dc10d7SGordon Ross spin_lock(&dev->track_lock);
32547dc10d7SGordon Ross list_add_tail(&obj->track_list, &dev->gem_objects_list, (caddr_t)obj);
32647dc10d7SGordon Ross spin_unlock(&dev->track_lock);
32747dc10d7SGordon Ross
32847dc10d7SGordon Ross INIT_LIST_HEAD(&obj->his_list);
32947dc10d7SGordon Ross drm_gem_object_track(obj, "obj init", 0, 0, NULL);
33047dc10d7SGordon Ross }
33147dc10d7SGordon Ross
33247dc10d7SGordon Ross INIT_LIST_HEAD(&obj->seg_list);
33347dc10d7SGordon Ross
33447dc10d7SGordon Ross return (0);
335829150b0SGordon Ross
336829150b0SGordon Ross err7:
33747dc10d7SGordon Ross gfxp_umem_cookie_destroy(map->umem_cookie);
338829150b0SGordon Ross err6:
339829150b0SGordon Ross drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
340829150b0SGordon Ross err5:
34147dc10d7SGordon Ross drm_gem_object_free_internal(obj, gen);
34247dc10d7SGordon Ross return (-1);
34347dc10d7SGordon Ross }
344829150b0SGordon Ross
34547dc10d7SGordon Ross /**
34647dc10d7SGordon Ross * Initialize an already allocated GEM object of the specified size with
34747dc10d7SGordon Ross * no GEM provided backing store. Instead the caller is responsible for
34847dc10d7SGordon Ross * backing the object and handling it.
34947dc10d7SGordon Ross */
drm_gem_private_object_init(struct drm_device * dev,struct drm_gem_object * obj,size_t size)35047dc10d7SGordon Ross int drm_gem_private_object_init(struct drm_device *dev,
35147dc10d7SGordon Ross struct drm_gem_object *obj, size_t size)
35247dc10d7SGordon Ross {
35347dc10d7SGordon Ross BUG_ON((size & (PAGE_SIZE - 1)) != 0);
35447dc10d7SGordon Ross
35547dc10d7SGordon Ross obj->dev = dev;
35647dc10d7SGordon Ross
35747dc10d7SGordon Ross kref_init(&obj->refcount);
35847dc10d7SGordon Ross atomic_set(&obj->handle_count, 0);
35947dc10d7SGordon Ross obj->size = size;
36047dc10d7SGordon Ross
36147dc10d7SGordon Ross return 0;
362829150b0SGordon Ross }
363829150b0SGordon Ross
36447dc10d7SGordon Ross /**
36547dc10d7SGordon Ross * Allocate a GEM object of the specified size with shmfs backing store
36647dc10d7SGordon Ross */
36747dc10d7SGordon Ross struct drm_gem_object *
drm_gem_object_alloc(struct drm_device * dev,size_t size)36847dc10d7SGordon Ross drm_gem_object_alloc(struct drm_device *dev, size_t size)
36947dc10d7SGordon Ross {
37047dc10d7SGordon Ross struct drm_gem_object *obj;
37147dc10d7SGordon Ross
37247dc10d7SGordon Ross obj = kzalloc(sizeof(*obj), GFP_KERNEL);
37347dc10d7SGordon Ross if (!obj)
37447dc10d7SGordon Ross goto free;
37547dc10d7SGordon Ross
37647dc10d7SGordon Ross if (drm_gem_object_init(dev, obj, size, 0) != 0) {
37747dc10d7SGordon Ross kmem_free(obj, sizeof (struct drm_gem_object));
37847dc10d7SGordon Ross return NULL;
37947dc10d7SGordon Ross }
38047dc10d7SGordon Ross
38147dc10d7SGordon Ross if (dev->driver->gem_init_object != NULL &&
38247dc10d7SGordon Ross dev->driver->gem_init_object(obj) != 0) {
38347dc10d7SGordon Ross goto fput;
38447dc10d7SGordon Ross }
38547dc10d7SGordon Ross return obj;
38647dc10d7SGordon Ross fput:
38747dc10d7SGordon Ross /* Object_init mangles the global counters - readjust them. */
38847dc10d7SGordon Ross drm_gem_object_release(obj);
38947dc10d7SGordon Ross kfree(obj, sizeof(*obj));
39047dc10d7SGordon Ross free:
39147dc10d7SGordon Ross return NULL;
39247dc10d7SGordon Ross }
39347dc10d7SGordon Ross
39447dc10d7SGordon Ross /**
395829150b0SGordon Ross * Removes the mapping from handle to filp for this object.
396829150b0SGordon Ross */
39747dc10d7SGordon Ross int
drm_gem_handle_delete(struct drm_file * filp,u32 handle)39847dc10d7SGordon Ross drm_gem_handle_delete(struct drm_file *filp, u32 handle)
399829150b0SGordon Ross {
400829150b0SGordon Ross struct drm_device *dev;
401829150b0SGordon Ross struct drm_gem_object *obj;
40247dc10d7SGordon Ross
40347dc10d7SGordon Ross /* This is gross. The idr system doesn't let us try a delete and
404829150b0SGordon Ross * return an error code. It just spews if you fail at deleting.
405829150b0SGordon Ross * So, we have to grab a lock around finding the object and then
406829150b0SGordon Ross * doing the delete on it and dropping the refcount, or the user
407829150b0SGordon Ross * could race us to double-decrement the refcount and cause a
408829150b0SGordon Ross * use-after-free later. Given the frequency of our handle lookups,
409829150b0SGordon Ross * we may want to use ida for number allocation and a hash table
410829150b0SGordon Ross * for the pointers, anyway.
411829150b0SGordon Ross */
412829150b0SGordon Ross spin_lock(&filp->table_lock);
413829150b0SGordon Ross
414829150b0SGordon Ross /* Check if we currently have a reference on the object */
415829150b0SGordon Ross obj = idr_list_find(&filp->object_idr, handle);
416829150b0SGordon Ross if (obj == NULL) {
417829150b0SGordon Ross spin_unlock(&filp->table_lock);
41847dc10d7SGordon Ross return -EINVAL;
419829150b0SGordon Ross }
420829150b0SGordon Ross dev = obj->dev;
421829150b0SGordon Ross
422829150b0SGordon Ross /* Release reference and decrement refcount. */
42347dc10d7SGordon Ross (void) idr_list_remove(&filp->object_idr, handle);
424829150b0SGordon Ross spin_unlock(&filp->table_lock);
425829150b0SGordon Ross
42647dc10d7SGordon Ross if (dev->driver->gem_close_object)
42747dc10d7SGordon Ross dev->driver->gem_close_object(obj, filp);
42847dc10d7SGordon Ross drm_gem_object_handle_unreference_unlocked(obj);
42947dc10d7SGordon Ross
43047dc10d7SGordon Ross return 0;
431829150b0SGordon Ross }
432829150b0SGordon Ross
43347dc10d7SGordon Ross /**
434829150b0SGordon Ross * Create a handle for this object. This adds a handle reference
435829150b0SGordon Ross * to the object, which includes a regular reference count. Callers
436829150b0SGordon Ross * will likely want to dereference the object afterwards.
437829150b0SGordon Ross */
438829150b0SGordon Ross int
drm_gem_handle_create(struct drm_file * file_priv,struct drm_gem_object * obj,u32 * handlep)439829150b0SGordon Ross drm_gem_handle_create(struct drm_file *file_priv,
44047dc10d7SGordon Ross struct drm_gem_object *obj,
44147dc10d7SGordon Ross u32 *handlep)
442829150b0SGordon Ross {
44347dc10d7SGordon Ross struct drm_device *dev = obj->dev;
444829150b0SGordon Ross int ret;
445829150b0SGordon Ross
446829150b0SGordon Ross /*
447829150b0SGordon Ross * Get the user-visible handle using idr.
448829150b0SGordon Ross */
449829150b0SGordon Ross again:
450829150b0SGordon Ross /* ensure there is space available to allocate a handle */
45147dc10d7SGordon Ross if (idr_list_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0)
45247dc10d7SGordon Ross return -ENOMEM;
453829150b0SGordon Ross
454829150b0SGordon Ross /* do the allocation under our spinlock */
455829150b0SGordon Ross spin_lock(&file_priv->table_lock);
45647dc10d7SGordon Ross ret = idr_list_get_new_above(&file_priv->object_idr, (void *)obj, (int *)handlep);
457829150b0SGordon Ross spin_unlock(&file_priv->table_lock);
458829150b0SGordon Ross if (ret == -EAGAIN)
459829150b0SGordon Ross goto again;
460829150b0SGordon Ross
46147dc10d7SGordon Ross if (ret != 0)
46247dc10d7SGordon Ross return ret;
463829150b0SGordon Ross
464829150b0SGordon Ross drm_gem_object_handle_reference(obj);
46547dc10d7SGordon Ross
46647dc10d7SGordon Ross if (dev->driver->gem_open_object) {
46747dc10d7SGordon Ross ret = dev->driver->gem_open_object(obj, file_priv);
46847dc10d7SGordon Ross if (ret) {
46947dc10d7SGordon Ross (void) drm_gem_handle_delete(file_priv, *handlep);
47047dc10d7SGordon Ross return ret;
47147dc10d7SGordon Ross }
47247dc10d7SGordon Ross }
47347dc10d7SGordon Ross
47447dc10d7SGordon Ross return 0;
475829150b0SGordon Ross }
476829150b0SGordon Ross
47747dc10d7SGordon Ross /** Returns a reference to the object named by the handle. */
478829150b0SGordon Ross struct drm_gem_object *
47947dc10d7SGordon Ross /* LINTED */
drm_gem_object_lookup(struct drm_device * dev,struct drm_file * filp,u32 handle)48047dc10d7SGordon Ross drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
48147dc10d7SGordon Ross u32 handle)
482829150b0SGordon Ross {
483829150b0SGordon Ross struct drm_gem_object *obj;
484829150b0SGordon Ross
485829150b0SGordon Ross spin_lock(&filp->table_lock);
486829150b0SGordon Ross
487829150b0SGordon Ross /* Check if we currently have a reference on the object */
488829150b0SGordon Ross obj = idr_list_find(&filp->object_idr, handle);
48947dc10d7SGordon Ross if (obj == NULL) {
49047dc10d7SGordon Ross spin_unlock(&filp->table_lock);
49147dc10d7SGordon Ross return NULL;
49247dc10d7SGordon Ross }
493829150b0SGordon Ross
494829150b0SGordon Ross drm_gem_object_reference(obj);
495829150b0SGordon Ross
496829150b0SGordon Ross spin_unlock(&filp->table_lock);
497829150b0SGordon Ross
49847dc10d7SGordon Ross return obj;
499829150b0SGordon Ross }
500829150b0SGordon Ross
50147dc10d7SGordon Ross /**
502829150b0SGordon Ross * Releases the handle to an mm object.
503829150b0SGordon Ross */
504829150b0SGordon Ross int
50547dc10d7SGordon Ross /* LINTED */
drm_gem_close_ioctl(DRM_IOCTL_ARGS)506829150b0SGordon Ross drm_gem_close_ioctl(DRM_IOCTL_ARGS)
507829150b0SGordon Ross {
50847dc10d7SGordon Ross struct drm_gem_close *args = data;
509829150b0SGordon Ross int ret;
510829150b0SGordon Ross
51147dc10d7SGordon Ross if (!(dev->driver->driver_features & DRIVER_GEM))
51247dc10d7SGordon Ross return -ENODEV;
513829150b0SGordon Ross
51447dc10d7SGordon Ross ret = drm_gem_handle_delete(file, args->handle);
515829150b0SGordon Ross
51647dc10d7SGordon Ross return ret;
517829150b0SGordon Ross }
518829150b0SGordon Ross
51947dc10d7SGordon Ross /**
520829150b0SGordon Ross * Create a global name for an object, returning the name.
521829150b0SGordon Ross *
522829150b0SGordon Ross * Note that the name does not hold a reference; when the object
523829150b0SGordon Ross * is freed, the name goes away.
524829150b0SGordon Ross */
525829150b0SGordon Ross int
52647dc10d7SGordon Ross /* LINTED */
drm_gem_flink_ioctl(DRM_IOCTL_ARGS)527829150b0SGordon Ross drm_gem_flink_ioctl(DRM_IOCTL_ARGS)
528829150b0SGordon Ross {
52947dc10d7SGordon Ross struct drm_gem_flink *args = data;
530829150b0SGordon Ross struct drm_gem_object *obj;
53147dc10d7SGordon Ross int ret;
532829150b0SGordon Ross
53347dc10d7SGordon Ross if (!(dev->driver->driver_features & DRIVER_GEM))
53447dc10d7SGordon Ross return -ENODEV;
535829150b0SGordon Ross
53647dc10d7SGordon Ross obj = drm_gem_object_lookup(dev, file, args->handle);
537829150b0SGordon Ross if (obj == NULL)
53847dc10d7SGordon Ross return -ENOENT;
53947dc10d7SGordon Ross
54047dc10d7SGordon Ross again:
54147dc10d7SGordon Ross if (idr_list_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
54247dc10d7SGordon Ross ret = -ENOMEM;
54347dc10d7SGordon Ross goto err;
54447dc10d7SGordon Ross }
54547dc10d7SGordon Ross
546829150b0SGordon Ross spin_lock(&dev->object_name_lock);
54747dc10d7SGordon Ross if (!obj->name) {
54847dc10d7SGordon Ross ret = idr_list_get_new_above(&dev->object_name_idr, (void *) obj,
54947dc10d7SGordon Ross &obj->name);
55047dc10d7SGordon Ross args->name = (uint64_t) obj->name;
55147dc10d7SGordon Ross spin_unlock(&dev->object_name_lock);
55247dc10d7SGordon Ross
55347dc10d7SGordon Ross if (ret == -EAGAIN)
55447dc10d7SGordon Ross goto again;
55547dc10d7SGordon Ross
55647dc10d7SGordon Ross if (ret != 0)
55747dc10d7SGordon Ross goto err;
55847dc10d7SGordon Ross
559829150b0SGordon Ross /* Allocate a reference for the name table. */
560829150b0SGordon Ross drm_gem_object_reference(obj);
56147dc10d7SGordon Ross } else {
56247dc10d7SGordon Ross args->name = (uint64_t) obj->name;
56347dc10d7SGordon Ross spin_unlock(&dev->object_name_lock);
56447dc10d7SGordon Ross ret = 0;
565829150b0SGordon Ross }
566829150b0SGordon Ross
56747dc10d7SGordon Ross err:
56847dc10d7SGordon Ross drm_gem_object_unreference_unlocked(obj);
56947dc10d7SGordon Ross return ret;
570829150b0SGordon Ross }
571829150b0SGordon Ross
57247dc10d7SGordon Ross /**
573829150b0SGordon Ross * Open an object using the global name, returning a handle and the size.
574829150b0SGordon Ross *
575829150b0SGordon Ross * This handle (of course) holds a reference to the object, so the object
576829150b0SGordon Ross * will not go away until the handle is deleted.
577829150b0SGordon Ross */
578829150b0SGordon Ross int
57947dc10d7SGordon Ross /* LINTED */
drm_gem_open_ioctl(DRM_IOCTL_ARGS)580829150b0SGordon Ross drm_gem_open_ioctl(DRM_IOCTL_ARGS)
581829150b0SGordon Ross {
58247dc10d7SGordon Ross struct drm_gem_open *args = data;
583829150b0SGordon Ross struct drm_gem_object *obj;
584829150b0SGordon Ross int ret;
58547dc10d7SGordon Ross u32 handle;
586829150b0SGordon Ross
58747dc10d7SGordon Ross if (!(dev->driver->driver_features & DRIVER_GEM))
58847dc10d7SGordon Ross return -ENODEV;
589829150b0SGordon Ross
590829150b0SGordon Ross spin_lock(&dev->object_name_lock);
59147dc10d7SGordon Ross obj = idr_list_find(&dev->object_name_idr, (int) args->name);
592829150b0SGordon Ross if (obj)
593829150b0SGordon Ross drm_gem_object_reference(obj);
594829150b0SGordon Ross spin_unlock(&dev->object_name_lock);
59547dc10d7SGordon Ross if (!obj)
59647dc10d7SGordon Ross return -ENOENT;
597829150b0SGordon Ross
59847dc10d7SGordon Ross ret = drm_gem_handle_create(file, obj, &handle);
59947dc10d7SGordon Ross drm_gem_object_unreference_unlocked(obj);
60047dc10d7SGordon Ross if (ret)
60147dc10d7SGordon Ross return ret;
602829150b0SGordon Ross
60347dc10d7SGordon Ross args->handle = handle;
60447dc10d7SGordon Ross args->size = obj->size;
605829150b0SGordon Ross
60647dc10d7SGordon Ross return 0;
607829150b0SGordon Ross }
608829150b0SGordon Ross
60947dc10d7SGordon Ross /**
610829150b0SGordon Ross * Called at device open time, sets up the structure for handling refcounting
611829150b0SGordon Ross * of mm objects.
612829150b0SGordon Ross */
613829150b0SGordon Ross void
61447dc10d7SGordon Ross /* LINTED */
drm_gem_open(struct drm_device * dev,struct drm_file * file_private)61547dc10d7SGordon Ross drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
616829150b0SGordon Ross {
617829150b0SGordon Ross idr_list_init(&file_private->object_idr);
61847dc10d7SGordon Ross spin_lock_init(&file_private->table_lock);
619829150b0SGordon Ross }
620829150b0SGordon Ross
62147dc10d7SGordon Ross /**
622829150b0SGordon Ross * Called at device close to release the file's
623829150b0SGordon Ross * handle references on objects.
624829150b0SGordon Ross */
62547dc10d7SGordon Ross static int
62647dc10d7SGordon Ross /* LINTED */
drm_gem_object_release_handle(int id,void * ptr,void * data)62747dc10d7SGordon Ross drm_gem_object_release_handle(int id, void *ptr, void *data)
628829150b0SGordon Ross {
62947dc10d7SGordon Ross struct drm_file *file_priv = data;
63047dc10d7SGordon Ross struct drm_gem_object *obj = ptr;
63147dc10d7SGordon Ross struct drm_device *dev = obj->dev;
63247dc10d7SGordon Ross
63347dc10d7SGordon Ross if (dev->driver->gem_close_object)
63447dc10d7SGordon Ross dev->driver->gem_close_object(obj, file_priv);
63547dc10d7SGordon Ross
63647dc10d7SGordon Ross drm_gem_object_handle_unreference_unlocked(obj);
63747dc10d7SGordon Ross
63847dc10d7SGordon Ross return 0;
639829150b0SGordon Ross }
640829150b0SGordon Ross
64147dc10d7SGordon Ross /**
642829150b0SGordon Ross * Called at close time when the filp is going away.
643829150b0SGordon Ross *
644829150b0SGordon Ross * Releases any remaining references on objects by this filp.
645829150b0SGordon Ross */
646829150b0SGordon Ross void
64747dc10d7SGordon Ross /* LINTED E_FUNC_ARG_UNUSED */
drm_gem_release(struct drm_device * dev,struct drm_file * file_private)648829150b0SGordon Ross drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
649829150b0SGordon Ross {
650829150b0SGordon Ross struct idr_list *entry;
65147dc10d7SGordon Ross struct drm_gem_object *obj;
652829150b0SGordon Ross
65347dc10d7SGordon Ross idr_list_for_each(entry, &file_private->object_idr) {
65447dc10d7SGordon Ross obj = (struct drm_gem_object *)entry->obj;
65547dc10d7SGordon Ross (void) drm_gem_object_release_handle(obj->name, obj, (void *)file_private);
65647dc10d7SGordon Ross }
657829150b0SGordon Ross idr_list_free(&file_private->object_idr);
65847dc10d7SGordon Ross }
659829150b0SGordon Ross
66047dc10d7SGordon Ross void
drm_gem_object_release(struct drm_gem_object * obj)66147dc10d7SGordon Ross drm_gem_object_release(struct drm_gem_object *obj)
66247dc10d7SGordon Ross {
66347dc10d7SGordon Ross struct drm_device *dev = obj->dev;
66447dc10d7SGordon Ross struct drm_local_map *map = obj->maplist.map;
66547dc10d7SGordon Ross
66647dc10d7SGordon Ross if (MDB_TRACK_ENABLE) {
66747dc10d7SGordon Ross spin_lock(&dev->track_lock);
66847dc10d7SGordon Ross list_del(&obj->track_list);
66947dc10d7SGordon Ross spin_unlock(&dev->track_lock);
67047dc10d7SGordon Ross
67147dc10d7SGordon Ross struct drm_history_list *r_list, *list_temp;
67247dc10d7SGordon Ross list_for_each_entry_safe(r_list, list_temp, struct drm_history_list, &obj->his_list, head) {
67347dc10d7SGordon Ross list_del(&r_list->head);
67447dc10d7SGordon Ross drm_free(r_list, sizeof (struct drm_history_list), DRM_MEM_MAPS);
67547dc10d7SGordon Ross }
67647dc10d7SGordon Ross list_del(&obj->his_list);
67747dc10d7SGordon Ross }
67847dc10d7SGordon Ross
67947dc10d7SGordon Ross (void) idr_remove(&dev->map_idr, obj->maplist.user_token >> PAGE_SHIFT);
68047dc10d7SGordon Ross gfxp_umem_cookie_destroy(map->umem_cookie);
68147dc10d7SGordon Ross drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
68247dc10d7SGordon Ross
68347dc10d7SGordon Ross kmem_free(obj->pfnarray, btopr(obj->real_size) * sizeof (pfn_t));
68447dc10d7SGordon Ross
68547dc10d7SGordon Ross if (obj->dma_hdl == NULL) {
68647dc10d7SGordon Ross gfxp_free_mempool(&obj->mempool_cookie, obj->kaddr, obj->real_size);
68747dc10d7SGordon Ross } else {
68847dc10d7SGordon Ross (void) ddi_dma_unbind_handle(obj->dma_hdl);
68947dc10d7SGordon Ross ddi_dma_mem_free(&obj->acc_hdl);
69047dc10d7SGordon Ross ddi_dma_free_handle(&obj->dma_hdl);
69147dc10d7SGordon Ross }
69247dc10d7SGordon Ross obj->kaddr = NULL;
693829150b0SGordon Ross }
694829150b0SGordon Ross
69547dc10d7SGordon Ross /**
696829150b0SGordon Ross * Called after the last reference to the object has been lost.
697829150b0SGordon Ross *
698829150b0SGordon Ross * Frees the object
699829150b0SGordon Ross */
700829150b0SGordon Ross void
drm_gem_object_free(struct kref * kref)70147dc10d7SGordon Ross drm_gem_object_free(struct kref *kref)
702829150b0SGordon Ross {
70347dc10d7SGordon Ross /* LINTED */
70447dc10d7SGordon Ross struct drm_gem_object *obj = (struct drm_gem_object *) kref;
705829150b0SGordon Ross struct drm_device *dev = obj->dev;
70647dc10d7SGordon Ross
70747dc10d7SGordon Ross // BUG_ON(!mutex_is_locked(&dev->struct_mutex));
708829150b0SGordon Ross
709829150b0SGordon Ross if (dev->driver->gem_free_object != NULL)
710829150b0SGordon Ross dev->driver->gem_free_object(obj);
71147dc10d7SGordon Ross }
712829150b0SGordon Ross
71347dc10d7SGordon Ross /* LINTED E_FUNC_ARG_UNUSED */
drm_gem_object_ref_bug(struct kref * list_kref)71447dc10d7SGordon Ross static void drm_gem_object_ref_bug(struct kref *list_kref)
71547dc10d7SGordon Ross {
71647dc10d7SGordon Ross BUG_ON(1);
717829150b0SGordon Ross }
718829150b0SGordon Ross
71947dc10d7SGordon Ross /**
720829150b0SGordon Ross * Called after the last handle to the object has been closed
721829150b0SGordon Ross *
722829150b0SGordon Ross * Removes any name for the object. Note that this must be
723829150b0SGordon Ross * called before drm_gem_object_free or we'll be touching
724829150b0SGordon Ross * freed memory
725829150b0SGordon Ross */
726829150b0SGordon Ross void
drm_gem_object_handle_free(struct drm_gem_object * obj)727829150b0SGordon Ross drm_gem_object_handle_free(struct drm_gem_object *obj)
728829150b0SGordon Ross {
729829150b0SGordon Ross struct drm_device *dev = obj->dev;
73047dc10d7SGordon Ross
731829150b0SGordon Ross /* Remove any name for this object */
732829150b0SGordon Ross spin_lock(&dev->object_name_lock);
73347dc10d7SGordon Ross if (obj->name) {
73447dc10d7SGordon Ross (void) idr_list_remove(&dev->object_name_idr, obj->name);
73547dc10d7SGordon Ross obj->name = 0;
736829150b0SGordon Ross spin_unlock(&dev->object_name_lock);
737829150b0SGordon Ross /*
738829150b0SGordon Ross * The object name held a reference to this object, drop
739829150b0SGordon Ross * that now.
74047dc10d7SGordon Ross *
74147dc10d7SGordon Ross * This cannot be the last reference, since the handle holds one too.
742829150b0SGordon Ross */
74347dc10d7SGordon Ross kref_put(&obj->refcount, drm_gem_object_ref_bug);
744829150b0SGordon Ross } else
745829150b0SGordon Ross spin_unlock(&dev->object_name_lock);
746829150b0SGordon Ross
747829150b0SGordon Ross }
74847dc10d7SGordon Ross
74947dc10d7SGordon Ross int
drm_gem_create_mmap_offset(struct drm_gem_object * obj)75047dc10d7SGordon Ross drm_gem_create_mmap_offset(struct drm_gem_object *obj)
75147dc10d7SGordon Ross {
75247dc10d7SGordon Ross obj->gtt_map_kaddr = gfxp_alloc_kernel_space(obj->real_size);
75347dc10d7SGordon Ross if (obj->gtt_map_kaddr == NULL) {
75447dc10d7SGordon Ross return -ENOMEM;
75547dc10d7SGordon Ross }
75647dc10d7SGordon Ross return 0;
75747dc10d7SGordon Ross }
75847dc10d7SGordon Ross
75947dc10d7SGordon Ross void
drm_gem_mmap(struct drm_gem_object * obj,pfn_t pfn)76047dc10d7SGordon Ross drm_gem_mmap(struct drm_gem_object *obj, pfn_t pfn)
76147dc10d7SGordon Ross {
762*e49fc716SGordon Ross ASSERT(obj->gtt_map_kaddr != NULL);
763*e49fc716SGordon Ross /* Does hat_devload() */
76447dc10d7SGordon Ross gfxp_load_kernel_space(pfn, obj->real_size, GFXP_MEMORY_WRITECOMBINED, obj->gtt_map_kaddr);
76547dc10d7SGordon Ross }
76647dc10d7SGordon Ross
76747dc10d7SGordon Ross void
drm_gem_release_mmap(struct drm_gem_object * obj)76847dc10d7SGordon Ross drm_gem_release_mmap(struct drm_gem_object *obj)
76947dc10d7SGordon Ross {
770*e49fc716SGordon Ross ASSERT(obj->gtt_map_kaddr != NULL);
771*e49fc716SGordon Ross /* Does hat_unload() */
77247dc10d7SGordon Ross gfxp_unload_kernel_space(obj->gtt_map_kaddr, obj->real_size);
77347dc10d7SGordon Ross }
77447dc10d7SGordon Ross
77547dc10d7SGordon Ross void
drm_gem_free_mmap_offset(struct drm_gem_object * obj)77647dc10d7SGordon Ross drm_gem_free_mmap_offset(struct drm_gem_object *obj)
77747dc10d7SGordon Ross {
77847dc10d7SGordon Ross struct ddi_umem_cookie *umem_cookie = obj->maplist.map->umem_cookie;
77947dc10d7SGordon Ross umem_cookie->cvaddr = obj->kaddr;
78047dc10d7SGordon Ross
78147dc10d7SGordon Ross if (obj->maplist.map->gtt_mmap == 0) {
78247dc10d7SGordon Ross gfxp_free_kernel_space(obj->gtt_map_kaddr, obj->real_size);
78347dc10d7SGordon Ross DRM_DEBUG("already freed, don't free more than once!");
78447dc10d7SGordon Ross }
78547dc10d7SGordon Ross
78647dc10d7SGordon Ross if (obj->maplist.map->gtt_mmap == 1) {
78747dc10d7SGordon Ross gfxp_unmap_kernel_space(obj->gtt_map_kaddr, obj->real_size);
78847dc10d7SGordon Ross obj->maplist.map->gtt_mmap = 0;
78947dc10d7SGordon Ross }
79047dc10d7SGordon Ross
79147dc10d7SGordon Ross obj->gtt_map_kaddr = NULL;
79247dc10d7SGordon Ross }
79347dc10d7SGordon Ross
79447dc10d7SGordon Ross void
drm_gem_object_track(struct drm_gem_object * obj,const char * name,uint32_t cur_seq,uint32_t last_seq,void * ptr)79547dc10d7SGordon Ross drm_gem_object_track(struct drm_gem_object *obj, const char *name,
79647dc10d7SGordon Ross uint32_t cur_seq, uint32_t last_seq, void* ptr)
79747dc10d7SGordon Ross {
79847dc10d7SGordon Ross struct drm_history_list *list;
79947dc10d7SGordon Ross list = drm_alloc(sizeof (struct drm_history_list), DRM_MEM_MAPS);
80047dc10d7SGordon Ross if (list != NULL) {
80147dc10d7SGordon Ross (void) memcpy(list->info, name, (strlen(name) * sizeof(char)));
80247dc10d7SGordon Ross list->cur_seq = cur_seq;
80347dc10d7SGordon Ross list->last_seq = last_seq;
80447dc10d7SGordon Ross list->ring_ptr = ptr;
80547dc10d7SGordon Ross list_add_tail(&list->head, &obj->his_list, (caddr_t)list);
80647dc10d7SGordon Ross }
80747dc10d7SGordon Ross }
808