17f3c3d6fSHasso Tepper /*- 27f3c3d6fSHasso Tepper * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 37f3c3d6fSHasso Tepper * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 47f3c3d6fSHasso Tepper * All Rights Reserved. 57f3c3d6fSHasso Tepper * 67f3c3d6fSHasso Tepper * Permission is hereby granted, free of charge, to any person obtaining a 77f3c3d6fSHasso Tepper * copy of this software and associated documentation files (the "Software"), 87f3c3d6fSHasso Tepper * to deal in the Software without restriction, including without limitation 97f3c3d6fSHasso Tepper * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107f3c3d6fSHasso Tepper * and/or sell copies of the Software, and to permit persons to whom the 117f3c3d6fSHasso Tepper * Software is furnished to do so, subject to the following conditions: 127f3c3d6fSHasso Tepper * 137f3c3d6fSHasso Tepper * The above copyright notice and this permission notice (including the next 147f3c3d6fSHasso Tepper * paragraph) shall be included in all copies or substantial portions of the 157f3c3d6fSHasso Tepper * Software. 167f3c3d6fSHasso Tepper * 177f3c3d6fSHasso Tepper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 187f3c3d6fSHasso Tepper * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197f3c3d6fSHasso Tepper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 207f3c3d6fSHasso Tepper * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 217f3c3d6fSHasso Tepper * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 227f3c3d6fSHasso Tepper * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 237f3c3d6fSHasso Tepper * OTHER DEALINGS IN THE SOFTWARE. 247f3c3d6fSHasso Tepper * 257f3c3d6fSHasso Tepper * Authors: 267f3c3d6fSHasso Tepper * Rickard E. (Rik) Faith <faith@valinux.com> 277f3c3d6fSHasso Tepper * Gareth Hughes <gareth@valinux.com> 287f3c3d6fSHasso Tepper * 295718399fSFrançois Tigeot * $FreeBSD: src/sys/dev/drm2/drm_bufs.c,v 1.1 2012/05/22 11:07:44 kib Exp $ 307f3c3d6fSHasso Tepper */ 317f3c3d6fSHasso Tepper 327f3c3d6fSHasso Tepper /** @file drm_bufs.c 337f3c3d6fSHasso Tepper * Implementation of the ioctls for setup of DRM mappings and DMA buffers. 347f3c3d6fSHasso Tepper */ 357f3c3d6fSHasso Tepper 365718399fSFrançois Tigeot #include <sys/conf.h> 375718399fSFrançois Tigeot #include <bus/pci/pcireg.h> 387f3c3d6fSHasso Tepper 3918e26a6dSFrançois Tigeot #include <drm/drmP.h> 407f3c3d6fSHasso Tepper 417f3c3d6fSHasso Tepper /* Allocation of PCI memory resources (framebuffer, registers, etc.) for 427f3c3d6fSHasso Tepper * drm_get_resource_*. Note that they are not RF_ACTIVE, so there's no virtual 437f3c3d6fSHasso Tepper * address for accessing them. Cleaned up at unload. 447f3c3d6fSHasso Tepper */ 45b3705d71SHasso Tepper static int drm_alloc_resource(struct drm_device *dev, int resource) 467f3c3d6fSHasso Tepper { 4799f70504SFrançois Tigeot struct resource *res; 4899f70504SFrançois Tigeot int rid; 4999f70504SFrançois Tigeot 505718399fSFrançois Tigeot DRM_LOCK_ASSERT(dev); 5199f70504SFrançois Tigeot 527f3c3d6fSHasso Tepper if (resource >= DRM_MAX_PCI_RESOURCE) { 537f3c3d6fSHasso Tepper DRM_ERROR("Resource %d too large\n", resource); 547f3c3d6fSHasso Tepper return 1; 557f3c3d6fSHasso Tepper } 567f3c3d6fSHasso Tepper 577f3c3d6fSHasso Tepper if (dev->pcir[resource] != NULL) { 587f3c3d6fSHasso Tepper return 0; 597f3c3d6fSHasso Tepper } 607f3c3d6fSHasso Tepper 615718399fSFrançois Tigeot DRM_UNLOCK(dev); 6299f70504SFrançois Tigeot rid = PCIR_BAR(resource); 6399f70504SFrançois Tigeot res = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &rid, 6499f70504SFrançois Tigeot RF_SHAREABLE); 655718399fSFrançois Tigeot DRM_LOCK(dev); 6699f70504SFrançois Tigeot if (res == NULL) { 677f3c3d6fSHasso Tepper DRM_ERROR("Couldn't find resource 0x%x\n", resource); 687f3c3d6fSHasso Tepper return 1; 697f3c3d6fSHasso Tepper } 707f3c3d6fSHasso Tepper 7199f70504SFrançois Tigeot if (dev->pcir[resource] == NULL) { 7299f70504SFrançois Tigeot dev->pcirid[resource] = rid; 7399f70504SFrançois Tigeot dev->pcir[resource] = res; 7499f70504SFrançois Tigeot } 7599f70504SFrançois Tigeot 767f3c3d6fSHasso Tepper return 0; 777f3c3d6fSHasso Tepper } 787f3c3d6fSHasso Tepper 79b3705d71SHasso Tepper unsigned long drm_get_resource_start(struct drm_device *dev, 80b3705d71SHasso Tepper unsigned int resource) 817f3c3d6fSHasso Tepper { 827f3c3d6fSHasso Tepper if (drm_alloc_resource(dev, resource) != 0) 837f3c3d6fSHasso Tepper return 0; 847f3c3d6fSHasso Tepper 857f3c3d6fSHasso Tepper return rman_get_start(dev->pcir[resource]); 867f3c3d6fSHasso Tepper } 877f3c3d6fSHasso Tepper 88b3705d71SHasso Tepper unsigned long drm_get_resource_len(struct drm_device *dev, 89b3705d71SHasso Tepper unsigned int resource) 907f3c3d6fSHasso Tepper { 917f3c3d6fSHasso Tepper if (drm_alloc_resource(dev, resource) != 0) 927f3c3d6fSHasso Tepper return 0; 937f3c3d6fSHasso Tepper 947f3c3d6fSHasso Tepper return rman_get_size(dev->pcir[resource]); 957f3c3d6fSHasso Tepper } 967f3c3d6fSHasso Tepper 97b3705d71SHasso Tepper int drm_addmap(struct drm_device * dev, unsigned long offset, 98b3705d71SHasso Tepper unsigned long size, 99b3705d71SHasso Tepper enum drm_map_type type, enum drm_map_flags flags, drm_local_map_t **map_ptr) 1007f3c3d6fSHasso Tepper { 101*f599cd46SFrançois Tigeot struct drm_local_map *map; 102*f599cd46SFrançois Tigeot struct drm_map_list *entry; 1037f3c3d6fSHasso Tepper int align; 1047f3c3d6fSHasso Tepper /*drm_agp_mem_t *entry; 1057f3c3d6fSHasso Tepper int valid;*/ 1067f3c3d6fSHasso Tepper 1077f3c3d6fSHasso Tepper /* Only allow shared memory to be removable since we only keep enough 1087f3c3d6fSHasso Tepper * book keeping information about shared memory to allow for removal 1097f3c3d6fSHasso Tepper * when processes fork. 1107f3c3d6fSHasso Tepper */ 1117f3c3d6fSHasso Tepper if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) { 1127f3c3d6fSHasso Tepper DRM_ERROR("Requested removable map for non-DRM_SHM\n"); 1137f3c3d6fSHasso Tepper return EINVAL; 1147f3c3d6fSHasso Tepper } 1157f3c3d6fSHasso Tepper if ((offset & PAGE_MASK) || (size & PAGE_MASK)) { 1167f3c3d6fSHasso Tepper DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n", 1177f3c3d6fSHasso Tepper offset, size); 1187f3c3d6fSHasso Tepper return EINVAL; 1197f3c3d6fSHasso Tepper } 1207f3c3d6fSHasso Tepper if (offset + size < offset) { 1217f3c3d6fSHasso Tepper DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n", 1227f3c3d6fSHasso Tepper offset, size); 1237f3c3d6fSHasso Tepper return EINVAL; 1247f3c3d6fSHasso Tepper } 1257f3c3d6fSHasso Tepper 1267f3c3d6fSHasso Tepper DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset, 1277f3c3d6fSHasso Tepper size, type); 1287f3c3d6fSHasso Tepper 1297f3c3d6fSHasso Tepper /* Check if this is just another version of a kernel-allocated map, and 1307f3c3d6fSHasso Tepper * just hand that back if so. 1317f3c3d6fSHasso Tepper */ 1327f3c3d6fSHasso Tepper if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER || 1337f3c3d6fSHasso Tepper type == _DRM_SHM) { 134*f599cd46SFrançois Tigeot list_for_each_entry(entry, &dev->maplist, head) { 135*f599cd46SFrançois Tigeot if (entry->map->type == type && (entry->map->offset == offset || 136*f599cd46SFrançois Tigeot (entry->map->type == _DRM_SHM && 137*f599cd46SFrançois Tigeot entry->map->flags == _DRM_CONTAINS_LOCK))) { 138*f599cd46SFrançois Tigeot entry->map->size = size; 1397f3c3d6fSHasso Tepper DRM_DEBUG("Found kernel map %d\n", type); 1407f3c3d6fSHasso Tepper goto done; 1417f3c3d6fSHasso Tepper } 1427f3c3d6fSHasso Tepper } 1437f3c3d6fSHasso Tepper } 1445718399fSFrançois Tigeot DRM_UNLOCK(dev); 1457f3c3d6fSHasso Tepper 1467f3c3d6fSHasso Tepper /* Allocate a new map structure, fill it in, and do any type-specific 1477f3c3d6fSHasso Tepper * initialization necessary. 1487f3c3d6fSHasso Tepper */ 1495718399fSFrançois Tigeot map = kmalloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT); 150b3705d71SHasso Tepper if (!map) { 1515718399fSFrançois Tigeot DRM_LOCK(dev); 1527f3c3d6fSHasso Tepper return ENOMEM; 153b3705d71SHasso Tepper } 1547f3c3d6fSHasso Tepper 1557f3c3d6fSHasso Tepper map->offset = offset; 1567f3c3d6fSHasso Tepper map->size = size; 1577f3c3d6fSHasso Tepper map->type = type; 1587f3c3d6fSHasso Tepper map->flags = flags; 15999f70504SFrançois Tigeot map->handle = (void *)((unsigned long)alloc_unr(dev->map_unrhdr) << 16099f70504SFrançois Tigeot DRM_MAP_HANDLE_SHIFT); 1617f3c3d6fSHasso Tepper 1627f3c3d6fSHasso Tepper switch (map->type) { 1637f3c3d6fSHasso Tepper case _DRM_REGISTERS: 16499f70504SFrançois Tigeot map->virtual = drm_ioremap(dev, map); 1657f3c3d6fSHasso Tepper if (!(map->flags & _DRM_WRITE_COMBINING)) 1667f3c3d6fSHasso Tepper break; 1677f3c3d6fSHasso Tepper /* FALLTHROUGH */ 1687f3c3d6fSHasso Tepper case _DRM_FRAME_BUFFER: 1697f3c3d6fSHasso Tepper if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0) 1707f3c3d6fSHasso Tepper map->mtrr = 1; 1717f3c3d6fSHasso Tepper break; 1727f3c3d6fSHasso Tepper case _DRM_SHM: 1735718399fSFrançois Tigeot map->virtual = kmalloc(map->size, DRM_MEM_MAPS, M_NOWAIT); 1747f3c3d6fSHasso Tepper DRM_DEBUG("%lu %d %p\n", 17599f70504SFrançois Tigeot map->size, drm_order(map->size), map->virtual); 17699f70504SFrançois Tigeot if (!map->virtual) { 1775718399fSFrançois Tigeot drm_free(map, DRM_MEM_MAPS); 1785718399fSFrançois Tigeot DRM_LOCK(dev); 1797f3c3d6fSHasso Tepper return ENOMEM; 1807f3c3d6fSHasso Tepper } 18199f70504SFrançois Tigeot map->offset = (unsigned long)map->virtual; 1827f3c3d6fSHasso Tepper if (map->flags & _DRM_CONTAINS_LOCK) { 1837f3c3d6fSHasso Tepper /* Prevent a 2nd X Server from creating a 2nd lock */ 1845718399fSFrançois Tigeot DRM_LOCK(dev); 1857f3c3d6fSHasso Tepper if (dev->lock.hw_lock != NULL) { 1865718399fSFrançois Tigeot DRM_UNLOCK(dev); 1875718399fSFrançois Tigeot drm_free(map->virtual, DRM_MEM_MAPS); 1885718399fSFrançois Tigeot drm_free(map, DRM_MEM_MAPS); 1897f3c3d6fSHasso Tepper return EBUSY; 1907f3c3d6fSHasso Tepper } 19199f70504SFrançois Tigeot dev->lock.hw_lock = map->virtual; /* Pointer to lock */ 1925718399fSFrançois Tigeot DRM_UNLOCK(dev); 1937f3c3d6fSHasso Tepper } 1947f3c3d6fSHasso Tepper break; 1957f3c3d6fSHasso Tepper case _DRM_AGP: 1967f3c3d6fSHasso Tepper /*valid = 0;*/ 1977f3c3d6fSHasso Tepper /* In some cases (i810 driver), user space may have already 1987f3c3d6fSHasso Tepper * added the AGP base itself, because dev->agp->base previously 1997f3c3d6fSHasso Tepper * only got set during AGP enable. So, only add the base 2007f3c3d6fSHasso Tepper * address if the map's offset isn't already within the 2017f3c3d6fSHasso Tepper * aperture. 2027f3c3d6fSHasso Tepper */ 2037f3c3d6fSHasso Tepper if (map->offset < dev->agp->base || 2047f3c3d6fSHasso Tepper map->offset > dev->agp->base + 2057f3c3d6fSHasso Tepper dev->agp->info.ai_aperture_size - 1) { 2067f3c3d6fSHasso Tepper map->offset += dev->agp->base; 2077f3c3d6fSHasso Tepper } 2087f3c3d6fSHasso Tepper map->mtrr = dev->agp->mtrr; /* for getmap */ 2097f3c3d6fSHasso Tepper /*for (entry = dev->agp->memory; entry; entry = entry->next) { 2107f3c3d6fSHasso Tepper if ((map->offset >= entry->bound) && 2117f3c3d6fSHasso Tepper (map->offset + map->size <= 2127f3c3d6fSHasso Tepper entry->bound + entry->pages * PAGE_SIZE)) { 2137f3c3d6fSHasso Tepper valid = 1; 2147f3c3d6fSHasso Tepper break; 2157f3c3d6fSHasso Tepper } 2167f3c3d6fSHasso Tepper } 2177f3c3d6fSHasso Tepper if (!valid) { 2185718399fSFrançois Tigeot drm_free(map, DRM_MEM_MAPS); 2195718399fSFrançois Tigeot DRM_LOCK(dev); 2207f3c3d6fSHasso Tepper return EACCES; 2217f3c3d6fSHasso Tepper }*/ 2227f3c3d6fSHasso Tepper break; 2237f3c3d6fSHasso Tepper case _DRM_SCATTER_GATHER: 2247f3c3d6fSHasso Tepper if (!dev->sg) { 2255718399fSFrançois Tigeot drm_free(map, DRM_MEM_MAPS); 2265718399fSFrançois Tigeot DRM_LOCK(dev); 2277f3c3d6fSHasso Tepper return EINVAL; 2287f3c3d6fSHasso Tepper } 22999f70504SFrançois Tigeot map->virtual = (void *)(dev->sg->vaddr + offset); 23099f70504SFrançois Tigeot map->offset = dev->sg->vaddr + offset; 2317f3c3d6fSHasso Tepper break; 2327f3c3d6fSHasso Tepper case _DRM_CONSISTENT: 2337f3c3d6fSHasso Tepper /* Unfortunately, we don't get any alignment specification from 2347f3c3d6fSHasso Tepper * the caller, so we have to guess. drm_pci_alloc requires 2357f3c3d6fSHasso Tepper * a power-of-two alignment, so try to align the bus address of 2367f3c3d6fSHasso Tepper * the map to it size if possible, otherwise just assume 2377f3c3d6fSHasso Tepper * PAGE_SIZE alignment. 2387f3c3d6fSHasso Tepper */ 2397f3c3d6fSHasso Tepper align = map->size; 2407f3c3d6fSHasso Tepper if ((align & (align - 1)) != 0) 2417f3c3d6fSHasso Tepper align = PAGE_SIZE; 2427f3c3d6fSHasso Tepper map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful); 2437f3c3d6fSHasso Tepper if (map->dmah == NULL) { 2445718399fSFrançois Tigeot drm_free(map, DRM_MEM_MAPS); 2455718399fSFrançois Tigeot DRM_LOCK(dev); 2467f3c3d6fSHasso Tepper return ENOMEM; 2477f3c3d6fSHasso Tepper } 24899f70504SFrançois Tigeot map->virtual = map->dmah->vaddr; 2497f3c3d6fSHasso Tepper map->offset = map->dmah->busaddr; 2507f3c3d6fSHasso Tepper break; 2517f3c3d6fSHasso Tepper default: 2527f3c3d6fSHasso Tepper DRM_ERROR("Bad map type %d\n", map->type); 2535718399fSFrançois Tigeot drm_free(map, DRM_MEM_MAPS); 2545718399fSFrançois Tigeot DRM_LOCK(dev); 2557f3c3d6fSHasso Tepper return EINVAL; 2567f3c3d6fSHasso Tepper } 2577f3c3d6fSHasso Tepper 2585718399fSFrançois Tigeot DRM_LOCK(dev); 259*f599cd46SFrançois Tigeot list_add(&entry->head, &dev->maplist); 2607f3c3d6fSHasso Tepper 2617f3c3d6fSHasso Tepper done: 2627f3c3d6fSHasso Tepper /* Jumped to, with lock held, when a kernel map is found. */ 2637f3c3d6fSHasso Tepper 2647f3c3d6fSHasso Tepper DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset, 2657f3c3d6fSHasso Tepper map->size); 2667f3c3d6fSHasso Tepper 2677f3c3d6fSHasso Tepper *map_ptr = map; 2687f3c3d6fSHasso Tepper 2697f3c3d6fSHasso Tepper return 0; 2707f3c3d6fSHasso Tepper } 2717f3c3d6fSHasso Tepper 272b3705d71SHasso Tepper int drm_addmap_ioctl(struct drm_device *dev, void *data, 273b3705d71SHasso Tepper struct drm_file *file_priv) 2747f3c3d6fSHasso Tepper { 275b3705d71SHasso Tepper struct drm_map *request = data; 2767f3c3d6fSHasso Tepper drm_local_map_t *map; 2777f3c3d6fSHasso Tepper int err; 2787f3c3d6fSHasso Tepper 2797f3c3d6fSHasso Tepper if (!(dev->flags & (FREAD|FWRITE))) 2807f3c3d6fSHasso Tepper return EACCES; /* Require read/write */ 2817f3c3d6fSHasso Tepper 2827f3c3d6fSHasso Tepper if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP) 2837f3c3d6fSHasso Tepper return EACCES; 2847f3c3d6fSHasso Tepper 2855718399fSFrançois Tigeot DRM_LOCK(dev); 2867f3c3d6fSHasso Tepper err = drm_addmap(dev, request->offset, request->size, request->type, 2877f3c3d6fSHasso Tepper request->flags, &map); 2885718399fSFrançois Tigeot DRM_UNLOCK(dev); 2897f3c3d6fSHasso Tepper if (err != 0) 2907f3c3d6fSHasso Tepper return err; 2917f3c3d6fSHasso Tepper 2927f3c3d6fSHasso Tepper request->offset = map->offset; 2937f3c3d6fSHasso Tepper request->size = map->size; 2947f3c3d6fSHasso Tepper request->type = map->type; 2957f3c3d6fSHasso Tepper request->flags = map->flags; 2967f3c3d6fSHasso Tepper request->mtrr = map->mtrr; 29799f70504SFrançois Tigeot request->handle = (void *)map->handle; 2987f3c3d6fSHasso Tepper 2997f3c3d6fSHasso Tepper return 0; 3007f3c3d6fSHasso Tepper } 3017f3c3d6fSHasso Tepper 302*f599cd46SFrançois Tigeot void drm_rmmap(struct drm_device *dev, struct drm_local_map *map) 3037f3c3d6fSHasso Tepper { 304*f599cd46SFrançois Tigeot struct drm_map_list *r_list = NULL, *list_t; 305*f599cd46SFrançois Tigeot int found = 0; 306*f599cd46SFrançois Tigeot 3075718399fSFrançois Tigeot DRM_LOCK_ASSERT(dev); 3087f3c3d6fSHasso Tepper 309c6bd1f0dSHasso Tepper if (map == NULL) 310c6bd1f0dSHasso Tepper return; 311c6bd1f0dSHasso Tepper 312*f599cd46SFrançois Tigeot /* Find the list entry for the map and remove it */ 313*f599cd46SFrançois Tigeot list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { 314*f599cd46SFrançois Tigeot if (r_list->map == map) { 315*f599cd46SFrançois Tigeot list_del(&r_list->head); 316*f599cd46SFrançois Tigeot drm_free(r_list, DRM_MEM_DRIVER); 317*f599cd46SFrançois Tigeot found = 1; 318*f599cd46SFrançois Tigeot break; 319*f599cd46SFrançois Tigeot } 320*f599cd46SFrançois Tigeot } 321*f599cd46SFrançois Tigeot 322*f599cd46SFrançois Tigeot if (!found) 323*f599cd46SFrançois Tigeot return; 3247f3c3d6fSHasso Tepper 3257f3c3d6fSHasso Tepper switch (map->type) { 3267f3c3d6fSHasso Tepper case _DRM_REGISTERS: 3277f3c3d6fSHasso Tepper if (map->bsr == NULL) 3287f3c3d6fSHasso Tepper drm_ioremapfree(map); 3297f3c3d6fSHasso Tepper /* FALLTHROUGH */ 3307f3c3d6fSHasso Tepper case _DRM_FRAME_BUFFER: 3317f3c3d6fSHasso Tepper if (map->mtrr) { 3325718399fSFrançois Tigeot int __unused retcode; 3337f3c3d6fSHasso Tepper 3347f3c3d6fSHasso Tepper retcode = drm_mtrr_del(0, map->offset, map->size, 3357f3c3d6fSHasso Tepper DRM_MTRR_WC); 3367f3c3d6fSHasso Tepper DRM_DEBUG("mtrr_del = %d\n", retcode); 3377f3c3d6fSHasso Tepper } 3387f3c3d6fSHasso Tepper break; 3397f3c3d6fSHasso Tepper case _DRM_SHM: 3405718399fSFrançois Tigeot drm_free(map->virtual, DRM_MEM_MAPS); 3417f3c3d6fSHasso Tepper break; 3427f3c3d6fSHasso Tepper case _DRM_AGP: 3437f3c3d6fSHasso Tepper case _DRM_SCATTER_GATHER: 3447f3c3d6fSHasso Tepper break; 3457f3c3d6fSHasso Tepper case _DRM_CONSISTENT: 3467f3c3d6fSHasso Tepper drm_pci_free(dev, map->dmah); 3477f3c3d6fSHasso Tepper break; 3487f3c3d6fSHasso Tepper default: 3497f3c3d6fSHasso Tepper DRM_ERROR("Bad map type %d\n", map->type); 3507f3c3d6fSHasso Tepper break; 3517f3c3d6fSHasso Tepper } 3527f3c3d6fSHasso Tepper 3537f3c3d6fSHasso Tepper if (map->bsr != NULL) { 3547f3c3d6fSHasso Tepper bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid, 3557f3c3d6fSHasso Tepper map->bsr); 3567f3c3d6fSHasso Tepper } 3577f3c3d6fSHasso Tepper 3585718399fSFrançois Tigeot DRM_UNLOCK(dev); 35999f70504SFrançois Tigeot if (map->handle) 36099f70504SFrançois Tigeot free_unr(dev->map_unrhdr, (unsigned long)map->handle >> 36199f70504SFrançois Tigeot DRM_MAP_HANDLE_SHIFT); 3625718399fSFrançois Tigeot DRM_LOCK(dev); 36399f70504SFrançois Tigeot 3645718399fSFrançois Tigeot drm_free(map, DRM_MEM_MAPS); 3657f3c3d6fSHasso Tepper } 3667f3c3d6fSHasso Tepper 367*f599cd46SFrançois Tigeot /* The rmmap ioctl appears to be unnecessary. All mappings are torn down on 368*f599cd46SFrançois Tigeot * the last close of the device, and this is necessary for cleanup when things 369*f599cd46SFrançois Tigeot * exit uncleanly. Therefore, having userland manually remove mappings seems 370*f599cd46SFrançois Tigeot * like a pointless exercise since they're going away anyway. 371*f599cd46SFrançois Tigeot * 372*f599cd46SFrançois Tigeot * One use case might be after addmap is allowed for normal users for SHM and 373*f599cd46SFrançois Tigeot * gets used by drivers that the server doesn't need to care about. This seems 374*f599cd46SFrançois Tigeot * unlikely. 375*f599cd46SFrançois Tigeot * 376*f599cd46SFrançois Tigeot * \param inode device inode. 377*f599cd46SFrançois Tigeot * \param file_priv DRM file private. 378*f599cd46SFrançois Tigeot * \param cmd command. 379*f599cd46SFrançois Tigeot * \param arg pointer to a struct drm_map structure. 380*f599cd46SFrançois Tigeot * \return zero on success or a negative value on error. 3817f3c3d6fSHasso Tepper */ 382b3705d71SHasso Tepper int drm_rmmap_ioctl(struct drm_device *dev, void *data, 383b3705d71SHasso Tepper struct drm_file *file_priv) 3847f3c3d6fSHasso Tepper { 385b3705d71SHasso Tepper struct drm_map *request = data; 386*f599cd46SFrançois Tigeot struct drm_local_map *map = NULL; 387*f599cd46SFrançois Tigeot struct drm_map_list *r_list; 3887f3c3d6fSHasso Tepper 3895718399fSFrançois Tigeot DRM_LOCK(dev); 390*f599cd46SFrançois Tigeot list_for_each_entry(r_list, &dev->maplist, head) { 391*f599cd46SFrançois Tigeot if (r_list->map && 392*f599cd46SFrançois Tigeot r_list->user_token == (unsigned long)request->handle && 393*f599cd46SFrançois Tigeot r_list->map->flags & _DRM_REMOVABLE) { 394*f599cd46SFrançois Tigeot map = r_list->map; 3957f3c3d6fSHasso Tepper break; 3967f3c3d6fSHasso Tepper } 397*f599cd46SFrançois Tigeot } 3987f3c3d6fSHasso Tepper 399*f599cd46SFrançois Tigeot /* List has wrapped around to the head pointer, or its empty we didn't 400*f599cd46SFrançois Tigeot * find anything. 401*f599cd46SFrançois Tigeot */ 402*f599cd46SFrançois Tigeot if (list_empty(&dev->maplist) || !map) { 4035718399fSFrançois Tigeot DRM_UNLOCK(dev); 404*f599cd46SFrançois Tigeot return -EINVAL; 405*f599cd46SFrançois Tigeot } 406*f599cd46SFrançois Tigeot 407*f599cd46SFrançois Tigeot /* Register and framebuffer maps are permanent */ 408*f599cd46SFrançois Tigeot if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { 409*f599cd46SFrançois Tigeot DRM_UNLOCK(dev); 410*f599cd46SFrançois Tigeot return 0; 4117f3c3d6fSHasso Tepper } 4127f3c3d6fSHasso Tepper 4137f3c3d6fSHasso Tepper drm_rmmap(dev, map); 4147f3c3d6fSHasso Tepper 4155718399fSFrançois Tigeot DRM_UNLOCK(dev); 4167f3c3d6fSHasso Tepper 4177f3c3d6fSHasso Tepper return 0; 4187f3c3d6fSHasso Tepper } 4197f3c3d6fSHasso Tepper 4207f3c3d6fSHasso Tepper 421b3705d71SHasso Tepper static void drm_cleanup_buf_error(struct drm_device *dev, 422b3705d71SHasso Tepper drm_buf_entry_t *entry) 4237f3c3d6fSHasso Tepper { 4247f3c3d6fSHasso Tepper int i; 4257f3c3d6fSHasso Tepper 4267f3c3d6fSHasso Tepper if (entry->seg_count) { 4277f3c3d6fSHasso Tepper for (i = 0; i < entry->seg_count; i++) { 4287f3c3d6fSHasso Tepper drm_pci_free(dev, entry->seglist[i]); 4297f3c3d6fSHasso Tepper } 4305718399fSFrançois Tigeot drm_free(entry->seglist, DRM_MEM_SEGS); 4317f3c3d6fSHasso Tepper 4327f3c3d6fSHasso Tepper entry->seg_count = 0; 4337f3c3d6fSHasso Tepper } 4347f3c3d6fSHasso Tepper 4357f3c3d6fSHasso Tepper if (entry->buf_count) { 4367f3c3d6fSHasso Tepper for (i = 0; i < entry->buf_count; i++) { 4375718399fSFrançois Tigeot drm_free(entry->buflist[i].dev_private, DRM_MEM_BUFS); 4387f3c3d6fSHasso Tepper } 4395718399fSFrançois Tigeot drm_free(entry->buflist, DRM_MEM_BUFS); 4407f3c3d6fSHasso Tepper 4417f3c3d6fSHasso Tepper entry->buf_count = 0; 4427f3c3d6fSHasso Tepper } 4437f3c3d6fSHasso Tepper } 4447f3c3d6fSHasso Tepper 445b3705d71SHasso Tepper static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) 4467f3c3d6fSHasso Tepper { 4477f3c3d6fSHasso Tepper drm_device_dma_t *dma = dev->dma; 4487f3c3d6fSHasso Tepper drm_buf_entry_t *entry; 4497f3c3d6fSHasso Tepper /*drm_agp_mem_t *agp_entry; 4507f3c3d6fSHasso Tepper int valid*/ 4517f3c3d6fSHasso Tepper drm_buf_t *buf; 4527f3c3d6fSHasso Tepper unsigned long offset; 4537f3c3d6fSHasso Tepper unsigned long agp_offset; 4547f3c3d6fSHasso Tepper int count; 4557f3c3d6fSHasso Tepper int order; 4567f3c3d6fSHasso Tepper int size; 4577f3c3d6fSHasso Tepper int alignment; 4587f3c3d6fSHasso Tepper int page_order; 4597f3c3d6fSHasso Tepper int total; 4607f3c3d6fSHasso Tepper int byte_count; 4617f3c3d6fSHasso Tepper int i; 4627f3c3d6fSHasso Tepper drm_buf_t **temp_buflist; 4637f3c3d6fSHasso Tepper 4647f3c3d6fSHasso Tepper count = request->count; 4657f3c3d6fSHasso Tepper order = drm_order(request->size); 4667f3c3d6fSHasso Tepper size = 1 << order; 4677f3c3d6fSHasso Tepper 4687f3c3d6fSHasso Tepper alignment = (request->flags & _DRM_PAGE_ALIGN) 4697f3c3d6fSHasso Tepper ? round_page(size) : size; 4707f3c3d6fSHasso Tepper page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 4717f3c3d6fSHasso Tepper total = PAGE_SIZE << page_order; 4727f3c3d6fSHasso Tepper 4737f3c3d6fSHasso Tepper byte_count = 0; 4747f3c3d6fSHasso Tepper agp_offset = dev->agp->base + request->agp_start; 4757f3c3d6fSHasso Tepper 4767f3c3d6fSHasso Tepper DRM_DEBUG("count: %d\n", count); 4777f3c3d6fSHasso Tepper DRM_DEBUG("order: %d\n", order); 4787f3c3d6fSHasso Tepper DRM_DEBUG("size: %d\n", size); 4797f3c3d6fSHasso Tepper DRM_DEBUG("agp_offset: 0x%lx\n", agp_offset); 4807f3c3d6fSHasso Tepper DRM_DEBUG("alignment: %d\n", alignment); 4817f3c3d6fSHasso Tepper DRM_DEBUG("page_order: %d\n", page_order); 4827f3c3d6fSHasso Tepper DRM_DEBUG("total: %d\n", total); 4837f3c3d6fSHasso Tepper 4847f3c3d6fSHasso Tepper /* Make sure buffers are located in AGP memory that we own */ 4857f3c3d6fSHasso Tepper /* Breaks MGA due to drm_alloc_agp not setting up entries for the 4867f3c3d6fSHasso Tepper * memory. Safe to ignore for now because these ioctls are still 4877f3c3d6fSHasso Tepper * root-only. 4887f3c3d6fSHasso Tepper */ 4897f3c3d6fSHasso Tepper /*valid = 0; 4907f3c3d6fSHasso Tepper for (agp_entry = dev->agp->memory; agp_entry; 4917f3c3d6fSHasso Tepper agp_entry = agp_entry->next) { 4927f3c3d6fSHasso Tepper if ((agp_offset >= agp_entry->bound) && 4937f3c3d6fSHasso Tepper (agp_offset + total * count <= 4947f3c3d6fSHasso Tepper agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { 4957f3c3d6fSHasso Tepper valid = 1; 4967f3c3d6fSHasso Tepper break; 4977f3c3d6fSHasso Tepper } 4987f3c3d6fSHasso Tepper } 4997f3c3d6fSHasso Tepper if (!valid) { 5007f3c3d6fSHasso Tepper DRM_DEBUG("zone invalid\n"); 5017f3c3d6fSHasso Tepper return EINVAL; 5027f3c3d6fSHasso Tepper }*/ 5037f3c3d6fSHasso Tepper 5047f3c3d6fSHasso Tepper entry = &dma->bufs[order]; 5057f3c3d6fSHasso Tepper 5065718399fSFrançois Tigeot entry->buflist = kmalloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 5077f3c3d6fSHasso Tepper M_NOWAIT | M_ZERO); 5087f3c3d6fSHasso Tepper if (!entry->buflist) { 5097f3c3d6fSHasso Tepper return ENOMEM; 5107f3c3d6fSHasso Tepper } 5117f3c3d6fSHasso Tepper 5127f3c3d6fSHasso Tepper entry->buf_size = size; 5137f3c3d6fSHasso Tepper entry->page_order = page_order; 5147f3c3d6fSHasso Tepper 5157f3c3d6fSHasso Tepper offset = 0; 5167f3c3d6fSHasso Tepper 5177f3c3d6fSHasso Tepper while (entry->buf_count < count) { 5187f3c3d6fSHasso Tepper buf = &entry->buflist[entry->buf_count]; 5197f3c3d6fSHasso Tepper buf->idx = dma->buf_count + entry->buf_count; 5207f3c3d6fSHasso Tepper buf->total = alignment; 5217f3c3d6fSHasso Tepper buf->order = order; 5227f3c3d6fSHasso Tepper buf->used = 0; 5237f3c3d6fSHasso Tepper 5247f3c3d6fSHasso Tepper buf->offset = (dma->byte_count + offset); 5257f3c3d6fSHasso Tepper buf->bus_address = agp_offset + offset; 5267f3c3d6fSHasso Tepper buf->address = (void *)(agp_offset + offset); 5277f3c3d6fSHasso Tepper buf->next = NULL; 5287f3c3d6fSHasso Tepper buf->pending = 0; 5297f3c3d6fSHasso Tepper buf->file_priv = NULL; 5307f3c3d6fSHasso Tepper 531b3705d71SHasso Tepper buf->dev_priv_size = dev->driver->buf_priv_size; 5325718399fSFrançois Tigeot buf->dev_private = kmalloc(buf->dev_priv_size, DRM_MEM_BUFS, 5337f3c3d6fSHasso Tepper M_NOWAIT | M_ZERO); 5347f3c3d6fSHasso Tepper if (buf->dev_private == NULL) { 5357f3c3d6fSHasso Tepper /* Set count correctly so we free the proper amount. */ 5367f3c3d6fSHasso Tepper entry->buf_count = count; 5377f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 5387f3c3d6fSHasso Tepper return ENOMEM; 5397f3c3d6fSHasso Tepper } 5407f3c3d6fSHasso Tepper 5417f3c3d6fSHasso Tepper offset += alignment; 5427f3c3d6fSHasso Tepper entry->buf_count++; 5437f3c3d6fSHasso Tepper byte_count += PAGE_SIZE << page_order; 5447f3c3d6fSHasso Tepper } 5457f3c3d6fSHasso Tepper 5467f3c3d6fSHasso Tepper DRM_DEBUG("byte_count: %d\n", byte_count); 5477f3c3d6fSHasso Tepper 5485718399fSFrançois Tigeot temp_buflist = krealloc(dma->buflist, 549b3705d71SHasso Tepper (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 550b3705d71SHasso Tepper DRM_MEM_BUFS, M_NOWAIT); 5517f3c3d6fSHasso Tepper if (temp_buflist == NULL) { 5527f3c3d6fSHasso Tepper /* Free the entry because it isn't valid */ 5537f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 5547f3c3d6fSHasso Tepper return ENOMEM; 5557f3c3d6fSHasso Tepper } 5567f3c3d6fSHasso Tepper dma->buflist = temp_buflist; 5577f3c3d6fSHasso Tepper 5587f3c3d6fSHasso Tepper for (i = 0; i < entry->buf_count; i++) { 5597f3c3d6fSHasso Tepper dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 5607f3c3d6fSHasso Tepper } 5617f3c3d6fSHasso Tepper 5627f3c3d6fSHasso Tepper dma->buf_count += entry->buf_count; 5637f3c3d6fSHasso Tepper dma->byte_count += byte_count; 5647f3c3d6fSHasso Tepper 5657f3c3d6fSHasso Tepper DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 5667f3c3d6fSHasso Tepper DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); 5677f3c3d6fSHasso Tepper 5687f3c3d6fSHasso Tepper request->count = entry->buf_count; 5697f3c3d6fSHasso Tepper request->size = size; 5707f3c3d6fSHasso Tepper 5717f3c3d6fSHasso Tepper dma->flags = _DRM_DMA_USE_AGP; 5727f3c3d6fSHasso Tepper 5737f3c3d6fSHasso Tepper return 0; 5747f3c3d6fSHasso Tepper } 5757f3c3d6fSHasso Tepper 576b3705d71SHasso Tepper static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) 5777f3c3d6fSHasso Tepper { 5787f3c3d6fSHasso Tepper drm_device_dma_t *dma = dev->dma; 5797f3c3d6fSHasso Tepper int count; 5807f3c3d6fSHasso Tepper int order; 5817f3c3d6fSHasso Tepper int size; 5827f3c3d6fSHasso Tepper int total; 5837f3c3d6fSHasso Tepper int page_order; 5847f3c3d6fSHasso Tepper drm_buf_entry_t *entry; 5857f3c3d6fSHasso Tepper drm_buf_t *buf; 5867f3c3d6fSHasso Tepper int alignment; 5877f3c3d6fSHasso Tepper unsigned long offset; 5887f3c3d6fSHasso Tepper int i; 5897f3c3d6fSHasso Tepper int byte_count; 5907f3c3d6fSHasso Tepper int page_count; 5917f3c3d6fSHasso Tepper unsigned long *temp_pagelist; 5927f3c3d6fSHasso Tepper drm_buf_t **temp_buflist; 5937f3c3d6fSHasso Tepper 5947f3c3d6fSHasso Tepper count = request->count; 5957f3c3d6fSHasso Tepper order = drm_order(request->size); 5967f3c3d6fSHasso Tepper size = 1 << order; 5977f3c3d6fSHasso Tepper 5987f3c3d6fSHasso Tepper DRM_DEBUG("count=%d, size=%d (%d), order=%d\n", 5997f3c3d6fSHasso Tepper request->count, request->size, size, order); 6007f3c3d6fSHasso Tepper 6017f3c3d6fSHasso Tepper alignment = (request->flags & _DRM_PAGE_ALIGN) 6027f3c3d6fSHasso Tepper ? round_page(size) : size; 6037f3c3d6fSHasso Tepper page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 6047f3c3d6fSHasso Tepper total = PAGE_SIZE << page_order; 6057f3c3d6fSHasso Tepper 6067f3c3d6fSHasso Tepper entry = &dma->bufs[order]; 6077f3c3d6fSHasso Tepper 6085718399fSFrançois Tigeot entry->buflist = kmalloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 6097f3c3d6fSHasso Tepper M_NOWAIT | M_ZERO); 6105718399fSFrançois Tigeot entry->seglist = kmalloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS, 6117f3c3d6fSHasso Tepper M_NOWAIT | M_ZERO); 6127f3c3d6fSHasso Tepper 6137f3c3d6fSHasso Tepper /* Keep the original pagelist until we know all the allocations 6147f3c3d6fSHasso Tepper * have succeeded 6157f3c3d6fSHasso Tepper */ 6165718399fSFrançois Tigeot temp_pagelist = kmalloc((dma->page_count + (count << page_order)) * 617b3705d71SHasso Tepper sizeof(*dma->pagelist), DRM_MEM_PAGES, M_NOWAIT); 6187f3c3d6fSHasso Tepper 6197f3c3d6fSHasso Tepper if (entry->buflist == NULL || entry->seglist == NULL || 6207f3c3d6fSHasso Tepper temp_pagelist == NULL) { 6215718399fSFrançois Tigeot drm_free(temp_pagelist, DRM_MEM_PAGES); 6225718399fSFrançois Tigeot drm_free(entry->seglist, DRM_MEM_SEGS); 6235718399fSFrançois Tigeot drm_free(entry->buflist, DRM_MEM_BUFS); 6247f3c3d6fSHasso Tepper return ENOMEM; 6257f3c3d6fSHasso Tepper } 6267f3c3d6fSHasso Tepper 6277f3c3d6fSHasso Tepper memcpy(temp_pagelist, dma->pagelist, dma->page_count * 6287f3c3d6fSHasso Tepper sizeof(*dma->pagelist)); 6297f3c3d6fSHasso Tepper 6307f3c3d6fSHasso Tepper DRM_DEBUG("pagelist: %d entries\n", 6317f3c3d6fSHasso Tepper dma->page_count + (count << page_order)); 6327f3c3d6fSHasso Tepper 6337f3c3d6fSHasso Tepper entry->buf_size = size; 6347f3c3d6fSHasso Tepper entry->page_order = page_order; 6357f3c3d6fSHasso Tepper byte_count = 0; 6367f3c3d6fSHasso Tepper page_count = 0; 6377f3c3d6fSHasso Tepper 6387f3c3d6fSHasso Tepper while (entry->buf_count < count) { 6395718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 6407f3c3d6fSHasso Tepper drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment, 6417f3c3d6fSHasso Tepper 0xfffffffful); 6425718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 6437f3c3d6fSHasso Tepper if (dmah == NULL) { 6447f3c3d6fSHasso Tepper /* Set count correctly so we free the proper amount. */ 6457f3c3d6fSHasso Tepper entry->buf_count = count; 6467f3c3d6fSHasso Tepper entry->seg_count = count; 6477f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 6485718399fSFrançois Tigeot drm_free(temp_pagelist, DRM_MEM_PAGES); 6497f3c3d6fSHasso Tepper return ENOMEM; 6507f3c3d6fSHasso Tepper } 6517f3c3d6fSHasso Tepper 6527f3c3d6fSHasso Tepper entry->seglist[entry->seg_count++] = dmah; 6537f3c3d6fSHasso Tepper for (i = 0; i < (1 << page_order); i++) { 6547f3c3d6fSHasso Tepper DRM_DEBUG("page %d @ %p\n", 6557f3c3d6fSHasso Tepper dma->page_count + page_count, 6567f3c3d6fSHasso Tepper (char *)dmah->vaddr + PAGE_SIZE * i); 6577f3c3d6fSHasso Tepper temp_pagelist[dma->page_count + page_count++] = 6587f3c3d6fSHasso Tepper (long)dmah->vaddr + PAGE_SIZE * i; 6597f3c3d6fSHasso Tepper } 6607f3c3d6fSHasso Tepper for (offset = 0; 6617f3c3d6fSHasso Tepper offset + size <= total && entry->buf_count < count; 6627f3c3d6fSHasso Tepper offset += alignment, ++entry->buf_count) { 6637f3c3d6fSHasso Tepper buf = &entry->buflist[entry->buf_count]; 6647f3c3d6fSHasso Tepper buf->idx = dma->buf_count + entry->buf_count; 6657f3c3d6fSHasso Tepper buf->total = alignment; 6667f3c3d6fSHasso Tepper buf->order = order; 6677f3c3d6fSHasso Tepper buf->used = 0; 6687f3c3d6fSHasso Tepper buf->offset = (dma->byte_count + byte_count + offset); 6697f3c3d6fSHasso Tepper buf->address = ((char *)dmah->vaddr + offset); 6707f3c3d6fSHasso Tepper buf->bus_address = dmah->busaddr + offset; 6717f3c3d6fSHasso Tepper buf->next = NULL; 6727f3c3d6fSHasso Tepper buf->pending = 0; 6737f3c3d6fSHasso Tepper buf->file_priv = NULL; 6747f3c3d6fSHasso Tepper 675b3705d71SHasso Tepper buf->dev_priv_size = dev->driver->buf_priv_size; 6765718399fSFrançois Tigeot buf->dev_private = kmalloc(buf->dev_priv_size, 677b3705d71SHasso Tepper DRM_MEM_BUFS, M_NOWAIT | M_ZERO); 6787f3c3d6fSHasso Tepper if (buf->dev_private == NULL) { 6797f3c3d6fSHasso Tepper /* Set count correctly so we free the proper amount. */ 6807f3c3d6fSHasso Tepper entry->buf_count = count; 6817f3c3d6fSHasso Tepper entry->seg_count = count; 6827f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 6835718399fSFrançois Tigeot drm_free(temp_pagelist, DRM_MEM_PAGES); 6847f3c3d6fSHasso Tepper return ENOMEM; 6857f3c3d6fSHasso Tepper } 6867f3c3d6fSHasso Tepper 6877f3c3d6fSHasso Tepper DRM_DEBUG("buffer %d @ %p\n", 6887f3c3d6fSHasso Tepper entry->buf_count, buf->address); 6897f3c3d6fSHasso Tepper } 6907f3c3d6fSHasso Tepper byte_count += PAGE_SIZE << page_order; 6917f3c3d6fSHasso Tepper } 6927f3c3d6fSHasso Tepper 6935718399fSFrançois Tigeot temp_buflist = krealloc(dma->buflist, 694b3705d71SHasso Tepper (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 695b3705d71SHasso Tepper DRM_MEM_BUFS, M_NOWAIT); 6967f3c3d6fSHasso Tepper if (temp_buflist == NULL) { 6977f3c3d6fSHasso Tepper /* Free the entry because it isn't valid */ 6987f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 6995718399fSFrançois Tigeot drm_free(temp_pagelist, DRM_MEM_PAGES); 7007f3c3d6fSHasso Tepper return ENOMEM; 7017f3c3d6fSHasso Tepper } 7027f3c3d6fSHasso Tepper dma->buflist = temp_buflist; 7037f3c3d6fSHasso Tepper 7047f3c3d6fSHasso Tepper for (i = 0; i < entry->buf_count; i++) { 7057f3c3d6fSHasso Tepper dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 7067f3c3d6fSHasso Tepper } 7077f3c3d6fSHasso Tepper 7087f3c3d6fSHasso Tepper /* No allocations failed, so now we can replace the orginal pagelist 7097f3c3d6fSHasso Tepper * with the new one. 7107f3c3d6fSHasso Tepper */ 7115718399fSFrançois Tigeot drm_free(dma->pagelist, DRM_MEM_PAGES); 7127f3c3d6fSHasso Tepper dma->pagelist = temp_pagelist; 7137f3c3d6fSHasso Tepper 7147f3c3d6fSHasso Tepper dma->buf_count += entry->buf_count; 7157f3c3d6fSHasso Tepper dma->seg_count += entry->seg_count; 7167f3c3d6fSHasso Tepper dma->page_count += entry->seg_count << page_order; 7177f3c3d6fSHasso Tepper dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); 7187f3c3d6fSHasso Tepper 7197f3c3d6fSHasso Tepper request->count = entry->buf_count; 7207f3c3d6fSHasso Tepper request->size = size; 7217f3c3d6fSHasso Tepper 7227f3c3d6fSHasso Tepper return 0; 7237f3c3d6fSHasso Tepper 7247f3c3d6fSHasso Tepper } 7257f3c3d6fSHasso Tepper 726b3705d71SHasso Tepper static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) 7277f3c3d6fSHasso Tepper { 7287f3c3d6fSHasso Tepper drm_device_dma_t *dma = dev->dma; 7297f3c3d6fSHasso Tepper drm_buf_entry_t *entry; 7307f3c3d6fSHasso Tepper drm_buf_t *buf; 7317f3c3d6fSHasso Tepper unsigned long offset; 7327f3c3d6fSHasso Tepper unsigned long agp_offset; 7337f3c3d6fSHasso Tepper int count; 7347f3c3d6fSHasso Tepper int order; 7357f3c3d6fSHasso Tepper int size; 7367f3c3d6fSHasso Tepper int alignment; 7377f3c3d6fSHasso Tepper int page_order; 7387f3c3d6fSHasso Tepper int total; 7397f3c3d6fSHasso Tepper int byte_count; 7407f3c3d6fSHasso Tepper int i; 7417f3c3d6fSHasso Tepper drm_buf_t **temp_buflist; 7427f3c3d6fSHasso Tepper 7437f3c3d6fSHasso Tepper count = request->count; 7447f3c3d6fSHasso Tepper order = drm_order(request->size); 7457f3c3d6fSHasso Tepper size = 1 << order; 7467f3c3d6fSHasso Tepper 7477f3c3d6fSHasso Tepper alignment = (request->flags & _DRM_PAGE_ALIGN) 7487f3c3d6fSHasso Tepper ? round_page(size) : size; 7497f3c3d6fSHasso Tepper page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 7507f3c3d6fSHasso Tepper total = PAGE_SIZE << page_order; 7517f3c3d6fSHasso Tepper 7527f3c3d6fSHasso Tepper byte_count = 0; 7537f3c3d6fSHasso Tepper agp_offset = request->agp_start; 7547f3c3d6fSHasso Tepper 7557f3c3d6fSHasso Tepper DRM_DEBUG("count: %d\n", count); 7567f3c3d6fSHasso Tepper DRM_DEBUG("order: %d\n", order); 7577f3c3d6fSHasso Tepper DRM_DEBUG("size: %d\n", size); 7587f3c3d6fSHasso Tepper DRM_DEBUG("agp_offset: %ld\n", agp_offset); 7597f3c3d6fSHasso Tepper DRM_DEBUG("alignment: %d\n", alignment); 7607f3c3d6fSHasso Tepper DRM_DEBUG("page_order: %d\n", page_order); 7617f3c3d6fSHasso Tepper DRM_DEBUG("total: %d\n", total); 7627f3c3d6fSHasso Tepper 7637f3c3d6fSHasso Tepper entry = &dma->bufs[order]; 7647f3c3d6fSHasso Tepper 7655718399fSFrançois Tigeot entry->buflist = kmalloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 7667f3c3d6fSHasso Tepper M_NOWAIT | M_ZERO); 7677f3c3d6fSHasso Tepper if (entry->buflist == NULL) 7687f3c3d6fSHasso Tepper return ENOMEM; 7697f3c3d6fSHasso Tepper 7707f3c3d6fSHasso Tepper entry->buf_size = size; 7717f3c3d6fSHasso Tepper entry->page_order = page_order; 7727f3c3d6fSHasso Tepper 7737f3c3d6fSHasso Tepper offset = 0; 7747f3c3d6fSHasso Tepper 7757f3c3d6fSHasso Tepper while (entry->buf_count < count) { 7767f3c3d6fSHasso Tepper buf = &entry->buflist[entry->buf_count]; 7777f3c3d6fSHasso Tepper buf->idx = dma->buf_count + entry->buf_count; 7787f3c3d6fSHasso Tepper buf->total = alignment; 7797f3c3d6fSHasso Tepper buf->order = order; 7807f3c3d6fSHasso Tepper buf->used = 0; 7817f3c3d6fSHasso Tepper 7827f3c3d6fSHasso Tepper buf->offset = (dma->byte_count + offset); 7837f3c3d6fSHasso Tepper buf->bus_address = agp_offset + offset; 78499f70504SFrançois Tigeot buf->address = (void *)(agp_offset + offset + dev->sg->vaddr); 7857f3c3d6fSHasso Tepper buf->next = NULL; 7867f3c3d6fSHasso Tepper buf->pending = 0; 7877f3c3d6fSHasso Tepper buf->file_priv = NULL; 7887f3c3d6fSHasso Tepper 789b3705d71SHasso Tepper buf->dev_priv_size = dev->driver->buf_priv_size; 7905718399fSFrançois Tigeot buf->dev_private = kmalloc(buf->dev_priv_size, DRM_MEM_BUFS, 7917f3c3d6fSHasso Tepper M_NOWAIT | M_ZERO); 7927f3c3d6fSHasso Tepper if (buf->dev_private == NULL) { 7937f3c3d6fSHasso Tepper /* Set count correctly so we free the proper amount. */ 7947f3c3d6fSHasso Tepper entry->buf_count = count; 7957f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 7967f3c3d6fSHasso Tepper return ENOMEM; 7977f3c3d6fSHasso Tepper } 7987f3c3d6fSHasso Tepper 7997f3c3d6fSHasso Tepper DRM_DEBUG("buffer %d @ %p\n", 8007f3c3d6fSHasso Tepper entry->buf_count, buf->address); 8017f3c3d6fSHasso Tepper 8027f3c3d6fSHasso Tepper offset += alignment; 8037f3c3d6fSHasso Tepper entry->buf_count++; 8047f3c3d6fSHasso Tepper byte_count += PAGE_SIZE << page_order; 8057f3c3d6fSHasso Tepper } 8067f3c3d6fSHasso Tepper 8077f3c3d6fSHasso Tepper DRM_DEBUG("byte_count: %d\n", byte_count); 8087f3c3d6fSHasso Tepper 8095718399fSFrançois Tigeot temp_buflist = krealloc(dma->buflist, 810b3705d71SHasso Tepper (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 811b3705d71SHasso Tepper DRM_MEM_BUFS, M_NOWAIT); 8127f3c3d6fSHasso Tepper if (temp_buflist == NULL) { 8137f3c3d6fSHasso Tepper /* Free the entry because it isn't valid */ 8147f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 8157f3c3d6fSHasso Tepper return ENOMEM; 8167f3c3d6fSHasso Tepper } 8177f3c3d6fSHasso Tepper dma->buflist = temp_buflist; 8187f3c3d6fSHasso Tepper 8197f3c3d6fSHasso Tepper for (i = 0; i < entry->buf_count; i++) { 8207f3c3d6fSHasso Tepper dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 8217f3c3d6fSHasso Tepper } 8227f3c3d6fSHasso Tepper 8237f3c3d6fSHasso Tepper dma->buf_count += entry->buf_count; 8247f3c3d6fSHasso Tepper dma->byte_count += byte_count; 8257f3c3d6fSHasso Tepper 8267f3c3d6fSHasso Tepper DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 8277f3c3d6fSHasso Tepper DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); 8287f3c3d6fSHasso Tepper 8297f3c3d6fSHasso Tepper request->count = entry->buf_count; 8307f3c3d6fSHasso Tepper request->size = size; 8317f3c3d6fSHasso Tepper 8327f3c3d6fSHasso Tepper dma->flags = _DRM_DMA_USE_SG; 8337f3c3d6fSHasso Tepper 8347f3c3d6fSHasso Tepper return 0; 8357f3c3d6fSHasso Tepper } 8367f3c3d6fSHasso Tepper 837b3705d71SHasso Tepper int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) 8387f3c3d6fSHasso Tepper { 8397f3c3d6fSHasso Tepper int order, ret; 8407f3c3d6fSHasso Tepper 8417f3c3d6fSHasso Tepper if (request->count < 0 || request->count > 4096) 8427f3c3d6fSHasso Tepper return EINVAL; 8437f3c3d6fSHasso Tepper 8447f3c3d6fSHasso Tepper order = drm_order(request->size); 8457f3c3d6fSHasso Tepper if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 8467f3c3d6fSHasso Tepper return EINVAL; 8477f3c3d6fSHasso Tepper 8485718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 849b3705d71SHasso Tepper 8507f3c3d6fSHasso Tepper /* No more allocations after first buffer-using ioctl. */ 8517f3c3d6fSHasso Tepper if (dev->buf_use != 0) { 8525718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 8537f3c3d6fSHasso Tepper return EBUSY; 8547f3c3d6fSHasso Tepper } 8557f3c3d6fSHasso Tepper /* No more than one allocation per order */ 8567f3c3d6fSHasso Tepper if (dev->dma->bufs[order].buf_count != 0) { 8575718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 8587f3c3d6fSHasso Tepper return ENOMEM; 8597f3c3d6fSHasso Tepper } 8607f3c3d6fSHasso Tepper 8617f3c3d6fSHasso Tepper ret = drm_do_addbufs_agp(dev, request); 8627f3c3d6fSHasso Tepper 8635718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 8647f3c3d6fSHasso Tepper 8657f3c3d6fSHasso Tepper return ret; 8667f3c3d6fSHasso Tepper } 8677f3c3d6fSHasso Tepper 868b3705d71SHasso Tepper int drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) 8697f3c3d6fSHasso Tepper { 8707f3c3d6fSHasso Tepper int order, ret; 8717f3c3d6fSHasso Tepper 8727f3c3d6fSHasso Tepper if (!DRM_SUSER(DRM_CURPROC)) 8737f3c3d6fSHasso Tepper return EACCES; 8747f3c3d6fSHasso Tepper 8757f3c3d6fSHasso Tepper if (request->count < 0 || request->count > 4096) 8767f3c3d6fSHasso Tepper return EINVAL; 8777f3c3d6fSHasso Tepper 8787f3c3d6fSHasso Tepper order = drm_order(request->size); 8797f3c3d6fSHasso Tepper if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 8807f3c3d6fSHasso Tepper return EINVAL; 8817f3c3d6fSHasso Tepper 8825718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 883b3705d71SHasso Tepper 8847f3c3d6fSHasso Tepper /* No more allocations after first buffer-using ioctl. */ 8857f3c3d6fSHasso Tepper if (dev->buf_use != 0) { 8865718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 8877f3c3d6fSHasso Tepper return EBUSY; 8887f3c3d6fSHasso Tepper } 8897f3c3d6fSHasso Tepper /* No more than one allocation per order */ 8907f3c3d6fSHasso Tepper if (dev->dma->bufs[order].buf_count != 0) { 8915718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 8927f3c3d6fSHasso Tepper return ENOMEM; 8937f3c3d6fSHasso Tepper } 8947f3c3d6fSHasso Tepper 8957f3c3d6fSHasso Tepper ret = drm_do_addbufs_sg(dev, request); 8967f3c3d6fSHasso Tepper 8975718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 8987f3c3d6fSHasso Tepper 8997f3c3d6fSHasso Tepper return ret; 9007f3c3d6fSHasso Tepper } 9017f3c3d6fSHasso Tepper 902b3705d71SHasso Tepper int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) 9037f3c3d6fSHasso Tepper { 9047f3c3d6fSHasso Tepper int order, ret; 9057f3c3d6fSHasso Tepper 9067f3c3d6fSHasso Tepper if (!DRM_SUSER(DRM_CURPROC)) 9077f3c3d6fSHasso Tepper return EACCES; 9087f3c3d6fSHasso Tepper 9097f3c3d6fSHasso Tepper if (request->count < 0 || request->count > 4096) 9107f3c3d6fSHasso Tepper return EINVAL; 9117f3c3d6fSHasso Tepper 9127f3c3d6fSHasso Tepper order = drm_order(request->size); 9137f3c3d6fSHasso Tepper if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 9147f3c3d6fSHasso Tepper return EINVAL; 9157f3c3d6fSHasso Tepper 9165718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 917b3705d71SHasso Tepper 9187f3c3d6fSHasso Tepper /* No more allocations after first buffer-using ioctl. */ 9197f3c3d6fSHasso Tepper if (dev->buf_use != 0) { 9205718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 9217f3c3d6fSHasso Tepper return EBUSY; 9227f3c3d6fSHasso Tepper } 9237f3c3d6fSHasso Tepper /* No more than one allocation per order */ 9247f3c3d6fSHasso Tepper if (dev->dma->bufs[order].buf_count != 0) { 9255718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 9267f3c3d6fSHasso Tepper return ENOMEM; 9277f3c3d6fSHasso Tepper } 9287f3c3d6fSHasso Tepper 9297f3c3d6fSHasso Tepper ret = drm_do_addbufs_pci(dev, request); 9307f3c3d6fSHasso Tepper 9315718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 9327f3c3d6fSHasso Tepper 9337f3c3d6fSHasso Tepper return ret; 9347f3c3d6fSHasso Tepper } 9357f3c3d6fSHasso Tepper 936b3705d71SHasso Tepper int drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 9377f3c3d6fSHasso Tepper { 938b3705d71SHasso Tepper struct drm_buf_desc *request = data; 9397f3c3d6fSHasso Tepper int err; 9407f3c3d6fSHasso Tepper 9417f3c3d6fSHasso Tepper if (request->flags & _DRM_AGP_BUFFER) 9427f3c3d6fSHasso Tepper err = drm_addbufs_agp(dev, request); 9437f3c3d6fSHasso Tepper else if (request->flags & _DRM_SG_BUFFER) 9447f3c3d6fSHasso Tepper err = drm_addbufs_sg(dev, request); 9457f3c3d6fSHasso Tepper else 9467f3c3d6fSHasso Tepper err = drm_addbufs_pci(dev, request); 9477f3c3d6fSHasso Tepper 9487f3c3d6fSHasso Tepper return err; 9497f3c3d6fSHasso Tepper } 9507f3c3d6fSHasso Tepper 951b3705d71SHasso Tepper int drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 9527f3c3d6fSHasso Tepper { 9537f3c3d6fSHasso Tepper drm_device_dma_t *dma = dev->dma; 954b3705d71SHasso Tepper struct drm_buf_info *request = data; 9557f3c3d6fSHasso Tepper int i; 9567f3c3d6fSHasso Tepper int count; 9577f3c3d6fSHasso Tepper int retcode = 0; 9587f3c3d6fSHasso Tepper 9595718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 9607f3c3d6fSHasso Tepper ++dev->buf_use; /* Can't allocate more after this call */ 9615718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 9627f3c3d6fSHasso Tepper 9637f3c3d6fSHasso Tepper for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 964b3705d71SHasso Tepper if (dma->bufs[i].buf_count) 965b3705d71SHasso Tepper ++count; 9667f3c3d6fSHasso Tepper } 9677f3c3d6fSHasso Tepper 9687f3c3d6fSHasso Tepper DRM_DEBUG("count = %d\n", count); 9697f3c3d6fSHasso Tepper 9707f3c3d6fSHasso Tepper if (request->count >= count) { 9717f3c3d6fSHasso Tepper for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 9727f3c3d6fSHasso Tepper if (dma->bufs[i].buf_count) { 973b3705d71SHasso Tepper struct drm_buf_desc from; 9747f3c3d6fSHasso Tepper 9757f3c3d6fSHasso Tepper from.count = dma->bufs[i].buf_count; 9767f3c3d6fSHasso Tepper from.size = dma->bufs[i].buf_size; 9777f3c3d6fSHasso Tepper from.low_mark = dma->bufs[i].freelist.low_mark; 9787f3c3d6fSHasso Tepper from.high_mark = dma->bufs[i].freelist.high_mark; 9797f3c3d6fSHasso Tepper 9807f3c3d6fSHasso Tepper if (DRM_COPY_TO_USER(&request->list[count], &from, 981b3705d71SHasso Tepper sizeof(struct drm_buf_desc)) != 0) { 9827f3c3d6fSHasso Tepper retcode = EFAULT; 9837f3c3d6fSHasso Tepper break; 9847f3c3d6fSHasso Tepper } 9857f3c3d6fSHasso Tepper 9867f3c3d6fSHasso Tepper DRM_DEBUG("%d %d %d %d %d\n", 987b3705d71SHasso Tepper i, dma->bufs[i].buf_count, 9887f3c3d6fSHasso Tepper dma->bufs[i].buf_size, 9897f3c3d6fSHasso Tepper dma->bufs[i].freelist.low_mark, 9907f3c3d6fSHasso Tepper dma->bufs[i].freelist.high_mark); 9917f3c3d6fSHasso Tepper ++count; 9927f3c3d6fSHasso Tepper } 9937f3c3d6fSHasso Tepper } 9947f3c3d6fSHasso Tepper } 9957f3c3d6fSHasso Tepper request->count = count; 9967f3c3d6fSHasso Tepper 9977f3c3d6fSHasso Tepper return retcode; 9987f3c3d6fSHasso Tepper } 9997f3c3d6fSHasso Tepper 1000b3705d71SHasso Tepper int drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 10017f3c3d6fSHasso Tepper { 10027f3c3d6fSHasso Tepper drm_device_dma_t *dma = dev->dma; 1003b3705d71SHasso Tepper struct drm_buf_desc *request = data; 10047f3c3d6fSHasso Tepper int order; 10057f3c3d6fSHasso Tepper 10067f3c3d6fSHasso Tepper DRM_DEBUG("%d, %d, %d\n", 10077f3c3d6fSHasso Tepper request->size, request->low_mark, request->high_mark); 10087f3c3d6fSHasso Tepper 10097f3c3d6fSHasso Tepper 10107f3c3d6fSHasso Tepper order = drm_order(request->size); 10117f3c3d6fSHasso Tepper if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER || 10127f3c3d6fSHasso Tepper request->low_mark < 0 || request->high_mark < 0) { 10137f3c3d6fSHasso Tepper return EINVAL; 10147f3c3d6fSHasso Tepper } 10157f3c3d6fSHasso Tepper 10165718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 10177f3c3d6fSHasso Tepper if (request->low_mark > dma->bufs[order].buf_count || 10187f3c3d6fSHasso Tepper request->high_mark > dma->bufs[order].buf_count) { 10195718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 10207f3c3d6fSHasso Tepper return EINVAL; 10217f3c3d6fSHasso Tepper } 10227f3c3d6fSHasso Tepper 10237f3c3d6fSHasso Tepper dma->bufs[order].freelist.low_mark = request->low_mark; 10247f3c3d6fSHasso Tepper dma->bufs[order].freelist.high_mark = request->high_mark; 10255718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 10267f3c3d6fSHasso Tepper 10277f3c3d6fSHasso Tepper return 0; 10287f3c3d6fSHasso Tepper } 10297f3c3d6fSHasso Tepper 1030b3705d71SHasso Tepper int drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 10317f3c3d6fSHasso Tepper { 10327f3c3d6fSHasso Tepper drm_device_dma_t *dma = dev->dma; 1033b3705d71SHasso Tepper struct drm_buf_free *request = data; 10347f3c3d6fSHasso Tepper int i; 10357f3c3d6fSHasso Tepper int idx; 10367f3c3d6fSHasso Tepper drm_buf_t *buf; 10377f3c3d6fSHasso Tepper int retcode = 0; 10387f3c3d6fSHasso Tepper 10397f3c3d6fSHasso Tepper DRM_DEBUG("%d\n", request->count); 10407f3c3d6fSHasso Tepper 10415718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 10427f3c3d6fSHasso Tepper for (i = 0; i < request->count; i++) { 10437f3c3d6fSHasso Tepper if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) { 10447f3c3d6fSHasso Tepper retcode = EFAULT; 10457f3c3d6fSHasso Tepper break; 10467f3c3d6fSHasso Tepper } 10477f3c3d6fSHasso Tepper if (idx < 0 || idx >= dma->buf_count) { 10487f3c3d6fSHasso Tepper DRM_ERROR("Index %d (of %d max)\n", 10497f3c3d6fSHasso Tepper idx, dma->buf_count - 1); 10507f3c3d6fSHasso Tepper retcode = EINVAL; 10517f3c3d6fSHasso Tepper break; 10527f3c3d6fSHasso Tepper } 10537f3c3d6fSHasso Tepper buf = dma->buflist[idx]; 10547f3c3d6fSHasso Tepper if (buf->file_priv != file_priv) { 10557f3c3d6fSHasso Tepper DRM_ERROR("Process %d freeing buffer not owned\n", 10567f3c3d6fSHasso Tepper DRM_CURRENTPID); 10577f3c3d6fSHasso Tepper retcode = EINVAL; 10587f3c3d6fSHasso Tepper break; 10597f3c3d6fSHasso Tepper } 10607f3c3d6fSHasso Tepper drm_free_buffer(dev, buf); 10617f3c3d6fSHasso Tepper } 10625718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 10637f3c3d6fSHasso Tepper 10647f3c3d6fSHasso Tepper return retcode; 10657f3c3d6fSHasso Tepper } 10667f3c3d6fSHasso Tepper 1067b3705d71SHasso Tepper int drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 10687f3c3d6fSHasso Tepper { 10697f3c3d6fSHasso Tepper drm_device_dma_t *dma = dev->dma; 10707f3c3d6fSHasso Tepper int retcode = 0; 10717f3c3d6fSHasso Tepper const int zero = 0; 10727f3c3d6fSHasso Tepper vm_offset_t address; 10737f3c3d6fSHasso Tepper struct vmspace *vms; 10747f3c3d6fSHasso Tepper vm_ooffset_t foff; 10757f3c3d6fSHasso Tepper vm_size_t size; 10767f3c3d6fSHasso Tepper vm_offset_t vaddr; 1077b3705d71SHasso Tepper struct drm_buf_map *request = data; 10787f3c3d6fSHasso Tepper int i; 10797f3c3d6fSHasso Tepper 10807f3c3d6fSHasso Tepper vms = DRM_CURPROC->td_proc->p_vmspace; 10817f3c3d6fSHasso Tepper 10825718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 10837f3c3d6fSHasso Tepper dev->buf_use++; /* Can't allocate more after this call */ 10845718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 10857f3c3d6fSHasso Tepper 10867f3c3d6fSHasso Tepper if (request->count < dma->buf_count) 10877f3c3d6fSHasso Tepper goto done; 10887f3c3d6fSHasso Tepper 1089b3705d71SHasso Tepper if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) || 1090b3705d71SHasso Tepper (drm_core_check_feature(dev, DRIVER_SG) && 1091b3705d71SHasso Tepper (dma->flags & _DRM_DMA_USE_SG))) { 10927f3c3d6fSHasso Tepper drm_local_map_t *map = dev->agp_buffer_map; 10937f3c3d6fSHasso Tepper 10947f3c3d6fSHasso Tepper if (map == NULL) { 10957f3c3d6fSHasso Tepper retcode = EINVAL; 10967f3c3d6fSHasso Tepper goto done; 10977f3c3d6fSHasso Tepper } 10987f3c3d6fSHasso Tepper size = round_page(map->size); 109999f70504SFrançois Tigeot foff = (unsigned long)map->handle; 11007f3c3d6fSHasso Tepper } else { 11017f3c3d6fSHasso Tepper size = round_page(dma->byte_count), 11027f3c3d6fSHasso Tepper foff = 0; 11037f3c3d6fSHasso Tepper } 11047f3c3d6fSHasso Tepper 11057f3c3d6fSHasso Tepper vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); 11067f3c3d6fSHasso Tepper retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1107b3705d71SHasso Tepper VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, 1108b3705d71SHasso Tepper SLIST_FIRST(&dev->devnode->si_hlist), foff); 11097f3c3d6fSHasso Tepper if (retcode) 11107f3c3d6fSHasso Tepper goto done; 11117f3c3d6fSHasso Tepper 11127f3c3d6fSHasso Tepper request->virtual = (void *)vaddr; 11137f3c3d6fSHasso Tepper 11147f3c3d6fSHasso Tepper for (i = 0; i < dma->buf_count; i++) { 11157f3c3d6fSHasso Tepper if (DRM_COPY_TO_USER(&request->list[i].idx, 11167f3c3d6fSHasso Tepper &dma->buflist[i]->idx, sizeof(request->list[0].idx))) { 11177f3c3d6fSHasso Tepper retcode = EFAULT; 11187f3c3d6fSHasso Tepper goto done; 11197f3c3d6fSHasso Tepper } 11207f3c3d6fSHasso Tepper if (DRM_COPY_TO_USER(&request->list[i].total, 11217f3c3d6fSHasso Tepper &dma->buflist[i]->total, sizeof(request->list[0].total))) { 11227f3c3d6fSHasso Tepper retcode = EFAULT; 11237f3c3d6fSHasso Tepper goto done; 11247f3c3d6fSHasso Tepper } 11257f3c3d6fSHasso Tepper if (DRM_COPY_TO_USER(&request->list[i].used, &zero, 11267f3c3d6fSHasso Tepper sizeof(zero))) { 11277f3c3d6fSHasso Tepper retcode = EFAULT; 11287f3c3d6fSHasso Tepper goto done; 11297f3c3d6fSHasso Tepper } 11307f3c3d6fSHasso Tepper address = vaddr + dma->buflist[i]->offset; /* *** */ 11317f3c3d6fSHasso Tepper if (DRM_COPY_TO_USER(&request->list[i].address, &address, 11327f3c3d6fSHasso Tepper sizeof(address))) { 11337f3c3d6fSHasso Tepper retcode = EFAULT; 11347f3c3d6fSHasso Tepper goto done; 11357f3c3d6fSHasso Tepper } 11367f3c3d6fSHasso Tepper } 11377f3c3d6fSHasso Tepper 11387f3c3d6fSHasso Tepper done: 11397f3c3d6fSHasso Tepper request->count = dma->buf_count; 11407f3c3d6fSHasso Tepper 11417f3c3d6fSHasso Tepper DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode); 11427f3c3d6fSHasso Tepper 11437f3c3d6fSHasso Tepper return retcode; 11447f3c3d6fSHasso Tepper } 1145b3705d71SHasso Tepper 1146b3705d71SHasso Tepper /* 1147b3705d71SHasso Tepper * Compute order. Can be made faster. 1148b3705d71SHasso Tepper */ 1149b3705d71SHasso Tepper int drm_order(unsigned long size) 1150b3705d71SHasso Tepper { 1151b3705d71SHasso Tepper int order; 1152b3705d71SHasso Tepper 1153b3705d71SHasso Tepper if (size == 0) 1154b3705d71SHasso Tepper return 0; 1155b3705d71SHasso Tepper 1156b3705d71SHasso Tepper order = flsl(size) - 1; 1157b3705d71SHasso Tepper if (size & ~(1ul << order)) 1158b3705d71SHasso Tepper ++order; 1159b3705d71SHasso Tepper 1160b3705d71SHasso Tepper return order; 1161b3705d71SHasso Tepper } 1162