diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/Makefile | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_agpsupport.c | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_cache.c | 76 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_drv.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_gem.c | 420 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_memory.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_mm.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_proc.c | 135 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_stub.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/Makefile | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 94 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 253 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 2497 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_debug.c | 201 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_proc.c | 292 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_tiling.c | 256 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 37 |
20 files changed, 4318 insertions, 62 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index e9f9a97ae00a..74da99495e21 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -4,8 +4,9 @@ | |||
4 | 4 | ||
5 | ccflags-y := -Iinclude/drm | 5 | ccflags-y := -Iinclude/drm |
6 | 6 | ||
7 | drm-y := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ | 7 | drm-y := drm_auth.o drm_bufs.o drm_cache.o \ |
8 | drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ | 8 | drm_context.o drm_dma.o drm_drawable.o \ |
9 | drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ | ||
9 | drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ | 10 | drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ |
10 | drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ | 11 | drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ |
11 | drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o | 12 | drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o |
diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index aefa5ac4c0b1..2639be2db9e5 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c | |||
@@ -33,6 +33,7 @@ | |||
33 | 33 | ||
34 | #include "drmP.h" | 34 | #include "drmP.h" |
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <asm/agp.h> | ||
36 | 37 | ||
37 | #if __OS_HAS_AGP | 38 | #if __OS_HAS_AGP |
38 | 39 | ||
@@ -452,4 +453,52 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle) | |||
452 | return agp_unbind_memory(handle); | 453 | return agp_unbind_memory(handle); |
453 | } | 454 | } |
454 | 455 | ||
455 | #endif /* __OS_HAS_AGP */ | 456 | /** |
457 | * Binds a collection of pages into AGP memory at the given offset, returning | ||
458 | * the AGP memory structure containing them. | ||
459 | * | ||
460 | * No reference is held on the pages during this time -- it is up to the | ||
461 | * caller to handle that. | ||
462 | */ | ||
463 | DRM_AGP_MEM * | ||
464 | drm_agp_bind_pages(struct drm_device *dev, | ||
465 | struct page **pages, | ||
466 | unsigned long num_pages, | ||
467 | uint32_t gtt_offset) | ||
468 | { | ||
469 | DRM_AGP_MEM *mem; | ||
470 | int ret, i; | ||
471 | |||
472 | DRM_DEBUG("\n"); | ||
473 | |||
474 | mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages, | ||
475 | AGP_USER_MEMORY); | ||
476 | if (mem == NULL) { | ||
477 | DRM_ERROR("Failed to allocate memory for %ld pages\n", | ||
478 | num_pages); | ||
479 | return NULL; | ||
480 | } | ||
481 | |||
482 | for (i = 0; i < num_pages; i++) | ||
483 | mem->memory[i] = phys_to_gart(page_to_phys(pages[i])); | ||
484 | mem->page_count = num_pages; | ||
485 | |||
486 | mem->is_flushed = true; | ||
487 | ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE); | ||
488 | if (ret != 0) { | ||
489 | DRM_ERROR("Failed to bind AGP memory: %d\n", ret); | ||
490 | agp_free_memory(mem); | ||
491 | return NULL; | ||
492 | } | ||
493 | |||
494 | return mem; | ||
495 | } | ||
496 | EXPORT_SYMBOL(drm_agp_bind_pages); | ||
497 | |||
498 | void drm_agp_chipset_flush(struct drm_device *dev) | ||
499 | { | ||
500 | agp_flush_chipset(dev->agp->bridge); | ||
501 | } | ||
502 | EXPORT_SYMBOL(drm_agp_chipset_flush); | ||
503 | |||
504 | #endif /* __OS_HAS_AGP */ | ||
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c new file mode 100644 index 000000000000..9475f7d9901d --- /dev/null +++ b/drivers/gpu/drm/drm_cache.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | **************************************************************************/ | ||
27 | /* | ||
28 | * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
29 | */ | ||
30 | |||
31 | #include "drmP.h" | ||
32 | |||
33 | #if defined(CONFIG_X86) | ||
34 | static void | ||
35 | drm_clflush_page(struct page *page) | ||
36 | { | ||
37 | uint8_t *page_virtual; | ||
38 | unsigned int i; | ||
39 | |||
40 | if (unlikely(page == NULL)) | ||
41 | return; | ||
42 | |||
43 | page_virtual = kmap_atomic(page, KM_USER0); | ||
44 | for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) | ||
45 | clflush(page_virtual + i); | ||
46 | kunmap_atomic(page_virtual, KM_USER0); | ||
47 | } | ||
48 | #endif | ||
49 | |||
50 | static void | ||
51 | drm_clflush_ipi_handler(void *null) | ||
52 | { | ||
53 | wbinvd(); | ||
54 | } | ||
55 | |||
56 | void | ||
57 | drm_clflush_pages(struct page *pages[], unsigned long num_pages) | ||
58 | { | ||
59 | |||
60 | #if defined(CONFIG_X86) | ||
61 | if (cpu_has_clflush) { | ||
62 | unsigned long i; | ||
63 | |||
64 | mb(); | ||
65 | for (i = 0; i < num_pages; ++i) | ||
66 | drm_clflush_page(*pages++); | ||
67 | mb(); | ||
68 | |||
69 | return; | ||
70 | } | ||
71 | #endif | ||
72 | |||
73 | if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0) | ||
74 | DRM_ERROR("Timed out waiting for cache flush.\n"); | ||
75 | } | ||
76 | EXPORT_SYMBOL(drm_clflush_pages); | ||
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index fb45fe7aeb8c..96f416afc3f6 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
@@ -119,6 +119,10 @@ static struct drm_ioctl_desc drm_ioctls[] = { | |||
119 | DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), | 119 | DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), |
120 | 120 | ||
121 | DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 121 | DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
122 | |||
123 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0), | ||
124 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), | ||
125 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), | ||
122 | }; | 126 | }; |
123 | 127 | ||
124 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) | 128 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) |
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index dcf8b4dc9549..0d46627663b1 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
@@ -256,6 +256,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
256 | 256 | ||
257 | INIT_LIST_HEAD(&priv->lhead); | 257 | INIT_LIST_HEAD(&priv->lhead); |
258 | 258 | ||
259 | if (dev->driver->driver_features & DRIVER_GEM) | ||
260 | drm_gem_open(dev, priv); | ||
261 | |||
259 | if (dev->driver->open) { | 262 | if (dev->driver->open) { |
260 | ret = dev->driver->open(dev, priv); | 263 | ret = dev->driver->open(dev, priv); |
261 | if (ret < 0) | 264 | if (ret < 0) |
@@ -400,6 +403,9 @@ int drm_release(struct inode *inode, struct file *filp) | |||
400 | dev->driver->reclaim_buffers(dev, file_priv); | 403 | dev->driver->reclaim_buffers(dev, file_priv); |
401 | } | 404 | } |
402 | 405 | ||
406 | if (dev->driver->driver_features & DRIVER_GEM) | ||
407 | drm_gem_release(dev, file_priv); | ||
408 | |||
403 | drm_fasync(-1, filp, 0); | 409 | drm_fasync(-1, filp, 0); |
404 | 410 | ||
405 | mutex_lock(&dev->ctxlist_mutex); | 411 | mutex_lock(&dev->ctxlist_mutex); |
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c new file mode 100644 index 000000000000..434155b387e9 --- /dev/null +++ b/drivers/gpu/drm/drm_gem.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/types.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/uaccess.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/file.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/mman.h> | ||
36 | #include <linux/pagemap.h> | ||
37 | #include "drmP.h" | ||
38 | |||
39 | /** @file drm_gem.c | ||
40 | * | ||
41 | * This file provides some of the base ioctls and library routines for | ||
42 | * the graphics memory manager implemented by each device driver. | ||
43 | * | ||
44 | * Because various devices have different requirements in terms of | ||
45 | * synchronization and migration strategies, implementing that is left up to | ||
46 | * the driver, and all that the general API provides should be generic -- | ||
47 | * allocating objects, reading/writing data with the cpu, freeing objects. | ||
48 | * Even there, platform-dependent optimizations for reading/writing data with | ||
49 | * the CPU mean we'll likely hook those out to driver-specific calls. However, | ||
50 | * the DRI2 implementation wants to have at least allocate/mmap be generic. | ||
51 | * | ||
52 | * The goal was to have swap-backed object allocation managed through | ||
53 | * struct file. However, file descriptors as handles to a struct file have | ||
54 | * two major failings: | ||
55 | * - Process limits prevent more than 1024 or so being used at a time by | ||
56 | * default. | ||
57 | * - Inability to allocate high fds will aggravate the X Server's select() | ||
58 | * handling, and likely that of many GL client applications as well. | ||
59 | * | ||
60 | * This led to a plan of using our own integer IDs (called handles, following | ||
61 | * DRM terminology) to mimic fds, and implement the fd syscalls we need as | ||
62 | * ioctls. The objects themselves will still include the struct file so | ||
63 | * that we can transition to fds if the required kernel infrastructure shows | ||
64 | * up at a later date, and as our interface with shmfs for memory allocation. | ||
65 | */ | ||
66 | |||
67 | /** | ||
68 | * Initialize the GEM device fields | ||
69 | */ | ||
70 | |||
71 | int | ||
72 | drm_gem_init(struct drm_device *dev) | ||
73 | { | ||
74 | spin_lock_init(&dev->object_name_lock); | ||
75 | idr_init(&dev->object_name_idr); | ||
76 | atomic_set(&dev->object_count, 0); | ||
77 | atomic_set(&dev->object_memory, 0); | ||
78 | atomic_set(&dev->pin_count, 0); | ||
79 | atomic_set(&dev->pin_memory, 0); | ||
80 | atomic_set(&dev->gtt_count, 0); | ||
81 | atomic_set(&dev->gtt_memory, 0); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * Allocate a GEM object of the specified size with shmfs backing store | ||
87 | */ | ||
88 | struct drm_gem_object * | ||
89 | drm_gem_object_alloc(struct drm_device *dev, size_t size) | ||
90 | { | ||
91 | struct drm_gem_object *obj; | ||
92 | |||
93 | BUG_ON((size & (PAGE_SIZE - 1)) != 0); | ||
94 | |||
95 | obj = kcalloc(1, sizeof(*obj), GFP_KERNEL); | ||
96 | |||
97 | obj->dev = dev; | ||
98 | obj->filp = shmem_file_setup("drm mm object", size, 0); | ||
99 | if (IS_ERR(obj->filp)) { | ||
100 | kfree(obj); | ||
101 | return NULL; | ||
102 | } | ||
103 | |||
104 | kref_init(&obj->refcount); | ||
105 | kref_init(&obj->handlecount); | ||
106 | obj->size = size; | ||
107 | if (dev->driver->gem_init_object != NULL && | ||
108 | dev->driver->gem_init_object(obj) != 0) { | ||
109 | fput(obj->filp); | ||
110 | kfree(obj); | ||
111 | return NULL; | ||
112 | } | ||
113 | atomic_inc(&dev->object_count); | ||
114 | atomic_add(obj->size, &dev->object_memory); | ||
115 | return obj; | ||
116 | } | ||
117 | EXPORT_SYMBOL(drm_gem_object_alloc); | ||
118 | |||
119 | /** | ||
120 | * Removes the mapping from handle to filp for this object. | ||
121 | */ | ||
122 | static int | ||
123 | drm_gem_handle_delete(struct drm_file *filp, int handle) | ||
124 | { | ||
125 | struct drm_device *dev; | ||
126 | struct drm_gem_object *obj; | ||
127 | |||
128 | /* This is gross. The idr system doesn't let us try a delete and | ||
129 | * return an error code. It just spews if you fail at deleting. | ||
130 | * So, we have to grab a lock around finding the object and then | ||
131 | * doing the delete on it and dropping the refcount, or the user | ||
132 | * could race us to double-decrement the refcount and cause a | ||
133 | * use-after-free later. Given the frequency of our handle lookups, | ||
134 | * we may want to use ida for number allocation and a hash table | ||
135 | * for the pointers, anyway. | ||
136 | */ | ||
137 | spin_lock(&filp->table_lock); | ||
138 | |||
139 | /* Check if we currently have a reference on the object */ | ||
140 | obj = idr_find(&filp->object_idr, handle); | ||
141 | if (obj == NULL) { | ||
142 | spin_unlock(&filp->table_lock); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | dev = obj->dev; | ||
146 | |||
147 | /* Release reference and decrement refcount. */ | ||
148 | idr_remove(&filp->object_idr, handle); | ||
149 | spin_unlock(&filp->table_lock); | ||
150 | |||
151 | mutex_lock(&dev->struct_mutex); | ||
152 | drm_gem_object_handle_unreference(obj); | ||
153 | mutex_unlock(&dev->struct_mutex); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * Create a handle for this object. This adds a handle reference | ||
160 | * to the object, which includes a regular reference count. Callers | ||
161 | * will likely want to dereference the object afterwards. | ||
162 | */ | ||
163 | int | ||
164 | drm_gem_handle_create(struct drm_file *file_priv, | ||
165 | struct drm_gem_object *obj, | ||
166 | int *handlep) | ||
167 | { | ||
168 | int ret; | ||
169 | |||
170 | /* | ||
171 | * Get the user-visible handle using idr. | ||
172 | */ | ||
173 | again: | ||
174 | /* ensure there is space available to allocate a handle */ | ||
175 | if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | /* do the allocation under our spinlock */ | ||
179 | spin_lock(&file_priv->table_lock); | ||
180 | ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep); | ||
181 | spin_unlock(&file_priv->table_lock); | ||
182 | if (ret == -EAGAIN) | ||
183 | goto again; | ||
184 | |||
185 | if (ret != 0) | ||
186 | return ret; | ||
187 | |||
188 | drm_gem_object_handle_reference(obj); | ||
189 | return 0; | ||
190 | } | ||
191 | EXPORT_SYMBOL(drm_gem_handle_create); | ||
192 | |||
193 | /** Returns a reference to the object named by the handle. */ | ||
194 | struct drm_gem_object * | ||
195 | drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, | ||
196 | int handle) | ||
197 | { | ||
198 | struct drm_gem_object *obj; | ||
199 | |||
200 | spin_lock(&filp->table_lock); | ||
201 | |||
202 | /* Check if we currently have a reference on the object */ | ||
203 | obj = idr_find(&filp->object_idr, handle); | ||
204 | if (obj == NULL) { | ||
205 | spin_unlock(&filp->table_lock); | ||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | drm_gem_object_reference(obj); | ||
210 | |||
211 | spin_unlock(&filp->table_lock); | ||
212 | |||
213 | return obj; | ||
214 | } | ||
215 | EXPORT_SYMBOL(drm_gem_object_lookup); | ||
216 | |||
217 | /** | ||
218 | * Releases the handle to an mm object. | ||
219 | */ | ||
220 | int | ||
221 | drm_gem_close_ioctl(struct drm_device *dev, void *data, | ||
222 | struct drm_file *file_priv) | ||
223 | { | ||
224 | struct drm_gem_close *args = data; | ||
225 | int ret; | ||
226 | |||
227 | if (!(dev->driver->driver_features & DRIVER_GEM)) | ||
228 | return -ENODEV; | ||
229 | |||
230 | ret = drm_gem_handle_delete(file_priv, args->handle); | ||
231 | |||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * Create a global name for an object, returning the name. | ||
237 | * | ||
238 | * Note that the name does not hold a reference; when the object | ||
239 | * is freed, the name goes away. | ||
240 | */ | ||
241 | int | ||
242 | drm_gem_flink_ioctl(struct drm_device *dev, void *data, | ||
243 | struct drm_file *file_priv) | ||
244 | { | ||
245 | struct drm_gem_flink *args = data; | ||
246 | struct drm_gem_object *obj; | ||
247 | int ret; | ||
248 | |||
249 | if (!(dev->driver->driver_features & DRIVER_GEM)) | ||
250 | return -ENODEV; | ||
251 | |||
252 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
253 | if (obj == NULL) | ||
254 | return -EINVAL; | ||
255 | |||
256 | again: | ||
257 | if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) | ||
258 | return -ENOMEM; | ||
259 | |||
260 | spin_lock(&dev->object_name_lock); | ||
261 | if (obj->name) { | ||
262 | spin_unlock(&dev->object_name_lock); | ||
263 | return -EEXIST; | ||
264 | } | ||
265 | ret = idr_get_new_above(&dev->object_name_idr, obj, 1, | ||
266 | &obj->name); | ||
267 | spin_unlock(&dev->object_name_lock); | ||
268 | if (ret == -EAGAIN) | ||
269 | goto again; | ||
270 | |||
271 | if (ret != 0) { | ||
272 | mutex_lock(&dev->struct_mutex); | ||
273 | drm_gem_object_unreference(obj); | ||
274 | mutex_unlock(&dev->struct_mutex); | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * Leave the reference from the lookup around as the | ||
280 | * name table now holds one | ||
281 | */ | ||
282 | args->name = (uint64_t) obj->name; | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * Open an object using the global name, returning a handle and the size. | ||
289 | * | ||
290 | * This handle (of course) holds a reference to the object, so the object | ||
291 | * will not go away until the handle is deleted. | ||
292 | */ | ||
293 | int | ||
294 | drm_gem_open_ioctl(struct drm_device *dev, void *data, | ||
295 | struct drm_file *file_priv) | ||
296 | { | ||
297 | struct drm_gem_open *args = data; | ||
298 | struct drm_gem_object *obj; | ||
299 | int ret; | ||
300 | int handle; | ||
301 | |||
302 | if (!(dev->driver->driver_features & DRIVER_GEM)) | ||
303 | return -ENODEV; | ||
304 | |||
305 | spin_lock(&dev->object_name_lock); | ||
306 | obj = idr_find(&dev->object_name_idr, (int) args->name); | ||
307 | if (obj) | ||
308 | drm_gem_object_reference(obj); | ||
309 | spin_unlock(&dev->object_name_lock); | ||
310 | if (!obj) | ||
311 | return -ENOENT; | ||
312 | |||
313 | ret = drm_gem_handle_create(file_priv, obj, &handle); | ||
314 | mutex_lock(&dev->struct_mutex); | ||
315 | drm_gem_object_unreference(obj); | ||
316 | mutex_unlock(&dev->struct_mutex); | ||
317 | if (ret) | ||
318 | return ret; | ||
319 | |||
320 | args->handle = handle; | ||
321 | args->size = obj->size; | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * Called at device open time, sets up the structure for handling refcounting | ||
328 | * of mm objects. | ||
329 | */ | ||
330 | void | ||
331 | drm_gem_open(struct drm_device *dev, struct drm_file *file_private) | ||
332 | { | ||
333 | idr_init(&file_private->object_idr); | ||
334 | spin_lock_init(&file_private->table_lock); | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * Called at device close to release the file's | ||
339 | * handle references on objects. | ||
340 | */ | ||
341 | static int | ||
342 | drm_gem_object_release_handle(int id, void *ptr, void *data) | ||
343 | { | ||
344 | struct drm_gem_object *obj = ptr; | ||
345 | |||
346 | drm_gem_object_handle_unreference(obj); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | /** | ||
352 | * Called at close time when the filp is going away. | ||
353 | * | ||
354 | * Releases any remaining references on objects by this filp. | ||
355 | */ | ||
356 | void | ||
357 | drm_gem_release(struct drm_device *dev, struct drm_file *file_private) | ||
358 | { | ||
359 | mutex_lock(&dev->struct_mutex); | ||
360 | idr_for_each(&file_private->object_idr, | ||
361 | &drm_gem_object_release_handle, NULL); | ||
362 | |||
363 | idr_destroy(&file_private->object_idr); | ||
364 | mutex_unlock(&dev->struct_mutex); | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * Called after the last reference to the object has been lost. | ||
369 | * | ||
370 | * Frees the object | ||
371 | */ | ||
372 | void | ||
373 | drm_gem_object_free(struct kref *kref) | ||
374 | { | ||
375 | struct drm_gem_object *obj = (struct drm_gem_object *) kref; | ||
376 | struct drm_device *dev = obj->dev; | ||
377 | |||
378 | BUG_ON(!mutex_is_locked(&dev->struct_mutex)); | ||
379 | |||
380 | if (dev->driver->gem_free_object != NULL) | ||
381 | dev->driver->gem_free_object(obj); | ||
382 | |||
383 | fput(obj->filp); | ||
384 | atomic_dec(&dev->object_count); | ||
385 | atomic_sub(obj->size, &dev->object_memory); | ||
386 | kfree(obj); | ||
387 | } | ||
388 | EXPORT_SYMBOL(drm_gem_object_free); | ||
389 | |||
390 | /** | ||
391 | * Called after the last handle to the object has been closed | ||
392 | * | ||
393 | * Removes any name for the object. Note that this must be | ||
394 | * called before drm_gem_object_free or we'll be touching | ||
395 | * freed memory | ||
396 | */ | ||
397 | void | ||
398 | drm_gem_object_handle_free(struct kref *kref) | ||
399 | { | ||
400 | struct drm_gem_object *obj = container_of(kref, | ||
401 | struct drm_gem_object, | ||
402 | handlecount); | ||
403 | struct drm_device *dev = obj->dev; | ||
404 | |||
405 | /* Remove any name for this object */ | ||
406 | spin_lock(&dev->object_name_lock); | ||
407 | if (obj->name) { | ||
408 | idr_remove(&dev->object_name_idr, obj->name); | ||
409 | spin_unlock(&dev->object_name_lock); | ||
410 | /* | ||
411 | * The object name held a reference to this object, drop | ||
412 | * that now. | ||
413 | */ | ||
414 | drm_gem_object_unreference(obj); | ||
415 | } else | ||
416 | spin_unlock(&dev->object_name_lock); | ||
417 | |||
418 | } | ||
419 | EXPORT_SYMBOL(drm_gem_object_handle_free); | ||
420 | |||
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index 0177012845c6..803bc9e7ce3c 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c | |||
@@ -133,6 +133,7 @@ int drm_free_agp(DRM_AGP_MEM * handle, int pages) | |||
133 | { | 133 | { |
134 | return drm_agp_free_memory(handle) ? 0 : -EINVAL; | 134 | return drm_agp_free_memory(handle) ? 0 : -EINVAL; |
135 | } | 135 | } |
136 | EXPORT_SYMBOL(drm_free_agp); | ||
136 | 137 | ||
137 | /** Wrapper around agp_bind_memory() */ | 138 | /** Wrapper around agp_bind_memory() */ |
138 | int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start) | 139 | int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start) |
@@ -145,6 +146,7 @@ int drm_unbind_agp(DRM_AGP_MEM * handle) | |||
145 | { | 146 | { |
146 | return drm_agp_unbind_memory(handle); | 147 | return drm_agp_unbind_memory(handle); |
147 | } | 148 | } |
149 | EXPORT_SYMBOL(drm_unbind_agp); | ||
148 | 150 | ||
149 | #else /* __OS_HAS_AGP */ | 151 | #else /* __OS_HAS_AGP */ |
150 | static inline void *agp_remap(unsigned long offset, unsigned long size, | 152 | static inline void *agp_remap(unsigned long offset, unsigned long size, |
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index dcff9e9b52e3..217ad7dc7076 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c | |||
@@ -169,6 +169,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent, | |||
169 | 169 | ||
170 | return child; | 170 | return child; |
171 | } | 171 | } |
172 | EXPORT_SYMBOL(drm_mm_get_block); | ||
172 | 173 | ||
173 | /* | 174 | /* |
174 | * Put a block. Merge with the previous and / or next block if they are free. | 175 | * Put a block. Merge with the previous and / or next block if they are free. |
@@ -217,6 +218,7 @@ void drm_mm_put_block(struct drm_mm_node * cur) | |||
217 | drm_free(cur, sizeof(*cur), DRM_MEM_MM); | 218 | drm_free(cur, sizeof(*cur), DRM_MEM_MM); |
218 | } | 219 | } |
219 | } | 220 | } |
221 | EXPORT_SYMBOL(drm_mm_put_block); | ||
220 | 222 | ||
221 | struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm, | 223 | struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm, |
222 | unsigned long size, | 224 | unsigned long size, |
@@ -265,6 +267,7 @@ int drm_mm_clean(struct drm_mm * mm) | |||
265 | 267 | ||
266 | return (head->next->next == head); | 268 | return (head->next->next == head); |
267 | } | 269 | } |
270 | EXPORT_SYMBOL(drm_mm_search_free); | ||
268 | 271 | ||
269 | int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) | 272 | int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) |
270 | { | 273 | { |
@@ -273,7 +276,7 @@ int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) | |||
273 | 276 | ||
274 | return drm_mm_create_tail_node(mm, start, size); | 277 | return drm_mm_create_tail_node(mm, start, size); |
275 | } | 278 | } |
276 | 279 | EXPORT_SYMBOL(drm_mm_init); | |
277 | 280 | ||
278 | void drm_mm_takedown(struct drm_mm * mm) | 281 | void drm_mm_takedown(struct drm_mm * mm) |
279 | { | 282 | { |
diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c index 93b1e0475c93..d490db4c0de0 100644 --- a/drivers/gpu/drm/drm_proc.c +++ b/drivers/gpu/drm/drm_proc.c | |||
@@ -49,6 +49,10 @@ static int drm_queues_info(char *buf, char **start, off_t offset, | |||
49 | int request, int *eof, void *data); | 49 | int request, int *eof, void *data); |
50 | static int drm_bufs_info(char *buf, char **start, off_t offset, | 50 | static int drm_bufs_info(char *buf, char **start, off_t offset, |
51 | int request, int *eof, void *data); | 51 | int request, int *eof, void *data); |
52 | static int drm_gem_name_info(char *buf, char **start, off_t offset, | ||
53 | int request, int *eof, void *data); | ||
54 | static int drm_gem_object_info(char *buf, char **start, off_t offset, | ||
55 | int request, int *eof, void *data); | ||
52 | #if DRM_DEBUG_CODE | 56 | #if DRM_DEBUG_CODE |
53 | static int drm_vma_info(char *buf, char **start, off_t offset, | 57 | static int drm_vma_info(char *buf, char **start, off_t offset, |
54 | int request, int *eof, void *data); | 58 | int request, int *eof, void *data); |
@@ -60,13 +64,16 @@ static int drm_vma_info(char *buf, char **start, off_t offset, | |||
60 | static struct drm_proc_list { | 64 | static struct drm_proc_list { |
61 | const char *name; /**< file name */ | 65 | const char *name; /**< file name */ |
62 | int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/ | 66 | int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/ |
67 | u32 driver_features; /**< Required driver features for this entry */ | ||
63 | } drm_proc_list[] = { | 68 | } drm_proc_list[] = { |
64 | {"name", drm_name_info}, | 69 | {"name", drm_name_info, 0}, |
65 | {"mem", drm_mem_info}, | 70 | {"mem", drm_mem_info, 0}, |
66 | {"vm", drm_vm_info}, | 71 | {"vm", drm_vm_info, 0}, |
67 | {"clients", drm_clients_info}, | 72 | {"clients", drm_clients_info, 0}, |
68 | {"queues", drm_queues_info}, | 73 | {"queues", drm_queues_info, 0}, |
69 | {"bufs", drm_bufs_info}, | 74 | {"bufs", drm_bufs_info, 0}, |
75 | {"gem_names", drm_gem_name_info, DRIVER_GEM}, | ||
76 | {"gem_objects", drm_gem_object_info, DRIVER_GEM}, | ||
70 | #if DRM_DEBUG_CODE | 77 | #if DRM_DEBUG_CODE |
71 | {"vma", drm_vma_info}, | 78 | {"vma", drm_vma_info}, |
72 | #endif | 79 | #endif |
@@ -90,8 +97,9 @@ static struct drm_proc_list { | |||
90 | int drm_proc_init(struct drm_minor *minor, int minor_id, | 97 | int drm_proc_init(struct drm_minor *minor, int minor_id, |
91 | struct proc_dir_entry *root) | 98 | struct proc_dir_entry *root) |
92 | { | 99 | { |
100 | struct drm_device *dev = minor->dev; | ||
93 | struct proc_dir_entry *ent; | 101 | struct proc_dir_entry *ent; |
94 | int i, j; | 102 | int i, j, ret; |
95 | char name[64]; | 103 | char name[64]; |
96 | 104 | ||
97 | sprintf(name, "%d", minor_id); | 105 | sprintf(name, "%d", minor_id); |
@@ -102,23 +110,42 @@ int drm_proc_init(struct drm_minor *minor, int minor_id, | |||
102 | } | 110 | } |
103 | 111 | ||
104 | for (i = 0; i < DRM_PROC_ENTRIES; i++) { | 112 | for (i = 0; i < DRM_PROC_ENTRIES; i++) { |
113 | u32 features = drm_proc_list[i].driver_features; | ||
114 | |||
115 | if (features != 0 && | ||
116 | (dev->driver->driver_features & features) != features) | ||
117 | continue; | ||
118 | |||
105 | ent = create_proc_entry(drm_proc_list[i].name, | 119 | ent = create_proc_entry(drm_proc_list[i].name, |
106 | S_IFREG | S_IRUGO, minor->dev_root); | 120 | S_IFREG | S_IRUGO, minor->dev_root); |
107 | if (!ent) { | 121 | if (!ent) { |
108 | DRM_ERROR("Cannot create /proc/dri/%s/%s\n", | 122 | DRM_ERROR("Cannot create /proc/dri/%s/%s\n", |
109 | name, drm_proc_list[i].name); | 123 | name, drm_proc_list[i].name); |
110 | for (j = 0; j < i; j++) | 124 | ret = -1; |
111 | remove_proc_entry(drm_proc_list[i].name, | 125 | goto fail; |
112 | minor->dev_root); | ||
113 | remove_proc_entry(name, root); | ||
114 | minor->dev_root = NULL; | ||
115 | return -1; | ||
116 | } | 126 | } |
117 | ent->read_proc = drm_proc_list[i].f; | 127 | ent->read_proc = drm_proc_list[i].f; |
118 | ent->data = minor; | 128 | ent->data = minor; |
119 | } | 129 | } |
120 | 130 | ||
131 | if (dev->driver->proc_init) { | ||
132 | ret = dev->driver->proc_init(minor); | ||
133 | if (ret) { | ||
134 | DRM_ERROR("DRM: Driver failed to initialize " | ||
135 | "/proc/dri.\n"); | ||
136 | goto fail; | ||
137 | } | ||
138 | } | ||
139 | |||
121 | return 0; | 140 | return 0; |
141 | fail: | ||
142 | |||
143 | for (j = 0; j < i; j++) | ||
144 | remove_proc_entry(drm_proc_list[i].name, | ||
145 | minor->dev_root); | ||
146 | remove_proc_entry(name, root); | ||
147 | minor->dev_root = NULL; | ||
148 | return ret; | ||
122 | } | 149 | } |
123 | 150 | ||
124 | /** | 151 | /** |
@@ -133,12 +160,16 @@ int drm_proc_init(struct drm_minor *minor, int minor_id, | |||
133 | */ | 160 | */ |
134 | int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) | 161 | int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) |
135 | { | 162 | { |
163 | struct drm_device *dev = minor->dev; | ||
136 | int i; | 164 | int i; |
137 | char name[64]; | 165 | char name[64]; |
138 | 166 | ||
139 | if (!root || !minor->dev_root) | 167 | if (!root || !minor->dev_root) |
140 | return 0; | 168 | return 0; |
141 | 169 | ||
170 | if (dev->driver->proc_cleanup) | ||
171 | dev->driver->proc_cleanup(minor); | ||
172 | |||
142 | for (i = 0; i < DRM_PROC_ENTRIES; i++) | 173 | for (i = 0; i < DRM_PROC_ENTRIES; i++) |
143 | remove_proc_entry(drm_proc_list[i].name, minor->dev_root); | 174 | remove_proc_entry(drm_proc_list[i].name, minor->dev_root); |
144 | sprintf(name, "%d", minor->index); | 175 | sprintf(name, "%d", minor->index); |
@@ -480,6 +511,84 @@ static int drm_clients_info(char *buf, char **start, off_t offset, | |||
480 | return ret; | 511 | return ret; |
481 | } | 512 | } |
482 | 513 | ||
514 | struct drm_gem_name_info_data { | ||
515 | int len; | ||
516 | char *buf; | ||
517 | int eof; | ||
518 | }; | ||
519 | |||
520 | static int drm_gem_one_name_info(int id, void *ptr, void *data) | ||
521 | { | ||
522 | struct drm_gem_object *obj = ptr; | ||
523 | struct drm_gem_name_info_data *nid = data; | ||
524 | |||
525 | DRM_INFO("name %d size %d\n", obj->name, obj->size); | ||
526 | if (nid->eof) | ||
527 | return 0; | ||
528 | |||
529 | nid->len += sprintf(&nid->buf[nid->len], | ||
530 | "%6d%9d%8d%9d\n", | ||
531 | obj->name, obj->size, | ||
532 | atomic_read(&obj->handlecount.refcount), | ||
533 | atomic_read(&obj->refcount.refcount)); | ||
534 | if (nid->len > DRM_PROC_LIMIT) { | ||
535 | nid->eof = 1; | ||
536 | return 0; | ||
537 | } | ||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int drm_gem_name_info(char *buf, char **start, off_t offset, | ||
542 | int request, int *eof, void *data) | ||
543 | { | ||
544 | struct drm_minor *minor = (struct drm_minor *) data; | ||
545 | struct drm_device *dev = minor->dev; | ||
546 | struct drm_gem_name_info_data nid; | ||
547 | |||
548 | if (offset > DRM_PROC_LIMIT) { | ||
549 | *eof = 1; | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | nid.len = sprintf(buf, " name size handles refcount\n"); | ||
554 | nid.buf = buf; | ||
555 | nid.eof = 0; | ||
556 | idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, &nid); | ||
557 | |||
558 | *start = &buf[offset]; | ||
559 | *eof = 0; | ||
560 | if (nid.len > request + offset) | ||
561 | return request; | ||
562 | *eof = 1; | ||
563 | return nid.len - offset; | ||
564 | } | ||
565 | |||
566 | static int drm_gem_object_info(char *buf, char **start, off_t offset, | ||
567 | int request, int *eof, void *data) | ||
568 | { | ||
569 | struct drm_minor *minor = (struct drm_minor *) data; | ||
570 | struct drm_device *dev = minor->dev; | ||
571 | int len = 0; | ||
572 | |||
573 | if (offset > DRM_PROC_LIMIT) { | ||
574 | *eof = 1; | ||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | *start = &buf[offset]; | ||
579 | *eof = 0; | ||
580 | DRM_PROC_PRINT("%d objects\n", atomic_read(&dev->object_count)); | ||
581 | DRM_PROC_PRINT("%d object bytes\n", atomic_read(&dev->object_memory)); | ||
582 | DRM_PROC_PRINT("%d pinned\n", atomic_read(&dev->pin_count)); | ||
583 | DRM_PROC_PRINT("%d pin bytes\n", atomic_read(&dev->pin_memory)); | ||
584 | DRM_PROC_PRINT("%d gtt bytes\n", atomic_read(&dev->gtt_memory)); | ||
585 | DRM_PROC_PRINT("%d gtt total\n", dev->gtt_total); | ||
586 | if (len > request + offset) | ||
587 | return request; | ||
588 | *eof = 1; | ||
589 | return len - offset; | ||
590 | } | ||
591 | |||
483 | #if DRM_DEBUG_CODE | 592 | #if DRM_DEBUG_CODE |
484 | 593 | ||
485 | static int drm__vma_info(char *buf, char **start, off_t offset, int request, | 594 | static int drm__vma_info(char *buf, char **start, off_t offset, int request, |
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index c2f584f3b46c..82f4657b8879 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c | |||
@@ -152,6 +152,15 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, | |||
152 | goto error_out_unreg; | 152 | goto error_out_unreg; |
153 | } | 153 | } |
154 | 154 | ||
155 | if (driver->driver_features & DRIVER_GEM) { | ||
156 | retcode = drm_gem_init(dev); | ||
157 | if (retcode) { | ||
158 | DRM_ERROR("Cannot initialize graphics execution " | ||
159 | "manager (GEM)\n"); | ||
160 | goto error_out_unreg; | ||
161 | } | ||
162 | } | ||
163 | |||
155 | return 0; | 164 | return 0; |
156 | 165 | ||
157 | error_out_unreg: | 166 | error_out_unreg: |
@@ -317,6 +326,7 @@ int drm_put_dev(struct drm_device * dev) | |||
317 | int drm_put_minor(struct drm_minor **minor_p) | 326 | int drm_put_minor(struct drm_minor **minor_p) |
318 | { | 327 | { |
319 | struct drm_minor *minor = *minor_p; | 328 | struct drm_minor *minor = *minor_p; |
329 | |||
320 | DRM_DEBUG("release secondary minor %d\n", minor->index); | 330 | DRM_DEBUG("release secondary minor %d\n", minor->index); |
321 | 331 | ||
322 | if (minor->type == DRM_MINOR_LEGACY) | 332 | if (minor->type == DRM_MINOR_LEGACY) |
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index c4bbda662e26..5ba78e4fd2b5 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile | |||
@@ -4,7 +4,11 @@ | |||
4 | 4 | ||
5 | ccflags-y := -Iinclude/drm | 5 | ccflags-y := -Iinclude/drm |
6 | i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_opregion.o \ | 6 | i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_opregion.o \ |
7 | i915_suspend.o | 7 | i915_suspend.o \ |
8 | i915_gem.o \ | ||
9 | i915_gem_debug.o \ | ||
10 | i915_gem_proc.o \ | ||
11 | i915_gem_tiling.o | ||
8 | 12 | ||
9 | i915-$(CONFIG_COMPAT) += i915_ioc32.o | 13 | i915-$(CONFIG_COMPAT) += i915_ioc32.o |
10 | 14 | ||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 63c6803d471b..f167ff68a4bf 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -170,24 +170,31 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) | |||
170 | dev_priv->sarea_priv = (drm_i915_sarea_t *) | 170 | dev_priv->sarea_priv = (drm_i915_sarea_t *) |
171 | ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); | 171 | ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); |
172 | 172 | ||
173 | dev_priv->ring.Start = init->ring_start; | 173 | if (init->ring_size != 0) { |
174 | dev_priv->ring.End = init->ring_end; | 174 | if (dev_priv->ring.ring_obj != NULL) { |
175 | dev_priv->ring.Size = init->ring_size; | 175 | i915_dma_cleanup(dev); |
176 | dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; | 176 | DRM_ERROR("Client tried to initialize ringbuffer in " |
177 | "GEM mode\n"); | ||
178 | return -EINVAL; | ||
179 | } | ||
177 | 180 | ||
178 | dev_priv->ring.map.offset = init->ring_start; | 181 | dev_priv->ring.Size = init->ring_size; |
179 | dev_priv->ring.map.size = init->ring_size; | 182 | dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; |
180 | dev_priv->ring.map.type = 0; | ||
181 | dev_priv->ring.map.flags = 0; | ||
182 | dev_priv->ring.map.mtrr = 0; | ||
183 | 183 | ||
184 | drm_core_ioremap(&dev_priv->ring.map, dev); | 184 | dev_priv->ring.map.offset = init->ring_start; |
185 | dev_priv->ring.map.size = init->ring_size; | ||
186 | dev_priv->ring.map.type = 0; | ||
187 | dev_priv->ring.map.flags = 0; | ||
188 | dev_priv->ring.map.mtrr = 0; | ||
185 | 189 | ||
186 | if (dev_priv->ring.map.handle == NULL) { | 190 | drm_core_ioremap(&dev_priv->ring.map, dev); |
187 | i915_dma_cleanup(dev); | 191 | |
188 | DRM_ERROR("can not ioremap virtual address for" | 192 | if (dev_priv->ring.map.handle == NULL) { |
189 | " ring buffer\n"); | 193 | i915_dma_cleanup(dev); |
190 | return -ENOMEM; | 194 | DRM_ERROR("can not ioremap virtual address for" |
195 | " ring buffer\n"); | ||
196 | return -ENOMEM; | ||
197 | } | ||
191 | } | 198 | } |
192 | 199 | ||
193 | dev_priv->ring.virtual_start = dev_priv->ring.map.handle; | 200 | dev_priv->ring.virtual_start = dev_priv->ring.map.handle; |
@@ -377,9 +384,10 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor | |||
377 | return 0; | 384 | return 0; |
378 | } | 385 | } |
379 | 386 | ||
380 | static int i915_emit_box(struct drm_device * dev, | 387 | int |
381 | struct drm_clip_rect __user * boxes, | 388 | i915_emit_box(struct drm_device *dev, |
382 | int i, int DR1, int DR4) | 389 | struct drm_clip_rect __user *boxes, |
390 | int i, int DR1, int DR4) | ||
383 | { | 391 | { |
384 | drm_i915_private_t *dev_priv = dev->dev_private; | 392 | drm_i915_private_t *dev_priv = dev->dev_private; |
385 | struct drm_clip_rect box; | 393 | struct drm_clip_rect box; |
@@ -681,6 +689,9 @@ static int i915_getparam(struct drm_device *dev, void *data, | |||
681 | case I915_PARAM_LAST_DISPATCH: | 689 | case I915_PARAM_LAST_DISPATCH: |
682 | value = READ_BREADCRUMB(dev_priv); | 690 | value = READ_BREADCRUMB(dev_priv); |
683 | break; | 691 | break; |
692 | case I915_PARAM_HAS_GEM: | ||
693 | value = 1; | ||
694 | break; | ||
684 | default: | 695 | default: |
685 | DRM_ERROR("Unknown parameter %d\n", param->param); | 696 | DRM_ERROR("Unknown parameter %d\n", param->param); |
686 | return -EINVAL; | 697 | return -EINVAL; |
@@ -784,6 +795,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
784 | memset(dev_priv, 0, sizeof(drm_i915_private_t)); | 795 | memset(dev_priv, 0, sizeof(drm_i915_private_t)); |
785 | 796 | ||
786 | dev->dev_private = (void *)dev_priv; | 797 | dev->dev_private = (void *)dev_priv; |
798 | dev_priv->dev = dev; | ||
787 | 799 | ||
788 | /* Add register map (needed for suspend/resume) */ | 800 | /* Add register map (needed for suspend/resume) */ |
789 | base = drm_get_resource_start(dev, mmio_bar); | 801 | base = drm_get_resource_start(dev, mmio_bar); |
@@ -793,6 +805,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
793 | _DRM_KERNEL | _DRM_DRIVER, | 805 | _DRM_KERNEL | _DRM_DRIVER, |
794 | &dev_priv->mmio_map); | 806 | &dev_priv->mmio_map); |
795 | 807 | ||
808 | i915_gem_load(dev); | ||
809 | |||
796 | /* Init HWS */ | 810 | /* Init HWS */ |
797 | if (!I915_NEED_GFX_HWS(dev)) { | 811 | if (!I915_NEED_GFX_HWS(dev)) { |
798 | ret = i915_init_phys_hws(dev); | 812 | ret = i915_init_phys_hws(dev); |
@@ -838,6 +852,25 @@ int i915_driver_unload(struct drm_device *dev) | |||
838 | return 0; | 852 | return 0; |
839 | } | 853 | } |
840 | 854 | ||
855 | int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) | ||
856 | { | ||
857 | struct drm_i915_file_private *i915_file_priv; | ||
858 | |||
859 | DRM_DEBUG("\n"); | ||
860 | i915_file_priv = (struct drm_i915_file_private *) | ||
861 | drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES); | ||
862 | |||
863 | if (!i915_file_priv) | ||
864 | return -ENOMEM; | ||
865 | |||
866 | file_priv->driver_priv = i915_file_priv; | ||
867 | |||
868 | i915_file_priv->mm.last_gem_seqno = 0; | ||
869 | i915_file_priv->mm.last_gem_throttle_seqno = 0; | ||
870 | |||
871 | return 0; | ||
872 | } | ||
873 | |||
841 | void i915_driver_lastclose(struct drm_device * dev) | 874 | void i915_driver_lastclose(struct drm_device * dev) |
842 | { | 875 | { |
843 | drm_i915_private_t *dev_priv = dev->dev_private; | 876 | drm_i915_private_t *dev_priv = dev->dev_private; |
@@ -845,6 +878,8 @@ void i915_driver_lastclose(struct drm_device * dev) | |||
845 | if (!dev_priv) | 878 | if (!dev_priv) |
846 | return; | 879 | return; |
847 | 880 | ||
881 | i915_gem_lastclose(dev); | ||
882 | |||
848 | if (dev_priv->agp_heap) | 883 | if (dev_priv->agp_heap) |
849 | i915_mem_takedown(&(dev_priv->agp_heap)); | 884 | i915_mem_takedown(&(dev_priv->agp_heap)); |
850 | 885 | ||
@@ -857,6 +892,13 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) | |||
857 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); | 892 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); |
858 | } | 893 | } |
859 | 894 | ||
895 | void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) | ||
896 | { | ||
897 | struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; | ||
898 | |||
899 | drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES); | ||
900 | } | ||
901 | |||
860 | struct drm_ioctl_desc i915_ioctls[] = { | 902 | struct drm_ioctl_desc i915_ioctls[] = { |
861 | DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 903 | DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
862 | DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), | 904 | DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), |
@@ -875,6 +917,22 @@ struct drm_ioctl_desc i915_ioctls[] = { | |||
875 | DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), | 917 | DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), |
876 | DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), | 918 | DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), |
877 | DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH), | 919 | DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH), |
920 | DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH), | ||
921 | DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH), | ||
922 | DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), | ||
923 | DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), | ||
924 | DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH), | ||
925 | DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH), | ||
926 | DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH), | ||
927 | DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH), | ||
928 | DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0), | ||
929 | DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0), | ||
930 | DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0), | ||
931 | DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), | ||
932 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0), | ||
933 | DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0), | ||
934 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0), | ||
935 | DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0), | ||
878 | }; | 936 | }; |
879 | 937 | ||
880 | int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); | 938 | int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 37af03f4db36..a80ead215282 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -85,12 +85,15 @@ static struct drm_driver driver = { | |||
85 | /* don't use mtrr's here, the Xserver or user space app should | 85 | /* don't use mtrr's here, the Xserver or user space app should |
86 | * deal with them for intel hardware. | 86 | * deal with them for intel hardware. |
87 | */ | 87 | */ |
88 | .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | | 88 | .driver_features = |
89 | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, | 89 | DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ |
90 | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM, | ||
90 | .load = i915_driver_load, | 91 | .load = i915_driver_load, |
91 | .unload = i915_driver_unload, | 92 | .unload = i915_driver_unload, |
93 | .open = i915_driver_open, | ||
92 | .lastclose = i915_driver_lastclose, | 94 | .lastclose = i915_driver_lastclose, |
93 | .preclose = i915_driver_preclose, | 95 | .preclose = i915_driver_preclose, |
96 | .postclose = i915_driver_postclose, | ||
94 | .suspend = i915_suspend, | 97 | .suspend = i915_suspend, |
95 | .resume = i915_resume, | 98 | .resume = i915_resume, |
96 | .device_is_agp = i915_driver_device_is_agp, | 99 | .device_is_agp = i915_driver_device_is_agp, |
@@ -104,6 +107,10 @@ static struct drm_driver driver = { | |||
104 | .reclaim_buffers = drm_core_reclaim_buffers, | 107 | .reclaim_buffers = drm_core_reclaim_buffers, |
105 | .get_map_ofs = drm_core_get_map_ofs, | 108 | .get_map_ofs = drm_core_get_map_ofs, |
106 | .get_reg_ofs = drm_core_get_reg_ofs, | 109 | .get_reg_ofs = drm_core_get_reg_ofs, |
110 | .proc_init = i915_gem_proc_init, | ||
111 | .proc_cleanup = i915_gem_proc_cleanup, | ||
112 | .gem_init_object = i915_gem_init_object, | ||
113 | .gem_free_object = i915_gem_free_object, | ||
107 | .ioctls = i915_ioctls, | 114 | .ioctls = i915_ioctls, |
108 | .fops = { | 115 | .fops = { |
109 | .owner = THIS_MODULE, | 116 | .owner = THIS_MODULE, |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d1a02bead458..87b071ab8647 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -39,7 +39,7 @@ | |||
39 | 39 | ||
40 | #define DRIVER_NAME "i915" | 40 | #define DRIVER_NAME "i915" |
41 | #define DRIVER_DESC "Intel Graphics" | 41 | #define DRIVER_DESC "Intel Graphics" |
42 | #define DRIVER_DATE "20060119" | 42 | #define DRIVER_DATE "20080730" |
43 | 43 | ||
44 | enum pipe { | 44 | enum pipe { |
45 | PIPE_A = 0, | 45 | PIPE_A = 0, |
@@ -60,16 +60,23 @@ enum pipe { | |||
60 | #define DRIVER_MINOR 6 | 60 | #define DRIVER_MINOR 6 |
61 | #define DRIVER_PATCHLEVEL 0 | 61 | #define DRIVER_PATCHLEVEL 0 |
62 | 62 | ||
63 | #define WATCH_COHERENCY 0 | ||
64 | #define WATCH_BUF 0 | ||
65 | #define WATCH_EXEC 0 | ||
66 | #define WATCH_LRU 0 | ||
67 | #define WATCH_RELOC 0 | ||
68 | #define WATCH_INACTIVE 0 | ||
69 | #define WATCH_PWRITE 0 | ||
70 | |||
63 | typedef struct _drm_i915_ring_buffer { | 71 | typedef struct _drm_i915_ring_buffer { |
64 | int tail_mask; | 72 | int tail_mask; |
65 | unsigned long Start; | ||
66 | unsigned long End; | ||
67 | unsigned long Size; | 73 | unsigned long Size; |
68 | u8 *virtual_start; | 74 | u8 *virtual_start; |
69 | int head; | 75 | int head; |
70 | int tail; | 76 | int tail; |
71 | int space; | 77 | int space; |
72 | drm_local_map_t map; | 78 | drm_local_map_t map; |
79 | struct drm_gem_object *ring_obj; | ||
73 | } drm_i915_ring_buffer_t; | 80 | } drm_i915_ring_buffer_t; |
74 | 81 | ||
75 | struct mem_block { | 82 | struct mem_block { |
@@ -101,6 +108,8 @@ struct intel_opregion { | |||
101 | }; | 108 | }; |
102 | 109 | ||
103 | typedef struct drm_i915_private { | 110 | typedef struct drm_i915_private { |
111 | struct drm_device *dev; | ||
112 | |||
104 | drm_local_map_t *sarea; | 113 | drm_local_map_t *sarea; |
105 | drm_local_map_t *mmio_map; | 114 | drm_local_map_t *mmio_map; |
106 | 115 | ||
@@ -113,6 +122,7 @@ typedef struct drm_i915_private { | |||
113 | uint32_t counter; | 122 | uint32_t counter; |
114 | unsigned int status_gfx_addr; | 123 | unsigned int status_gfx_addr; |
115 | drm_local_map_t hws_map; | 124 | drm_local_map_t hws_map; |
125 | struct drm_gem_object *hws_obj; | ||
116 | 126 | ||
117 | unsigned int cpp; | 127 | unsigned int cpp; |
118 | int back_offset; | 128 | int back_offset; |
@@ -122,7 +132,6 @@ typedef struct drm_i915_private { | |||
122 | 132 | ||
123 | wait_queue_head_t irq_queue; | 133 | wait_queue_head_t irq_queue; |
124 | atomic_t irq_received; | 134 | atomic_t irq_received; |
125 | atomic_t irq_emitted; | ||
126 | /** Protects user_irq_refcount and irq_mask_reg */ | 135 | /** Protects user_irq_refcount and irq_mask_reg */ |
127 | spinlock_t user_irq_lock; | 136 | spinlock_t user_irq_lock; |
128 | /** Refcount for i915_user_irq_get() versus i915_user_irq_put(). */ | 137 | /** Refcount for i915_user_irq_get() versus i915_user_irq_put(). */ |
@@ -230,8 +239,174 @@ typedef struct drm_i915_private { | |||
230 | u8 saveDACMASK; | 239 | u8 saveDACMASK; |
231 | u8 saveDACDATA[256*3]; /* 256 3-byte colors */ | 240 | u8 saveDACDATA[256*3]; /* 256 3-byte colors */ |
232 | u8 saveCR[37]; | 241 | u8 saveCR[37]; |
242 | |||
243 | struct { | ||
244 | struct drm_mm gtt_space; | ||
245 | |||
246 | /** | ||
247 | * List of objects currently involved in rendering from the | ||
248 | * ringbuffer. | ||
249 | * | ||
250 | * A reference is held on the buffer while on this list. | ||
251 | */ | ||
252 | struct list_head active_list; | ||
253 | |||
254 | /** | ||
255 | * List of objects which are not in the ringbuffer but which | ||
256 | * still have a write_domain which needs to be flushed before | ||
257 | * unbinding. | ||
258 | * | ||
259 | * A reference is held on the buffer while on this list. | ||
260 | */ | ||
261 | struct list_head flushing_list; | ||
262 | |||
263 | /** | ||
264 | * LRU list of objects which are not in the ringbuffer and | ||
265 | * are ready to unbind, but are still in the GTT. | ||
266 | * | ||
267 | * A reference is not held on the buffer while on this list, | ||
268 | * as merely being GTT-bound shouldn't prevent its being | ||
269 | * freed, and we'll pull it off the list in the free path. | ||
270 | */ | ||
271 | struct list_head inactive_list; | ||
272 | |||
273 | /** | ||
274 | * List of breadcrumbs associated with GPU requests currently | ||
275 | * outstanding. | ||
276 | */ | ||
277 | struct list_head request_list; | ||
278 | |||
279 | /** | ||
280 | * We leave the user IRQ off as much as possible, | ||
281 | * but this means that requests will finish and never | ||
282 | * be retired once the system goes idle. Set a timer to | ||
283 | * fire periodically while the ring is running. When it | ||
284 | * fires, go retire requests. | ||
285 | */ | ||
286 | struct delayed_work retire_work; | ||
287 | |||
288 | uint32_t next_gem_seqno; | ||
289 | |||
290 | /** | ||
291 | * Waiting sequence number, if any | ||
292 | */ | ||
293 | uint32_t waiting_gem_seqno; | ||
294 | |||
295 | /** | ||
296 | * Last seq seen at irq time | ||
297 | */ | ||
298 | uint32_t irq_gem_seqno; | ||
299 | |||
300 | /** | ||
301 | * Flag if the X Server, and thus DRM, is not currently in | ||
302 | * control of the device. | ||
303 | * | ||
304 | * This is set between LeaveVT and EnterVT. It needs to be | ||
305 | * replaced with a semaphore. It also needs to be | ||
306 | * transitioned away from for kernel modesetting. | ||
307 | */ | ||
308 | int suspended; | ||
309 | |||
310 | /** | ||
311 | * Flag if the hardware appears to be wedged. | ||
312 | * | ||
313 | * This is set when attempts to idle the device timeout. | ||
314 | * It prevents command submission from occuring and makes | ||
315 | * every pending request fail | ||
316 | */ | ||
317 | int wedged; | ||
318 | |||
319 | /** Bit 6 swizzling required for X tiling */ | ||
320 | uint32_t bit_6_swizzle_x; | ||
321 | /** Bit 6 swizzling required for Y tiling */ | ||
322 | uint32_t bit_6_swizzle_y; | ||
323 | } mm; | ||
233 | } drm_i915_private_t; | 324 | } drm_i915_private_t; |
234 | 325 | ||
326 | /** driver private structure attached to each drm_gem_object */ | ||
327 | struct drm_i915_gem_object { | ||
328 | struct drm_gem_object *obj; | ||
329 | |||
330 | /** Current space allocated to this object in the GTT, if any. */ | ||
331 | struct drm_mm_node *gtt_space; | ||
332 | |||
333 | /** This object's place on the active/flushing/inactive lists */ | ||
334 | struct list_head list; | ||
335 | |||
336 | /** | ||
337 | * This is set if the object is on the active or flushing lists | ||
338 | * (has pending rendering), and is not set if it's on inactive (ready | ||
339 | * to be unbound). | ||
340 | */ | ||
341 | int active; | ||
342 | |||
343 | /** | ||
344 | * This is set if the object has been written to since last bound | ||
345 | * to the GTT | ||
346 | */ | ||
347 | int dirty; | ||
348 | |||
349 | /** AGP memory structure for our GTT binding. */ | ||
350 | DRM_AGP_MEM *agp_mem; | ||
351 | |||
352 | struct page **page_list; | ||
353 | |||
354 | /** | ||
355 | * Current offset of the object in GTT space. | ||
356 | * | ||
357 | * This is the same as gtt_space->start | ||
358 | */ | ||
359 | uint32_t gtt_offset; | ||
360 | |||
361 | /** Boolean whether this object has a valid gtt offset. */ | ||
362 | int gtt_bound; | ||
363 | |||
364 | /** How many users have pinned this object in GTT space */ | ||
365 | int pin_count; | ||
366 | |||
367 | /** Breadcrumb of last rendering to the buffer. */ | ||
368 | uint32_t last_rendering_seqno; | ||
369 | |||
370 | /** Current tiling mode for the object. */ | ||
371 | uint32_t tiling_mode; | ||
372 | |||
373 | /** | ||
374 | * Flagging of which individual pages are valid in GEM_DOMAIN_CPU when | ||
375 | * GEM_DOMAIN_CPU is not in the object's read domain. | ||
376 | */ | ||
377 | uint8_t *page_cpu_valid; | ||
378 | }; | ||
379 | |||
380 | /** | ||
381 | * Request queue structure. | ||
382 | * | ||
383 | * The request queue allows us to note sequence numbers that have been emitted | ||
384 | * and may be associated with active buffers to be retired. | ||
385 | * | ||
386 | * By keeping this list, we can avoid having to do questionable | ||
387 | * sequence-number comparisons on buffer last_rendering_seqnos, and associate | ||
388 | * an emission time with seqnos for tracking how far ahead of the GPU we are. | ||
389 | */ | ||
390 | struct drm_i915_gem_request { | ||
391 | /** GEM sequence number associated with this request. */ | ||
392 | uint32_t seqno; | ||
393 | |||
394 | /** Time at which this request was emitted, in jiffies. */ | ||
395 | unsigned long emitted_jiffies; | ||
396 | |||
397 | /** Cache domains that were flushed at the start of the request. */ | ||
398 | uint32_t flush_domains; | ||
399 | |||
400 | struct list_head list; | ||
401 | }; | ||
402 | |||
403 | struct drm_i915_file_private { | ||
404 | struct { | ||
405 | uint32_t last_gem_seqno; | ||
406 | uint32_t last_gem_throttle_seqno; | ||
407 | } mm; | ||
408 | }; | ||
409 | |||
235 | extern struct drm_ioctl_desc i915_ioctls[]; | 410 | extern struct drm_ioctl_desc i915_ioctls[]; |
236 | extern int i915_max_ioctl; | 411 | extern int i915_max_ioctl; |
237 | 412 | ||
@@ -239,18 +414,26 @@ extern int i915_max_ioctl; | |||
239 | extern void i915_kernel_lost_context(struct drm_device * dev); | 414 | extern void i915_kernel_lost_context(struct drm_device * dev); |
240 | extern int i915_driver_load(struct drm_device *, unsigned long flags); | 415 | extern int i915_driver_load(struct drm_device *, unsigned long flags); |
241 | extern int i915_driver_unload(struct drm_device *); | 416 | extern int i915_driver_unload(struct drm_device *); |
417 | extern int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv); | ||
242 | extern void i915_driver_lastclose(struct drm_device * dev); | 418 | extern void i915_driver_lastclose(struct drm_device * dev); |
243 | extern void i915_driver_preclose(struct drm_device *dev, | 419 | extern void i915_driver_preclose(struct drm_device *dev, |
244 | struct drm_file *file_priv); | 420 | struct drm_file *file_priv); |
421 | extern void i915_driver_postclose(struct drm_device *dev, | ||
422 | struct drm_file *file_priv); | ||
245 | extern int i915_driver_device_is_agp(struct drm_device * dev); | 423 | extern int i915_driver_device_is_agp(struct drm_device * dev); |
246 | extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, | 424 | extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, |
247 | unsigned long arg); | 425 | unsigned long arg); |
426 | extern int i915_emit_box(struct drm_device *dev, | ||
427 | struct drm_clip_rect __user *boxes, | ||
428 | int i, int DR1, int DR4); | ||
248 | 429 | ||
249 | /* i915_irq.c */ | 430 | /* i915_irq.c */ |
250 | extern int i915_irq_emit(struct drm_device *dev, void *data, | 431 | extern int i915_irq_emit(struct drm_device *dev, void *data, |
251 | struct drm_file *file_priv); | 432 | struct drm_file *file_priv); |
252 | extern int i915_irq_wait(struct drm_device *dev, void *data, | 433 | extern int i915_irq_wait(struct drm_device *dev, void *data, |
253 | struct drm_file *file_priv); | 434 | struct drm_file *file_priv); |
435 | void i915_user_irq_get(struct drm_device *dev); | ||
436 | void i915_user_irq_put(struct drm_device *dev); | ||
254 | 437 | ||
255 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); | 438 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); |
256 | extern void i915_driver_irq_preinstall(struct drm_device * dev); | 439 | extern void i915_driver_irq_preinstall(struct drm_device * dev); |
@@ -279,6 +462,67 @@ extern int i915_mem_destroy_heap(struct drm_device *dev, void *data, | |||
279 | extern void i915_mem_takedown(struct mem_block **heap); | 462 | extern void i915_mem_takedown(struct mem_block **heap); |
280 | extern void i915_mem_release(struct drm_device * dev, | 463 | extern void i915_mem_release(struct drm_device * dev, |
281 | struct drm_file *file_priv, struct mem_block *heap); | 464 | struct drm_file *file_priv, struct mem_block *heap); |
465 | /* i915_gem.c */ | ||
466 | int i915_gem_init_ioctl(struct drm_device *dev, void *data, | ||
467 | struct drm_file *file_priv); | ||
468 | int i915_gem_create_ioctl(struct drm_device *dev, void *data, | ||
469 | struct drm_file *file_priv); | ||
470 | int i915_gem_pread_ioctl(struct drm_device *dev, void *data, | ||
471 | struct drm_file *file_priv); | ||
472 | int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | ||
473 | struct drm_file *file_priv); | ||
474 | int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, | ||
475 | struct drm_file *file_priv); | ||
476 | int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, | ||
477 | struct drm_file *file_priv); | ||
478 | int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, | ||
479 | struct drm_file *file_priv); | ||
480 | int i915_gem_execbuffer(struct drm_device *dev, void *data, | ||
481 | struct drm_file *file_priv); | ||
482 | int i915_gem_pin_ioctl(struct drm_device *dev, void *data, | ||
483 | struct drm_file *file_priv); | ||
484 | int i915_gem_unpin_ioctl(struct drm_device *dev, void *data, | ||
485 | struct drm_file *file_priv); | ||
486 | int i915_gem_busy_ioctl(struct drm_device *dev, void *data, | ||
487 | struct drm_file *file_priv); | ||
488 | int i915_gem_throttle_ioctl(struct drm_device *dev, void *data, | ||
489 | struct drm_file *file_priv); | ||
490 | int i915_gem_entervt_ioctl(struct drm_device *dev, void *data, | ||
491 | struct drm_file *file_priv); | ||
492 | int i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, | ||
493 | struct drm_file *file_priv); | ||
494 | int i915_gem_set_tiling(struct drm_device *dev, void *data, | ||
495 | struct drm_file *file_priv); | ||
496 | int i915_gem_get_tiling(struct drm_device *dev, void *data, | ||
497 | struct drm_file *file_priv); | ||
498 | void i915_gem_load(struct drm_device *dev); | ||
499 | int i915_gem_proc_init(struct drm_minor *minor); | ||
500 | void i915_gem_proc_cleanup(struct drm_minor *minor); | ||
501 | int i915_gem_init_object(struct drm_gem_object *obj); | ||
502 | void i915_gem_free_object(struct drm_gem_object *obj); | ||
503 | int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment); | ||
504 | void i915_gem_object_unpin(struct drm_gem_object *obj); | ||
505 | void i915_gem_lastclose(struct drm_device *dev); | ||
506 | uint32_t i915_get_gem_seqno(struct drm_device *dev); | ||
507 | void i915_gem_retire_requests(struct drm_device *dev); | ||
508 | void i915_gem_retire_work_handler(struct work_struct *work); | ||
509 | void i915_gem_clflush_object(struct drm_gem_object *obj); | ||
510 | |||
511 | /* i915_gem_tiling.c */ | ||
512 | void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); | ||
513 | |||
514 | /* i915_gem_debug.c */ | ||
515 | void i915_gem_dump_object(struct drm_gem_object *obj, int len, | ||
516 | const char *where, uint32_t mark); | ||
517 | #if WATCH_INACTIVE | ||
518 | void i915_verify_inactive(struct drm_device *dev, char *file, int line); | ||
519 | #else | ||
520 | #define i915_verify_inactive(dev, file, line) | ||
521 | #endif | ||
522 | void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle); | ||
523 | void i915_gem_dump_object(struct drm_gem_object *obj, int len, | ||
524 | const char *where, uint32_t mark); | ||
525 | void i915_dump_lru(struct drm_device *dev, const char *where); | ||
282 | 526 | ||
283 | /* i915_suspend.c */ | 527 | /* i915_suspend.c */ |
284 | extern int i915_save_state(struct drm_device *dev); | 528 | extern int i915_save_state(struct drm_device *dev); |
@@ -347,6 +591,7 @@ extern void opregion_enable_asle(struct drm_device *dev); | |||
347 | */ | 591 | */ |
348 | #define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) | 592 | #define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) |
349 | #define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, 5) | 593 | #define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, 5) |
594 | #define I915_GEM_HWS_INDEX 0x10 | ||
350 | 595 | ||
351 | extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | 596 | extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); |
352 | 597 | ||
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c new file mode 100644 index 000000000000..90ae8a0369f7 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -0,0 +1,2497 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "drmP.h" | ||
29 | #include "drm.h" | ||
30 | #include "i915_drm.h" | ||
31 | #include "i915_drv.h" | ||
32 | #include <linux/swap.h> | ||
33 | |||
34 | static int | ||
35 | i915_gem_object_set_domain(struct drm_gem_object *obj, | ||
36 | uint32_t read_domains, | ||
37 | uint32_t write_domain); | ||
38 | static int | ||
39 | i915_gem_object_set_domain_range(struct drm_gem_object *obj, | ||
40 | uint64_t offset, | ||
41 | uint64_t size, | ||
42 | uint32_t read_domains, | ||
43 | uint32_t write_domain); | ||
44 | static int | ||
45 | i915_gem_set_domain(struct drm_gem_object *obj, | ||
46 | struct drm_file *file_priv, | ||
47 | uint32_t read_domains, | ||
48 | uint32_t write_domain); | ||
49 | static int i915_gem_object_get_page_list(struct drm_gem_object *obj); | ||
50 | static void i915_gem_object_free_page_list(struct drm_gem_object *obj); | ||
51 | static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); | ||
52 | |||
53 | int | ||
54 | i915_gem_init_ioctl(struct drm_device *dev, void *data, | ||
55 | struct drm_file *file_priv) | ||
56 | { | ||
57 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
58 | struct drm_i915_gem_init *args = data; | ||
59 | |||
60 | mutex_lock(&dev->struct_mutex); | ||
61 | |||
62 | if (args->gtt_start >= args->gtt_end || | ||
63 | (args->gtt_start & (PAGE_SIZE - 1)) != 0 || | ||
64 | (args->gtt_end & (PAGE_SIZE - 1)) != 0) { | ||
65 | mutex_unlock(&dev->struct_mutex); | ||
66 | return -EINVAL; | ||
67 | } | ||
68 | |||
69 | drm_mm_init(&dev_priv->mm.gtt_space, args->gtt_start, | ||
70 | args->gtt_end - args->gtt_start); | ||
71 | |||
72 | dev->gtt_total = (uint32_t) (args->gtt_end - args->gtt_start); | ||
73 | |||
74 | mutex_unlock(&dev->struct_mutex); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Creates a new mm object and returns a handle to it. | ||
82 | */ | ||
83 | int | ||
84 | i915_gem_create_ioctl(struct drm_device *dev, void *data, | ||
85 | struct drm_file *file_priv) | ||
86 | { | ||
87 | struct drm_i915_gem_create *args = data; | ||
88 | struct drm_gem_object *obj; | ||
89 | int handle, ret; | ||
90 | |||
91 | args->size = roundup(args->size, PAGE_SIZE); | ||
92 | |||
93 | /* Allocate the new object */ | ||
94 | obj = drm_gem_object_alloc(dev, args->size); | ||
95 | if (obj == NULL) | ||
96 | return -ENOMEM; | ||
97 | |||
98 | ret = drm_gem_handle_create(file_priv, obj, &handle); | ||
99 | mutex_lock(&dev->struct_mutex); | ||
100 | drm_gem_object_handle_unreference(obj); | ||
101 | mutex_unlock(&dev->struct_mutex); | ||
102 | |||
103 | if (ret) | ||
104 | return ret; | ||
105 | |||
106 | args->handle = handle; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * Reads data from the object referenced by handle. | ||
113 | * | ||
114 | * On error, the contents of *data are undefined. | ||
115 | */ | ||
116 | int | ||
117 | i915_gem_pread_ioctl(struct drm_device *dev, void *data, | ||
118 | struct drm_file *file_priv) | ||
119 | { | ||
120 | struct drm_i915_gem_pread *args = data; | ||
121 | struct drm_gem_object *obj; | ||
122 | struct drm_i915_gem_object *obj_priv; | ||
123 | ssize_t read; | ||
124 | loff_t offset; | ||
125 | int ret; | ||
126 | |||
127 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
128 | if (obj == NULL) | ||
129 | return -EBADF; | ||
130 | obj_priv = obj->driver_private; | ||
131 | |||
132 | /* Bounds check source. | ||
133 | * | ||
134 | * XXX: This could use review for overflow issues... | ||
135 | */ | ||
136 | if (args->offset > obj->size || args->size > obj->size || | ||
137 | args->offset + args->size > obj->size) { | ||
138 | drm_gem_object_unreference(obj); | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | |||
142 | mutex_lock(&dev->struct_mutex); | ||
143 | |||
144 | ret = i915_gem_object_set_domain_range(obj, args->offset, args->size, | ||
145 | I915_GEM_DOMAIN_CPU, 0); | ||
146 | if (ret != 0) { | ||
147 | drm_gem_object_unreference(obj); | ||
148 | mutex_unlock(&dev->struct_mutex); | ||
149 | } | ||
150 | |||
151 | offset = args->offset; | ||
152 | |||
153 | read = vfs_read(obj->filp, (char __user *)(uintptr_t)args->data_ptr, | ||
154 | args->size, &offset); | ||
155 | if (read != args->size) { | ||
156 | drm_gem_object_unreference(obj); | ||
157 | mutex_unlock(&dev->struct_mutex); | ||
158 | if (read < 0) | ||
159 | return read; | ||
160 | else | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | |||
164 | drm_gem_object_unreference(obj); | ||
165 | mutex_unlock(&dev->struct_mutex); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int | ||
171 | i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, | ||
172 | struct drm_i915_gem_pwrite *args, | ||
173 | struct drm_file *file_priv) | ||
174 | { | ||
175 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
176 | ssize_t remain; | ||
177 | loff_t offset; | ||
178 | char __user *user_data; | ||
179 | char *vaddr; | ||
180 | int i, o, l; | ||
181 | int ret = 0; | ||
182 | unsigned long pfn; | ||
183 | unsigned long unwritten; | ||
184 | |||
185 | user_data = (char __user *) (uintptr_t) args->data_ptr; | ||
186 | remain = args->size; | ||
187 | if (!access_ok(VERIFY_READ, user_data, remain)) | ||
188 | return -EFAULT; | ||
189 | |||
190 | |||
191 | mutex_lock(&dev->struct_mutex); | ||
192 | ret = i915_gem_object_pin(obj, 0); | ||
193 | if (ret) { | ||
194 | mutex_unlock(&dev->struct_mutex); | ||
195 | return ret; | ||
196 | } | ||
197 | ret = i915_gem_set_domain(obj, file_priv, | ||
198 | I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); | ||
199 | if (ret) | ||
200 | goto fail; | ||
201 | |||
202 | obj_priv = obj->driver_private; | ||
203 | offset = obj_priv->gtt_offset + args->offset; | ||
204 | obj_priv->dirty = 1; | ||
205 | |||
206 | while (remain > 0) { | ||
207 | /* Operation in this page | ||
208 | * | ||
209 | * i = page number | ||
210 | * o = offset within page | ||
211 | * l = bytes to copy | ||
212 | */ | ||
213 | i = offset >> PAGE_SHIFT; | ||
214 | o = offset & (PAGE_SIZE-1); | ||
215 | l = remain; | ||
216 | if ((o + l) > PAGE_SIZE) | ||
217 | l = PAGE_SIZE - o; | ||
218 | |||
219 | pfn = (dev->agp->base >> PAGE_SHIFT) + i; | ||
220 | |||
221 | #ifdef CONFIG_HIGHMEM | ||
222 | /* kmap_atomic can't map IO pages on non-HIGHMEM kernels | ||
223 | */ | ||
224 | vaddr = kmap_atomic_pfn(pfn, KM_USER0); | ||
225 | #if WATCH_PWRITE | ||
226 | DRM_INFO("pwrite i %d o %d l %d pfn %ld vaddr %p\n", | ||
227 | i, o, l, pfn, vaddr); | ||
228 | #endif | ||
229 | unwritten = __copy_from_user_inatomic_nocache(vaddr + o, | ||
230 | user_data, l); | ||
231 | kunmap_atomic(vaddr, KM_USER0); | ||
232 | |||
233 | if (unwritten) | ||
234 | #endif /* CONFIG_HIGHMEM */ | ||
235 | { | ||
236 | vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE); | ||
237 | #if WATCH_PWRITE | ||
238 | DRM_INFO("pwrite slow i %d o %d l %d " | ||
239 | "pfn %ld vaddr %p\n", | ||
240 | i, o, l, pfn, vaddr); | ||
241 | #endif | ||
242 | if (vaddr == NULL) { | ||
243 | ret = -EFAULT; | ||
244 | goto fail; | ||
245 | } | ||
246 | unwritten = __copy_from_user(vaddr + o, user_data, l); | ||
247 | #if WATCH_PWRITE | ||
248 | DRM_INFO("unwritten %ld\n", unwritten); | ||
249 | #endif | ||
250 | iounmap(vaddr); | ||
251 | if (unwritten) { | ||
252 | ret = -EFAULT; | ||
253 | goto fail; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | remain -= l; | ||
258 | user_data += l; | ||
259 | offset += l; | ||
260 | } | ||
261 | #if WATCH_PWRITE && 1 | ||
262 | i915_gem_clflush_object(obj); | ||
263 | i915_gem_dump_object(obj, args->offset + args->size, __func__, ~0); | ||
264 | i915_gem_clflush_object(obj); | ||
265 | #endif | ||
266 | |||
267 | fail: | ||
268 | i915_gem_object_unpin(obj); | ||
269 | mutex_unlock(&dev->struct_mutex); | ||
270 | |||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | int | ||
275 | i915_gem_shmem_pwrite(struct drm_device *dev, struct drm_gem_object *obj, | ||
276 | struct drm_i915_gem_pwrite *args, | ||
277 | struct drm_file *file_priv) | ||
278 | { | ||
279 | int ret; | ||
280 | loff_t offset; | ||
281 | ssize_t written; | ||
282 | |||
283 | mutex_lock(&dev->struct_mutex); | ||
284 | |||
285 | ret = i915_gem_set_domain(obj, file_priv, | ||
286 | I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU); | ||
287 | if (ret) { | ||
288 | mutex_unlock(&dev->struct_mutex); | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | offset = args->offset; | ||
293 | |||
294 | written = vfs_write(obj->filp, | ||
295 | (char __user *)(uintptr_t) args->data_ptr, | ||
296 | args->size, &offset); | ||
297 | if (written != args->size) { | ||
298 | mutex_unlock(&dev->struct_mutex); | ||
299 | if (written < 0) | ||
300 | return written; | ||
301 | else | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | mutex_unlock(&dev->struct_mutex); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | /** | ||
311 | * Writes data to the object referenced by handle. | ||
312 | * | ||
313 | * On error, the contents of the buffer that were to be modified are undefined. | ||
314 | */ | ||
315 | int | ||
316 | i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | ||
317 | struct drm_file *file_priv) | ||
318 | { | ||
319 | struct drm_i915_gem_pwrite *args = data; | ||
320 | struct drm_gem_object *obj; | ||
321 | struct drm_i915_gem_object *obj_priv; | ||
322 | int ret = 0; | ||
323 | |||
324 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
325 | if (obj == NULL) | ||
326 | return -EBADF; | ||
327 | obj_priv = obj->driver_private; | ||
328 | |||
329 | /* Bounds check destination. | ||
330 | * | ||
331 | * XXX: This could use review for overflow issues... | ||
332 | */ | ||
333 | if (args->offset > obj->size || args->size > obj->size || | ||
334 | args->offset + args->size > obj->size) { | ||
335 | drm_gem_object_unreference(obj); | ||
336 | return -EINVAL; | ||
337 | } | ||
338 | |||
339 | /* We can only do the GTT pwrite on untiled buffers, as otherwise | ||
340 | * it would end up going through the fenced access, and we'll get | ||
341 | * different detiling behavior between reading and writing. | ||
342 | * pread/pwrite currently are reading and writing from the CPU | ||
343 | * perspective, requiring manual detiling by the client. | ||
344 | */ | ||
345 | if (obj_priv->tiling_mode == I915_TILING_NONE && | ||
346 | dev->gtt_total != 0) | ||
347 | ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv); | ||
348 | else | ||
349 | ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv); | ||
350 | |||
351 | #if WATCH_PWRITE | ||
352 | if (ret) | ||
353 | DRM_INFO("pwrite failed %d\n", ret); | ||
354 | #endif | ||
355 | |||
356 | drm_gem_object_unreference(obj); | ||
357 | |||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * Called when user space prepares to use an object | ||
363 | */ | ||
364 | int | ||
365 | i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, | ||
366 | struct drm_file *file_priv) | ||
367 | { | ||
368 | struct drm_i915_gem_set_domain *args = data; | ||
369 | struct drm_gem_object *obj; | ||
370 | int ret; | ||
371 | |||
372 | if (!(dev->driver->driver_features & DRIVER_GEM)) | ||
373 | return -ENODEV; | ||
374 | |||
375 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
376 | if (obj == NULL) | ||
377 | return -EBADF; | ||
378 | |||
379 | mutex_lock(&dev->struct_mutex); | ||
380 | #if WATCH_BUF | ||
381 | DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n", | ||
382 | obj, obj->size, args->read_domains, args->write_domain); | ||
383 | #endif | ||
384 | ret = i915_gem_set_domain(obj, file_priv, | ||
385 | args->read_domains, args->write_domain); | ||
386 | drm_gem_object_unreference(obj); | ||
387 | mutex_unlock(&dev->struct_mutex); | ||
388 | return ret; | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * Called when user space has done writes to this buffer | ||
393 | */ | ||
394 | int | ||
395 | i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, | ||
396 | struct drm_file *file_priv) | ||
397 | { | ||
398 | struct drm_i915_gem_sw_finish *args = data; | ||
399 | struct drm_gem_object *obj; | ||
400 | struct drm_i915_gem_object *obj_priv; | ||
401 | int ret = 0; | ||
402 | |||
403 | if (!(dev->driver->driver_features & DRIVER_GEM)) | ||
404 | return -ENODEV; | ||
405 | |||
406 | mutex_lock(&dev->struct_mutex); | ||
407 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
408 | if (obj == NULL) { | ||
409 | mutex_unlock(&dev->struct_mutex); | ||
410 | return -EBADF; | ||
411 | } | ||
412 | |||
413 | #if WATCH_BUF | ||
414 | DRM_INFO("%s: sw_finish %d (%p %d)\n", | ||
415 | __func__, args->handle, obj, obj->size); | ||
416 | #endif | ||
417 | obj_priv = obj->driver_private; | ||
418 | |||
419 | /* Pinned buffers may be scanout, so flush the cache */ | ||
420 | if ((obj->write_domain & I915_GEM_DOMAIN_CPU) && obj_priv->pin_count) { | ||
421 | i915_gem_clflush_object(obj); | ||
422 | drm_agp_chipset_flush(dev); | ||
423 | } | ||
424 | drm_gem_object_unreference(obj); | ||
425 | mutex_unlock(&dev->struct_mutex); | ||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | /** | ||
430 | * Maps the contents of an object, returning the address it is mapped | ||
431 | * into. | ||
432 | * | ||
433 | * While the mapping holds a reference on the contents of the object, it doesn't | ||
434 | * imply a ref on the object itself. | ||
435 | */ | ||
436 | int | ||
437 | i915_gem_mmap_ioctl(struct drm_device *dev, void *data, | ||
438 | struct drm_file *file_priv) | ||
439 | { | ||
440 | struct drm_i915_gem_mmap *args = data; | ||
441 | struct drm_gem_object *obj; | ||
442 | loff_t offset; | ||
443 | unsigned long addr; | ||
444 | |||
445 | if (!(dev->driver->driver_features & DRIVER_GEM)) | ||
446 | return -ENODEV; | ||
447 | |||
448 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
449 | if (obj == NULL) | ||
450 | return -EBADF; | ||
451 | |||
452 | offset = args->offset; | ||
453 | |||
454 | down_write(¤t->mm->mmap_sem); | ||
455 | addr = do_mmap(obj->filp, 0, args->size, | ||
456 | PROT_READ | PROT_WRITE, MAP_SHARED, | ||
457 | args->offset); | ||
458 | up_write(¤t->mm->mmap_sem); | ||
459 | mutex_lock(&dev->struct_mutex); | ||
460 | drm_gem_object_unreference(obj); | ||
461 | mutex_unlock(&dev->struct_mutex); | ||
462 | if (IS_ERR((void *)addr)) | ||
463 | return addr; | ||
464 | |||
465 | args->addr_ptr = (uint64_t) addr; | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static void | ||
471 | i915_gem_object_free_page_list(struct drm_gem_object *obj) | ||
472 | { | ||
473 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
474 | int page_count = obj->size / PAGE_SIZE; | ||
475 | int i; | ||
476 | |||
477 | if (obj_priv->page_list == NULL) | ||
478 | return; | ||
479 | |||
480 | |||
481 | for (i = 0; i < page_count; i++) | ||
482 | if (obj_priv->page_list[i] != NULL) { | ||
483 | if (obj_priv->dirty) | ||
484 | set_page_dirty(obj_priv->page_list[i]); | ||
485 | mark_page_accessed(obj_priv->page_list[i]); | ||
486 | page_cache_release(obj_priv->page_list[i]); | ||
487 | } | ||
488 | obj_priv->dirty = 0; | ||
489 | |||
490 | drm_free(obj_priv->page_list, | ||
491 | page_count * sizeof(struct page *), | ||
492 | DRM_MEM_DRIVER); | ||
493 | obj_priv->page_list = NULL; | ||
494 | } | ||
495 | |||
496 | static void | ||
497 | i915_gem_object_move_to_active(struct drm_gem_object *obj) | ||
498 | { | ||
499 | struct drm_device *dev = obj->dev; | ||
500 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
501 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
502 | |||
503 | /* Add a reference if we're newly entering the active list. */ | ||
504 | if (!obj_priv->active) { | ||
505 | drm_gem_object_reference(obj); | ||
506 | obj_priv->active = 1; | ||
507 | } | ||
508 | /* Move from whatever list we were on to the tail of execution. */ | ||
509 | list_move_tail(&obj_priv->list, | ||
510 | &dev_priv->mm.active_list); | ||
511 | } | ||
512 | |||
513 | |||
514 | static void | ||
515 | i915_gem_object_move_to_inactive(struct drm_gem_object *obj) | ||
516 | { | ||
517 | struct drm_device *dev = obj->dev; | ||
518 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
519 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
520 | |||
521 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
522 | if (obj_priv->pin_count != 0) | ||
523 | list_del_init(&obj_priv->list); | ||
524 | else | ||
525 | list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); | ||
526 | |||
527 | if (obj_priv->active) { | ||
528 | obj_priv->active = 0; | ||
529 | drm_gem_object_unreference(obj); | ||
530 | } | ||
531 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
532 | } | ||
533 | |||
534 | /** | ||
535 | * Creates a new sequence number, emitting a write of it to the status page | ||
536 | * plus an interrupt, which will trigger i915_user_interrupt_handler. | ||
537 | * | ||
538 | * Must be called with struct_lock held. | ||
539 | * | ||
540 | * Returned sequence numbers are nonzero on success. | ||
541 | */ | ||
542 | static uint32_t | ||
543 | i915_add_request(struct drm_device *dev, uint32_t flush_domains) | ||
544 | { | ||
545 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
546 | struct drm_i915_gem_request *request; | ||
547 | uint32_t seqno; | ||
548 | int was_empty; | ||
549 | RING_LOCALS; | ||
550 | |||
551 | request = drm_calloc(1, sizeof(*request), DRM_MEM_DRIVER); | ||
552 | if (request == NULL) | ||
553 | return 0; | ||
554 | |||
555 | /* Grab the seqno we're going to make this request be, and bump the | ||
556 | * next (skipping 0 so it can be the reserved no-seqno value). | ||
557 | */ | ||
558 | seqno = dev_priv->mm.next_gem_seqno; | ||
559 | dev_priv->mm.next_gem_seqno++; | ||
560 | if (dev_priv->mm.next_gem_seqno == 0) | ||
561 | dev_priv->mm.next_gem_seqno++; | ||
562 | |||
563 | BEGIN_LP_RING(4); | ||
564 | OUT_RING(MI_STORE_DWORD_INDEX); | ||
565 | OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); | ||
566 | OUT_RING(seqno); | ||
567 | |||
568 | OUT_RING(MI_USER_INTERRUPT); | ||
569 | ADVANCE_LP_RING(); | ||
570 | |||
571 | DRM_DEBUG("%d\n", seqno); | ||
572 | |||
573 | request->seqno = seqno; | ||
574 | request->emitted_jiffies = jiffies; | ||
575 | request->flush_domains = flush_domains; | ||
576 | was_empty = list_empty(&dev_priv->mm.request_list); | ||
577 | list_add_tail(&request->list, &dev_priv->mm.request_list); | ||
578 | |||
579 | if (was_empty) | ||
580 | schedule_delayed_work(&dev_priv->mm.retire_work, HZ); | ||
581 | return seqno; | ||
582 | } | ||
583 | |||
584 | /** | ||
585 | * Command execution barrier | ||
586 | * | ||
587 | * Ensures that all commands in the ring are finished | ||
588 | * before signalling the CPU | ||
589 | */ | ||
590 | uint32_t | ||
591 | i915_retire_commands(struct drm_device *dev) | ||
592 | { | ||
593 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
594 | uint32_t cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; | ||
595 | uint32_t flush_domains = 0; | ||
596 | RING_LOCALS; | ||
597 | |||
598 | /* The sampler always gets flushed on i965 (sigh) */ | ||
599 | if (IS_I965G(dev)) | ||
600 | flush_domains |= I915_GEM_DOMAIN_SAMPLER; | ||
601 | BEGIN_LP_RING(2); | ||
602 | OUT_RING(cmd); | ||
603 | OUT_RING(0); /* noop */ | ||
604 | ADVANCE_LP_RING(); | ||
605 | return flush_domains; | ||
606 | } | ||
607 | |||
608 | /** | ||
609 | * Moves buffers associated only with the given active seqno from the active | ||
610 | * to inactive list, potentially freeing them. | ||
611 | */ | ||
612 | static void | ||
613 | i915_gem_retire_request(struct drm_device *dev, | ||
614 | struct drm_i915_gem_request *request) | ||
615 | { | ||
616 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
617 | |||
618 | /* Move any buffers on the active list that are no longer referenced | ||
619 | * by the ringbuffer to the flushing/inactive lists as appropriate. | ||
620 | */ | ||
621 | while (!list_empty(&dev_priv->mm.active_list)) { | ||
622 | struct drm_gem_object *obj; | ||
623 | struct drm_i915_gem_object *obj_priv; | ||
624 | |||
625 | obj_priv = list_first_entry(&dev_priv->mm.active_list, | ||
626 | struct drm_i915_gem_object, | ||
627 | list); | ||
628 | obj = obj_priv->obj; | ||
629 | |||
630 | /* If the seqno being retired doesn't match the oldest in the | ||
631 | * list, then the oldest in the list must still be newer than | ||
632 | * this seqno. | ||
633 | */ | ||
634 | if (obj_priv->last_rendering_seqno != request->seqno) | ||
635 | return; | ||
636 | #if WATCH_LRU | ||
637 | DRM_INFO("%s: retire %d moves to inactive list %p\n", | ||
638 | __func__, request->seqno, obj); | ||
639 | #endif | ||
640 | |||
641 | if (obj->write_domain != 0) { | ||
642 | list_move_tail(&obj_priv->list, | ||
643 | &dev_priv->mm.flushing_list); | ||
644 | } else { | ||
645 | i915_gem_object_move_to_inactive(obj); | ||
646 | } | ||
647 | } | ||
648 | |||
649 | if (request->flush_domains != 0) { | ||
650 | struct drm_i915_gem_object *obj_priv, *next; | ||
651 | |||
652 | /* Clear the write domain and activity from any buffers | ||
653 | * that are just waiting for a flush matching the one retired. | ||
654 | */ | ||
655 | list_for_each_entry_safe(obj_priv, next, | ||
656 | &dev_priv->mm.flushing_list, list) { | ||
657 | struct drm_gem_object *obj = obj_priv->obj; | ||
658 | |||
659 | if (obj->write_domain & request->flush_domains) { | ||
660 | obj->write_domain = 0; | ||
661 | i915_gem_object_move_to_inactive(obj); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | } | ||
666 | } | ||
667 | |||
668 | /** | ||
669 | * Returns true if seq1 is later than seq2. | ||
670 | */ | ||
671 | static int | ||
672 | i915_seqno_passed(uint32_t seq1, uint32_t seq2) | ||
673 | { | ||
674 | return (int32_t)(seq1 - seq2) >= 0; | ||
675 | } | ||
676 | |||
677 | uint32_t | ||
678 | i915_get_gem_seqno(struct drm_device *dev) | ||
679 | { | ||
680 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
681 | |||
682 | return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX); | ||
683 | } | ||
684 | |||
685 | /** | ||
686 | * This function clears the request list as sequence numbers are passed. | ||
687 | */ | ||
688 | void | ||
689 | i915_gem_retire_requests(struct drm_device *dev) | ||
690 | { | ||
691 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
692 | uint32_t seqno; | ||
693 | |||
694 | seqno = i915_get_gem_seqno(dev); | ||
695 | |||
696 | while (!list_empty(&dev_priv->mm.request_list)) { | ||
697 | struct drm_i915_gem_request *request; | ||
698 | uint32_t retiring_seqno; | ||
699 | |||
700 | request = list_first_entry(&dev_priv->mm.request_list, | ||
701 | struct drm_i915_gem_request, | ||
702 | list); | ||
703 | retiring_seqno = request->seqno; | ||
704 | |||
705 | if (i915_seqno_passed(seqno, retiring_seqno) || | ||
706 | dev_priv->mm.wedged) { | ||
707 | i915_gem_retire_request(dev, request); | ||
708 | |||
709 | list_del(&request->list); | ||
710 | drm_free(request, sizeof(*request), DRM_MEM_DRIVER); | ||
711 | } else | ||
712 | break; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | void | ||
717 | i915_gem_retire_work_handler(struct work_struct *work) | ||
718 | { | ||
719 | drm_i915_private_t *dev_priv; | ||
720 | struct drm_device *dev; | ||
721 | |||
722 | dev_priv = container_of(work, drm_i915_private_t, | ||
723 | mm.retire_work.work); | ||
724 | dev = dev_priv->dev; | ||
725 | |||
726 | mutex_lock(&dev->struct_mutex); | ||
727 | i915_gem_retire_requests(dev); | ||
728 | if (!list_empty(&dev_priv->mm.request_list)) | ||
729 | schedule_delayed_work(&dev_priv->mm.retire_work, HZ); | ||
730 | mutex_unlock(&dev->struct_mutex); | ||
731 | } | ||
732 | |||
733 | /** | ||
734 | * Waits for a sequence number to be signaled, and cleans up the | ||
735 | * request and object lists appropriately for that event. | ||
736 | */ | ||
737 | int | ||
738 | i915_wait_request(struct drm_device *dev, uint32_t seqno) | ||
739 | { | ||
740 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
741 | int ret = 0; | ||
742 | |||
743 | BUG_ON(seqno == 0); | ||
744 | |||
745 | if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) { | ||
746 | dev_priv->mm.waiting_gem_seqno = seqno; | ||
747 | i915_user_irq_get(dev); | ||
748 | ret = wait_event_interruptible(dev_priv->irq_queue, | ||
749 | i915_seqno_passed(i915_get_gem_seqno(dev), | ||
750 | seqno) || | ||
751 | dev_priv->mm.wedged); | ||
752 | i915_user_irq_put(dev); | ||
753 | dev_priv->mm.waiting_gem_seqno = 0; | ||
754 | } | ||
755 | if (dev_priv->mm.wedged) | ||
756 | ret = -EIO; | ||
757 | |||
758 | if (ret && ret != -ERESTARTSYS) | ||
759 | DRM_ERROR("%s returns %d (awaiting %d at %d)\n", | ||
760 | __func__, ret, seqno, i915_get_gem_seqno(dev)); | ||
761 | |||
762 | /* Directly dispatch request retiring. While we have the work queue | ||
763 | * to handle this, the waiter on a request often wants an associated | ||
764 | * buffer to have made it to the inactive list, and we would need | ||
765 | * a separate wait queue to handle that. | ||
766 | */ | ||
767 | if (ret == 0) | ||
768 | i915_gem_retire_requests(dev); | ||
769 | |||
770 | return ret; | ||
771 | } | ||
772 | |||
773 | static void | ||
774 | i915_gem_flush(struct drm_device *dev, | ||
775 | uint32_t invalidate_domains, | ||
776 | uint32_t flush_domains) | ||
777 | { | ||
778 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
779 | uint32_t cmd; | ||
780 | RING_LOCALS; | ||
781 | |||
782 | #if WATCH_EXEC | ||
783 | DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, | ||
784 | invalidate_domains, flush_domains); | ||
785 | #endif | ||
786 | |||
787 | if (flush_domains & I915_GEM_DOMAIN_CPU) | ||
788 | drm_agp_chipset_flush(dev); | ||
789 | |||
790 | if ((invalidate_domains | flush_domains) & ~(I915_GEM_DOMAIN_CPU | | ||
791 | I915_GEM_DOMAIN_GTT)) { | ||
792 | /* | ||
793 | * read/write caches: | ||
794 | * | ||
795 | * I915_GEM_DOMAIN_RENDER is always invalidated, but is | ||
796 | * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is | ||
797 | * also flushed at 2d versus 3d pipeline switches. | ||
798 | * | ||
799 | * read-only caches: | ||
800 | * | ||
801 | * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if | ||
802 | * MI_READ_FLUSH is set, and is always flushed on 965. | ||
803 | * | ||
804 | * I915_GEM_DOMAIN_COMMAND may not exist? | ||
805 | * | ||
806 | * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is | ||
807 | * invalidated when MI_EXE_FLUSH is set. | ||
808 | * | ||
809 | * I915_GEM_DOMAIN_VERTEX, which exists on 965, is | ||
810 | * invalidated with every MI_FLUSH. | ||
811 | * | ||
812 | * TLBs: | ||
813 | * | ||
814 | * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND | ||
815 | * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and | ||
816 | * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER | ||
817 | * are flushed at any MI_FLUSH. | ||
818 | */ | ||
819 | |||
820 | cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; | ||
821 | if ((invalidate_domains|flush_domains) & | ||
822 | I915_GEM_DOMAIN_RENDER) | ||
823 | cmd &= ~MI_NO_WRITE_FLUSH; | ||
824 | if (!IS_I965G(dev)) { | ||
825 | /* | ||
826 | * On the 965, the sampler cache always gets flushed | ||
827 | * and this bit is reserved. | ||
828 | */ | ||
829 | if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) | ||
830 | cmd |= MI_READ_FLUSH; | ||
831 | } | ||
832 | if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) | ||
833 | cmd |= MI_EXE_FLUSH; | ||
834 | |||
835 | #if WATCH_EXEC | ||
836 | DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); | ||
837 | #endif | ||
838 | BEGIN_LP_RING(2); | ||
839 | OUT_RING(cmd); | ||
840 | OUT_RING(0); /* noop */ | ||
841 | ADVANCE_LP_RING(); | ||
842 | } | ||
843 | } | ||
844 | |||
845 | /** | ||
846 | * Ensures that all rendering to the object has completed and the object is | ||
847 | * safe to unbind from the GTT or access from the CPU. | ||
848 | */ | ||
849 | static int | ||
850 | i915_gem_object_wait_rendering(struct drm_gem_object *obj) | ||
851 | { | ||
852 | struct drm_device *dev = obj->dev; | ||
853 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
854 | int ret; | ||
855 | |||
856 | /* If there are writes queued to the buffer, flush and | ||
857 | * create a new seqno to wait for. | ||
858 | */ | ||
859 | if (obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) { | ||
860 | uint32_t write_domain = obj->write_domain; | ||
861 | #if WATCH_BUF | ||
862 | DRM_INFO("%s: flushing object %p from write domain %08x\n", | ||
863 | __func__, obj, write_domain); | ||
864 | #endif | ||
865 | i915_gem_flush(dev, 0, write_domain); | ||
866 | |||
867 | i915_gem_object_move_to_active(obj); | ||
868 | obj_priv->last_rendering_seqno = i915_add_request(dev, | ||
869 | write_domain); | ||
870 | BUG_ON(obj_priv->last_rendering_seqno == 0); | ||
871 | #if WATCH_LRU | ||
872 | DRM_INFO("%s: flush moves to exec list %p\n", __func__, obj); | ||
873 | #endif | ||
874 | } | ||
875 | |||
876 | /* If there is rendering queued on the buffer being evicted, wait for | ||
877 | * it. | ||
878 | */ | ||
879 | if (obj_priv->active) { | ||
880 | #if WATCH_BUF | ||
881 | DRM_INFO("%s: object %p wait for seqno %08x\n", | ||
882 | __func__, obj, obj_priv->last_rendering_seqno); | ||
883 | #endif | ||
884 | ret = i915_wait_request(dev, obj_priv->last_rendering_seqno); | ||
885 | if (ret != 0) | ||
886 | return ret; | ||
887 | } | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | /** | ||
893 | * Unbinds an object from the GTT aperture. | ||
894 | */ | ||
895 | static int | ||
896 | i915_gem_object_unbind(struct drm_gem_object *obj) | ||
897 | { | ||
898 | struct drm_device *dev = obj->dev; | ||
899 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
900 | int ret = 0; | ||
901 | |||
902 | #if WATCH_BUF | ||
903 | DRM_INFO("%s:%d %p\n", __func__, __LINE__, obj); | ||
904 | DRM_INFO("gtt_space %p\n", obj_priv->gtt_space); | ||
905 | #endif | ||
906 | if (obj_priv->gtt_space == NULL) | ||
907 | return 0; | ||
908 | |||
909 | if (obj_priv->pin_count != 0) { | ||
910 | DRM_ERROR("Attempting to unbind pinned buffer\n"); | ||
911 | return -EINVAL; | ||
912 | } | ||
913 | |||
914 | /* Wait for any rendering to complete | ||
915 | */ | ||
916 | ret = i915_gem_object_wait_rendering(obj); | ||
917 | if (ret) { | ||
918 | DRM_ERROR("wait_rendering failed: %d\n", ret); | ||
919 | return ret; | ||
920 | } | ||
921 | |||
922 | /* Move the object to the CPU domain to ensure that | ||
923 | * any possible CPU writes while it's not in the GTT | ||
924 | * are flushed when we go to remap it. This will | ||
925 | * also ensure that all pending GPU writes are finished | ||
926 | * before we unbind. | ||
927 | */ | ||
928 | ret = i915_gem_object_set_domain(obj, I915_GEM_DOMAIN_CPU, | ||
929 | I915_GEM_DOMAIN_CPU); | ||
930 | if (ret) { | ||
931 | DRM_ERROR("set_domain failed: %d\n", ret); | ||
932 | return ret; | ||
933 | } | ||
934 | |||
935 | if (obj_priv->agp_mem != NULL) { | ||
936 | drm_unbind_agp(obj_priv->agp_mem); | ||
937 | drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); | ||
938 | obj_priv->agp_mem = NULL; | ||
939 | } | ||
940 | |||
941 | BUG_ON(obj_priv->active); | ||
942 | |||
943 | i915_gem_object_free_page_list(obj); | ||
944 | |||
945 | if (obj_priv->gtt_space) { | ||
946 | atomic_dec(&dev->gtt_count); | ||
947 | atomic_sub(obj->size, &dev->gtt_memory); | ||
948 | |||
949 | drm_mm_put_block(obj_priv->gtt_space); | ||
950 | obj_priv->gtt_space = NULL; | ||
951 | } | ||
952 | |||
953 | /* Remove ourselves from the LRU list if present. */ | ||
954 | if (!list_empty(&obj_priv->list)) | ||
955 | list_del_init(&obj_priv->list); | ||
956 | |||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | static int | ||
961 | i915_gem_evict_something(struct drm_device *dev) | ||
962 | { | ||
963 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
964 | struct drm_gem_object *obj; | ||
965 | struct drm_i915_gem_object *obj_priv; | ||
966 | int ret = 0; | ||
967 | |||
968 | for (;;) { | ||
969 | /* If there's an inactive buffer available now, grab it | ||
970 | * and be done. | ||
971 | */ | ||
972 | if (!list_empty(&dev_priv->mm.inactive_list)) { | ||
973 | obj_priv = list_first_entry(&dev_priv->mm.inactive_list, | ||
974 | struct drm_i915_gem_object, | ||
975 | list); | ||
976 | obj = obj_priv->obj; | ||
977 | BUG_ON(obj_priv->pin_count != 0); | ||
978 | #if WATCH_LRU | ||
979 | DRM_INFO("%s: evicting %p\n", __func__, obj); | ||
980 | #endif | ||
981 | BUG_ON(obj_priv->active); | ||
982 | |||
983 | /* Wait on the rendering and unbind the buffer. */ | ||
984 | ret = i915_gem_object_unbind(obj); | ||
985 | break; | ||
986 | } | ||
987 | |||
988 | /* If we didn't get anything, but the ring is still processing | ||
989 | * things, wait for one of those things to finish and hopefully | ||
990 | * leave us a buffer to evict. | ||
991 | */ | ||
992 | if (!list_empty(&dev_priv->mm.request_list)) { | ||
993 | struct drm_i915_gem_request *request; | ||
994 | |||
995 | request = list_first_entry(&dev_priv->mm.request_list, | ||
996 | struct drm_i915_gem_request, | ||
997 | list); | ||
998 | |||
999 | ret = i915_wait_request(dev, request->seqno); | ||
1000 | if (ret) | ||
1001 | break; | ||
1002 | |||
1003 | /* if waiting caused an object to become inactive, | ||
1004 | * then loop around and wait for it. Otherwise, we | ||
1005 | * assume that waiting freed and unbound something, | ||
1006 | * so there should now be some space in the GTT | ||
1007 | */ | ||
1008 | if (!list_empty(&dev_priv->mm.inactive_list)) | ||
1009 | continue; | ||
1010 | break; | ||
1011 | } | ||
1012 | |||
1013 | /* If we didn't have anything on the request list but there | ||
1014 | * are buffers awaiting a flush, emit one and try again. | ||
1015 | * When we wait on it, those buffers waiting for that flush | ||
1016 | * will get moved to inactive. | ||
1017 | */ | ||
1018 | if (!list_empty(&dev_priv->mm.flushing_list)) { | ||
1019 | obj_priv = list_first_entry(&dev_priv->mm.flushing_list, | ||
1020 | struct drm_i915_gem_object, | ||
1021 | list); | ||
1022 | obj = obj_priv->obj; | ||
1023 | |||
1024 | i915_gem_flush(dev, | ||
1025 | obj->write_domain, | ||
1026 | obj->write_domain); | ||
1027 | i915_add_request(dev, obj->write_domain); | ||
1028 | |||
1029 | obj = NULL; | ||
1030 | continue; | ||
1031 | } | ||
1032 | |||
1033 | DRM_ERROR("inactive empty %d request empty %d " | ||
1034 | "flushing empty %d\n", | ||
1035 | list_empty(&dev_priv->mm.inactive_list), | ||
1036 | list_empty(&dev_priv->mm.request_list), | ||
1037 | list_empty(&dev_priv->mm.flushing_list)); | ||
1038 | /* If we didn't do any of the above, there's nothing to be done | ||
1039 | * and we just can't fit it in. | ||
1040 | */ | ||
1041 | return -ENOMEM; | ||
1042 | } | ||
1043 | return ret; | ||
1044 | } | ||
1045 | |||
1046 | static int | ||
1047 | i915_gem_object_get_page_list(struct drm_gem_object *obj) | ||
1048 | { | ||
1049 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1050 | int page_count, i; | ||
1051 | struct address_space *mapping; | ||
1052 | struct inode *inode; | ||
1053 | struct page *page; | ||
1054 | int ret; | ||
1055 | |||
1056 | if (obj_priv->page_list) | ||
1057 | return 0; | ||
1058 | |||
1059 | /* Get the list of pages out of our struct file. They'll be pinned | ||
1060 | * at this point until we release them. | ||
1061 | */ | ||
1062 | page_count = obj->size / PAGE_SIZE; | ||
1063 | BUG_ON(obj_priv->page_list != NULL); | ||
1064 | obj_priv->page_list = drm_calloc(page_count, sizeof(struct page *), | ||
1065 | DRM_MEM_DRIVER); | ||
1066 | if (obj_priv->page_list == NULL) { | ||
1067 | DRM_ERROR("Faled to allocate page list\n"); | ||
1068 | return -ENOMEM; | ||
1069 | } | ||
1070 | |||
1071 | inode = obj->filp->f_path.dentry->d_inode; | ||
1072 | mapping = inode->i_mapping; | ||
1073 | for (i = 0; i < page_count; i++) { | ||
1074 | page = read_mapping_page(mapping, i, NULL); | ||
1075 | if (IS_ERR(page)) { | ||
1076 | ret = PTR_ERR(page); | ||
1077 | DRM_ERROR("read_mapping_page failed: %d\n", ret); | ||
1078 | i915_gem_object_free_page_list(obj); | ||
1079 | return ret; | ||
1080 | } | ||
1081 | obj_priv->page_list[i] = page; | ||
1082 | } | ||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | /** | ||
1087 | * Finds free space in the GTT aperture and binds the object there. | ||
1088 | */ | ||
1089 | static int | ||
1090 | i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) | ||
1091 | { | ||
1092 | struct drm_device *dev = obj->dev; | ||
1093 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1094 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1095 | struct drm_mm_node *free_space; | ||
1096 | int page_count, ret; | ||
1097 | |||
1098 | if (alignment == 0) | ||
1099 | alignment = PAGE_SIZE; | ||
1100 | if (alignment & (PAGE_SIZE - 1)) { | ||
1101 | DRM_ERROR("Invalid object alignment requested %u\n", alignment); | ||
1102 | return -EINVAL; | ||
1103 | } | ||
1104 | |||
1105 | search_free: | ||
1106 | free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, | ||
1107 | obj->size, alignment, 0); | ||
1108 | if (free_space != NULL) { | ||
1109 | obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size, | ||
1110 | alignment); | ||
1111 | if (obj_priv->gtt_space != NULL) { | ||
1112 | obj_priv->gtt_space->private = obj; | ||
1113 | obj_priv->gtt_offset = obj_priv->gtt_space->start; | ||
1114 | } | ||
1115 | } | ||
1116 | if (obj_priv->gtt_space == NULL) { | ||
1117 | /* If the gtt is empty and we're still having trouble | ||
1118 | * fitting our object in, we're out of memory. | ||
1119 | */ | ||
1120 | #if WATCH_LRU | ||
1121 | DRM_INFO("%s: GTT full, evicting something\n", __func__); | ||
1122 | #endif | ||
1123 | if (list_empty(&dev_priv->mm.inactive_list) && | ||
1124 | list_empty(&dev_priv->mm.flushing_list) && | ||
1125 | list_empty(&dev_priv->mm.active_list)) { | ||
1126 | DRM_ERROR("GTT full, but LRU list empty\n"); | ||
1127 | return -ENOMEM; | ||
1128 | } | ||
1129 | |||
1130 | ret = i915_gem_evict_something(dev); | ||
1131 | if (ret != 0) { | ||
1132 | DRM_ERROR("Failed to evict a buffer %d\n", ret); | ||
1133 | return ret; | ||
1134 | } | ||
1135 | goto search_free; | ||
1136 | } | ||
1137 | |||
1138 | #if WATCH_BUF | ||
1139 | DRM_INFO("Binding object of size %d at 0x%08x\n", | ||
1140 | obj->size, obj_priv->gtt_offset); | ||
1141 | #endif | ||
1142 | ret = i915_gem_object_get_page_list(obj); | ||
1143 | if (ret) { | ||
1144 | drm_mm_put_block(obj_priv->gtt_space); | ||
1145 | obj_priv->gtt_space = NULL; | ||
1146 | return ret; | ||
1147 | } | ||
1148 | |||
1149 | page_count = obj->size / PAGE_SIZE; | ||
1150 | /* Create an AGP memory structure pointing at our pages, and bind it | ||
1151 | * into the GTT. | ||
1152 | */ | ||
1153 | obj_priv->agp_mem = drm_agp_bind_pages(dev, | ||
1154 | obj_priv->page_list, | ||
1155 | page_count, | ||
1156 | obj_priv->gtt_offset); | ||
1157 | if (obj_priv->agp_mem == NULL) { | ||
1158 | i915_gem_object_free_page_list(obj); | ||
1159 | drm_mm_put_block(obj_priv->gtt_space); | ||
1160 | obj_priv->gtt_space = NULL; | ||
1161 | return -ENOMEM; | ||
1162 | } | ||
1163 | atomic_inc(&dev->gtt_count); | ||
1164 | atomic_add(obj->size, &dev->gtt_memory); | ||
1165 | |||
1166 | /* Assert that the object is not currently in any GPU domain. As it | ||
1167 | * wasn't in the GTT, there shouldn't be any way it could have been in | ||
1168 | * a GPU cache | ||
1169 | */ | ||
1170 | BUG_ON(obj->read_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); | ||
1171 | BUG_ON(obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); | ||
1172 | |||
1173 | return 0; | ||
1174 | } | ||
1175 | |||
1176 | void | ||
1177 | i915_gem_clflush_object(struct drm_gem_object *obj) | ||
1178 | { | ||
1179 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1180 | |||
1181 | /* If we don't have a page list set up, then we're not pinned | ||
1182 | * to GPU, and we can ignore the cache flush because it'll happen | ||
1183 | * again at bind time. | ||
1184 | */ | ||
1185 | if (obj_priv->page_list == NULL) | ||
1186 | return; | ||
1187 | |||
1188 | drm_clflush_pages(obj_priv->page_list, obj->size / PAGE_SIZE); | ||
1189 | } | ||
1190 | |||
1191 | /* | ||
1192 | * Set the next domain for the specified object. This | ||
1193 | * may not actually perform the necessary flushing/invaliding though, | ||
1194 | * as that may want to be batched with other set_domain operations | ||
1195 | * | ||
1196 | * This is (we hope) the only really tricky part of gem. The goal | ||
1197 | * is fairly simple -- track which caches hold bits of the object | ||
1198 | * and make sure they remain coherent. A few concrete examples may | ||
1199 | * help to explain how it works. For shorthand, we use the notation | ||
1200 | * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the | ||
1201 | * a pair of read and write domain masks. | ||
1202 | * | ||
1203 | * Case 1: the batch buffer | ||
1204 | * | ||
1205 | * 1. Allocated | ||
1206 | * 2. Written by CPU | ||
1207 | * 3. Mapped to GTT | ||
1208 | * 4. Read by GPU | ||
1209 | * 5. Unmapped from GTT | ||
1210 | * 6. Freed | ||
1211 | * | ||
1212 | * Let's take these a step at a time | ||
1213 | * | ||
1214 | * 1. Allocated | ||
1215 | * Pages allocated from the kernel may still have | ||
1216 | * cache contents, so we set them to (CPU, CPU) always. | ||
1217 | * 2. Written by CPU (using pwrite) | ||
1218 | * The pwrite function calls set_domain (CPU, CPU) and | ||
1219 | * this function does nothing (as nothing changes) | ||
1220 | * 3. Mapped by GTT | ||
1221 | * This function asserts that the object is not | ||
1222 | * currently in any GPU-based read or write domains | ||
1223 | * 4. Read by GPU | ||
1224 | * i915_gem_execbuffer calls set_domain (COMMAND, 0). | ||
1225 | * As write_domain is zero, this function adds in the | ||
1226 | * current read domains (CPU+COMMAND, 0). | ||
1227 | * flush_domains is set to CPU. | ||
1228 | * invalidate_domains is set to COMMAND | ||
1229 | * clflush is run to get data out of the CPU caches | ||
1230 | * then i915_dev_set_domain calls i915_gem_flush to | ||
1231 | * emit an MI_FLUSH and drm_agp_chipset_flush | ||
1232 | * 5. Unmapped from GTT | ||
1233 | * i915_gem_object_unbind calls set_domain (CPU, CPU) | ||
1234 | * flush_domains and invalidate_domains end up both zero | ||
1235 | * so no flushing/invalidating happens | ||
1236 | * 6. Freed | ||
1237 | * yay, done | ||
1238 | * | ||
1239 | * Case 2: The shared render buffer | ||
1240 | * | ||
1241 | * 1. Allocated | ||
1242 | * 2. Mapped to GTT | ||
1243 | * 3. Read/written by GPU | ||
1244 | * 4. set_domain to (CPU,CPU) | ||
1245 | * 5. Read/written by CPU | ||
1246 | * 6. Read/written by GPU | ||
1247 | * | ||
1248 | * 1. Allocated | ||
1249 | * Same as last example, (CPU, CPU) | ||
1250 | * 2. Mapped to GTT | ||
1251 | * Nothing changes (assertions find that it is not in the GPU) | ||
1252 | * 3. Read/written by GPU | ||
1253 | * execbuffer calls set_domain (RENDER, RENDER) | ||
1254 | * flush_domains gets CPU | ||
1255 | * invalidate_domains gets GPU | ||
1256 | * clflush (obj) | ||
1257 | * MI_FLUSH and drm_agp_chipset_flush | ||
1258 | * 4. set_domain (CPU, CPU) | ||
1259 | * flush_domains gets GPU | ||
1260 | * invalidate_domains gets CPU | ||
1261 | * wait_rendering (obj) to make sure all drawing is complete. | ||
1262 | * This will include an MI_FLUSH to get the data from GPU | ||
1263 | * to memory | ||
1264 | * clflush (obj) to invalidate the CPU cache | ||
1265 | * Another MI_FLUSH in i915_gem_flush (eliminate this somehow?) | ||
1266 | * 5. Read/written by CPU | ||
1267 | * cache lines are loaded and dirtied | ||
1268 | * 6. Read written by GPU | ||
1269 | * Same as last GPU access | ||
1270 | * | ||
1271 | * Case 3: The constant buffer | ||
1272 | * | ||
1273 | * 1. Allocated | ||
1274 | * 2. Written by CPU | ||
1275 | * 3. Read by GPU | ||
1276 | * 4. Updated (written) by CPU again | ||
1277 | * 5. Read by GPU | ||
1278 | * | ||
1279 | * 1. Allocated | ||
1280 | * (CPU, CPU) | ||
1281 | * 2. Written by CPU | ||
1282 | * (CPU, CPU) | ||
1283 | * 3. Read by GPU | ||
1284 | * (CPU+RENDER, 0) | ||
1285 | * flush_domains = CPU | ||
1286 | * invalidate_domains = RENDER | ||
1287 | * clflush (obj) | ||
1288 | * MI_FLUSH | ||
1289 | * drm_agp_chipset_flush | ||
1290 | * 4. Updated (written) by CPU again | ||
1291 | * (CPU, CPU) | ||
1292 | * flush_domains = 0 (no previous write domain) | ||
1293 | * invalidate_domains = 0 (no new read domains) | ||
1294 | * 5. Read by GPU | ||
1295 | * (CPU+RENDER, 0) | ||
1296 | * flush_domains = CPU | ||
1297 | * invalidate_domains = RENDER | ||
1298 | * clflush (obj) | ||
1299 | * MI_FLUSH | ||
1300 | * drm_agp_chipset_flush | ||
1301 | */ | ||
1302 | static int | ||
1303 | i915_gem_object_set_domain(struct drm_gem_object *obj, | ||
1304 | uint32_t read_domains, | ||
1305 | uint32_t write_domain) | ||
1306 | { | ||
1307 | struct drm_device *dev = obj->dev; | ||
1308 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1309 | uint32_t invalidate_domains = 0; | ||
1310 | uint32_t flush_domains = 0; | ||
1311 | int ret; | ||
1312 | |||
1313 | #if WATCH_BUF | ||
1314 | DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n", | ||
1315 | __func__, obj, | ||
1316 | obj->read_domains, read_domains, | ||
1317 | obj->write_domain, write_domain); | ||
1318 | #endif | ||
1319 | /* | ||
1320 | * If the object isn't moving to a new write domain, | ||
1321 | * let the object stay in multiple read domains | ||
1322 | */ | ||
1323 | if (write_domain == 0) | ||
1324 | read_domains |= obj->read_domains; | ||
1325 | else | ||
1326 | obj_priv->dirty = 1; | ||
1327 | |||
1328 | /* | ||
1329 | * Flush the current write domain if | ||
1330 | * the new read domains don't match. Invalidate | ||
1331 | * any read domains which differ from the old | ||
1332 | * write domain | ||
1333 | */ | ||
1334 | if (obj->write_domain && obj->write_domain != read_domains) { | ||
1335 | flush_domains |= obj->write_domain; | ||
1336 | invalidate_domains |= read_domains & ~obj->write_domain; | ||
1337 | } | ||
1338 | /* | ||
1339 | * Invalidate any read caches which may have | ||
1340 | * stale data. That is, any new read domains. | ||
1341 | */ | ||
1342 | invalidate_domains |= read_domains & ~obj->read_domains; | ||
1343 | if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) { | ||
1344 | #if WATCH_BUF | ||
1345 | DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n", | ||
1346 | __func__, flush_domains, invalidate_domains); | ||
1347 | #endif | ||
1348 | /* | ||
1349 | * If we're invaliding the CPU cache and flushing a GPU cache, | ||
1350 | * then pause for rendering so that the GPU caches will be | ||
1351 | * flushed before the cpu cache is invalidated | ||
1352 | */ | ||
1353 | if ((invalidate_domains & I915_GEM_DOMAIN_CPU) && | ||
1354 | (flush_domains & ~(I915_GEM_DOMAIN_CPU | | ||
1355 | I915_GEM_DOMAIN_GTT))) { | ||
1356 | ret = i915_gem_object_wait_rendering(obj); | ||
1357 | if (ret) | ||
1358 | return ret; | ||
1359 | } | ||
1360 | i915_gem_clflush_object(obj); | ||
1361 | } | ||
1362 | |||
1363 | if ((write_domain | flush_domains) != 0) | ||
1364 | obj->write_domain = write_domain; | ||
1365 | |||
1366 | /* If we're invalidating the CPU domain, clear the per-page CPU | ||
1367 | * domain list as well. | ||
1368 | */ | ||
1369 | if (obj_priv->page_cpu_valid != NULL && | ||
1370 | (write_domain != 0 || | ||
1371 | read_domains & I915_GEM_DOMAIN_CPU)) { | ||
1372 | drm_free(obj_priv->page_cpu_valid, obj->size / PAGE_SIZE, | ||
1373 | DRM_MEM_DRIVER); | ||
1374 | obj_priv->page_cpu_valid = NULL; | ||
1375 | } | ||
1376 | obj->read_domains = read_domains; | ||
1377 | |||
1378 | dev->invalidate_domains |= invalidate_domains; | ||
1379 | dev->flush_domains |= flush_domains; | ||
1380 | #if WATCH_BUF | ||
1381 | DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n", | ||
1382 | __func__, | ||
1383 | obj->read_domains, obj->write_domain, | ||
1384 | dev->invalidate_domains, dev->flush_domains); | ||
1385 | #endif | ||
1386 | return 0; | ||
1387 | } | ||
1388 | |||
1389 | /** | ||
1390 | * Set the read/write domain on a range of the object. | ||
1391 | * | ||
1392 | * Currently only implemented for CPU reads, otherwise drops to normal | ||
1393 | * i915_gem_object_set_domain(). | ||
1394 | */ | ||
1395 | static int | ||
1396 | i915_gem_object_set_domain_range(struct drm_gem_object *obj, | ||
1397 | uint64_t offset, | ||
1398 | uint64_t size, | ||
1399 | uint32_t read_domains, | ||
1400 | uint32_t write_domain) | ||
1401 | { | ||
1402 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1403 | int ret, i; | ||
1404 | |||
1405 | if (obj->read_domains & I915_GEM_DOMAIN_CPU) | ||
1406 | return 0; | ||
1407 | |||
1408 | if (read_domains != I915_GEM_DOMAIN_CPU || | ||
1409 | write_domain != 0) | ||
1410 | return i915_gem_object_set_domain(obj, | ||
1411 | read_domains, write_domain); | ||
1412 | |||
1413 | /* Wait on any GPU rendering to the object to be flushed. */ | ||
1414 | if (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) { | ||
1415 | ret = i915_gem_object_wait_rendering(obj); | ||
1416 | if (ret) | ||
1417 | return ret; | ||
1418 | } | ||
1419 | |||
1420 | if (obj_priv->page_cpu_valid == NULL) { | ||
1421 | obj_priv->page_cpu_valid = drm_calloc(1, obj->size / PAGE_SIZE, | ||
1422 | DRM_MEM_DRIVER); | ||
1423 | } | ||
1424 | |||
1425 | /* Flush the cache on any pages that are still invalid from the CPU's | ||
1426 | * perspective. | ||
1427 | */ | ||
1428 | for (i = offset / PAGE_SIZE; i <= (offset + size - 1) / PAGE_SIZE; i++) { | ||
1429 | if (obj_priv->page_cpu_valid[i]) | ||
1430 | continue; | ||
1431 | |||
1432 | drm_clflush_pages(obj_priv->page_list + i, 1); | ||
1433 | |||
1434 | obj_priv->page_cpu_valid[i] = 1; | ||
1435 | } | ||
1436 | |||
1437 | return 0; | ||
1438 | } | ||
1439 | |||
1440 | /** | ||
1441 | * Once all of the objects have been set in the proper domain, | ||
1442 | * perform the necessary flush and invalidate operations. | ||
1443 | * | ||
1444 | * Returns the write domains flushed, for use in flush tracking. | ||
1445 | */ | ||
1446 | static uint32_t | ||
1447 | i915_gem_dev_set_domain(struct drm_device *dev) | ||
1448 | { | ||
1449 | uint32_t flush_domains = dev->flush_domains; | ||
1450 | |||
1451 | /* | ||
1452 | * Now that all the buffers are synced to the proper domains, | ||
1453 | * flush and invalidate the collected domains | ||
1454 | */ | ||
1455 | if (dev->invalidate_domains | dev->flush_domains) { | ||
1456 | #if WATCH_EXEC | ||
1457 | DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", | ||
1458 | __func__, | ||
1459 | dev->invalidate_domains, | ||
1460 | dev->flush_domains); | ||
1461 | #endif | ||
1462 | i915_gem_flush(dev, | ||
1463 | dev->invalidate_domains, | ||
1464 | dev->flush_domains); | ||
1465 | dev->invalidate_domains = 0; | ||
1466 | dev->flush_domains = 0; | ||
1467 | } | ||
1468 | |||
1469 | return flush_domains; | ||
1470 | } | ||
1471 | |||
1472 | /** | ||
1473 | * Pin an object to the GTT and evaluate the relocations landing in it. | ||
1474 | */ | ||
1475 | static int | ||
1476 | i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | ||
1477 | struct drm_file *file_priv, | ||
1478 | struct drm_i915_gem_exec_object *entry) | ||
1479 | { | ||
1480 | struct drm_device *dev = obj->dev; | ||
1481 | struct drm_i915_gem_relocation_entry reloc; | ||
1482 | struct drm_i915_gem_relocation_entry __user *relocs; | ||
1483 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1484 | int i, ret; | ||
1485 | uint32_t last_reloc_offset = -1; | ||
1486 | void *reloc_page = NULL; | ||
1487 | |||
1488 | /* Choose the GTT offset for our buffer and put it there. */ | ||
1489 | ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment); | ||
1490 | if (ret) | ||
1491 | return ret; | ||
1492 | |||
1493 | entry->offset = obj_priv->gtt_offset; | ||
1494 | |||
1495 | relocs = (struct drm_i915_gem_relocation_entry __user *) | ||
1496 | (uintptr_t) entry->relocs_ptr; | ||
1497 | /* Apply the relocations, using the GTT aperture to avoid cache | ||
1498 | * flushing requirements. | ||
1499 | */ | ||
1500 | for (i = 0; i < entry->relocation_count; i++) { | ||
1501 | struct drm_gem_object *target_obj; | ||
1502 | struct drm_i915_gem_object *target_obj_priv; | ||
1503 | uint32_t reloc_val, reloc_offset, *reloc_entry; | ||
1504 | int ret; | ||
1505 | |||
1506 | ret = copy_from_user(&reloc, relocs + i, sizeof(reloc)); | ||
1507 | if (ret != 0) { | ||
1508 | i915_gem_object_unpin(obj); | ||
1509 | return ret; | ||
1510 | } | ||
1511 | |||
1512 | target_obj = drm_gem_object_lookup(obj->dev, file_priv, | ||
1513 | reloc.target_handle); | ||
1514 | if (target_obj == NULL) { | ||
1515 | i915_gem_object_unpin(obj); | ||
1516 | return -EBADF; | ||
1517 | } | ||
1518 | target_obj_priv = target_obj->driver_private; | ||
1519 | |||
1520 | /* The target buffer should have appeared before us in the | ||
1521 | * exec_object list, so it should have a GTT space bound by now. | ||
1522 | */ | ||
1523 | if (target_obj_priv->gtt_space == NULL) { | ||
1524 | DRM_ERROR("No GTT space found for object %d\n", | ||
1525 | reloc.target_handle); | ||
1526 | drm_gem_object_unreference(target_obj); | ||
1527 | i915_gem_object_unpin(obj); | ||
1528 | return -EINVAL; | ||
1529 | } | ||
1530 | |||
1531 | if (reloc.offset > obj->size - 4) { | ||
1532 | DRM_ERROR("Relocation beyond object bounds: " | ||
1533 | "obj %p target %d offset %d size %d.\n", | ||
1534 | obj, reloc.target_handle, | ||
1535 | (int) reloc.offset, (int) obj->size); | ||
1536 | drm_gem_object_unreference(target_obj); | ||
1537 | i915_gem_object_unpin(obj); | ||
1538 | return -EINVAL; | ||
1539 | } | ||
1540 | if (reloc.offset & 3) { | ||
1541 | DRM_ERROR("Relocation not 4-byte aligned: " | ||
1542 | "obj %p target %d offset %d.\n", | ||
1543 | obj, reloc.target_handle, | ||
1544 | (int) reloc.offset); | ||
1545 | drm_gem_object_unreference(target_obj); | ||
1546 | i915_gem_object_unpin(obj); | ||
1547 | return -EINVAL; | ||
1548 | } | ||
1549 | |||
1550 | if (reloc.write_domain && target_obj->pending_write_domain && | ||
1551 | reloc.write_domain != target_obj->pending_write_domain) { | ||
1552 | DRM_ERROR("Write domain conflict: " | ||
1553 | "obj %p target %d offset %d " | ||
1554 | "new %08x old %08x\n", | ||
1555 | obj, reloc.target_handle, | ||
1556 | (int) reloc.offset, | ||
1557 | reloc.write_domain, | ||
1558 | target_obj->pending_write_domain); | ||
1559 | drm_gem_object_unreference(target_obj); | ||
1560 | i915_gem_object_unpin(obj); | ||
1561 | return -EINVAL; | ||
1562 | } | ||
1563 | |||
1564 | #if WATCH_RELOC | ||
1565 | DRM_INFO("%s: obj %p offset %08x target %d " | ||
1566 | "read %08x write %08x gtt %08x " | ||
1567 | "presumed %08x delta %08x\n", | ||
1568 | __func__, | ||
1569 | obj, | ||
1570 | (int) reloc.offset, | ||
1571 | (int) reloc.target_handle, | ||
1572 | (int) reloc.read_domains, | ||
1573 | (int) reloc.write_domain, | ||
1574 | (int) target_obj_priv->gtt_offset, | ||
1575 | (int) reloc.presumed_offset, | ||
1576 | reloc.delta); | ||
1577 | #endif | ||
1578 | |||
1579 | target_obj->pending_read_domains |= reloc.read_domains; | ||
1580 | target_obj->pending_write_domain |= reloc.write_domain; | ||
1581 | |||
1582 | /* If the relocation already has the right value in it, no | ||
1583 | * more work needs to be done. | ||
1584 | */ | ||
1585 | if (target_obj_priv->gtt_offset == reloc.presumed_offset) { | ||
1586 | drm_gem_object_unreference(target_obj); | ||
1587 | continue; | ||
1588 | } | ||
1589 | |||
1590 | /* Now that we're going to actually write some data in, | ||
1591 | * make sure that any rendering using this buffer's contents | ||
1592 | * is completed. | ||
1593 | */ | ||
1594 | i915_gem_object_wait_rendering(obj); | ||
1595 | |||
1596 | /* As we're writing through the gtt, flush | ||
1597 | * any CPU writes before we write the relocations | ||
1598 | */ | ||
1599 | if (obj->write_domain & I915_GEM_DOMAIN_CPU) { | ||
1600 | i915_gem_clflush_object(obj); | ||
1601 | drm_agp_chipset_flush(dev); | ||
1602 | obj->write_domain = 0; | ||
1603 | } | ||
1604 | |||
1605 | /* Map the page containing the relocation we're going to | ||
1606 | * perform. | ||
1607 | */ | ||
1608 | reloc_offset = obj_priv->gtt_offset + reloc.offset; | ||
1609 | if (reloc_page == NULL || | ||
1610 | (last_reloc_offset & ~(PAGE_SIZE - 1)) != | ||
1611 | (reloc_offset & ~(PAGE_SIZE - 1))) { | ||
1612 | if (reloc_page != NULL) | ||
1613 | iounmap(reloc_page); | ||
1614 | |||
1615 | reloc_page = ioremap(dev->agp->base + | ||
1616 | (reloc_offset & ~(PAGE_SIZE - 1)), | ||
1617 | PAGE_SIZE); | ||
1618 | last_reloc_offset = reloc_offset; | ||
1619 | if (reloc_page == NULL) { | ||
1620 | drm_gem_object_unreference(target_obj); | ||
1621 | i915_gem_object_unpin(obj); | ||
1622 | return -ENOMEM; | ||
1623 | } | ||
1624 | } | ||
1625 | |||
1626 | reloc_entry = (uint32_t *)((char *)reloc_page + | ||
1627 | (reloc_offset & (PAGE_SIZE - 1))); | ||
1628 | reloc_val = target_obj_priv->gtt_offset + reloc.delta; | ||
1629 | |||
1630 | #if WATCH_BUF | ||
1631 | DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n", | ||
1632 | obj, (unsigned int) reloc.offset, | ||
1633 | readl(reloc_entry), reloc_val); | ||
1634 | #endif | ||
1635 | writel(reloc_val, reloc_entry); | ||
1636 | |||
1637 | /* Write the updated presumed offset for this entry back out | ||
1638 | * to the user. | ||
1639 | */ | ||
1640 | reloc.presumed_offset = target_obj_priv->gtt_offset; | ||
1641 | ret = copy_to_user(relocs + i, &reloc, sizeof(reloc)); | ||
1642 | if (ret != 0) { | ||
1643 | drm_gem_object_unreference(target_obj); | ||
1644 | i915_gem_object_unpin(obj); | ||
1645 | return ret; | ||
1646 | } | ||
1647 | |||
1648 | drm_gem_object_unreference(target_obj); | ||
1649 | } | ||
1650 | |||
1651 | if (reloc_page != NULL) | ||
1652 | iounmap(reloc_page); | ||
1653 | |||
1654 | #if WATCH_BUF | ||
1655 | if (0) | ||
1656 | i915_gem_dump_object(obj, 128, __func__, ~0); | ||
1657 | #endif | ||
1658 | return 0; | ||
1659 | } | ||
1660 | |||
1661 | /** Dispatch a batchbuffer to the ring | ||
1662 | */ | ||
1663 | static int | ||
1664 | i915_dispatch_gem_execbuffer(struct drm_device *dev, | ||
1665 | struct drm_i915_gem_execbuffer *exec, | ||
1666 | uint64_t exec_offset) | ||
1667 | { | ||
1668 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1669 | struct drm_clip_rect __user *boxes = (struct drm_clip_rect __user *) | ||
1670 | (uintptr_t) exec->cliprects_ptr; | ||
1671 | int nbox = exec->num_cliprects; | ||
1672 | int i = 0, count; | ||
1673 | uint32_t exec_start, exec_len; | ||
1674 | RING_LOCALS; | ||
1675 | |||
1676 | exec_start = (uint32_t) exec_offset + exec->batch_start_offset; | ||
1677 | exec_len = (uint32_t) exec->batch_len; | ||
1678 | |||
1679 | if ((exec_start | exec_len) & 0x7) { | ||
1680 | DRM_ERROR("alignment\n"); | ||
1681 | return -EINVAL; | ||
1682 | } | ||
1683 | |||
1684 | if (!exec_start) | ||
1685 | return -EINVAL; | ||
1686 | |||
1687 | count = nbox ? nbox : 1; | ||
1688 | |||
1689 | for (i = 0; i < count; i++) { | ||
1690 | if (i < nbox) { | ||
1691 | int ret = i915_emit_box(dev, boxes, i, | ||
1692 | exec->DR1, exec->DR4); | ||
1693 | if (ret) | ||
1694 | return ret; | ||
1695 | } | ||
1696 | |||
1697 | if (IS_I830(dev) || IS_845G(dev)) { | ||
1698 | BEGIN_LP_RING(4); | ||
1699 | OUT_RING(MI_BATCH_BUFFER); | ||
1700 | OUT_RING(exec_start | MI_BATCH_NON_SECURE); | ||
1701 | OUT_RING(exec_start + exec_len - 4); | ||
1702 | OUT_RING(0); | ||
1703 | ADVANCE_LP_RING(); | ||
1704 | } else { | ||
1705 | BEGIN_LP_RING(2); | ||
1706 | if (IS_I965G(dev)) { | ||
1707 | OUT_RING(MI_BATCH_BUFFER_START | | ||
1708 | (2 << 6) | | ||
1709 | MI_BATCH_NON_SECURE_I965); | ||
1710 | OUT_RING(exec_start); | ||
1711 | } else { | ||
1712 | OUT_RING(MI_BATCH_BUFFER_START | | ||
1713 | (2 << 6)); | ||
1714 | OUT_RING(exec_start | MI_BATCH_NON_SECURE); | ||
1715 | } | ||
1716 | ADVANCE_LP_RING(); | ||
1717 | } | ||
1718 | } | ||
1719 | |||
1720 | /* XXX breadcrumb */ | ||
1721 | return 0; | ||
1722 | } | ||
1723 | |||
1724 | /* Throttle our rendering by waiting until the ring has completed our requests | ||
1725 | * emitted over 20 msec ago. | ||
1726 | * | ||
1727 | * This should get us reasonable parallelism between CPU and GPU but also | ||
1728 | * relatively low latency when blocking on a particular request to finish. | ||
1729 | */ | ||
1730 | static int | ||
1731 | i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) | ||
1732 | { | ||
1733 | struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; | ||
1734 | int ret = 0; | ||
1735 | uint32_t seqno; | ||
1736 | |||
1737 | mutex_lock(&dev->struct_mutex); | ||
1738 | seqno = i915_file_priv->mm.last_gem_throttle_seqno; | ||
1739 | i915_file_priv->mm.last_gem_throttle_seqno = | ||
1740 | i915_file_priv->mm.last_gem_seqno; | ||
1741 | if (seqno) | ||
1742 | ret = i915_wait_request(dev, seqno); | ||
1743 | mutex_unlock(&dev->struct_mutex); | ||
1744 | return ret; | ||
1745 | } | ||
1746 | |||
1747 | int | ||
1748 | i915_gem_execbuffer(struct drm_device *dev, void *data, | ||
1749 | struct drm_file *file_priv) | ||
1750 | { | ||
1751 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1752 | struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; | ||
1753 | struct drm_i915_gem_execbuffer *args = data; | ||
1754 | struct drm_i915_gem_exec_object *exec_list = NULL; | ||
1755 | struct drm_gem_object **object_list = NULL; | ||
1756 | struct drm_gem_object *batch_obj; | ||
1757 | int ret, i, pinned = 0; | ||
1758 | uint64_t exec_offset; | ||
1759 | uint32_t seqno, flush_domains; | ||
1760 | |||
1761 | #if WATCH_EXEC | ||
1762 | DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", | ||
1763 | (int) args->buffers_ptr, args->buffer_count, args->batch_len); | ||
1764 | #endif | ||
1765 | |||
1766 | /* Copy in the exec list from userland */ | ||
1767 | exec_list = drm_calloc(sizeof(*exec_list), args->buffer_count, | ||
1768 | DRM_MEM_DRIVER); | ||
1769 | object_list = drm_calloc(sizeof(*object_list), args->buffer_count, | ||
1770 | DRM_MEM_DRIVER); | ||
1771 | if (exec_list == NULL || object_list == NULL) { | ||
1772 | DRM_ERROR("Failed to allocate exec or object list " | ||
1773 | "for %d buffers\n", | ||
1774 | args->buffer_count); | ||
1775 | ret = -ENOMEM; | ||
1776 | goto pre_mutex_err; | ||
1777 | } | ||
1778 | ret = copy_from_user(exec_list, | ||
1779 | (struct drm_i915_relocation_entry __user *) | ||
1780 | (uintptr_t) args->buffers_ptr, | ||
1781 | sizeof(*exec_list) * args->buffer_count); | ||
1782 | if (ret != 0) { | ||
1783 | DRM_ERROR("copy %d exec entries failed %d\n", | ||
1784 | args->buffer_count, ret); | ||
1785 | goto pre_mutex_err; | ||
1786 | } | ||
1787 | |||
1788 | mutex_lock(&dev->struct_mutex); | ||
1789 | |||
1790 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
1791 | |||
1792 | if (dev_priv->mm.wedged) { | ||
1793 | DRM_ERROR("Execbuf while wedged\n"); | ||
1794 | mutex_unlock(&dev->struct_mutex); | ||
1795 | return -EIO; | ||
1796 | } | ||
1797 | |||
1798 | if (dev_priv->mm.suspended) { | ||
1799 | DRM_ERROR("Execbuf while VT-switched.\n"); | ||
1800 | mutex_unlock(&dev->struct_mutex); | ||
1801 | return -EBUSY; | ||
1802 | } | ||
1803 | |||
1804 | /* Zero the gloabl flush/invalidate flags. These | ||
1805 | * will be modified as each object is bound to the | ||
1806 | * gtt | ||
1807 | */ | ||
1808 | dev->invalidate_domains = 0; | ||
1809 | dev->flush_domains = 0; | ||
1810 | |||
1811 | /* Look up object handles and perform the relocations */ | ||
1812 | for (i = 0; i < args->buffer_count; i++) { | ||
1813 | object_list[i] = drm_gem_object_lookup(dev, file_priv, | ||
1814 | exec_list[i].handle); | ||
1815 | if (object_list[i] == NULL) { | ||
1816 | DRM_ERROR("Invalid object handle %d at index %d\n", | ||
1817 | exec_list[i].handle, i); | ||
1818 | ret = -EBADF; | ||
1819 | goto err; | ||
1820 | } | ||
1821 | |||
1822 | object_list[i]->pending_read_domains = 0; | ||
1823 | object_list[i]->pending_write_domain = 0; | ||
1824 | ret = i915_gem_object_pin_and_relocate(object_list[i], | ||
1825 | file_priv, | ||
1826 | &exec_list[i]); | ||
1827 | if (ret) { | ||
1828 | DRM_ERROR("object bind and relocate failed %d\n", ret); | ||
1829 | goto err; | ||
1830 | } | ||
1831 | pinned = i + 1; | ||
1832 | } | ||
1833 | |||
1834 | /* Set the pending read domains for the batch buffer to COMMAND */ | ||
1835 | batch_obj = object_list[args->buffer_count-1]; | ||
1836 | batch_obj->pending_read_domains = I915_GEM_DOMAIN_COMMAND; | ||
1837 | batch_obj->pending_write_domain = 0; | ||
1838 | |||
1839 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
1840 | |||
1841 | for (i = 0; i < args->buffer_count; i++) { | ||
1842 | struct drm_gem_object *obj = object_list[i]; | ||
1843 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1844 | |||
1845 | if (obj_priv->gtt_space == NULL) { | ||
1846 | /* We evicted the buffer in the process of validating | ||
1847 | * our set of buffers in. We could try to recover by | ||
1848 | * kicking them everything out and trying again from | ||
1849 | * the start. | ||
1850 | */ | ||
1851 | ret = -ENOMEM; | ||
1852 | goto err; | ||
1853 | } | ||
1854 | |||
1855 | /* make sure all previous memory operations have passed */ | ||
1856 | ret = i915_gem_object_set_domain(obj, | ||
1857 | obj->pending_read_domains, | ||
1858 | obj->pending_write_domain); | ||
1859 | if (ret) | ||
1860 | goto err; | ||
1861 | } | ||
1862 | |||
1863 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
1864 | |||
1865 | /* Flush/invalidate caches and chipset buffer */ | ||
1866 | flush_domains = i915_gem_dev_set_domain(dev); | ||
1867 | |||
1868 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
1869 | |||
1870 | #if WATCH_COHERENCY | ||
1871 | for (i = 0; i < args->buffer_count; i++) { | ||
1872 | i915_gem_object_check_coherency(object_list[i], | ||
1873 | exec_list[i].handle); | ||
1874 | } | ||
1875 | #endif | ||
1876 | |||
1877 | exec_offset = exec_list[args->buffer_count - 1].offset; | ||
1878 | |||
1879 | #if WATCH_EXEC | ||
1880 | i915_gem_dump_object(object_list[args->buffer_count - 1], | ||
1881 | args->batch_len, | ||
1882 | __func__, | ||
1883 | ~0); | ||
1884 | #endif | ||
1885 | |||
1886 | (void)i915_add_request(dev, flush_domains); | ||
1887 | |||
1888 | /* Exec the batchbuffer */ | ||
1889 | ret = i915_dispatch_gem_execbuffer(dev, args, exec_offset); | ||
1890 | if (ret) { | ||
1891 | DRM_ERROR("dispatch failed %d\n", ret); | ||
1892 | goto err; | ||
1893 | } | ||
1894 | |||
1895 | /* | ||
1896 | * Ensure that the commands in the batch buffer are | ||
1897 | * finished before the interrupt fires | ||
1898 | */ | ||
1899 | flush_domains = i915_retire_commands(dev); | ||
1900 | |||
1901 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
1902 | |||
1903 | /* | ||
1904 | * Get a seqno representing the execution of the current buffer, | ||
1905 | * which we can wait on. We would like to mitigate these interrupts, | ||
1906 | * likely by only creating seqnos occasionally (so that we have | ||
1907 | * *some* interrupts representing completion of buffers that we can | ||
1908 | * wait on when trying to clear up gtt space). | ||
1909 | */ | ||
1910 | seqno = i915_add_request(dev, flush_domains); | ||
1911 | BUG_ON(seqno == 0); | ||
1912 | i915_file_priv->mm.last_gem_seqno = seqno; | ||
1913 | for (i = 0; i < args->buffer_count; i++) { | ||
1914 | struct drm_gem_object *obj = object_list[i]; | ||
1915 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1916 | |||
1917 | i915_gem_object_move_to_active(obj); | ||
1918 | obj_priv->last_rendering_seqno = seqno; | ||
1919 | #if WATCH_LRU | ||
1920 | DRM_INFO("%s: move to exec list %p\n", __func__, obj); | ||
1921 | #endif | ||
1922 | } | ||
1923 | #if WATCH_LRU | ||
1924 | i915_dump_lru(dev, __func__); | ||
1925 | #endif | ||
1926 | |||
1927 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
1928 | |||
1929 | /* Copy the new buffer offsets back to the user's exec list. */ | ||
1930 | ret = copy_to_user((struct drm_i915_relocation_entry __user *) | ||
1931 | (uintptr_t) args->buffers_ptr, | ||
1932 | exec_list, | ||
1933 | sizeof(*exec_list) * args->buffer_count); | ||
1934 | if (ret) | ||
1935 | DRM_ERROR("failed to copy %d exec entries " | ||
1936 | "back to user (%d)\n", | ||
1937 | args->buffer_count, ret); | ||
1938 | err: | ||
1939 | if (object_list != NULL) { | ||
1940 | for (i = 0; i < pinned; i++) | ||
1941 | i915_gem_object_unpin(object_list[i]); | ||
1942 | |||
1943 | for (i = 0; i < args->buffer_count; i++) | ||
1944 | drm_gem_object_unreference(object_list[i]); | ||
1945 | } | ||
1946 | mutex_unlock(&dev->struct_mutex); | ||
1947 | |||
1948 | pre_mutex_err: | ||
1949 | drm_free(object_list, sizeof(*object_list) * args->buffer_count, | ||
1950 | DRM_MEM_DRIVER); | ||
1951 | drm_free(exec_list, sizeof(*exec_list) * args->buffer_count, | ||
1952 | DRM_MEM_DRIVER); | ||
1953 | |||
1954 | return ret; | ||
1955 | } | ||
1956 | |||
1957 | int | ||
1958 | i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) | ||
1959 | { | ||
1960 | struct drm_device *dev = obj->dev; | ||
1961 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1962 | int ret; | ||
1963 | |||
1964 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
1965 | if (obj_priv->gtt_space == NULL) { | ||
1966 | ret = i915_gem_object_bind_to_gtt(obj, alignment); | ||
1967 | if (ret != 0) { | ||
1968 | DRM_ERROR("Failure to bind: %d", ret); | ||
1969 | return ret; | ||
1970 | } | ||
1971 | } | ||
1972 | obj_priv->pin_count++; | ||
1973 | |||
1974 | /* If the object is not active and not pending a flush, | ||
1975 | * remove it from the inactive list | ||
1976 | */ | ||
1977 | if (obj_priv->pin_count == 1) { | ||
1978 | atomic_inc(&dev->pin_count); | ||
1979 | atomic_add(obj->size, &dev->pin_memory); | ||
1980 | if (!obj_priv->active && | ||
1981 | (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | | ||
1982 | I915_GEM_DOMAIN_GTT)) == 0 && | ||
1983 | !list_empty(&obj_priv->list)) | ||
1984 | list_del_init(&obj_priv->list); | ||
1985 | } | ||
1986 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
1987 | |||
1988 | return 0; | ||
1989 | } | ||
1990 | |||
1991 | void | ||
1992 | i915_gem_object_unpin(struct drm_gem_object *obj) | ||
1993 | { | ||
1994 | struct drm_device *dev = obj->dev; | ||
1995 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1996 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1997 | |||
1998 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
1999 | obj_priv->pin_count--; | ||
2000 | BUG_ON(obj_priv->pin_count < 0); | ||
2001 | BUG_ON(obj_priv->gtt_space == NULL); | ||
2002 | |||
2003 | /* If the object is no longer pinned, and is | ||
2004 | * neither active nor being flushed, then stick it on | ||
2005 | * the inactive list | ||
2006 | */ | ||
2007 | if (obj_priv->pin_count == 0) { | ||
2008 | if (!obj_priv->active && | ||
2009 | (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | | ||
2010 | I915_GEM_DOMAIN_GTT)) == 0) | ||
2011 | list_move_tail(&obj_priv->list, | ||
2012 | &dev_priv->mm.inactive_list); | ||
2013 | atomic_dec(&dev->pin_count); | ||
2014 | atomic_sub(obj->size, &dev->pin_memory); | ||
2015 | } | ||
2016 | i915_verify_inactive(dev, __FILE__, __LINE__); | ||
2017 | } | ||
2018 | |||
2019 | int | ||
2020 | i915_gem_pin_ioctl(struct drm_device *dev, void *data, | ||
2021 | struct drm_file *file_priv) | ||
2022 | { | ||
2023 | struct drm_i915_gem_pin *args = data; | ||
2024 | struct drm_gem_object *obj; | ||
2025 | struct drm_i915_gem_object *obj_priv; | ||
2026 | int ret; | ||
2027 | |||
2028 | mutex_lock(&dev->struct_mutex); | ||
2029 | |||
2030 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
2031 | if (obj == NULL) { | ||
2032 | DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n", | ||
2033 | args->handle); | ||
2034 | mutex_unlock(&dev->struct_mutex); | ||
2035 | return -EBADF; | ||
2036 | } | ||
2037 | obj_priv = obj->driver_private; | ||
2038 | |||
2039 | ret = i915_gem_object_pin(obj, args->alignment); | ||
2040 | if (ret != 0) { | ||
2041 | drm_gem_object_unreference(obj); | ||
2042 | mutex_unlock(&dev->struct_mutex); | ||
2043 | return ret; | ||
2044 | } | ||
2045 | |||
2046 | /* XXX - flush the CPU caches for pinned objects | ||
2047 | * as the X server doesn't manage domains yet | ||
2048 | */ | ||
2049 | if (obj->write_domain & I915_GEM_DOMAIN_CPU) { | ||
2050 | i915_gem_clflush_object(obj); | ||
2051 | drm_agp_chipset_flush(dev); | ||
2052 | obj->write_domain = 0; | ||
2053 | } | ||
2054 | args->offset = obj_priv->gtt_offset; | ||
2055 | drm_gem_object_unreference(obj); | ||
2056 | mutex_unlock(&dev->struct_mutex); | ||
2057 | |||
2058 | return 0; | ||
2059 | } | ||
2060 | |||
2061 | int | ||
2062 | i915_gem_unpin_ioctl(struct drm_device *dev, void *data, | ||
2063 | struct drm_file *file_priv) | ||
2064 | { | ||
2065 | struct drm_i915_gem_pin *args = data; | ||
2066 | struct drm_gem_object *obj; | ||
2067 | |||
2068 | mutex_lock(&dev->struct_mutex); | ||
2069 | |||
2070 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
2071 | if (obj == NULL) { | ||
2072 | DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n", | ||
2073 | args->handle); | ||
2074 | mutex_unlock(&dev->struct_mutex); | ||
2075 | return -EBADF; | ||
2076 | } | ||
2077 | |||
2078 | i915_gem_object_unpin(obj); | ||
2079 | |||
2080 | drm_gem_object_unreference(obj); | ||
2081 | mutex_unlock(&dev->struct_mutex); | ||
2082 | return 0; | ||
2083 | } | ||
2084 | |||
2085 | int | ||
2086 | i915_gem_busy_ioctl(struct drm_device *dev, void *data, | ||
2087 | struct drm_file *file_priv) | ||
2088 | { | ||
2089 | struct drm_i915_gem_busy *args = data; | ||
2090 | struct drm_gem_object *obj; | ||
2091 | struct drm_i915_gem_object *obj_priv; | ||
2092 | |||
2093 | mutex_lock(&dev->struct_mutex); | ||
2094 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
2095 | if (obj == NULL) { | ||
2096 | DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n", | ||
2097 | args->handle); | ||
2098 | mutex_unlock(&dev->struct_mutex); | ||
2099 | return -EBADF; | ||
2100 | } | ||
2101 | |||
2102 | obj_priv = obj->driver_private; | ||
2103 | args->busy = obj_priv->active; | ||
2104 | |||
2105 | drm_gem_object_unreference(obj); | ||
2106 | mutex_unlock(&dev->struct_mutex); | ||
2107 | return 0; | ||
2108 | } | ||
2109 | |||
2110 | int | ||
2111 | i915_gem_throttle_ioctl(struct drm_device *dev, void *data, | ||
2112 | struct drm_file *file_priv) | ||
2113 | { | ||
2114 | return i915_gem_ring_throttle(dev, file_priv); | ||
2115 | } | ||
2116 | |||
2117 | int i915_gem_init_object(struct drm_gem_object *obj) | ||
2118 | { | ||
2119 | struct drm_i915_gem_object *obj_priv; | ||
2120 | |||
2121 | obj_priv = drm_calloc(1, sizeof(*obj_priv), DRM_MEM_DRIVER); | ||
2122 | if (obj_priv == NULL) | ||
2123 | return -ENOMEM; | ||
2124 | |||
2125 | /* | ||
2126 | * We've just allocated pages from the kernel, | ||
2127 | * so they've just been written by the CPU with | ||
2128 | * zeros. They'll need to be clflushed before we | ||
2129 | * use them with the GPU. | ||
2130 | */ | ||
2131 | obj->write_domain = I915_GEM_DOMAIN_CPU; | ||
2132 | obj->read_domains = I915_GEM_DOMAIN_CPU; | ||
2133 | |||
2134 | obj->driver_private = obj_priv; | ||
2135 | obj_priv->obj = obj; | ||
2136 | INIT_LIST_HEAD(&obj_priv->list); | ||
2137 | return 0; | ||
2138 | } | ||
2139 | |||
2140 | void i915_gem_free_object(struct drm_gem_object *obj) | ||
2141 | { | ||
2142 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
2143 | |||
2144 | while (obj_priv->pin_count > 0) | ||
2145 | i915_gem_object_unpin(obj); | ||
2146 | |||
2147 | i915_gem_object_unbind(obj); | ||
2148 | |||
2149 | drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER); | ||
2150 | drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); | ||
2151 | } | ||
2152 | |||
2153 | static int | ||
2154 | i915_gem_set_domain(struct drm_gem_object *obj, | ||
2155 | struct drm_file *file_priv, | ||
2156 | uint32_t read_domains, | ||
2157 | uint32_t write_domain) | ||
2158 | { | ||
2159 | struct drm_device *dev = obj->dev; | ||
2160 | int ret; | ||
2161 | uint32_t flush_domains; | ||
2162 | |||
2163 | BUG_ON(!mutex_is_locked(&dev->struct_mutex)); | ||
2164 | |||
2165 | ret = i915_gem_object_set_domain(obj, read_domains, write_domain); | ||
2166 | if (ret) | ||
2167 | return ret; | ||
2168 | flush_domains = i915_gem_dev_set_domain(obj->dev); | ||
2169 | |||
2170 | if (flush_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) | ||
2171 | (void) i915_add_request(dev, flush_domains); | ||
2172 | |||
2173 | return 0; | ||
2174 | } | ||
2175 | |||
2176 | /** Unbinds all objects that are on the given buffer list. */ | ||
2177 | static int | ||
2178 | i915_gem_evict_from_list(struct drm_device *dev, struct list_head *head) | ||
2179 | { | ||
2180 | struct drm_gem_object *obj; | ||
2181 | struct drm_i915_gem_object *obj_priv; | ||
2182 | int ret; | ||
2183 | |||
2184 | while (!list_empty(head)) { | ||
2185 | obj_priv = list_first_entry(head, | ||
2186 | struct drm_i915_gem_object, | ||
2187 | list); | ||
2188 | obj = obj_priv->obj; | ||
2189 | |||
2190 | if (obj_priv->pin_count != 0) { | ||
2191 | DRM_ERROR("Pinned object in unbind list\n"); | ||
2192 | mutex_unlock(&dev->struct_mutex); | ||
2193 | return -EINVAL; | ||
2194 | } | ||
2195 | |||
2196 | ret = i915_gem_object_unbind(obj); | ||
2197 | if (ret != 0) { | ||
2198 | DRM_ERROR("Error unbinding object in LeaveVT: %d\n", | ||
2199 | ret); | ||
2200 | mutex_unlock(&dev->struct_mutex); | ||
2201 | return ret; | ||
2202 | } | ||
2203 | } | ||
2204 | |||
2205 | |||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2209 | static int | ||
2210 | i915_gem_idle(struct drm_device *dev) | ||
2211 | { | ||
2212 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2213 | uint32_t seqno, cur_seqno, last_seqno; | ||
2214 | int stuck, ret; | ||
2215 | |||
2216 | if (dev_priv->mm.suspended) | ||
2217 | return 0; | ||
2218 | |||
2219 | /* Hack! Don't let anybody do execbuf while we don't control the chip. | ||
2220 | * We need to replace this with a semaphore, or something. | ||
2221 | */ | ||
2222 | dev_priv->mm.suspended = 1; | ||
2223 | |||
2224 | i915_kernel_lost_context(dev); | ||
2225 | |||
2226 | /* Flush the GPU along with all non-CPU write domains | ||
2227 | */ | ||
2228 | i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT), | ||
2229 | ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); | ||
2230 | seqno = i915_add_request(dev, ~(I915_GEM_DOMAIN_CPU | | ||
2231 | I915_GEM_DOMAIN_GTT)); | ||
2232 | |||
2233 | if (seqno == 0) { | ||
2234 | mutex_unlock(&dev->struct_mutex); | ||
2235 | return -ENOMEM; | ||
2236 | } | ||
2237 | |||
2238 | dev_priv->mm.waiting_gem_seqno = seqno; | ||
2239 | last_seqno = 0; | ||
2240 | stuck = 0; | ||
2241 | for (;;) { | ||
2242 | cur_seqno = i915_get_gem_seqno(dev); | ||
2243 | if (i915_seqno_passed(cur_seqno, seqno)) | ||
2244 | break; | ||
2245 | if (last_seqno == cur_seqno) { | ||
2246 | if (stuck++ > 100) { | ||
2247 | DRM_ERROR("hardware wedged\n"); | ||
2248 | dev_priv->mm.wedged = 1; | ||
2249 | DRM_WAKEUP(&dev_priv->irq_queue); | ||
2250 | break; | ||
2251 | } | ||
2252 | } | ||
2253 | msleep(10); | ||
2254 | last_seqno = cur_seqno; | ||
2255 | } | ||
2256 | dev_priv->mm.waiting_gem_seqno = 0; | ||
2257 | |||
2258 | i915_gem_retire_requests(dev); | ||
2259 | |||
2260 | /* Active and flushing should now be empty as we've | ||
2261 | * waited for a sequence higher than any pending execbuffer | ||
2262 | */ | ||
2263 | BUG_ON(!list_empty(&dev_priv->mm.active_list)); | ||
2264 | BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); | ||
2265 | |||
2266 | /* Request should now be empty as we've also waited | ||
2267 | * for the last request in the list | ||
2268 | */ | ||
2269 | BUG_ON(!list_empty(&dev_priv->mm.request_list)); | ||
2270 | |||
2271 | /* Move all buffers out of the GTT. */ | ||
2272 | ret = i915_gem_evict_from_list(dev, &dev_priv->mm.inactive_list); | ||
2273 | if (ret) | ||
2274 | return ret; | ||
2275 | |||
2276 | BUG_ON(!list_empty(&dev_priv->mm.active_list)); | ||
2277 | BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); | ||
2278 | BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); | ||
2279 | BUG_ON(!list_empty(&dev_priv->mm.request_list)); | ||
2280 | return 0; | ||
2281 | } | ||
2282 | |||
2283 | static int | ||
2284 | i915_gem_init_hws(struct drm_device *dev) | ||
2285 | { | ||
2286 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2287 | struct drm_gem_object *obj; | ||
2288 | struct drm_i915_gem_object *obj_priv; | ||
2289 | int ret; | ||
2290 | |||
2291 | /* If we need a physical address for the status page, it's already | ||
2292 | * initialized at driver load time. | ||
2293 | */ | ||
2294 | if (!I915_NEED_GFX_HWS(dev)) | ||
2295 | return 0; | ||
2296 | |||
2297 | obj = drm_gem_object_alloc(dev, 4096); | ||
2298 | if (obj == NULL) { | ||
2299 | DRM_ERROR("Failed to allocate status page\n"); | ||
2300 | return -ENOMEM; | ||
2301 | } | ||
2302 | obj_priv = obj->driver_private; | ||
2303 | |||
2304 | ret = i915_gem_object_pin(obj, 4096); | ||
2305 | if (ret != 0) { | ||
2306 | drm_gem_object_unreference(obj); | ||
2307 | return ret; | ||
2308 | } | ||
2309 | |||
2310 | dev_priv->status_gfx_addr = obj_priv->gtt_offset; | ||
2311 | dev_priv->hws_map.offset = dev->agp->base + obj_priv->gtt_offset; | ||
2312 | dev_priv->hws_map.size = 4096; | ||
2313 | dev_priv->hws_map.type = 0; | ||
2314 | dev_priv->hws_map.flags = 0; | ||
2315 | dev_priv->hws_map.mtrr = 0; | ||
2316 | |||
2317 | drm_core_ioremap(&dev_priv->hws_map, dev); | ||
2318 | if (dev_priv->hws_map.handle == NULL) { | ||
2319 | DRM_ERROR("Failed to map status page.\n"); | ||
2320 | memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); | ||
2321 | drm_gem_object_unreference(obj); | ||
2322 | return -EINVAL; | ||
2323 | } | ||
2324 | dev_priv->hws_obj = obj; | ||
2325 | dev_priv->hw_status_page = dev_priv->hws_map.handle; | ||
2326 | memset(dev_priv->hw_status_page, 0, PAGE_SIZE); | ||
2327 | I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); | ||
2328 | DRM_DEBUG("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); | ||
2329 | |||
2330 | return 0; | ||
2331 | } | ||
2332 | |||
2333 | static int | ||
2334 | i915_gem_init_ringbuffer(struct drm_device *dev) | ||
2335 | { | ||
2336 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2337 | struct drm_gem_object *obj; | ||
2338 | struct drm_i915_gem_object *obj_priv; | ||
2339 | int ret; | ||
2340 | |||
2341 | ret = i915_gem_init_hws(dev); | ||
2342 | if (ret != 0) | ||
2343 | return ret; | ||
2344 | |||
2345 | obj = drm_gem_object_alloc(dev, 128 * 1024); | ||
2346 | if (obj == NULL) { | ||
2347 | DRM_ERROR("Failed to allocate ringbuffer\n"); | ||
2348 | return -ENOMEM; | ||
2349 | } | ||
2350 | obj_priv = obj->driver_private; | ||
2351 | |||
2352 | ret = i915_gem_object_pin(obj, 4096); | ||
2353 | if (ret != 0) { | ||
2354 | drm_gem_object_unreference(obj); | ||
2355 | return ret; | ||
2356 | } | ||
2357 | |||
2358 | /* Set up the kernel mapping for the ring. */ | ||
2359 | dev_priv->ring.Size = obj->size; | ||
2360 | dev_priv->ring.tail_mask = obj->size - 1; | ||
2361 | |||
2362 | dev_priv->ring.map.offset = dev->agp->base + obj_priv->gtt_offset; | ||
2363 | dev_priv->ring.map.size = obj->size; | ||
2364 | dev_priv->ring.map.type = 0; | ||
2365 | dev_priv->ring.map.flags = 0; | ||
2366 | dev_priv->ring.map.mtrr = 0; | ||
2367 | |||
2368 | drm_core_ioremap(&dev_priv->ring.map, dev); | ||
2369 | if (dev_priv->ring.map.handle == NULL) { | ||
2370 | DRM_ERROR("Failed to map ringbuffer.\n"); | ||
2371 | memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); | ||
2372 | drm_gem_object_unreference(obj); | ||
2373 | return -EINVAL; | ||
2374 | } | ||
2375 | dev_priv->ring.ring_obj = obj; | ||
2376 | dev_priv->ring.virtual_start = dev_priv->ring.map.handle; | ||
2377 | |||
2378 | /* Stop the ring if it's running. */ | ||
2379 | I915_WRITE(PRB0_CTL, 0); | ||
2380 | I915_WRITE(PRB0_HEAD, 0); | ||
2381 | I915_WRITE(PRB0_TAIL, 0); | ||
2382 | I915_WRITE(PRB0_START, 0); | ||
2383 | |||
2384 | /* Initialize the ring. */ | ||
2385 | I915_WRITE(PRB0_START, obj_priv->gtt_offset); | ||
2386 | I915_WRITE(PRB0_CTL, | ||
2387 | ((obj->size - 4096) & RING_NR_PAGES) | | ||
2388 | RING_NO_REPORT | | ||
2389 | RING_VALID); | ||
2390 | |||
2391 | /* Update our cache of the ring state */ | ||
2392 | i915_kernel_lost_context(dev); | ||
2393 | |||
2394 | return 0; | ||
2395 | } | ||
2396 | |||
2397 | static void | ||
2398 | i915_gem_cleanup_ringbuffer(struct drm_device *dev) | ||
2399 | { | ||
2400 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2401 | |||
2402 | if (dev_priv->ring.ring_obj == NULL) | ||
2403 | return; | ||
2404 | |||
2405 | drm_core_ioremapfree(&dev_priv->ring.map, dev); | ||
2406 | |||
2407 | i915_gem_object_unpin(dev_priv->ring.ring_obj); | ||
2408 | drm_gem_object_unreference(dev_priv->ring.ring_obj); | ||
2409 | dev_priv->ring.ring_obj = NULL; | ||
2410 | memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); | ||
2411 | |||
2412 | if (dev_priv->hws_obj != NULL) { | ||
2413 | i915_gem_object_unpin(dev_priv->hws_obj); | ||
2414 | drm_gem_object_unreference(dev_priv->hws_obj); | ||
2415 | dev_priv->hws_obj = NULL; | ||
2416 | memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); | ||
2417 | |||
2418 | /* Write high address into HWS_PGA when disabling. */ | ||
2419 | I915_WRITE(HWS_PGA, 0x1ffff000); | ||
2420 | } | ||
2421 | } | ||
2422 | |||
2423 | int | ||
2424 | i915_gem_entervt_ioctl(struct drm_device *dev, void *data, | ||
2425 | struct drm_file *file_priv) | ||
2426 | { | ||
2427 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2428 | int ret; | ||
2429 | |||
2430 | if (dev_priv->mm.wedged) { | ||
2431 | DRM_ERROR("Reenabling wedged hardware, good luck\n"); | ||
2432 | dev_priv->mm.wedged = 0; | ||
2433 | } | ||
2434 | |||
2435 | ret = i915_gem_init_ringbuffer(dev); | ||
2436 | if (ret != 0) | ||
2437 | return ret; | ||
2438 | |||
2439 | mutex_lock(&dev->struct_mutex); | ||
2440 | BUG_ON(!list_empty(&dev_priv->mm.active_list)); | ||
2441 | BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); | ||
2442 | BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); | ||
2443 | BUG_ON(!list_empty(&dev_priv->mm.request_list)); | ||
2444 | dev_priv->mm.suspended = 0; | ||
2445 | mutex_unlock(&dev->struct_mutex); | ||
2446 | return 0; | ||
2447 | } | ||
2448 | |||
2449 | int | ||
2450 | i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, | ||
2451 | struct drm_file *file_priv) | ||
2452 | { | ||
2453 | int ret; | ||
2454 | |||
2455 | mutex_lock(&dev->struct_mutex); | ||
2456 | ret = i915_gem_idle(dev); | ||
2457 | if (ret == 0) | ||
2458 | i915_gem_cleanup_ringbuffer(dev); | ||
2459 | mutex_unlock(&dev->struct_mutex); | ||
2460 | |||
2461 | return 0; | ||
2462 | } | ||
2463 | |||
2464 | void | ||
2465 | i915_gem_lastclose(struct drm_device *dev) | ||
2466 | { | ||
2467 | int ret; | ||
2468 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2469 | |||
2470 | mutex_lock(&dev->struct_mutex); | ||
2471 | |||
2472 | if (dev_priv->ring.ring_obj != NULL) { | ||
2473 | ret = i915_gem_idle(dev); | ||
2474 | if (ret) | ||
2475 | DRM_ERROR("failed to idle hardware: %d\n", ret); | ||
2476 | |||
2477 | i915_gem_cleanup_ringbuffer(dev); | ||
2478 | } | ||
2479 | |||
2480 | mutex_unlock(&dev->struct_mutex); | ||
2481 | } | ||
2482 | |||
2483 | void | ||
2484 | i915_gem_load(struct drm_device *dev) | ||
2485 | { | ||
2486 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2487 | |||
2488 | INIT_LIST_HEAD(&dev_priv->mm.active_list); | ||
2489 | INIT_LIST_HEAD(&dev_priv->mm.flushing_list); | ||
2490 | INIT_LIST_HEAD(&dev_priv->mm.inactive_list); | ||
2491 | INIT_LIST_HEAD(&dev_priv->mm.request_list); | ||
2492 | INIT_DELAYED_WORK(&dev_priv->mm.retire_work, | ||
2493 | i915_gem_retire_work_handler); | ||
2494 | dev_priv->mm.next_gem_seqno = 1; | ||
2495 | |||
2496 | i915_gem_detect_bit_6_swizzle(dev); | ||
2497 | } | ||
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c new file mode 100644 index 000000000000..131c088f8c8a --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_debug.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Keith Packard <keithp@keithp.com> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "drmP.h" | ||
29 | #include "drm.h" | ||
30 | #include "i915_drm.h" | ||
31 | #include "i915_drv.h" | ||
32 | |||
33 | #if WATCH_INACTIVE | ||
34 | void | ||
35 | i915_verify_inactive(struct drm_device *dev, char *file, int line) | ||
36 | { | ||
37 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
38 | struct drm_gem_object *obj; | ||
39 | struct drm_i915_gem_object *obj_priv; | ||
40 | |||
41 | list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { | ||
42 | obj = obj_priv->obj; | ||
43 | if (obj_priv->pin_count || obj_priv->active || | ||
44 | (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | | ||
45 | I915_GEM_DOMAIN_GTT))) | ||
46 | DRM_ERROR("inactive %p (p %d a %d w %x) %s:%d\n", | ||
47 | obj, | ||
48 | obj_priv->pin_count, obj_priv->active, | ||
49 | obj->write_domain, file, line); | ||
50 | } | ||
51 | } | ||
52 | #endif /* WATCH_INACTIVE */ | ||
53 | |||
54 | |||
55 | #if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE | ||
56 | static void | ||
57 | i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end, | ||
58 | uint32_t bias, uint32_t mark) | ||
59 | { | ||
60 | uint32_t *mem = kmap_atomic(page, KM_USER0); | ||
61 | int i; | ||
62 | for (i = start; i < end; i += 4) | ||
63 | DRM_INFO("%08x: %08x%s\n", | ||
64 | (int) (bias + i), mem[i / 4], | ||
65 | (bias + i == mark) ? " ********" : ""); | ||
66 | kunmap_atomic(mem, KM_USER0); | ||
67 | /* give syslog time to catch up */ | ||
68 | msleep(1); | ||
69 | } | ||
70 | |||
71 | void | ||
72 | i915_gem_dump_object(struct drm_gem_object *obj, int len, | ||
73 | const char *where, uint32_t mark) | ||
74 | { | ||
75 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
76 | int page; | ||
77 | |||
78 | DRM_INFO("%s: object at offset %08x\n", where, obj_priv->gtt_offset); | ||
79 | for (page = 0; page < (len + PAGE_SIZE-1) / PAGE_SIZE; page++) { | ||
80 | int page_len, chunk, chunk_len; | ||
81 | |||
82 | page_len = len - page * PAGE_SIZE; | ||
83 | if (page_len > PAGE_SIZE) | ||
84 | page_len = PAGE_SIZE; | ||
85 | |||
86 | for (chunk = 0; chunk < page_len; chunk += 128) { | ||
87 | chunk_len = page_len - chunk; | ||
88 | if (chunk_len > 128) | ||
89 | chunk_len = 128; | ||
90 | i915_gem_dump_page(obj_priv->page_list[page], | ||
91 | chunk, chunk + chunk_len, | ||
92 | obj_priv->gtt_offset + | ||
93 | page * PAGE_SIZE, | ||
94 | mark); | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | #endif | ||
99 | |||
100 | #if WATCH_LRU | ||
101 | void | ||
102 | i915_dump_lru(struct drm_device *dev, const char *where) | ||
103 | { | ||
104 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
105 | struct drm_i915_gem_object *obj_priv; | ||
106 | |||
107 | DRM_INFO("active list %s {\n", where); | ||
108 | list_for_each_entry(obj_priv, &dev_priv->mm.active_list, | ||
109 | list) | ||
110 | { | ||
111 | DRM_INFO(" %p: %08x\n", obj_priv, | ||
112 | obj_priv->last_rendering_seqno); | ||
113 | } | ||
114 | DRM_INFO("}\n"); | ||
115 | DRM_INFO("flushing list %s {\n", where); | ||
116 | list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, | ||
117 | list) | ||
118 | { | ||
119 | DRM_INFO(" %p: %08x\n", obj_priv, | ||
120 | obj_priv->last_rendering_seqno); | ||
121 | } | ||
122 | DRM_INFO("}\n"); | ||
123 | DRM_INFO("inactive %s {\n", where); | ||
124 | list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { | ||
125 | DRM_INFO(" %p: %08x\n", obj_priv, | ||
126 | obj_priv->last_rendering_seqno); | ||
127 | } | ||
128 | DRM_INFO("}\n"); | ||
129 | } | ||
130 | #endif | ||
131 | |||
132 | |||
133 | #if WATCH_COHERENCY | ||
134 | void | ||
135 | i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle) | ||
136 | { | ||
137 | struct drm_device *dev = obj->dev; | ||
138 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
139 | int page; | ||
140 | uint32_t *gtt_mapping; | ||
141 | uint32_t *backing_map = NULL; | ||
142 | int bad_count = 0; | ||
143 | |||
144 | DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %dkb):\n", | ||
145 | __func__, obj, obj_priv->gtt_offset, handle, | ||
146 | obj->size / 1024); | ||
147 | |||
148 | gtt_mapping = ioremap(dev->agp->base + obj_priv->gtt_offset, | ||
149 | obj->size); | ||
150 | if (gtt_mapping == NULL) { | ||
151 | DRM_ERROR("failed to map GTT space\n"); | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | for (page = 0; page < obj->size / PAGE_SIZE; page++) { | ||
156 | int i; | ||
157 | |||
158 | backing_map = kmap_atomic(obj_priv->page_list[page], KM_USER0); | ||
159 | |||
160 | if (backing_map == NULL) { | ||
161 | DRM_ERROR("failed to map backing page\n"); | ||
162 | goto out; | ||
163 | } | ||
164 | |||
165 | for (i = 0; i < PAGE_SIZE / 4; i++) { | ||
166 | uint32_t cpuval = backing_map[i]; | ||
167 | uint32_t gttval = readl(gtt_mapping + | ||
168 | page * 1024 + i); | ||
169 | |||
170 | if (cpuval != gttval) { | ||
171 | DRM_INFO("incoherent CPU vs GPU at 0x%08x: " | ||
172 | "0x%08x vs 0x%08x\n", | ||
173 | (int)(obj_priv->gtt_offset + | ||
174 | page * PAGE_SIZE + i * 4), | ||
175 | cpuval, gttval); | ||
176 | if (bad_count++ >= 8) { | ||
177 | DRM_INFO("...\n"); | ||
178 | goto out; | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | kunmap_atomic(backing_map, KM_USER0); | ||
183 | backing_map = NULL; | ||
184 | } | ||
185 | |||
186 | out: | ||
187 | if (backing_map != NULL) | ||
188 | kunmap_atomic(backing_map, KM_USER0); | ||
189 | iounmap(gtt_mapping); | ||
190 | |||
191 | /* give syslog time to catch up */ | ||
192 | msleep(1); | ||
193 | |||
194 | /* Directly flush the object, since we just loaded values with the CPU | ||
195 | * from the backing pages and we don't want to disturb the cache | ||
196 | * management that we're trying to observe. | ||
197 | */ | ||
198 | |||
199 | i915_gem_clflush_object(obj); | ||
200 | } | ||
201 | #endif | ||
diff --git a/drivers/gpu/drm/i915/i915_gem_proc.c b/drivers/gpu/drm/i915/i915_gem_proc.c new file mode 100644 index 000000000000..15d4160415b0 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_proc.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * Keith Packard <keithp@keithp.com> | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include "drmP.h" | ||
30 | #include "drm.h" | ||
31 | #include "i915_drm.h" | ||
32 | #include "i915_drv.h" | ||
33 | |||
34 | static int i915_gem_active_info(char *buf, char **start, off_t offset, | ||
35 | int request, int *eof, void *data) | ||
36 | { | ||
37 | struct drm_minor *minor = (struct drm_minor *) data; | ||
38 | struct drm_device *dev = minor->dev; | ||
39 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
40 | struct drm_i915_gem_object *obj_priv; | ||
41 | int len = 0; | ||
42 | |||
43 | if (offset > DRM_PROC_LIMIT) { | ||
44 | *eof = 1; | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | *start = &buf[offset]; | ||
49 | *eof = 0; | ||
50 | DRM_PROC_PRINT("Active:\n"); | ||
51 | list_for_each_entry(obj_priv, &dev_priv->mm.active_list, | ||
52 | list) | ||
53 | { | ||
54 | struct drm_gem_object *obj = obj_priv->obj; | ||
55 | if (obj->name) { | ||
56 | DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n", | ||
57 | obj, obj->name, | ||
58 | obj->read_domains, obj->write_domain, | ||
59 | obj_priv->last_rendering_seqno); | ||
60 | } else { | ||
61 | DRM_PROC_PRINT(" %p: %08x %08x %d\n", | ||
62 | obj, | ||
63 | obj->read_domains, obj->write_domain, | ||
64 | obj_priv->last_rendering_seqno); | ||
65 | } | ||
66 | } | ||
67 | if (len > request + offset) | ||
68 | return request; | ||
69 | *eof = 1; | ||
70 | return len - offset; | ||
71 | } | ||
72 | |||
73 | static int i915_gem_flushing_info(char *buf, char **start, off_t offset, | ||
74 | int request, int *eof, void *data) | ||
75 | { | ||
76 | struct drm_minor *minor = (struct drm_minor *) data; | ||
77 | struct drm_device *dev = minor->dev; | ||
78 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
79 | struct drm_i915_gem_object *obj_priv; | ||
80 | int len = 0; | ||
81 | |||
82 | if (offset > DRM_PROC_LIMIT) { | ||
83 | *eof = 1; | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | *start = &buf[offset]; | ||
88 | *eof = 0; | ||
89 | DRM_PROC_PRINT("Flushing:\n"); | ||
90 | list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, | ||
91 | list) | ||
92 | { | ||
93 | struct drm_gem_object *obj = obj_priv->obj; | ||
94 | if (obj->name) { | ||
95 | DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n", | ||
96 | obj, obj->name, | ||
97 | obj->read_domains, obj->write_domain, | ||
98 | obj_priv->last_rendering_seqno); | ||
99 | } else { | ||
100 | DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj, | ||
101 | obj->read_domains, obj->write_domain, | ||
102 | obj_priv->last_rendering_seqno); | ||
103 | } | ||
104 | } | ||
105 | if (len > request + offset) | ||
106 | return request; | ||
107 | *eof = 1; | ||
108 | return len - offset; | ||
109 | } | ||
110 | |||
111 | static int i915_gem_inactive_info(char *buf, char **start, off_t offset, | ||
112 | int request, int *eof, void *data) | ||
113 | { | ||
114 | struct drm_minor *minor = (struct drm_minor *) data; | ||
115 | struct drm_device *dev = minor->dev; | ||
116 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
117 | struct drm_i915_gem_object *obj_priv; | ||
118 | int len = 0; | ||
119 | |||
120 | if (offset > DRM_PROC_LIMIT) { | ||
121 | *eof = 1; | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | *start = &buf[offset]; | ||
126 | *eof = 0; | ||
127 | DRM_PROC_PRINT("Inactive:\n"); | ||
128 | list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, | ||
129 | list) | ||
130 | { | ||
131 | struct drm_gem_object *obj = obj_priv->obj; | ||
132 | if (obj->name) { | ||
133 | DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n", | ||
134 | obj, obj->name, | ||
135 | obj->read_domains, obj->write_domain, | ||
136 | obj_priv->last_rendering_seqno); | ||
137 | } else { | ||
138 | DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj, | ||
139 | obj->read_domains, obj->write_domain, | ||
140 | obj_priv->last_rendering_seqno); | ||
141 | } | ||
142 | } | ||
143 | if (len > request + offset) | ||
144 | return request; | ||
145 | *eof = 1; | ||
146 | return len - offset; | ||
147 | } | ||
148 | |||
149 | static int i915_gem_request_info(char *buf, char **start, off_t offset, | ||
150 | int request, int *eof, void *data) | ||
151 | { | ||
152 | struct drm_minor *minor = (struct drm_minor *) data; | ||
153 | struct drm_device *dev = minor->dev; | ||
154 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
155 | struct drm_i915_gem_request *gem_request; | ||
156 | int len = 0; | ||
157 | |||
158 | if (offset > DRM_PROC_LIMIT) { | ||
159 | *eof = 1; | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | *start = &buf[offset]; | ||
164 | *eof = 0; | ||
165 | DRM_PROC_PRINT("Request:\n"); | ||
166 | list_for_each_entry(gem_request, &dev_priv->mm.request_list, | ||
167 | list) | ||
168 | { | ||
169 | DRM_PROC_PRINT(" %d @ %d %08x\n", | ||
170 | gem_request->seqno, | ||
171 | (int) (jiffies - gem_request->emitted_jiffies), | ||
172 | gem_request->flush_domains); | ||
173 | } | ||
174 | if (len > request + offset) | ||
175 | return request; | ||
176 | *eof = 1; | ||
177 | return len - offset; | ||
178 | } | ||
179 | |||
180 | static int i915_gem_seqno_info(char *buf, char **start, off_t offset, | ||
181 | int request, int *eof, void *data) | ||
182 | { | ||
183 | struct drm_minor *minor = (struct drm_minor *) data; | ||
184 | struct drm_device *dev = minor->dev; | ||
185 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
186 | int len = 0; | ||
187 | |||
188 | if (offset > DRM_PROC_LIMIT) { | ||
189 | *eof = 1; | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | *start = &buf[offset]; | ||
194 | *eof = 0; | ||
195 | DRM_PROC_PRINT("Current sequence: %d\n", i915_get_gem_seqno(dev)); | ||
196 | DRM_PROC_PRINT("Waiter sequence: %d\n", | ||
197 | dev_priv->mm.waiting_gem_seqno); | ||
198 | DRM_PROC_PRINT("IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno); | ||
199 | if (len > request + offset) | ||
200 | return request; | ||
201 | *eof = 1; | ||
202 | return len - offset; | ||
203 | } | ||
204 | |||
205 | |||
206 | static int i915_interrupt_info(char *buf, char **start, off_t offset, | ||
207 | int request, int *eof, void *data) | ||
208 | { | ||
209 | struct drm_minor *minor = (struct drm_minor *) data; | ||
210 | struct drm_device *dev = minor->dev; | ||
211 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
212 | int len = 0; | ||
213 | |||
214 | if (offset > DRM_PROC_LIMIT) { | ||
215 | *eof = 1; | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | *start = &buf[offset]; | ||
220 | *eof = 0; | ||
221 | DRM_PROC_PRINT("Interrupt enable: %08x\n", | ||
222 | I915_READ(IER)); | ||
223 | DRM_PROC_PRINT("Interrupt identity: %08x\n", | ||
224 | I915_READ(IIR)); | ||
225 | DRM_PROC_PRINT("Interrupt mask: %08x\n", | ||
226 | I915_READ(IMR)); | ||
227 | DRM_PROC_PRINT("Pipe A stat: %08x\n", | ||
228 | I915_READ(PIPEASTAT)); | ||
229 | DRM_PROC_PRINT("Pipe B stat: %08x\n", | ||
230 | I915_READ(PIPEBSTAT)); | ||
231 | DRM_PROC_PRINT("Interrupts received: %d\n", | ||
232 | atomic_read(&dev_priv->irq_received)); | ||
233 | DRM_PROC_PRINT("Current sequence: %d\n", | ||
234 | i915_get_gem_seqno(dev)); | ||
235 | DRM_PROC_PRINT("Waiter sequence: %d\n", | ||
236 | dev_priv->mm.waiting_gem_seqno); | ||
237 | DRM_PROC_PRINT("IRQ sequence: %d\n", | ||
238 | dev_priv->mm.irq_gem_seqno); | ||
239 | if (len > request + offset) | ||
240 | return request; | ||
241 | *eof = 1; | ||
242 | return len - offset; | ||
243 | } | ||
244 | |||
245 | static struct drm_proc_list { | ||
246 | /** file name */ | ||
247 | const char *name; | ||
248 | /** proc callback*/ | ||
249 | int (*f) (char *, char **, off_t, int, int *, void *); | ||
250 | } i915_gem_proc_list[] = { | ||
251 | {"i915_gem_active", i915_gem_active_info}, | ||
252 | {"i915_gem_flushing", i915_gem_flushing_info}, | ||
253 | {"i915_gem_inactive", i915_gem_inactive_info}, | ||
254 | {"i915_gem_request", i915_gem_request_info}, | ||
255 | {"i915_gem_seqno", i915_gem_seqno_info}, | ||
256 | {"i915_gem_interrupt", i915_interrupt_info}, | ||
257 | }; | ||
258 | |||
259 | #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list) | ||
260 | |||
261 | int i915_gem_proc_init(struct drm_minor *minor) | ||
262 | { | ||
263 | struct proc_dir_entry *ent; | ||
264 | int i, j; | ||
265 | |||
266 | for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) { | ||
267 | ent = create_proc_entry(i915_gem_proc_list[i].name, | ||
268 | S_IFREG | S_IRUGO, minor->dev_root); | ||
269 | if (!ent) { | ||
270 | DRM_ERROR("Cannot create /proc/dri/.../%s\n", | ||
271 | i915_gem_proc_list[i].name); | ||
272 | for (j = 0; j < i; j++) | ||
273 | remove_proc_entry(i915_gem_proc_list[i].name, | ||
274 | minor->dev_root); | ||
275 | return -1; | ||
276 | } | ||
277 | ent->read_proc = i915_gem_proc_list[i].f; | ||
278 | ent->data = minor; | ||
279 | } | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | void i915_gem_proc_cleanup(struct drm_minor *minor) | ||
284 | { | ||
285 | int i; | ||
286 | |||
287 | if (!minor->dev_root) | ||
288 | return; | ||
289 | |||
290 | for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) | ||
291 | remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root); | ||
292 | } | ||
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c new file mode 100644 index 000000000000..0c1b3a0834e1 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "drmP.h" | ||
29 | #include "drm.h" | ||
30 | #include "i915_drm.h" | ||
31 | #include "i915_drv.h" | ||
32 | |||
33 | /** @file i915_gem_tiling.c | ||
34 | * | ||
35 | * Support for managing tiling state of buffer objects. | ||
36 | * | ||
37 | * The idea behind tiling is to increase cache hit rates by rearranging | ||
38 | * pixel data so that a group of pixel accesses are in the same cacheline. | ||
39 | * Performance improvement from doing this on the back/depth buffer are on | ||
40 | * the order of 30%. | ||
41 | * | ||
42 | * Intel architectures make this somewhat more complicated, though, by | ||
43 | * adjustments made to addressing of data when the memory is in interleaved | ||
44 | * mode (matched pairs of DIMMS) to improve memory bandwidth. | ||
45 | * For interleaved memory, the CPU sends every sequential 64 bytes | ||
46 | * to an alternate memory channel so it can get the bandwidth from both. | ||
47 | * | ||
48 | * The GPU also rearranges its accesses for increased bandwidth to interleaved | ||
49 | * memory, and it matches what the CPU does for non-tiled. However, when tiled | ||
50 | * it does it a little differently, since one walks addresses not just in the | ||
51 | * X direction but also Y. So, along with alternating channels when bit | ||
52 | * 6 of the address flips, it also alternates when other bits flip -- Bits 9 | ||
53 | * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines) | ||
54 | * are common to both the 915 and 965-class hardware. | ||
55 | * | ||
56 | * The CPU also sometimes XORs in higher bits as well, to improve | ||
57 | * bandwidth doing strided access like we do so frequently in graphics. This | ||
58 | * is called "Channel XOR Randomization" in the MCH documentation. The result | ||
59 | * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address | ||
60 | * decode. | ||
61 | * | ||
62 | * All of this bit 6 XORing has an effect on our memory management, | ||
63 | * as we need to make sure that the 3d driver can correctly address object | ||
64 | * contents. | ||
65 | * | ||
66 | * If we don't have interleaved memory, all tiling is safe and no swizzling is | ||
67 | * required. | ||
68 | * | ||
69 | * When bit 17 is XORed in, we simply refuse to tile at all. Bit | ||
70 | * 17 is not just a page offset, so as we page an objet out and back in, | ||
71 | * individual pages in it will have different bit 17 addresses, resulting in | ||
72 | * each 64 bytes being swapped with its neighbor! | ||
73 | * | ||
74 | * Otherwise, if interleaved, we have to tell the 3d driver what the address | ||
75 | * swizzling it needs to do is, since it's writing with the CPU to the pages | ||
76 | * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the | ||
77 | * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling | ||
78 | * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order | ||
79 | * to match what the GPU expects. | ||
80 | */ | ||
81 | |||
82 | /** | ||
83 | * Detects bit 6 swizzling of address lookup between IGD access and CPU | ||
84 | * access through main memory. | ||
85 | */ | ||
86 | void | ||
87 | i915_gem_detect_bit_6_swizzle(struct drm_device *dev) | ||
88 | { | ||
89 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
90 | uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; | ||
91 | uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; | ||
92 | |||
93 | if (!IS_I9XX(dev)) { | ||
94 | /* As far as we know, the 865 doesn't have these bit 6 | ||
95 | * swizzling issues. | ||
96 | */ | ||
97 | swizzle_x = I915_BIT_6_SWIZZLE_NONE; | ||
98 | swizzle_y = I915_BIT_6_SWIZZLE_NONE; | ||
99 | } else if (!IS_I965G(dev) || IS_I965GM(dev)) { | ||
100 | uint32_t dcc; | ||
101 | |||
102 | /* On 915-945 and GM965, channel interleave by the CPU is | ||
103 | * determined by DCC. The CPU will alternate based on bit 6 | ||
104 | * in interleaved mode, and the GPU will then also alternate | ||
105 | * on bit 6, 9, and 10 for X, but the CPU may also optionally | ||
106 | * alternate based on bit 17 (XOR not disabled and XOR | ||
107 | * bit == 17). | ||
108 | */ | ||
109 | dcc = I915_READ(DCC); | ||
110 | switch (dcc & DCC_ADDRESSING_MODE_MASK) { | ||
111 | case DCC_ADDRESSING_MODE_SINGLE_CHANNEL: | ||
112 | case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC: | ||
113 | swizzle_x = I915_BIT_6_SWIZZLE_NONE; | ||
114 | swizzle_y = I915_BIT_6_SWIZZLE_NONE; | ||
115 | break; | ||
116 | case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED: | ||
117 | if (IS_I915G(dev) || IS_I915GM(dev) || | ||
118 | dcc & DCC_CHANNEL_XOR_DISABLE) { | ||
119 | swizzle_x = I915_BIT_6_SWIZZLE_9_10; | ||
120 | swizzle_y = I915_BIT_6_SWIZZLE_9; | ||
121 | } else if (IS_I965GM(dev)) { | ||
122 | /* GM965 only does bit 11-based channel | ||
123 | * randomization | ||
124 | */ | ||
125 | swizzle_x = I915_BIT_6_SWIZZLE_9_10_11; | ||
126 | swizzle_y = I915_BIT_6_SWIZZLE_9_11; | ||
127 | } else { | ||
128 | /* Bit 17 or perhaps other swizzling */ | ||
129 | swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; | ||
130 | swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; | ||
131 | } | ||
132 | break; | ||
133 | } | ||
134 | if (dcc == 0xffffffff) { | ||
135 | DRM_ERROR("Couldn't read from MCHBAR. " | ||
136 | "Disabling tiling.\n"); | ||
137 | swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; | ||
138 | swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; | ||
139 | } | ||
140 | } else { | ||
141 | /* The 965, G33, and newer, have a very flexible memory | ||
142 | * configuration. It will enable dual-channel mode | ||
143 | * (interleaving) on as much memory as it can, and the GPU | ||
144 | * will additionally sometimes enable different bit 6 | ||
145 | * swizzling for tiled objects from the CPU. | ||
146 | * | ||
147 | * Here's what I found on the G965: | ||
148 | * slot fill memory size swizzling | ||
149 | * 0A 0B 1A 1B 1-ch 2-ch | ||
150 | * 512 0 0 0 512 0 O | ||
151 | * 512 0 512 0 16 1008 X | ||
152 | * 512 0 0 512 16 1008 X | ||
153 | * 0 512 0 512 16 1008 X | ||
154 | * 1024 1024 1024 0 2048 1024 O | ||
155 | * | ||
156 | * We could probably detect this based on either the DRB | ||
157 | * matching, which was the case for the swizzling required in | ||
158 | * the table above, or from the 1-ch value being less than | ||
159 | * the minimum size of a rank. | ||
160 | */ | ||
161 | if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) { | ||
162 | swizzle_x = I915_BIT_6_SWIZZLE_NONE; | ||
163 | swizzle_y = I915_BIT_6_SWIZZLE_NONE; | ||
164 | } else { | ||
165 | swizzle_x = I915_BIT_6_SWIZZLE_9_10; | ||
166 | swizzle_y = I915_BIT_6_SWIZZLE_9; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | dev_priv->mm.bit_6_swizzle_x = swizzle_x; | ||
171 | dev_priv->mm.bit_6_swizzle_y = swizzle_y; | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * Sets the tiling mode of an object, returning the required swizzling of | ||
176 | * bit 6 of addresses in the object. | ||
177 | */ | ||
178 | int | ||
179 | i915_gem_set_tiling(struct drm_device *dev, void *data, | ||
180 | struct drm_file *file_priv) | ||
181 | { | ||
182 | struct drm_i915_gem_set_tiling *args = data; | ||
183 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
184 | struct drm_gem_object *obj; | ||
185 | struct drm_i915_gem_object *obj_priv; | ||
186 | |||
187 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
188 | if (obj == NULL) | ||
189 | return -EINVAL; | ||
190 | obj_priv = obj->driver_private; | ||
191 | |||
192 | mutex_lock(&dev->struct_mutex); | ||
193 | |||
194 | if (args->tiling_mode == I915_TILING_NONE) { | ||
195 | obj_priv->tiling_mode = I915_TILING_NONE; | ||
196 | args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; | ||
197 | } else { | ||
198 | if (args->tiling_mode == I915_TILING_X) | ||
199 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; | ||
200 | else | ||
201 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y; | ||
202 | /* If we can't handle the swizzling, make it untiled. */ | ||
203 | if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) { | ||
204 | args->tiling_mode = I915_TILING_NONE; | ||
205 | args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; | ||
206 | } | ||
207 | } | ||
208 | obj_priv->tiling_mode = args->tiling_mode; | ||
209 | |||
210 | mutex_unlock(&dev->struct_mutex); | ||
211 | |||
212 | drm_gem_object_unreference(obj); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * Returns the current tiling mode and required bit 6 swizzling for the object. | ||
219 | */ | ||
220 | int | ||
221 | i915_gem_get_tiling(struct drm_device *dev, void *data, | ||
222 | struct drm_file *file_priv) | ||
223 | { | ||
224 | struct drm_i915_gem_get_tiling *args = data; | ||
225 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
226 | struct drm_gem_object *obj; | ||
227 | struct drm_i915_gem_object *obj_priv; | ||
228 | |||
229 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
230 | if (obj == NULL) | ||
231 | return -EINVAL; | ||
232 | obj_priv = obj->driver_private; | ||
233 | |||
234 | mutex_lock(&dev->struct_mutex); | ||
235 | |||
236 | args->tiling_mode = obj_priv->tiling_mode; | ||
237 | switch (obj_priv->tiling_mode) { | ||
238 | case I915_TILING_X: | ||
239 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; | ||
240 | break; | ||
241 | case I915_TILING_Y: | ||
242 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y; | ||
243 | break; | ||
244 | case I915_TILING_NONE: | ||
245 | args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; | ||
246 | break; | ||
247 | default: | ||
248 | DRM_ERROR("unknown tiling mode\n"); | ||
249 | } | ||
250 | |||
251 | mutex_unlock(&dev->struct_mutex); | ||
252 | |||
253 | drm_gem_object_unreference(obj); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f8759597233b..f295bdf16e2d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -407,15 +407,20 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
407 | I915_WRITE(PIPEBSTAT, pipeb_stats); | 407 | I915_WRITE(PIPEBSTAT, pipeb_stats); |
408 | } | 408 | } |
409 | 409 | ||
410 | if (iir & I915_ASLE_INTERRUPT) | 410 | I915_WRITE(IIR, iir); |
411 | opregion_asle_intr(dev); | 411 | if (dev->pdev->msi_enabled) |
412 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | ||
413 | (void) I915_READ(IIR); /* Flush posted writes */ | ||
412 | 414 | ||
413 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 415 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
414 | 416 | ||
415 | if (dev->pdev->msi_enabled) | 417 | if (iir & I915_USER_INTERRUPT) { |
416 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | 418 | dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); |
417 | I915_WRITE(IIR, iir); | 419 | DRM_WAKEUP(&dev_priv->irq_queue); |
418 | (void) I915_READ(IIR); | 420 | } |
421 | |||
422 | if (iir & I915_ASLE_INTERRUPT) | ||
423 | opregion_asle_intr(dev); | ||
419 | 424 | ||
420 | if (vblank && dev_priv->swaps_pending > 0) | 425 | if (vblank && dev_priv->swaps_pending > 0) |
421 | drm_locked_tasklet(dev, i915_vblank_tasklet); | 426 | drm_locked_tasklet(dev, i915_vblank_tasklet); |
@@ -449,7 +454,7 @@ static int i915_emit_irq(struct drm_device * dev) | |||
449 | return dev_priv->counter; | 454 | return dev_priv->counter; |
450 | } | 455 | } |
451 | 456 | ||
452 | static void i915_user_irq_get(struct drm_device *dev) | 457 | void i915_user_irq_get(struct drm_device *dev) |
453 | { | 458 | { |
454 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 459 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
455 | 460 | ||
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 43ad2cb8b9f5..5c2d9f206d05 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -25,19 +25,6 @@ | |||
25 | #ifndef _I915_REG_H_ | 25 | #ifndef _I915_REG_H_ |
26 | #define _I915_REG_H_ | 26 | #define _I915_REG_H_ |
27 | 27 | ||
28 | /* MCH MMIO space */ | ||
29 | /** 915-945 and GM965 MCH register controlling DRAM channel access */ | ||
30 | #define DCC 0x200 | ||
31 | #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) | ||
32 | #define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC (1 << 0) | ||
33 | #define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED (2 << 0) | ||
34 | #define DCC_ADDRESSING_MODE_MASK (3 << 0) | ||
35 | #define DCC_CHANNEL_XOR_DISABLE (1 << 10) | ||
36 | |||
37 | /** 965 MCH register controlling DRAM channel configuration */ | ||
38 | #define CHDECMISC 0x111 | ||
39 | #define CHDECMISC_FLEXMEMORY (1 << 1) | ||
40 | |||
41 | /* | 28 | /* |
42 | * The Bridge device's PCI config space has information about the | 29 | * The Bridge device's PCI config space has information about the |
43 | * fb aperture size and the amount of pre-reserved memory. | 30 | * fb aperture size and the amount of pre-reserved memory. |
@@ -516,6 +503,30 @@ | |||
516 | #define PALETTE_A 0x0a000 | 503 | #define PALETTE_A 0x0a000 |
517 | #define PALETTE_B 0x0a800 | 504 | #define PALETTE_B 0x0a800 |
518 | 505 | ||
506 | /* MCH MMIO space */ | ||
507 | |||
508 | /* | ||
509 | * MCHBAR mirror. | ||
510 | * | ||
511 | * This mirrors the MCHBAR MMIO space whose location is determined by | ||
512 | * device 0 function 0's pci config register 0x44 or 0x48 and matches it in | ||
513 | * every way. It is not accessible from the CP register read instructions. | ||
514 | * | ||
515 | */ | ||
516 | #define MCHBAR_MIRROR_BASE 0x10000 | ||
517 | |||
518 | /** 915-945 and GM965 MCH register controlling DRAM channel access */ | ||
519 | #define DCC 0x10200 | ||
520 | #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) | ||
521 | #define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC (1 << 0) | ||
522 | #define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED (2 << 0) | ||
523 | #define DCC_ADDRESSING_MODE_MASK (3 << 0) | ||
524 | #define DCC_CHANNEL_XOR_DISABLE (1 << 10) | ||
525 | |||
526 | /** 965 MCH register controlling DRAM channel configuration */ | ||
527 | #define C0DRB3 0x10206 | ||
528 | #define C1DRB3 0x10606 | ||
529 | |||
519 | /* | 530 | /* |
520 | * Overlay regs | 531 | * Overlay regs |
521 | */ | 532 | */ |