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