1 /*- 2 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 3 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 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 "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * Author: 26 * Rickard E. (Rik) Faith <faith@valinux.com> 27 * Gareth Hughes <gareth@valinux.com> 28 * 29 */ 30 31 /** @file drm_agpsupport.c 32 * Support code for tying the kernel AGP support to DRM drivers and 33 * the DRM's AGP ioctls. 34 */ 35 36 #include "dev/drm/drmP.h" 37 38 #include <dev/agp/agpreg.h> 39 #include <bus/pci/pcireg.h> 40 41 /* Returns 1 if AGP or 0 if not. */ 42 static int 43 drm_device_find_capability(struct drm_device *dev, int cap) 44 { 45 return (pci_find_extcap(dev->device, cap, NULL) == 0); 46 } 47 48 int drm_device_is_agp(struct drm_device *dev) 49 { 50 if (dev->driver->device_is_agp != NULL) { 51 int ret; 52 53 /* device_is_agp returns a tristate, 0 = not AGP, 1 = definitely 54 * AGP, 2 = fall back to PCI capability 55 */ 56 ret = (*dev->driver->device_is_agp)(dev); 57 if (ret != DRM_MIGHT_BE_AGP) 58 return ret; 59 } 60 61 return (drm_device_find_capability(dev, PCIY_AGP)); 62 } 63 64 int drm_device_is_pcie(struct drm_device *dev) 65 { 66 return (drm_device_find_capability(dev, PCIY_EXPRESS)); 67 } 68 69 int drm_agp_info(struct drm_device * dev, struct drm_agp_info *info) 70 { 71 struct agp_info *kern; 72 73 if (!dev->agp || !dev->agp->acquired) 74 return EINVAL; 75 76 kern = &dev->agp->info; 77 agp_get_info(dev->agp->agpdev, kern); 78 info->agp_version_major = 1; 79 info->agp_version_minor = 0; 80 info->mode = kern->ai_mode; 81 info->aperture_base = kern->ai_aperture_base; 82 info->aperture_size = kern->ai_aperture_size; 83 info->memory_allowed = kern->ai_memory_allowed; 84 info->memory_used = kern->ai_memory_used; 85 info->id_vendor = kern->ai_devid & 0xffff; 86 info->id_device = kern->ai_devid >> 16; 87 88 return 0; 89 } 90 91 int drm_agp_info_ioctl(struct drm_device *dev, void *data, 92 struct drm_file *file_priv) 93 { 94 int err; 95 struct drm_agp_info info; 96 97 err = drm_agp_info(dev, &info); 98 if (err != 0) 99 return err; 100 101 *(struct drm_agp_info *) data = info; 102 return 0; 103 } 104 105 int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, 106 struct drm_file *file_priv) 107 { 108 109 return drm_agp_acquire(dev); 110 } 111 112 int drm_agp_acquire(struct drm_device *dev) 113 { 114 int retcode; 115 116 if (!dev->agp || dev->agp->acquired) 117 return EINVAL; 118 119 retcode = agp_acquire(dev->agp->agpdev); 120 if (retcode) 121 return retcode; 122 123 dev->agp->acquired = 1; 124 return 0; 125 } 126 127 int drm_agp_release_ioctl(struct drm_device *dev, void *data, 128 struct drm_file *file_priv) 129 { 130 131 return drm_agp_release(dev); 132 } 133 134 int drm_agp_release(struct drm_device * dev) 135 { 136 if (!dev->agp || !dev->agp->acquired) 137 return EINVAL; 138 agp_release(dev->agp->agpdev); 139 dev->agp->acquired = 0; 140 return 0; 141 } 142 143 int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode) 144 { 145 146 if (!dev->agp || !dev->agp->acquired) 147 return EINVAL; 148 149 dev->agp->mode = mode.mode; 150 agp_enable(dev->agp->agpdev, mode.mode); 151 dev->agp->enabled = 1; 152 return 0; 153 } 154 155 int drm_agp_enable_ioctl(struct drm_device *dev, void *data, 156 struct drm_file *file_priv) 157 { 158 struct drm_agp_mode mode; 159 160 mode = *(struct drm_agp_mode *) data; 161 162 return drm_agp_enable(dev, mode); 163 } 164 165 int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) 166 { 167 drm_agp_mem_t *entry; 168 void *handle; 169 unsigned long pages; 170 u_int32_t type; 171 struct agp_memory_info info; 172 173 if (!dev->agp || !dev->agp->acquired) 174 return EINVAL; 175 176 entry = malloc(sizeof(*entry), DRM_MEM_AGPLISTS, M_NOWAIT | M_ZERO); 177 if (entry == NULL) 178 return ENOMEM; 179 180 pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; 181 type = (u_int32_t) request->type; 182 183 DRM_UNLOCK(); 184 handle = drm_agp_allocate_memory(pages, type); 185 DRM_LOCK(); 186 if (handle == NULL) { 187 free(entry, DRM_MEM_AGPLISTS); 188 return ENOMEM; 189 } 190 191 entry->handle = handle; 192 entry->bound = 0; 193 entry->pages = pages; 194 entry->prev = NULL; 195 entry->next = dev->agp->memory; 196 if (dev->agp->memory) 197 dev->agp->memory->prev = entry; 198 dev->agp->memory = entry; 199 200 agp_memory_info(dev->agp->agpdev, entry->handle, &info); 201 202 request->handle = (unsigned long) entry->handle; 203 request->physical = info.ami_physical; 204 205 return 0; 206 } 207 208 int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, 209 struct drm_file *file_priv) 210 { 211 struct drm_agp_buffer request; 212 int retcode; 213 214 request = *(struct drm_agp_buffer *) data; 215 216 DRM_LOCK(); 217 retcode = drm_agp_alloc(dev, &request); 218 DRM_UNLOCK(); 219 220 *(struct drm_agp_buffer *) data = request; 221 222 return retcode; 223 } 224 225 static drm_agp_mem_t * drm_agp_lookup_entry(struct drm_device *dev, 226 void *handle) 227 { 228 drm_agp_mem_t *entry; 229 230 for (entry = dev->agp->memory; entry; entry = entry->next) { 231 if (entry->handle == handle) return entry; 232 } 233 return NULL; 234 } 235 236 int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) 237 { 238 drm_agp_mem_t *entry; 239 int retcode; 240 241 if (!dev->agp || !dev->agp->acquired) 242 return EINVAL; 243 244 entry = drm_agp_lookup_entry(dev, (void *)request->handle); 245 if (entry == NULL || !entry->bound) 246 return EINVAL; 247 248 DRM_UNLOCK(); 249 retcode = drm_agp_unbind_memory(entry->handle); 250 DRM_LOCK(); 251 252 if (retcode == 0) 253 entry->bound = 0; 254 255 return retcode; 256 } 257 258 int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, 259 struct drm_file *file_priv) 260 { 261 struct drm_agp_binding request; 262 int retcode; 263 264 request = *(struct drm_agp_binding *) data; 265 266 DRM_LOCK(); 267 retcode = drm_agp_unbind(dev, &request); 268 DRM_UNLOCK(); 269 270 return retcode; 271 } 272 273 int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) 274 { 275 drm_agp_mem_t *entry; 276 int retcode; 277 int page; 278 279 if (!dev->agp || !dev->agp->acquired) 280 return EINVAL; 281 282 DRM_DEBUG("agp_bind, page_size=%x\n", PAGE_SIZE); 283 284 entry = drm_agp_lookup_entry(dev, (void *)request->handle); 285 if (entry == NULL || entry->bound) 286 return EINVAL; 287 288 page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE; 289 290 DRM_UNLOCK(); 291 retcode = drm_agp_bind_memory(entry->handle, page); 292 DRM_LOCK(); 293 if (retcode == 0) 294 entry->bound = dev->agp->base + (page << PAGE_SHIFT); 295 296 return retcode; 297 } 298 299 int drm_agp_bind_ioctl(struct drm_device *dev, void *data, 300 struct drm_file *file_priv) 301 { 302 struct drm_agp_binding request; 303 int retcode; 304 305 request = *(struct drm_agp_binding *) data; 306 307 DRM_LOCK(); 308 retcode = drm_agp_bind(dev, &request); 309 DRM_UNLOCK(); 310 311 return retcode; 312 } 313 314 int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) 315 { 316 drm_agp_mem_t *entry; 317 318 if (!dev->agp || !dev->agp->acquired) 319 return EINVAL; 320 321 entry = drm_agp_lookup_entry(dev, (void*)request->handle); 322 if (entry == NULL) 323 return EINVAL; 324 325 if (entry->prev) 326 entry->prev->next = entry->next; 327 else 328 dev->agp->memory = entry->next; 329 if (entry->next) 330 entry->next->prev = entry->prev; 331 332 DRM_UNLOCK(); 333 if (entry->bound) 334 drm_agp_unbind_memory(entry->handle); 335 drm_agp_free_memory(entry->handle); 336 DRM_LOCK(); 337 338 free(entry, DRM_MEM_AGPLISTS); 339 340 return 0; 341 342 } 343 344 int drm_agp_free_ioctl(struct drm_device *dev, void *data, 345 struct drm_file *file_priv) 346 { 347 struct drm_agp_buffer request; 348 int retcode; 349 350 request = *(struct drm_agp_buffer *) data; 351 352 DRM_LOCK(); 353 retcode = drm_agp_free(dev, &request); 354 DRM_UNLOCK(); 355 356 return retcode; 357 } 358 359 drm_agp_head_t *drm_agp_init(void) 360 { 361 device_t agpdev; 362 drm_agp_head_t *head = NULL; 363 int agp_available = 1; 364 365 agpdev = DRM_AGP_FIND_DEVICE(); 366 if (!agpdev) 367 agp_available = 0; 368 369 DRM_DEBUG("agp_available = %d\n", agp_available); 370 371 if (agp_available) { 372 head = malloc(sizeof(*head), DRM_MEM_AGPLISTS, 373 M_NOWAIT | M_ZERO); 374 if (head == NULL) 375 return NULL; 376 head->agpdev = agpdev; 377 agp_get_info(agpdev, &head->info); 378 head->base = head->info.ai_aperture_base; 379 head->memory = NULL; 380 DRM_INFO("AGP at 0x%08lx %dMB\n", 381 (long)head->info.ai_aperture_base, 382 (int)(head->info.ai_aperture_size >> 20)); 383 } 384 return head; 385 } 386 387 void *drm_agp_allocate_memory(size_t pages, u32 type) 388 { 389 device_t agpdev; 390 391 agpdev = DRM_AGP_FIND_DEVICE(); 392 if (!agpdev) 393 return NULL; 394 395 return agp_alloc_memory(agpdev, type, pages << AGP_PAGE_SHIFT); 396 } 397 398 int drm_agp_free_memory(void *handle) 399 { 400 device_t agpdev; 401 402 agpdev = DRM_AGP_FIND_DEVICE(); 403 if (!agpdev || !handle) 404 return 0; 405 406 agp_free_memory(agpdev, handle); 407 return 1; 408 } 409 410 int drm_agp_bind_memory(void *handle, off_t start) 411 { 412 device_t agpdev; 413 414 agpdev = DRM_AGP_FIND_DEVICE(); 415 if (!agpdev || !handle) 416 return EINVAL; 417 418 return agp_bind_memory(agpdev, handle, start * PAGE_SIZE); 419 } 420 421 int drm_agp_unbind_memory(void *handle) 422 { 423 device_t agpdev; 424 425 agpdev = DRM_AGP_FIND_DEVICE(); 426 if (!agpdev || !handle) 427 return EINVAL; 428 429 return agp_unbind_memory(agpdev, handle); 430 } 431