xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/drm_agpsupport.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /*	$NetBSD: drm_agpsupport.c,v 1.10 2018/08/28 03:41:38 riastradh Exp $	*/
2 
3 /**
4  * \file drm_agpsupport.c
5  * DRM support for AGP/GART backend
6  *
7  * \author Rickard E. (Rik) Faith <faith@valinux.com>
8  * \author Gareth Hughes <gareth@valinux.com>
9  */
10 
11 /*
12  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
13  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14  * All Rights Reserved.
15  *
16  * Permission is hereby granted, free of charge, to any person obtaining a
17  * copy of this software and associated documentation files (the "Software"),
18  * to deal in the Software without restriction, including without limitation
19  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20  * and/or sell copies of the Software, and to permit persons to whom the
21  * Software is furnished to do so, subject to the following conditions:
22  *
23  * The above copyright notice and this permission notice (including the next
24  * paragraph) shall be included in all copies or substantial portions of the
25  * Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
30  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33  * OTHER DEALINGS IN THE SOFTWARE.
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: drm_agpsupport.c,v 1.10 2018/08/28 03:41:38 riastradh Exp $");
38 
39 #include <drm/drmP.h>
40 #include <linux/errno.h>
41 #include <linux/export.h>
42 #include <linux/module.h>
43 #include <linux/slab.h>
44 #include "drm_legacy.h"
45 
46 #include <asm/agp.h>
47 
48 /**
49  * Get AGP information.
50  *
51  * \param inode device inode.
52  * \param file_priv DRM file private.
53  * \param cmd command.
54  * \param arg pointer to a (output) drm_agp_info structure.
55  * \return zero on success or a negative number on failure.
56  *
57  * Verifies the AGP device has been initialized and acquired and fills in the
58  * drm_agp_info structure with the information in drm_agp_head::agp_info.
59  */
60 static int drm_agp_info_hook(struct drm_device *dev, struct drm_agp_info *info)
61 {
62 	struct agp_kern_info *kern;
63 
64 	if (!dev->agp || !dev->agp->acquired)
65 		return -EINVAL;
66 
67 	kern = &dev->agp->agp_info;
68 #if __NetBSD__
69 	info->agp_version_major = 1;
70 	info->agp_version_minor = 0;
71 	info->mode = kern->aki_info.ai_mode;
72 	info->aperture_base = kern->aki_info.ai_aperture_base;
73 	info->aperture_size = kern->aki_info.ai_aperture_size;
74 	info->memory_allowed = kern->aki_info.ai_memory_allowed;
75 	info->memory_used = kern->aki_info.ai_memory_used;
76 	info->id_vendor = PCI_VENDOR(kern->aki_info.ai_devid);
77 	info->id_device = PCI_PRODUCT(kern->aki_info.ai_devid);
78 #else
79 	info->agp_version_major = kern->version.major;
80 	info->agp_version_minor = kern->version.minor;
81 	info->mode = kern->mode;
82 	info->aperture_base = kern->aper_base;
83 	info->aperture_size = kern->aper_size * 1024 * 1024;
84 	info->memory_allowed = kern->max_memory << PAGE_SHIFT;
85 	info->memory_used = kern->current_memory << PAGE_SHIFT;
86 	info->id_vendor = kern->device->vendor;
87 	info->id_device = kern->device->device;
88 #endif
89 
90 	return 0;
91 }
92 
93 EXPORT_SYMBOL(drm_agp_info);
94 
95 static int drm_agp_info_ioctl_hook(struct drm_device *dev, void *data,
96 		       struct drm_file *file_priv)
97 {
98 	struct drm_agp_info *info = data;
99 	int err;
100 
101 	err = drm_agp_info(dev, info);
102 	if (err)
103 		return err;
104 
105 	return 0;
106 }
107 
108 /**
109  * Acquire the AGP device.
110  *
111  * \param dev DRM device that is to acquire AGP.
112  * \return zero on success or a negative number on failure.
113  *
114  * Verifies the AGP device hasn't been acquired before and calls
115  * \c agp_backend_acquire.
116  */
117 static int drm_agp_acquire_hook(struct drm_device * dev)
118 {
119 	if (!dev->agp)
120 		return -ENODEV;
121 	if (dev->agp->acquired)
122 		return -EBUSY;
123 	if (!(dev->agp->bridge = agp_backend_acquire(dev->pdev)))
124 		return -ENODEV;
125 	dev->agp->acquired = 1;
126 	return 0;
127 }
128 
129 EXPORT_SYMBOL(drm_agp_acquire);
130 
131 /**
132  * Acquire the AGP device (ioctl).
133  *
134  * \param inode device inode.
135  * \param file_priv DRM file private.
136  * \param cmd command.
137  * \param arg user argument.
138  * \return zero on success or a negative number on failure.
139  *
140  * Verifies the AGP device hasn't been acquired before and calls
141  * \c agp_backend_acquire.
142  */
143 static int drm_agp_acquire_ioctl_hook(struct drm_device *dev, void *data,
144 			  struct drm_file *file_priv)
145 {
146 	return drm_agp_acquire((struct drm_device *) file_priv->minor->dev);
147 }
148 
149 /**
150  * Release the AGP device.
151  *
152  * \param dev DRM device that is to release AGP.
153  * \return zero on success or a negative number on failure.
154  *
155  * Verifies the AGP device has been acquired and calls \c agp_backend_release.
156  */
157 static int drm_agp_release_hook(struct drm_device * dev)
158 {
159 	if (!dev->agp || !dev->agp->acquired)
160 		return -EINVAL;
161 	agp_backend_release(dev->agp->bridge);
162 	dev->agp->acquired = 0;
163 	return 0;
164 }
165 EXPORT_SYMBOL(drm_agp_release);
166 
167 static int drm_agp_release_ioctl_hook(struct drm_device *dev, void *data,
168 			  struct drm_file *file_priv)
169 {
170 	return drm_agp_release(dev);
171 }
172 
173 /**
174  * Enable the AGP bus.
175  *
176  * \param dev DRM device that has previously acquired AGP.
177  * \param mode Requested AGP mode.
178  * \return zero on success or a negative number on failure.
179  *
180  * Verifies the AGP device has been acquired but not enabled, and calls
181  * \c agp_enable.
182  */
183 static int drm_agp_enable_hook(struct drm_device * dev, struct drm_agp_mode mode)
184 {
185 	if (!dev->agp || !dev->agp->acquired)
186 		return -EINVAL;
187 
188 	dev->agp->mode = mode.mode;
189 	agp_enable(dev->agp->bridge, mode.mode);
190 	dev->agp->enabled = 1;
191 	return 0;
192 }
193 
194 EXPORT_SYMBOL(drm_agp_enable);
195 
196 static int drm_agp_enable_ioctl_hook(struct drm_device *dev, void *data,
197 			 struct drm_file *file_priv)
198 {
199 	struct drm_agp_mode *mode = data;
200 
201 	return drm_agp_enable(dev, *mode);
202 }
203 
204 /**
205  * Allocate AGP memory.
206  *
207  * \param inode device inode.
208  * \param file_priv file private pointer.
209  * \param cmd command.
210  * \param arg pointer to a drm_agp_buffer structure.
211  * \return zero on success or a negative number on failure.
212  *
213  * Verifies the AGP device is present and has been acquired, allocates the
214  * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it.
215  */
216 static int drm_agp_alloc_hook(struct drm_device *dev, struct drm_agp_buffer *request)
217 {
218 	struct drm_agp_mem *entry;
219 	struct agp_memory *memory;
220 	unsigned long pages;
221 	u32 type;
222 
223 	if (!dev->agp || !dev->agp->acquired)
224 		return -EINVAL;
225 	if (!(entry = kzalloc(sizeof(*entry), GFP_KERNEL)))
226 		return -ENOMEM;
227 
228 	pages = (request->size + AGP_PAGE_SIZE - 1) / AGP_PAGE_SIZE;
229 	type = (u32) request->type;
230 	if (!(memory = agp_allocate_memory(dev->agp->bridge, pages, type))) {
231 		kfree(entry);
232 		return -ENOMEM;
233 	}
234 
235 #ifdef __NetBSD__
236 	/* I presume the `+ 1' is there to avoid an id of 0 or something.  */
237 	entry->handle = (unsigned long)memory->am_id + 1;
238 #else
239 	entry->handle = (unsigned long)memory->key + 1;
240 #endif
241 	entry->memory = memory;
242 	entry->bound = 0;
243 	entry->pages = pages;
244 	list_add(&entry->head, &dev->agp->memory);
245 
246 	request->handle = entry->handle;
247 #ifdef __NetBSD__
248 	{
249 		struct agp_memory_info info;
250 		agp_memory_info(dev->agp->bridge, memory, &info);
251 		request->physical = info.ami_physical;
252 	}
253 #else
254 	request->physical = memory->physical;
255 #endif
256 
257 	return 0;
258 }
259 EXPORT_SYMBOL(drm_agp_alloc);
260 
261 
262 static int drm_agp_alloc_ioctl_hook(struct drm_device *dev, void *data,
263 			struct drm_file *file_priv)
264 {
265 	struct drm_agp_buffer *request = data;
266 
267 	return drm_agp_alloc(dev, request);
268 }
269 
270 /**
271  * Search for the AGP memory entry associated with a handle.
272  *
273  * \param dev DRM device structure.
274  * \param handle AGP memory handle.
275  * \return pointer to the drm_agp_mem structure associated with \p handle.
276  *
277  * Walks through drm_agp_head::memory until finding a matching handle.
278  */
279 static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev,
280 					   unsigned long handle)
281 {
282 	struct drm_agp_mem *entry;
283 
284 	list_for_each_entry(entry, &dev->agp->memory, head) {
285 		if (entry->handle == handle)
286 			return entry;
287 	}
288 	return NULL;
289 }
290 
291 /**
292  * Unbind AGP memory from the GATT (ioctl).
293  *
294  * \param inode device inode.
295  * \param file_priv DRM file private.
296  * \param cmd command.
297  * \param arg pointer to a drm_agp_binding structure.
298  * \return zero on success or a negative number on failure.
299  *
300  * Verifies the AGP device is present and acquired, looks-up the AGP memory
301  * entry and passes it to the unbind_agp() function.
302  */
303 static int drm_agp_unbind_hook(struct drm_device *dev, struct drm_agp_binding *request)
304 {
305 	struct drm_agp_mem *entry;
306 	int ret;
307 
308 	if (!dev->agp || !dev->agp->acquired)
309 		return -EINVAL;
310 	if (!(entry = drm_agp_lookup_entry(dev, request->handle)))
311 		return -EINVAL;
312 	if (!entry->bound)
313 		return -EINVAL;
314 #ifdef __NetBSD__
315 	ret = drm_unbind_agp(dev->agp->bridge, entry->memory);
316 #else
317 	ret = drm_unbind_agp(entry->memory);
318 #endif
319 	if (ret == 0)
320 		entry->bound = 0;
321 	return ret;
322 }
323 EXPORT_SYMBOL(drm_agp_unbind);
324 
325 
326 static int drm_agp_unbind_ioctl_hook(struct drm_device *dev, void *data,
327 			 struct drm_file *file_priv)
328 {
329 	struct drm_agp_binding *request = data;
330 
331 	return drm_agp_unbind(dev, request);
332 }
333 
334 /**
335  * Bind AGP memory into the GATT (ioctl)
336  *
337  * \param inode device inode.
338  * \param file_priv DRM file private.
339  * \param cmd command.
340  * \param arg pointer to a drm_agp_binding structure.
341  * \return zero on success or a negative number on failure.
342  *
343  * Verifies the AGP device is present and has been acquired and that no memory
344  * is currently bound into the GATT. Looks-up the AGP memory entry and passes
345  * it to bind_agp() function.
346  */
347 static int drm_agp_bind_hook(struct drm_device *dev, struct drm_agp_binding *request)
348 {
349 	struct drm_agp_mem *entry;
350 	int retcode;
351 	int page;
352 
353 	if (!dev->agp || !dev->agp->acquired)
354 		return -EINVAL;
355 	if (!(entry = drm_agp_lookup_entry(dev, request->handle)))
356 		return -EINVAL;
357 	if (entry->bound)
358 		return -EINVAL;
359 	page = (request->offset + AGP_PAGE_SIZE - 1) / AGP_PAGE_SIZE;
360 #ifdef __NetBSD__
361 	if ((retcode = drm_bind_agp(dev->agp->bridge, entry->memory, page)))
362 		return retcode;
363 #else
364 	if ((retcode = drm_bind_agp(entry->memory, page)))
365 		return retcode;
366 #endif
367 	entry->bound = dev->agp->base + (page << PAGE_SHIFT);
368 	DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n",
369 		  dev->agp->base, entry->bound);
370 	return 0;
371 }
372 EXPORT_SYMBOL(drm_agp_bind);
373 
374 
375 static int drm_agp_bind_ioctl_hook(struct drm_device *dev, void *data,
376 		       struct drm_file *file_priv)
377 {
378 	struct drm_agp_binding *request = data;
379 
380 	return drm_agp_bind(dev, request);
381 }
382 
383 /**
384  * Free AGP memory (ioctl).
385  *
386  * \param inode device inode.
387  * \param file_priv DRM file private.
388  * \param cmd command.
389  * \param arg pointer to a drm_agp_buffer structure.
390  * \return zero on success or a negative number on failure.
391  *
392  * Verifies the AGP device is present and has been acquired and looks up the
393  * AGP memory entry. If the memory it's currently bound, unbind it via
394  * unbind_agp(). Frees it via free_agp() as well as the entry itself
395  * and unlinks from the doubly linked list it's inserted in.
396  */
397 static int drm_agp_free_hook(struct drm_device *dev, struct drm_agp_buffer *request)
398 {
399 	struct drm_agp_mem *entry;
400 
401 	if (!dev->agp || !dev->agp->acquired)
402 		return -EINVAL;
403 	if (!(entry = drm_agp_lookup_entry(dev, request->handle)))
404 		return -EINVAL;
405 	if (entry->bound)
406 #ifdef __NetBSD__
407 		drm_unbind_agp(dev->agp->bridge, entry->memory);
408 #else
409 		drm_unbind_agp(entry->memory);
410 #endif
411 
412 	list_del(&entry->head);
413 
414 #ifdef __NetBSD__
415 	drm_free_agp(dev->agp->bridge, entry->memory, entry->pages);
416 #else
417 	drm_free_agp(entry->memory, entry->pages);
418 #endif
419 	kfree(entry);
420 	return 0;
421 }
422 EXPORT_SYMBOL(drm_agp_free);
423 
424 
425 
426 static int drm_agp_free_ioctl_hook(struct drm_device *dev, void *data,
427 		       struct drm_file *file_priv)
428 {
429 	struct drm_agp_buffer *request = data;
430 
431 	return drm_agp_free(dev, request);
432 }
433 
434 /**
435  * Initialize the AGP resources.
436  *
437  * \return pointer to a drm_agp_head structure.
438  *
439  * Gets the drm_agp_t structure which is made available by the agpgart module
440  * via the inter_module_* functions. Creates and initializes a drm_agp_head
441  * structure.
442  *
443  * Note that final cleanup of the kmalloced structure is directly done in
444  * drm_pci_agp_destroy.
445  */
446 static struct drm_agp_head *drm_agp_init_hook(struct drm_device *dev)
447 {
448 	struct drm_agp_head *head = NULL;
449 
450 	if (!(head = kzalloc(sizeof(*head), GFP_KERNEL)))
451 		return NULL;
452 	head->bridge = agp_find_bridge(dev->pdev);
453 	if (!head->bridge) {
454 		if (!(head->bridge = agp_backend_acquire(dev->pdev))) {
455 			kfree(head);
456 			return NULL;
457 		}
458 		agp_copy_info(head->bridge, &head->agp_info);
459 		agp_backend_release(head->bridge);
460 	} else {
461 		agp_copy_info(head->bridge, &head->agp_info);
462 	}
463 #ifndef __NetBSD__
464 	/* Why would anything even attach in this case?  */
465 	if (head->agp_info.chipset == NOT_SUPPORTED) {
466 		kfree(head);
467 		return NULL;
468 	}
469 #endif
470 	INIT_LIST_HEAD(&head->memory);
471 #ifdef __NetBSD__
472 	head->cant_use_aperture = false; /* XXX */
473 	head->page_mask = ~0UL;
474 	head->base = head->agp_info.aki_info.ai_aperture_base;
475 #else
476 	head->cant_use_aperture = head->agp_info.cant_use_aperture;
477 	head->page_mask = head->agp_info.page_mask;
478 	head->base = head->agp_info.aper_base;
479 #endif
480 	return head;
481 }
482 
483 /**
484  * drm_agp_clear - Clear AGP resource list
485  * @dev: DRM device
486  *
487  * Iterate over all AGP resources and remove them. But keep the AGP head
488  * intact so it can still be used. It is safe to call this if AGP is disabled or
489  * was already removed.
490  *
491  * If DRIVER_MODESET is active, nothing is done to protect the modesetting
492  * resources from getting destroyed. Drivers are responsible of cleaning them up
493  * during device shutdown.
494  */
495 static void drm_agp_clear_hook(struct drm_device *dev)
496 {
497 	struct drm_agp_mem *entry, *tempe;
498 
499 	if (!dev->agp)
500 		return;
501 	if (drm_core_check_feature(dev, DRIVER_MODESET))
502 		return;
503 
504 	list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) {
505 #ifdef __NetBSD__
506 		if (entry->bound)
507 			drm_unbind_agp(dev->agp->bridge, entry->memory);
508 		drm_free_agp(dev->agp->bridge, entry->memory, entry->pages);
509 #else
510 		if (entry->bound)
511 			drm_unbind_agp(entry->memory);
512 		drm_free_agp(entry->memory, entry->pages);
513 #endif
514 		kfree(entry);
515 	}
516 	INIT_LIST_HEAD(&dev->agp->memory);
517 
518 	if (dev->agp->acquired)
519 		drm_agp_release(dev);
520 
521 	dev->agp->acquired = 0;
522 	dev->agp->enabled = 0;
523 }
524 
525 #ifndef __NetBSD__		/* XXX Dead code that doesn't make sense...  */
526 /**
527  * Binds a collection of pages into AGP memory at the given offset, returning
528  * the AGP memory structure containing them.
529  *
530  * No reference is held on the pages during this time -- it is up to the
531  * caller to handle that.
532  */
533 struct agp_memory *
534 drm_agp_bind_pages(struct drm_device *dev,
535 		   struct page **pages,
536 		   unsigned long num_pages,
537 		   uint32_t gtt_offset,
538 		   u32 type)
539 {
540 	struct agp_memory *mem;
541 	int ret, i;
542 
543 	DRM_DEBUG("\n");
544 
545 	mem = agp_allocate_memory(dev->agp->bridge, num_pages,
546 				      type);
547 	if (mem == NULL) {
548 		DRM_ERROR("Failed to allocate memory for %ld pages\n",
549 			  num_pages);
550 		return NULL;
551 	}
552 
553 	for (i = 0; i < num_pages; i++)
554 		mem->pages[i] = pages[i];
555 	mem->page_count = num_pages;
556 
557 	mem->is_flushed = true;
558 	ret = agp_bind_memory(mem, gtt_offset / AGP_PAGE_SIZE);
559 	if (ret != 0) {
560 		DRM_ERROR("Failed to bind AGP memory: %d\n", ret);
561 		agp_free_memory(mem);
562 		return NULL;
563 	}
564 
565 	return mem;
566 }
567 EXPORT_SYMBOL(drm_agp_bind_pages);
568 #endif
569 
570 #ifdef __NetBSD__
571 
572 static void __pci_iomem *
573 drm_agp_borrow_hook(struct drm_device *dev, unsigned i, bus_size_t size)
574 {
575 	struct pci_dev *pdev = dev->pdev;
576 
577 	if (!agp_i810_borrow(pdev->pd_resources[i].addr, size,
578 		&pdev->pd_resources[i].bsh))
579 		return NULL;
580 	/* XXX Synchronize with pci_iomap in linux_pci.c.  */
581 	pdev->pd_resources[i].bst = pdev->pd_pa.pa_memt;
582 	pdev->pd_resources[i].kva = bus_space_vaddr(pdev->pd_resources[i].bst,
583 	    pdev->pd_resources[i].bsh);
584 	pdev->pd_resources[i].mapped = true;
585 
586 	return pdev->pd_resources[i].kva;
587 }
588 
589 static void
590 drm_agp_flush_hook(void)
591 {
592 
593 	agp_flush_cache();
594 }
595 
596 static const struct drm_agp_hooks agp_hooks = {
597 	.agph_info = drm_agp_info_hook,
598 	.agph_info_ioctl = drm_agp_info_ioctl_hook,
599 	.agph_acquire = drm_agp_acquire_hook,
600 	.agph_acquire_ioctl = drm_agp_acquire_ioctl_hook,
601 	.agph_release = drm_agp_release_hook,
602 	.agph_release_ioctl = drm_agp_release_ioctl_hook,
603 	.agph_enable = drm_agp_enable_hook,
604 	.agph_enable_ioctl = drm_agp_enable_ioctl_hook,
605 	.agph_alloc = drm_agp_alloc_hook,
606 	.agph_alloc_ioctl = drm_agp_alloc_ioctl_hook,
607 	.agph_unbind = drm_agp_unbind_hook,
608 	.agph_unbind_ioctl = drm_agp_unbind_ioctl_hook,
609 	.agph_bind = drm_agp_bind_hook,
610 	.agph_bind_ioctl = drm_agp_bind_ioctl_hook,
611 	.agph_free = drm_agp_free_hook,
612 	.agph_free_ioctl = drm_agp_free_ioctl_hook,
613 	.agph_init = drm_agp_init_hook,
614 	.agph_clear = drm_agp_clear_hook,
615 	.agph_borrow = drm_agp_borrow_hook,
616 	.agph_flush = drm_agp_flush_hook,
617 };
618 
619 #include <sys/module.h>
620 #include <sys/once.h>
621 
622 MODULE(MODULE_CLASS_MISC, drmkms_agp, "drmkms"); /* XXX agp */
623 
624 static int
625 drmkms_agp_init(void)
626 {
627 
628 	return drm_agp_register(&agp_hooks);
629 }
630 
631 int
632 drmkms_agp_guarantee_initialized(void)
633 {
634 #ifdef _MODULE
635 	return 0;
636 #else
637 	static ONCE_DECL(drmkms_agp_init_once);
638 
639 	return RUN_ONCE(&drmkms_agp_init_once, &drmkms_agp_init);
640 #endif
641 }
642 
643 static int
644 drmkms_agp_fini(void)
645 {
646 
647 	return drm_agp_deregister(&agp_hooks);
648 }
649 
650 static int
651 drmkms_agp_modcmd(modcmd_t cmd, void *arg __unused)
652 {
653 	int error;
654 
655 	switch (cmd) {
656 	case MODULE_CMD_INIT:
657 #ifdef _MODULE
658 		error = drmkms_agp_init();
659 #else
660 		error = drmkms_agp_guarantee_initialized();
661 #endif
662 		if (error)
663 			return error;
664 		return 0;
665 	case MODULE_CMD_FINI:
666 		error = drmkms_agp_fini();
667 		if (error)
668 			return error;
669 		return 0;
670 	default:
671 		return ENOTTY;
672 	}
673 }
674 
675 #endif	/* __NetBSD__ */
676