1 | /* |
2 | * Copyright 2013 Red Hat Inc. |
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 shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
22 | * Authors: Dave Airlie |
23 | * Alon Levy |
24 | */ |
25 | |
26 | #ifndef QXL_DRV_H |
27 | #define QXL_DRV_H |
28 | |
29 | /* |
30 | * Definitions taken from spice-protocol, plus kernel driver specific bits. |
31 | */ |
32 | |
33 | #include <linux/iosys-map.h> |
34 | #include <linux/dma-fence.h> |
35 | #include <linux/firmware.h> |
36 | #include <linux/platform_device.h> |
37 | #include <linux/workqueue.h> |
38 | |
39 | #include <drm/drm_crtc.h> |
40 | #include <drm/drm_encoder.h> |
41 | #include <drm/drm_gem_ttm_helper.h> |
42 | #include <drm/drm_ioctl.h> |
43 | #include <drm/drm_gem.h> |
44 | #include <drm/qxl_drm.h> |
45 | #include <drm/ttm/ttm_bo.h> |
46 | #include <drm/ttm/ttm_execbuf_util.h> |
47 | #include <drm/ttm/ttm_placement.h> |
48 | |
49 | #include "qxl_dev.h" |
50 | |
51 | struct iosys_map; |
52 | |
53 | #define DRIVER_AUTHOR "Dave Airlie" |
54 | |
55 | #define DRIVER_NAME "qxl" |
56 | #define DRIVER_DESC "RH QXL" |
57 | #define DRIVER_DATE "20120117" |
58 | |
59 | #define DRIVER_MAJOR 0 |
60 | #define DRIVER_MINOR 1 |
61 | #define DRIVER_PATCHLEVEL 0 |
62 | |
63 | #define QXL_DEBUGFS_MAX_COMPONENTS 32 |
64 | |
65 | extern int qxl_num_crtc; |
66 | |
67 | #define QXL_INTERRUPT_MASK (\ |
68 | QXL_INTERRUPT_DISPLAY |\ |
69 | QXL_INTERRUPT_CURSOR |\ |
70 | QXL_INTERRUPT_IO_CMD |\ |
71 | QXL_INTERRUPT_CLIENT_MONITORS_CONFIG) |
72 | |
73 | struct qxl_bo { |
74 | struct ttm_buffer_object tbo; |
75 | |
76 | /* Protected by gem.mutex */ |
77 | struct list_head list; |
78 | /* Protected by tbo.reserved */ |
79 | struct ttm_place placements[3]; |
80 | struct ttm_placement placement; |
81 | struct iosys_map map; |
82 | void *kptr; |
83 | unsigned int map_count; |
84 | int type; |
85 | |
86 | /* Constant after initialization */ |
87 | unsigned int is_primary:1; /* is this now a primary surface */ |
88 | unsigned int is_dumb:1; |
89 | struct qxl_bo *shadow; |
90 | unsigned int hw_surf_alloc:1; |
91 | struct qxl_surface surf; |
92 | uint32_t surface_id; |
93 | struct qxl_release *surf_create; |
94 | }; |
95 | #define gem_to_qxl_bo(gobj) container_of((gobj), struct qxl_bo, tbo.base) |
96 | #define to_qxl_bo(tobj) container_of((tobj), struct qxl_bo, tbo) |
97 | |
98 | struct qxl_gem { |
99 | struct mutex mutex; |
100 | struct list_head objects; |
101 | }; |
102 | |
103 | struct qxl_bo_list { |
104 | struct ttm_validate_buffer tv; |
105 | }; |
106 | |
107 | struct qxl_crtc { |
108 | struct drm_crtc base; |
109 | int index; |
110 | |
111 | struct qxl_bo *cursor_bo; |
112 | }; |
113 | |
114 | struct qxl_output { |
115 | int index; |
116 | struct drm_connector base; |
117 | struct drm_encoder enc; |
118 | }; |
119 | |
120 | #define to_qxl_crtc(x) container_of(x, struct qxl_crtc, base) |
121 | #define drm_connector_to_qxl_output(x) container_of(x, struct qxl_output, base) |
122 | |
123 | struct qxl_mman { |
124 | struct ttm_device bdev; |
125 | }; |
126 | |
127 | struct qxl_memslot { |
128 | int index; |
129 | const char *name; |
130 | uint8_t generation; |
131 | uint64_t start_phys_addr; |
132 | uint64_t size; |
133 | uint64_t high_bits; |
134 | }; |
135 | |
136 | enum { |
137 | QXL_RELEASE_DRAWABLE, |
138 | QXL_RELEASE_SURFACE_CMD, |
139 | QXL_RELEASE_CURSOR_CMD, |
140 | }; |
141 | |
142 | /* drm_ prefix to differentiate from qxl_release_info in |
143 | * spice-protocol/qxl_dev.h */ |
144 | #define QXL_MAX_RES 96 |
145 | struct qxl_release { |
146 | struct dma_fence base; |
147 | |
148 | int id; |
149 | int type; |
150 | struct qxl_bo *release_bo; |
151 | uint32_t release_offset; |
152 | uint32_t surface_release_id; |
153 | struct ww_acquire_ctx ticket; |
154 | struct list_head bos; |
155 | }; |
156 | |
157 | struct qxl_drm_chunk { |
158 | struct list_head head; |
159 | struct qxl_bo *bo; |
160 | }; |
161 | |
162 | struct qxl_drm_image { |
163 | struct qxl_bo *bo; |
164 | struct list_head chunk_list; |
165 | }; |
166 | |
167 | /* |
168 | * Debugfs |
169 | */ |
170 | struct qxl_debugfs { |
171 | struct drm_info_list *files; |
172 | unsigned int num_files; |
173 | }; |
174 | |
175 | struct qxl_device { |
176 | struct drm_device ddev; |
177 | |
178 | resource_size_t vram_base, vram_size; |
179 | resource_size_t surfaceram_base, surfaceram_size; |
180 | resource_size_t rom_base, rom_size; |
181 | struct qxl_rom *rom; |
182 | |
183 | struct qxl_mode *modes; |
184 | struct qxl_bo *monitors_config_bo; |
185 | struct qxl_monitors_config *monitors_config; |
186 | |
187 | /* last received client_monitors_config */ |
188 | struct qxl_monitors_config *client_monitors_config; |
189 | |
190 | int io_base; |
191 | void *ram; |
192 | struct qxl_mman mman; |
193 | struct qxl_gem gem; |
194 | |
195 | void *ram_physical; |
196 | |
197 | struct qxl_ring *release_ring; |
198 | struct qxl_ring *command_ring; |
199 | struct qxl_ring *cursor_ring; |
200 | |
201 | struct qxl_ram_header *; |
202 | |
203 | struct qxl_bo *primary_bo; |
204 | struct qxl_bo *dumb_shadow_bo; |
205 | struct qxl_head *dumb_heads; |
206 | |
207 | struct qxl_memslot main_slot; |
208 | struct qxl_memslot surfaces_slot; |
209 | |
210 | spinlock_t release_lock; |
211 | struct idr release_idr; |
212 | uint32_t release_seqno; |
213 | atomic_t release_count; |
214 | wait_queue_head_t release_event; |
215 | spinlock_t release_idr_lock; |
216 | struct mutex async_io_mutex; |
217 | unsigned int last_sent_io_cmd; |
218 | |
219 | /* interrupt handling */ |
220 | atomic_t irq_received; |
221 | atomic_t irq_received_display; |
222 | atomic_t irq_received_cursor; |
223 | atomic_t irq_received_io_cmd; |
224 | unsigned int irq_received_error; |
225 | wait_queue_head_t display_event; |
226 | wait_queue_head_t cursor_event; |
227 | wait_queue_head_t io_cmd_event; |
228 | struct work_struct client_monitors_config_work; |
229 | |
230 | /* debugfs */ |
231 | struct qxl_debugfs debugfs[QXL_DEBUGFS_MAX_COMPONENTS]; |
232 | unsigned int debugfs_count; |
233 | |
234 | struct mutex update_area_mutex; |
235 | |
236 | struct idr surf_id_idr; |
237 | spinlock_t surf_id_idr_lock; |
238 | int last_alloced_surf_id; |
239 | |
240 | struct mutex surf_evict_mutex; |
241 | struct io_mapping *vram_mapping; |
242 | struct io_mapping *surface_mapping; |
243 | |
244 | /* */ |
245 | struct mutex release_mutex; |
246 | struct qxl_bo *current_release_bo[3]; |
247 | int current_release_bo_offset[3]; |
248 | |
249 | struct work_struct gc_work; |
250 | |
251 | struct drm_property *hotplug_mode_update_property; |
252 | int monitors_config_width; |
253 | int monitors_config_height; |
254 | }; |
255 | |
256 | #define to_qxl(dev) container_of(dev, struct qxl_device, ddev) |
257 | |
258 | int qxl_device_init(struct qxl_device *qdev, struct pci_dev *pdev); |
259 | void qxl_device_fini(struct qxl_device *qdev); |
260 | |
261 | int qxl_modeset_init(struct qxl_device *qdev); |
262 | void qxl_modeset_fini(struct qxl_device *qdev); |
263 | |
264 | int qxl_bo_init(struct qxl_device *qdev); |
265 | void qxl_bo_fini(struct qxl_device *qdev); |
266 | |
267 | void qxl_reinit_memslots(struct qxl_device *qdev); |
268 | int qxl_surf_evict(struct qxl_device *qdev); |
269 | int qxl_vram_evict(struct qxl_device *qdev); |
270 | |
271 | struct qxl_ring *qxl_ring_create(struct qxl_ring_header *, |
272 | int element_size, |
273 | int n_elements, |
274 | int prod_notify, |
275 | wait_queue_head_t *push_event); |
276 | void qxl_ring_free(struct qxl_ring *ring); |
277 | int qxl_check_idle(struct qxl_ring *ring); |
278 | |
279 | static inline uint64_t |
280 | qxl_bo_physical_address(struct qxl_device *qdev, struct qxl_bo *bo, |
281 | unsigned long offset) |
282 | { |
283 | struct qxl_memslot *slot = |
284 | (bo->tbo.resource->mem_type == TTM_PL_VRAM) |
285 | ? &qdev->main_slot : &qdev->surfaces_slot; |
286 | |
287 | /* TODO - need to hold one of the locks to read bo->tbo.resource->start */ |
288 | |
289 | return slot->high_bits | ((bo->tbo.resource->start << PAGE_SHIFT) + offset); |
290 | } |
291 | |
292 | /* qxl_display.c */ |
293 | void qxl_display_read_client_monitors_config(struct qxl_device *qdev); |
294 | int qxl_create_monitors_object(struct qxl_device *qdev); |
295 | int qxl_destroy_monitors_object(struct qxl_device *qdev); |
296 | |
297 | /* qxl_gem.c */ |
298 | void qxl_gem_init(struct qxl_device *qdev); |
299 | void qxl_gem_fini(struct qxl_device *qdev); |
300 | int qxl_gem_object_create(struct qxl_device *qdev, int size, |
301 | int alignment, int initial_domain, |
302 | bool discardable, bool kernel, |
303 | struct qxl_surface *surf, |
304 | struct drm_gem_object **obj); |
305 | int qxl_gem_object_create_with_handle(struct qxl_device *qdev, |
306 | struct drm_file *file_priv, |
307 | u32 domain, |
308 | size_t size, |
309 | struct qxl_surface *surf, |
310 | struct drm_gem_object **gobj, |
311 | uint32_t *handle); |
312 | void qxl_gem_object_free(struct drm_gem_object *gobj); |
313 | int qxl_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv); |
314 | void qxl_gem_object_close(struct drm_gem_object *obj, |
315 | struct drm_file *file_priv); |
316 | void qxl_bo_force_delete(struct qxl_device *qdev); |
317 | |
318 | /* qxl_dumb.c */ |
319 | int qxl_mode_dumb_create(struct drm_file *file_priv, |
320 | struct drm_device *dev, |
321 | struct drm_mode_create_dumb *args); |
322 | |
323 | /* qxl ttm */ |
324 | int qxl_ttm_init(struct qxl_device *qdev); |
325 | void qxl_ttm_fini(struct qxl_device *qdev); |
326 | int qxl_ttm_io_mem_reserve(struct ttm_device *bdev, |
327 | struct ttm_resource *mem); |
328 | |
329 | /* qxl image */ |
330 | |
331 | int qxl_image_init(struct qxl_device *qdev, |
332 | struct qxl_release *release, |
333 | struct qxl_drm_image *dimage, |
334 | const uint8_t *data, |
335 | int x, int y, int width, int height, |
336 | int depth, int stride); |
337 | int |
338 | qxl_image_alloc_objects(struct qxl_device *qdev, |
339 | struct qxl_release *release, |
340 | struct qxl_drm_image **image_ptr, |
341 | int height, int stride); |
342 | void qxl_image_free_objects(struct qxl_device *qdev, struct qxl_drm_image *dimage); |
343 | |
344 | /* qxl io operations (qxl_cmd.c) */ |
345 | |
346 | void qxl_io_create_primary(struct qxl_device *qdev, |
347 | struct qxl_bo *bo); |
348 | void qxl_io_destroy_primary(struct qxl_device *qdev); |
349 | void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id); |
350 | void qxl_io_notify_oom(struct qxl_device *qdev); |
351 | |
352 | int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf, |
353 | const struct qxl_rect *area); |
354 | |
355 | void qxl_io_reset(struct qxl_device *qdev); |
356 | void qxl_io_monitors_config(struct qxl_device *qdev); |
357 | int qxl_ring_push(struct qxl_ring *ring, const void *new_elt, bool interruptible); |
358 | void qxl_io_flush_release(struct qxl_device *qdev); |
359 | void qxl_io_flush_surfaces(struct qxl_device *qdev); |
360 | |
361 | union qxl_release_info *qxl_release_map(struct qxl_device *qdev, |
362 | struct qxl_release *release); |
363 | void qxl_release_unmap(struct qxl_device *qdev, |
364 | struct qxl_release *release, |
365 | union qxl_release_info *info); |
366 | int qxl_release_list_add(struct qxl_release *release, struct qxl_bo *bo); |
367 | int qxl_release_reserve_list(struct qxl_release *release, bool no_intr); |
368 | void qxl_release_backoff_reserve_list(struct qxl_release *release); |
369 | void qxl_release_fence_buffer_objects(struct qxl_release *release); |
370 | |
371 | int qxl_alloc_surface_release_reserved(struct qxl_device *qdev, |
372 | enum qxl_surface_cmd_type surface_cmd_type, |
373 | struct qxl_release *create_rel, |
374 | struct qxl_release **release); |
375 | int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size, |
376 | int type, struct qxl_release **release, |
377 | struct qxl_bo **rbo); |
378 | |
379 | int |
380 | qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *release, |
381 | uint32_t type, bool interruptible); |
382 | int |
383 | qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *release, |
384 | uint32_t type, bool interruptible); |
385 | int qxl_alloc_bo_reserved(struct qxl_device *qdev, |
386 | struct qxl_release *release, |
387 | unsigned long size, |
388 | struct qxl_bo **_bo); |
389 | /* qxl drawing commands */ |
390 | |
391 | void qxl_draw_dirty_fb(struct qxl_device *qdev, |
392 | struct drm_framebuffer *fb, |
393 | struct qxl_bo *bo, |
394 | unsigned int flags, unsigned int color, |
395 | struct drm_clip_rect *clips, |
396 | unsigned int num_clips, int inc, |
397 | uint32_t dumb_shadow_offset); |
398 | |
399 | void qxl_release_free(struct qxl_device *qdev, |
400 | struct qxl_release *release); |
401 | |
402 | /* used by qxl_debugfs_release */ |
403 | struct qxl_release *qxl_release_from_id_locked(struct qxl_device *qdev, |
404 | uint64_t id); |
405 | |
406 | bool qxl_queue_garbage_collect(struct qxl_device *qdev, bool flush); |
407 | int qxl_garbage_collect(struct qxl_device *qdev); |
408 | |
409 | /* debugfs */ |
410 | |
411 | void qxl_debugfs_init(struct drm_minor *minor); |
412 | void qxl_ttm_debugfs_init(struct qxl_device *qdev); |
413 | |
414 | /* qxl_prime.c */ |
415 | int qxl_gem_prime_pin(struct drm_gem_object *obj); |
416 | void qxl_gem_prime_unpin(struct drm_gem_object *obj); |
417 | struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj); |
418 | struct drm_gem_object *qxl_gem_prime_import_sg_table( |
419 | struct drm_device *dev, struct dma_buf_attachment *attach, |
420 | struct sg_table *sgt); |
421 | int qxl_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map); |
422 | void qxl_gem_prime_vunmap(struct drm_gem_object *obj, |
423 | struct iosys_map *map); |
424 | |
425 | /* qxl_irq.c */ |
426 | int qxl_irq_init(struct qxl_device *qdev); |
427 | |
428 | void qxl_debugfs_add_files(struct qxl_device *qdev, |
429 | struct drm_info_list *files, |
430 | unsigned int nfiles); |
431 | |
432 | int qxl_surface_id_alloc(struct qxl_device *qdev, |
433 | struct qxl_bo *surf); |
434 | void qxl_surface_id_dealloc(struct qxl_device *qdev, |
435 | uint32_t surface_id); |
436 | int qxl_hw_surface_alloc(struct qxl_device *qdev, |
437 | struct qxl_bo *surf); |
438 | int qxl_hw_surface_dealloc(struct qxl_device *qdev, |
439 | struct qxl_bo *surf); |
440 | |
441 | int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo); |
442 | |
443 | void qxl_surface_evict(struct qxl_device *qdev, struct qxl_bo *surf, bool freeing); |
444 | |
445 | /* qxl_ioctl.c */ |
446 | int qxl_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); |
447 | int qxl_map_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); |
448 | int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); |
449 | int qxl_update_area_ioctl(struct drm_device *dev, void *data, struct drm_file *file); |
450 | int qxl_getparam_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); |
451 | int qxl_clientcap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); |
452 | int qxl_alloc_surf_ioctl(struct drm_device *dev, void *data, struct drm_file *file); |
453 | |
454 | #endif |
455 | |