1df4baf3dSFrançois Tigeot /* 21b13d190SFrançois Tigeot * Legacy: Generic DRM Buffer Management 3df4baf3dSFrançois Tigeot * 47f3c3d6fSHasso Tepper * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 57f3c3d6fSHasso Tepper * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 67f3c3d6fSHasso Tepper * All Rights Reserved. 77f3c3d6fSHasso Tepper * 81b13d190SFrançois Tigeot * Author: Rickard E. (Rik) Faith <faith@valinux.com> 91b13d190SFrançois Tigeot * Author: Gareth Hughes <gareth@valinux.com> 101b13d190SFrançois Tigeot * 117f3c3d6fSHasso Tepper * Permission is hereby granted, free of charge, to any person obtaining a 127f3c3d6fSHasso Tepper * copy of this software and associated documentation files (the "Software"), 137f3c3d6fSHasso Tepper * to deal in the Software without restriction, including without limitation 147f3c3d6fSHasso Tepper * the rights to use, copy, modify, merge, publish, distribute, sublicense, 157f3c3d6fSHasso Tepper * and/or sell copies of the Software, and to permit persons to whom the 167f3c3d6fSHasso Tepper * Software is furnished to do so, subject to the following conditions: 177f3c3d6fSHasso Tepper * 187f3c3d6fSHasso Tepper * The above copyright notice and this permission notice (including the next 197f3c3d6fSHasso Tepper * paragraph) shall be included in all copies or substantial portions of the 207f3c3d6fSHasso Tepper * Software. 217f3c3d6fSHasso Tepper * 227f3c3d6fSHasso Tepper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 237f3c3d6fSHasso Tepper * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 247f3c3d6fSHasso Tepper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 257f3c3d6fSHasso Tepper * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 267f3c3d6fSHasso Tepper * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 277f3c3d6fSHasso Tepper * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 287f3c3d6fSHasso Tepper * OTHER DEALINGS IN THE SOFTWARE. 297f3c3d6fSHasso Tepper */ 307f3c3d6fSHasso Tepper 315718399fSFrançois Tigeot #include <sys/conf.h> 325718399fSFrançois Tigeot #include <bus/pci/pcireg.h> 33df4baf3dSFrançois Tigeot #include <linux/types.h> 34df4baf3dSFrançois Tigeot #include <linux/export.h> 3518e26a6dSFrançois Tigeot #include <drm/drmP.h> 361b13d190SFrançois Tigeot #include "drm_legacy.h" 377f3c3d6fSHasso Tepper 381b13d190SFrançois Tigeot int drm_legacy_addmap(struct drm_device * dev, resource_size_t offset, 39df4baf3dSFrançois Tigeot unsigned int size, enum drm_map_type type, 40df4baf3dSFrançois Tigeot enum drm_map_flags flags, struct drm_local_map **map_ptr) 417f3c3d6fSHasso Tepper { 42f599cd46SFrançois Tigeot struct drm_local_map *map; 4379d1f0c0SFrançois Tigeot struct drm_map_list *entry = NULL; 445c002123SFrançois Tigeot drm_dma_handle_t *dmah; 4579d1f0c0SFrançois Tigeot 4679d1f0c0SFrançois Tigeot /* Allocate a new map structure, fill it in, and do any type-specific 4779d1f0c0SFrançois Tigeot * initialization necessary. 4879d1f0c0SFrançois Tigeot */ 49f8677ba6SMatthew Dillon map = kmalloc(sizeof(*map), M_DRM, M_ZERO | M_WAITOK | M_NULLOK); 5079d1f0c0SFrançois Tigeot if (!map) { 51b922632fSImre Vadász return -ENOMEM; 5279d1f0c0SFrançois Tigeot } 5379d1f0c0SFrançois Tigeot 5479d1f0c0SFrançois Tigeot map->offset = offset; 5579d1f0c0SFrançois Tigeot map->size = size; 5679d1f0c0SFrançois Tigeot map->type = type; 5779d1f0c0SFrançois Tigeot map->flags = flags; 587f3c3d6fSHasso Tepper 597f3c3d6fSHasso Tepper /* Only allow shared memory to be removable since we only keep enough 607f3c3d6fSHasso Tepper * book keeping information about shared memory to allow for removal 617f3c3d6fSHasso Tepper * when processes fork. 627f3c3d6fSHasso Tepper */ 637f3c3d6fSHasso Tepper if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) { 647f3c3d6fSHasso Tepper DRM_ERROR("Requested removable map for non-DRM_SHM\n"); 655a3b77d5SFrançois Tigeot drm_free(map, M_DRM); 66b922632fSImre Vadász return -EINVAL; 677f3c3d6fSHasso Tepper } 687f3c3d6fSHasso Tepper if ((offset & PAGE_MASK) || (size & PAGE_MASK)) { 692ffc4fa7SSascha Wildner DRM_ERROR("offset/size not page aligned: 0x%jx/0x%04x\n", 702ffc4fa7SSascha Wildner (uintmax_t)offset, size); 715a3b77d5SFrançois Tigeot drm_free(map, M_DRM); 72b922632fSImre Vadász return -EINVAL; 737f3c3d6fSHasso Tepper } 747f3c3d6fSHasso Tepper if (offset + size < offset) { 752ffc4fa7SSascha Wildner DRM_ERROR("offset and size wrap around: 0x%jx/0x%04x\n", 762ffc4fa7SSascha Wildner (uintmax_t)offset, size); 775a3b77d5SFrançois Tigeot drm_free(map, M_DRM); 78b922632fSImre Vadász return -EINVAL; 797f3c3d6fSHasso Tepper } 807f3c3d6fSHasso Tepper 81df4baf3dSFrançois Tigeot DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n", 82df4baf3dSFrançois Tigeot (unsigned long long)map->offset, map->size, map->type); 837f3c3d6fSHasso Tepper 847f3c3d6fSHasso Tepper /* Check if this is just another version of a kernel-allocated map, and 857f3c3d6fSHasso Tepper * just hand that back if so. 867f3c3d6fSHasso Tepper */ 877f3c3d6fSHasso Tepper if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER || 887f3c3d6fSHasso Tepper type == _DRM_SHM) { 89f599cd46SFrançois Tigeot list_for_each_entry(entry, &dev->maplist, head) { 90f599cd46SFrançois Tigeot if (entry->map->type == type && (entry->map->offset == offset || 91f599cd46SFrançois Tigeot (entry->map->type == _DRM_SHM && 92f599cd46SFrançois Tigeot entry->map->flags == _DRM_CONTAINS_LOCK))) { 93f599cd46SFrançois Tigeot entry->map->size = size; 947f3c3d6fSHasso Tepper DRM_DEBUG("Found kernel map %d\n", type); 957f3c3d6fSHasso Tepper goto done; 967f3c3d6fSHasso Tepper } 977f3c3d6fSHasso Tepper } 987f3c3d6fSHasso Tepper } 997f3c3d6fSHasso Tepper 1007f3c3d6fSHasso Tepper switch (map->type) { 1017f3c3d6fSHasso Tepper case _DRM_REGISTERS: 1027f3c3d6fSHasso Tepper case _DRM_FRAME_BUFFER: 1036431cd91SFrançois Tigeot 1046431cd91SFrançois Tigeot if (map->type == _DRM_FRAME_BUFFER || 1056431cd91SFrançois Tigeot (map->flags & _DRM_WRITE_COMBINING)) { 1066431cd91SFrançois Tigeot map->mtrr = 1076431cd91SFrançois Tigeot arch_phys_wc_add(map->offset, map->size); 1086431cd91SFrançois Tigeot } 1096431cd91SFrançois Tigeot if (map->type == _DRM_REGISTERS) { 1106431cd91SFrançois Tigeot if (map->flags & _DRM_WRITE_COMBINING) 1116431cd91SFrançois Tigeot map->handle = ioremap_wc(map->offset, 1126431cd91SFrançois Tigeot map->size); 1136431cd91SFrançois Tigeot else 1146431cd91SFrançois Tigeot map->handle = ioremap(map->offset, map->size); 1156431cd91SFrançois Tigeot if (!map->handle) { 1166431cd91SFrançois Tigeot kfree(map); 1176431cd91SFrançois Tigeot return -ENOMEM; 1186431cd91SFrançois Tigeot } 1196431cd91SFrançois Tigeot } 1206431cd91SFrançois Tigeot 1217f3c3d6fSHasso Tepper break; 1227f3c3d6fSHasso Tepper case _DRM_SHM: 123f8677ba6SMatthew Dillon map->handle = kmalloc(map->size, M_DRM, M_WAITOK | M_NULLOK); 1247f3c3d6fSHasso Tepper DRM_DEBUG("%lu %d %p\n", 1254cd92098Szrj map->size, order_base_2(map->size), map->handle); 1265c002123SFrançois Tigeot if (!map->handle) { 1275a3b77d5SFrançois Tigeot drm_free(map, M_DRM); 128b922632fSImre Vadász return -ENOMEM; 1297f3c3d6fSHasso Tepper } 1305c002123SFrançois Tigeot map->offset = (unsigned long)map->handle; 1317f3c3d6fSHasso Tepper if (map->flags & _DRM_CONTAINS_LOCK) { 1327f3c3d6fSHasso Tepper /* Prevent a 2nd X Server from creating a 2nd lock */ 13379f713b0SFrançois Tigeot DRM_LOCK(dev); 13479f713b0SFrançois Tigeot if (dev->lock.hw_lock != NULL) { 13579f713b0SFrançois Tigeot DRM_UNLOCK(dev); 1365c002123SFrançois Tigeot drm_free(map->handle, M_DRM); 1375a3b77d5SFrançois Tigeot drm_free(map, M_DRM); 138b922632fSImre Vadász return -EBUSY; 1397f3c3d6fSHasso Tepper } 14079f713b0SFrançois Tigeot dev->lock.hw_lock = map->handle; /* Pointer to lock */ 14179f713b0SFrançois Tigeot DRM_UNLOCK(dev); 1427f3c3d6fSHasso Tepper } 1437f3c3d6fSHasso Tepper break; 1447f3c3d6fSHasso Tepper case _DRM_AGP: 145*53e4e524Szrj 146*53e4e524Szrj if (!dev->agp) { 147*53e4e524Szrj kfree(map); 148*53e4e524Szrj return -EINVAL; 149*53e4e524Szrj } 1507f3c3d6fSHasso Tepper /*valid = 0;*/ 1517f3c3d6fSHasso Tepper /* In some cases (i810 driver), user space may have already 1527f3c3d6fSHasso Tepper * added the AGP base itself, because dev->agp->base previously 1537f3c3d6fSHasso Tepper * only got set during AGP enable. So, only add the base 1547f3c3d6fSHasso Tepper * address if the map's offset isn't already within the 1557f3c3d6fSHasso Tepper * aperture. 1567f3c3d6fSHasso Tepper */ 1577f3c3d6fSHasso Tepper if (map->offset < dev->agp->base || 1587f3c3d6fSHasso Tepper map->offset > dev->agp->base + 1599d567857SJean-Sébastien Pédron dev->agp->agp_info.ai_aperture_size - 1) { 1607f3c3d6fSHasso Tepper map->offset += dev->agp->base; 1617f3c3d6fSHasso Tepper } 1629d567857SJean-Sébastien Pédron map->mtrr = dev->agp->agp_mtrr; /* for getmap */ 1637f3c3d6fSHasso Tepper /*for (entry = dev->agp->memory; entry; entry = entry->next) { 1647f3c3d6fSHasso Tepper if ((map->offset >= entry->bound) && 1657f3c3d6fSHasso Tepper (map->offset + map->size <= 1667f3c3d6fSHasso Tepper entry->bound + entry->pages * PAGE_SIZE)) { 1677f3c3d6fSHasso Tepper valid = 1; 1687f3c3d6fSHasso Tepper break; 1697f3c3d6fSHasso Tepper } 1707f3c3d6fSHasso Tepper } 1717f3c3d6fSHasso Tepper if (!valid) { 1725a3b77d5SFrançois Tigeot drm_free(map, M_DRM); 173b922632fSImre Vadász return -EACCES; 1747f3c3d6fSHasso Tepper }*/ 1757f3c3d6fSHasso Tepper break; 1767f3c3d6fSHasso Tepper case _DRM_SCATTER_GATHER: 1777f3c3d6fSHasso Tepper if (!dev->sg) { 1785a3b77d5SFrançois Tigeot drm_free(map, M_DRM); 179b922632fSImre Vadász return -EINVAL; 1807f3c3d6fSHasso Tepper } 1815c002123SFrançois Tigeot map->handle = (void *)(uintptr_t)(dev->sg->vaddr + offset); 18299f70504SFrançois Tigeot map->offset = dev->sg->vaddr + offset; 1837f3c3d6fSHasso Tepper break; 1847f3c3d6fSHasso Tepper case _DRM_CONSISTENT: 185b31e9d59SFrançois Tigeot /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G, 186b31e9d59SFrançois Tigeot * As we're limiting the address to 2^32-1 (or less), 187b31e9d59SFrançois Tigeot * casting it down to 32 bits is no problem, but we 188b31e9d59SFrançois Tigeot * need to point to a 64bit variable first. */ 189b31e9d59SFrançois Tigeot dmah = drm_pci_alloc(dev, map->size, map->size); 1905c002123SFrançois Tigeot if (!dmah) { 191158486a6SFrançois Tigeot kfree(map); 192b31e9d59SFrançois Tigeot return -ENOMEM; 1937f3c3d6fSHasso Tepper } 1945c002123SFrançois Tigeot map->handle = dmah->vaddr; 195b31e9d59SFrançois Tigeot map->offset = dmah->busaddr; 1967f3c3d6fSHasso Tepper break; 1977f3c3d6fSHasso Tepper default: 1987f3c3d6fSHasso Tepper DRM_ERROR("Bad map type %d\n", map->type); 1995a3b77d5SFrançois Tigeot drm_free(map, M_DRM); 200b922632fSImre Vadász return -EINVAL; 2017f3c3d6fSHasso Tepper } 2027f3c3d6fSHasso Tepper 203f599cd46SFrançois Tigeot list_add(&entry->head, &dev->maplist); 2047f3c3d6fSHasso Tepper 2057f3c3d6fSHasso Tepper done: 2067f3c3d6fSHasso Tepper /* Jumped to, with lock held, when a kernel map is found. */ 2077f3c3d6fSHasso Tepper 2087f3c3d6fSHasso Tepper DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset, 2097f3c3d6fSHasso Tepper map->size); 2107f3c3d6fSHasso Tepper 2117f3c3d6fSHasso Tepper *map_ptr = map; 2127f3c3d6fSHasso Tepper 2137f3c3d6fSHasso Tepper return 0; 2147f3c3d6fSHasso Tepper } 2157f3c3d6fSHasso Tepper 216df4baf3dSFrançois Tigeot /** 217df4baf3dSFrançois Tigeot * Ioctl to specify a range of memory that is available for mapping by a 218df4baf3dSFrançois Tigeot * non-root process. 219df4baf3dSFrançois Tigeot * 220df4baf3dSFrançois Tigeot * \param inode device inode. 221df4baf3dSFrançois Tigeot * \param file_priv DRM file private. 222df4baf3dSFrançois Tigeot * \param cmd command. 223df4baf3dSFrançois Tigeot * \param arg pointer to a drm_map structure. 224df4baf3dSFrançois Tigeot * \return zero on success or a negative value on error. 225df4baf3dSFrançois Tigeot * 226df4baf3dSFrançois Tigeot */ 2271b13d190SFrançois Tigeot int drm_legacy_addmap_ioctl(struct drm_device *dev, void *data, 228b3705d71SHasso Tepper struct drm_file *file_priv) 2297f3c3d6fSHasso Tepper { 230b3705d71SHasso Tepper struct drm_map *request = data; 2317f3c3d6fSHasso Tepper drm_local_map_t *map; 2327f3c3d6fSHasso Tepper int err; 2337f3c3d6fSHasso Tepper 2347f3c3d6fSHasso Tepper if (!(dev->flags & (FREAD|FWRITE))) 235b922632fSImre Vadász return -EACCES; /* Require read/write */ 2367f3c3d6fSHasso Tepper 237c6f73aabSFrançois Tigeot if (!capable(CAP_SYS_ADMIN) && request->type != _DRM_AGP) 238b922632fSImre Vadász return -EACCES; 2397f3c3d6fSHasso Tepper 24079f713b0SFrançois Tigeot DRM_LOCK(dev); 2411b13d190SFrançois Tigeot err = drm_legacy_addmap(dev, request->offset, request->size, request->type, 2427f3c3d6fSHasso Tepper request->flags, &map); 24379f713b0SFrançois Tigeot DRM_UNLOCK(dev); 24479f713b0SFrançois Tigeot if (err != 0) 2457f3c3d6fSHasso Tepper return err; 2467f3c3d6fSHasso Tepper 2477f3c3d6fSHasso Tepper request->offset = map->offset; 2487f3c3d6fSHasso Tepper request->size = map->size; 2497f3c3d6fSHasso Tepper request->type = map->type; 2507f3c3d6fSHasso Tepper request->flags = map->flags; 2517f3c3d6fSHasso Tepper request->mtrr = map->mtrr; 25299f70504SFrançois Tigeot request->handle = (void *)map->handle; 2537f3c3d6fSHasso Tepper 2547f3c3d6fSHasso Tepper return 0; 2557f3c3d6fSHasso Tepper } 2567f3c3d6fSHasso Tepper 2571b13d190SFrançois Tigeot /** 2581b13d190SFrançois Tigeot * Remove a map private from list and deallocate resources if the mapping 2591b13d190SFrançois Tigeot * isn't in use. 2601b13d190SFrançois Tigeot * 2611b13d190SFrançois Tigeot * Searches the map on drm_device::maplist, removes it from the list, see if 2621b13d190SFrançois Tigeot * its being used, and free any associate resource (such as MTRR's) if it's not 2631b13d190SFrançois Tigeot * being on use. 2641b13d190SFrançois Tigeot * 2651b13d190SFrançois Tigeot * \sa drm_legacy_addmap 2661b13d190SFrançois Tigeot */ 2671b13d190SFrançois Tigeot int drm_legacy_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) 2687f3c3d6fSHasso Tepper { 269f599cd46SFrançois Tigeot struct drm_map_list *r_list = NULL, *list_t; 2705c002123SFrançois Tigeot drm_dma_handle_t dmah; 271f599cd46SFrançois Tigeot int found = 0; 27279f713b0SFrançois Tigeot 273f599cd46SFrançois Tigeot /* Find the list entry for the map and remove it */ 274f599cd46SFrançois Tigeot list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { 275f599cd46SFrançois Tigeot if (r_list->map == map) { 276f599cd46SFrançois Tigeot list_del(&r_list->head); 2771b13d190SFrançois Tigeot kfree(r_list); 278f599cd46SFrançois Tigeot found = 1; 279f599cd46SFrançois Tigeot break; 280f599cd46SFrançois Tigeot } 281f599cd46SFrançois Tigeot } 282f599cd46SFrançois Tigeot 283f599cd46SFrançois Tigeot if (!found) 2841b13d190SFrançois Tigeot return -EINVAL; 2857f3c3d6fSHasso Tepper 2867f3c3d6fSHasso Tepper switch (map->type) { 2877f3c3d6fSHasso Tepper case _DRM_REGISTERS: 2886431cd91SFrançois Tigeot drm_legacy_ioremapfree(map, dev); 2897f3c3d6fSHasso Tepper /* FALLTHROUGH */ 2907f3c3d6fSHasso Tepper case _DRM_FRAME_BUFFER: 2916431cd91SFrançois Tigeot arch_phys_wc_del(map->mtrr); 2927f3c3d6fSHasso Tepper break; 2937f3c3d6fSHasso Tepper case _DRM_SHM: 2945c002123SFrançois Tigeot drm_free(map->handle, M_DRM); 2957f3c3d6fSHasso Tepper break; 2967f3c3d6fSHasso Tepper case _DRM_AGP: 2977f3c3d6fSHasso Tepper case _DRM_SCATTER_GATHER: 2987f3c3d6fSHasso Tepper break; 2997f3c3d6fSHasso Tepper case _DRM_CONSISTENT: 3005c002123SFrançois Tigeot dmah.vaddr = map->handle; 3015c002123SFrançois Tigeot dmah.busaddr = map->offset; 3021b13d190SFrançois Tigeot dmah.size = map->size; 3031b13d190SFrançois Tigeot __drm_legacy_pci_free(dev, &dmah); 3047f3c3d6fSHasso Tepper break; 3051b13d190SFrançois Tigeot } 3061b13d190SFrançois Tigeot kfree(map); 3071b13d190SFrançois Tigeot 3081b13d190SFrançois Tigeot return 0; 3097f3c3d6fSHasso Tepper } 31079f713b0SFrançois Tigeot 3111b13d190SFrançois Tigeot int drm_legacy_rmmap(struct drm_device *dev, struct drm_local_map *map) 3121b13d190SFrançois Tigeot { 3131b13d190SFrançois Tigeot int ret; 3141b13d190SFrançois Tigeot 3151b13d190SFrançois Tigeot mutex_lock(&dev->struct_mutex); 3161b13d190SFrançois Tigeot ret = drm_legacy_rmmap_locked(dev, map); 3171b13d190SFrançois Tigeot mutex_unlock(&dev->struct_mutex); 3181b13d190SFrançois Tigeot 3191b13d190SFrançois Tigeot return ret; 3207f3c3d6fSHasso Tepper } 3211b13d190SFrançois Tigeot EXPORT_SYMBOL(drm_legacy_rmmap); 3227f3c3d6fSHasso Tepper 323f599cd46SFrançois Tigeot /* The rmmap ioctl appears to be unnecessary. All mappings are torn down on 324f599cd46SFrançois Tigeot * the last close of the device, and this is necessary for cleanup when things 325f599cd46SFrançois Tigeot * exit uncleanly. Therefore, having userland manually remove mappings seems 326f599cd46SFrançois Tigeot * like a pointless exercise since they're going away anyway. 327f599cd46SFrançois Tigeot * 328f599cd46SFrançois Tigeot * One use case might be after addmap is allowed for normal users for SHM and 329f599cd46SFrançois Tigeot * gets used by drivers that the server doesn't need to care about. This seems 330f599cd46SFrançois Tigeot * unlikely. 331f599cd46SFrançois Tigeot * 332f599cd46SFrançois Tigeot * \param inode device inode. 333f599cd46SFrançois Tigeot * \param file_priv DRM file private. 334f599cd46SFrançois Tigeot * \param cmd command. 335f599cd46SFrançois Tigeot * \param arg pointer to a struct drm_map structure. 336f599cd46SFrançois Tigeot * \return zero on success or a negative value on error. 3377f3c3d6fSHasso Tepper */ 3381b13d190SFrançois Tigeot int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data, 339b3705d71SHasso Tepper struct drm_file *file_priv) 3407f3c3d6fSHasso Tepper { 341b3705d71SHasso Tepper struct drm_map *request = data; 342f599cd46SFrançois Tigeot struct drm_local_map *map = NULL; 343f599cd46SFrançois Tigeot struct drm_map_list *r_list; 3447f3c3d6fSHasso Tepper 3455718399fSFrançois Tigeot DRM_LOCK(dev); 346f599cd46SFrançois Tigeot list_for_each_entry(r_list, &dev->maplist, head) { 347f599cd46SFrançois Tigeot if (r_list->map && 348f599cd46SFrançois Tigeot r_list->user_token == (unsigned long)request->handle && 349f599cd46SFrançois Tigeot r_list->map->flags & _DRM_REMOVABLE) { 350f599cd46SFrançois Tigeot map = r_list->map; 3517f3c3d6fSHasso Tepper break; 3527f3c3d6fSHasso Tepper } 353f599cd46SFrançois Tigeot } 3547f3c3d6fSHasso Tepper 355f599cd46SFrançois Tigeot /* List has wrapped around to the head pointer, or its empty we didn't 356f599cd46SFrançois Tigeot * find anything. 357f599cd46SFrançois Tigeot */ 358f599cd46SFrançois Tigeot if (list_empty(&dev->maplist) || !map) { 3595718399fSFrançois Tigeot DRM_UNLOCK(dev); 360f599cd46SFrançois Tigeot return -EINVAL; 361f599cd46SFrançois Tigeot } 362f599cd46SFrançois Tigeot 363f599cd46SFrançois Tigeot /* Register and framebuffer maps are permanent */ 364f599cd46SFrançois Tigeot if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { 365f599cd46SFrançois Tigeot DRM_UNLOCK(dev); 366f599cd46SFrançois Tigeot return 0; 3677f3c3d6fSHasso Tepper } 3687f3c3d6fSHasso Tepper 3691b13d190SFrançois Tigeot drm_legacy_rmmap(dev, map); 3707f3c3d6fSHasso Tepper 3715718399fSFrançois Tigeot DRM_UNLOCK(dev); 3727f3c3d6fSHasso Tepper 3737f3c3d6fSHasso Tepper return 0; 3747f3c3d6fSHasso Tepper } 3757f3c3d6fSHasso Tepper 376df4baf3dSFrançois Tigeot /** 377df4baf3dSFrançois Tigeot * Cleanup after an error on one of the addbufs() functions. 378df4baf3dSFrançois Tigeot * 379df4baf3dSFrançois Tigeot * \param dev DRM device. 380df4baf3dSFrançois Tigeot * \param entry buffer entry where the error occurred. 381df4baf3dSFrançois Tigeot * 382df4baf3dSFrançois Tigeot * Frees any pages and buffers associated with the given entry. 383df4baf3dSFrançois Tigeot */ 384b3705d71SHasso Tepper static void drm_cleanup_buf_error(struct drm_device * dev, 385df4baf3dSFrançois Tigeot struct drm_buf_entry * entry) 3867f3c3d6fSHasso Tepper { 3877f3c3d6fSHasso Tepper int i; 3887f3c3d6fSHasso Tepper 3897f3c3d6fSHasso Tepper if (entry->seg_count) { 3907f3c3d6fSHasso Tepper for (i = 0; i < entry->seg_count; i++) { 3917f3c3d6fSHasso Tepper drm_pci_free(dev, entry->seglist[i]); 3927f3c3d6fSHasso Tepper } 3935a3b77d5SFrançois Tigeot drm_free(entry->seglist, M_DRM); 3947f3c3d6fSHasso Tepper 3957f3c3d6fSHasso Tepper entry->seg_count = 0; 3967f3c3d6fSHasso Tepper } 3977f3c3d6fSHasso Tepper 3987f3c3d6fSHasso Tepper if (entry->buf_count) { 3997f3c3d6fSHasso Tepper for (i = 0; i < entry->buf_count; i++) { 4005a3b77d5SFrançois Tigeot drm_free(entry->buflist[i].dev_private, M_DRM); 4017f3c3d6fSHasso Tepper } 4025a3b77d5SFrançois Tigeot drm_free(entry->buflist, M_DRM); 4037f3c3d6fSHasso Tepper 4047f3c3d6fSHasso Tepper entry->buf_count = 0; 4057f3c3d6fSHasso Tepper } 4067f3c3d6fSHasso Tepper } 4077f3c3d6fSHasso Tepper 408b3705d71SHasso Tepper static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) 4097f3c3d6fSHasso Tepper { 4104250aa95Szrj struct drm_device_dma *dma = dev->dma; 4114250aa95Szrj struct drm_buf_entry *entry; 4124250aa95Szrj /* struct drm_agp_mem *agp_entry; */ 4134250aa95Szrj /* int valid */ 4144250aa95Szrj struct drm_buf *buf; 4157f3c3d6fSHasso Tepper unsigned long offset; 4167f3c3d6fSHasso Tepper unsigned long agp_offset; 4177f3c3d6fSHasso Tepper int count; 4187f3c3d6fSHasso Tepper int order; 4197f3c3d6fSHasso Tepper int size; 4207f3c3d6fSHasso Tepper int alignment; 4217f3c3d6fSHasso Tepper int page_order; 4227f3c3d6fSHasso Tepper int total; 4237f3c3d6fSHasso Tepper int byte_count; 4247f3c3d6fSHasso Tepper int i; 4254250aa95Szrj struct drm_buf **temp_buflist; 4267f3c3d6fSHasso Tepper 4277f3c3d6fSHasso Tepper count = request->count; 4284cd92098Szrj order = order_base_2(request->size); 4297f3c3d6fSHasso Tepper size = 1 << order; 4307f3c3d6fSHasso Tepper 4317f3c3d6fSHasso Tepper alignment = (request->flags & _DRM_PAGE_ALIGN) 4327f3c3d6fSHasso Tepper ? round_page(size) : size; 4337f3c3d6fSHasso Tepper page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 4347f3c3d6fSHasso Tepper total = PAGE_SIZE << page_order; 4357f3c3d6fSHasso Tepper 4367f3c3d6fSHasso Tepper byte_count = 0; 4377f3c3d6fSHasso Tepper agp_offset = dev->agp->base + request->agp_start; 4387f3c3d6fSHasso Tepper 4397f3c3d6fSHasso Tepper DRM_DEBUG("count: %d\n", count); 4407f3c3d6fSHasso Tepper DRM_DEBUG("order: %d\n", order); 4417f3c3d6fSHasso Tepper DRM_DEBUG("size: %d\n", size); 4427f3c3d6fSHasso Tepper DRM_DEBUG("agp_offset: 0x%lx\n", agp_offset); 4437f3c3d6fSHasso Tepper DRM_DEBUG("alignment: %d\n", alignment); 4447f3c3d6fSHasso Tepper DRM_DEBUG("page_order: %d\n", page_order); 4457f3c3d6fSHasso Tepper DRM_DEBUG("total: %d\n", total); 4467f3c3d6fSHasso Tepper 4477f3c3d6fSHasso Tepper /* Make sure buffers are located in AGP memory that we own */ 4487f3c3d6fSHasso Tepper /* Breaks MGA due to drm_alloc_agp not setting up entries for the 4497f3c3d6fSHasso Tepper * memory. Safe to ignore for now because these ioctls are still 4507f3c3d6fSHasso Tepper * root-only. 4517f3c3d6fSHasso Tepper */ 4527f3c3d6fSHasso Tepper /*valid = 0; 4537f3c3d6fSHasso Tepper for (agp_entry = dev->agp->memory; agp_entry; 4547f3c3d6fSHasso Tepper agp_entry = agp_entry->next) { 4557f3c3d6fSHasso Tepper if ((agp_offset >= agp_entry->bound) && 4567f3c3d6fSHasso Tepper (agp_offset + total * count <= 4577f3c3d6fSHasso Tepper agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { 4587f3c3d6fSHasso Tepper valid = 1; 4597f3c3d6fSHasso Tepper break; 4607f3c3d6fSHasso Tepper } 4617f3c3d6fSHasso Tepper } 4627f3c3d6fSHasso Tepper if (!valid) { 4637f3c3d6fSHasso Tepper DRM_DEBUG("zone invalid\n"); 464b922632fSImre Vadász return -EINVAL; 4657f3c3d6fSHasso Tepper }*/ 4667f3c3d6fSHasso Tepper 4677f3c3d6fSHasso Tepper entry = &dma->bufs[order]; 4687f3c3d6fSHasso Tepper 4695a3b77d5SFrançois Tigeot entry->buflist = kmalloc(count * sizeof(*entry->buflist), M_DRM, 470f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK | M_ZERO); 4717f3c3d6fSHasso Tepper if (!entry->buflist) { 472b922632fSImre Vadász return -ENOMEM; 4737f3c3d6fSHasso Tepper } 4747f3c3d6fSHasso Tepper 4757f3c3d6fSHasso Tepper entry->buf_size = size; 4767f3c3d6fSHasso Tepper entry->page_order = page_order; 4777f3c3d6fSHasso Tepper 4787f3c3d6fSHasso Tepper offset = 0; 4797f3c3d6fSHasso Tepper 4807f3c3d6fSHasso Tepper while (entry->buf_count < count) { 4817f3c3d6fSHasso Tepper buf = &entry->buflist[entry->buf_count]; 4827f3c3d6fSHasso Tepper buf->idx = dma->buf_count + entry->buf_count; 4837f3c3d6fSHasso Tepper buf->total = alignment; 4847f3c3d6fSHasso Tepper buf->order = order; 4857f3c3d6fSHasso Tepper buf->used = 0; 4867f3c3d6fSHasso Tepper 4877f3c3d6fSHasso Tepper buf->offset = (dma->byte_count + offset); 4887f3c3d6fSHasso Tepper buf->bus_address = agp_offset + offset; 4897f3c3d6fSHasso Tepper buf->address = (void *)(agp_offset + offset); 4907f3c3d6fSHasso Tepper buf->next = NULL; 4917f3c3d6fSHasso Tepper buf->pending = 0; 4927f3c3d6fSHasso Tepper buf->file_priv = NULL; 4937f3c3d6fSHasso Tepper 494ba55f2f5SFrançois Tigeot buf->dev_priv_size = dev->driver->dev_priv_size; 4955a3b77d5SFrançois Tigeot buf->dev_private = kmalloc(buf->dev_priv_size, M_DRM, 496f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK | M_ZERO); 4977f3c3d6fSHasso Tepper if (buf->dev_private == NULL) { 4987f3c3d6fSHasso Tepper /* Set count correctly so we free the proper amount. */ 4997f3c3d6fSHasso Tepper entry->buf_count = count; 5007f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 501b922632fSImre Vadász return -ENOMEM; 5027f3c3d6fSHasso Tepper } 5037f3c3d6fSHasso Tepper 5047f3c3d6fSHasso Tepper offset += alignment; 5057f3c3d6fSHasso Tepper entry->buf_count++; 5067f3c3d6fSHasso Tepper byte_count += PAGE_SIZE << page_order; 5077f3c3d6fSHasso Tepper } 5087f3c3d6fSHasso Tepper 5097f3c3d6fSHasso Tepper DRM_DEBUG("byte_count: %d\n", byte_count); 5107f3c3d6fSHasso Tepper 5115718399fSFrançois Tigeot temp_buflist = krealloc(dma->buflist, 512b3705d71SHasso Tepper (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 513f8677ba6SMatthew Dillon M_DRM, M_WAITOK | M_NULLOK); 5147f3c3d6fSHasso Tepper if (temp_buflist == NULL) { 5157f3c3d6fSHasso Tepper /* Free the entry because it isn't valid */ 5167f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 517b922632fSImre Vadász return -ENOMEM; 5187f3c3d6fSHasso Tepper } 5197f3c3d6fSHasso Tepper dma->buflist = temp_buflist; 5207f3c3d6fSHasso Tepper 5217f3c3d6fSHasso Tepper for (i = 0; i < entry->buf_count; i++) { 5227f3c3d6fSHasso Tepper dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 5237f3c3d6fSHasso Tepper } 5247f3c3d6fSHasso Tepper 5257f3c3d6fSHasso Tepper dma->buf_count += entry->buf_count; 5267f3c3d6fSHasso Tepper dma->byte_count += byte_count; 5277f3c3d6fSHasso Tepper 5287f3c3d6fSHasso Tepper DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 5297f3c3d6fSHasso Tepper DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); 5307f3c3d6fSHasso Tepper 5317f3c3d6fSHasso Tepper request->count = entry->buf_count; 5327f3c3d6fSHasso Tepper request->size = size; 5337f3c3d6fSHasso Tepper 5347f3c3d6fSHasso Tepper dma->flags = _DRM_DMA_USE_AGP; 5357f3c3d6fSHasso Tepper 5367f3c3d6fSHasso Tepper return 0; 5377f3c3d6fSHasso Tepper } 5387f3c3d6fSHasso Tepper 539b3705d71SHasso Tepper static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) 5407f3c3d6fSHasso Tepper { 5414250aa95Szrj struct drm_device_dma *dma = dev->dma; 5427f3c3d6fSHasso Tepper int count; 5437f3c3d6fSHasso Tepper int order; 5447f3c3d6fSHasso Tepper int size; 5457f3c3d6fSHasso Tepper int total; 5467f3c3d6fSHasso Tepper int page_order; 5474250aa95Szrj struct drm_buf_entry *entry; 548b31e9d59SFrançois Tigeot drm_dma_handle_t *dmah; 5494250aa95Szrj struct drm_buf *buf; 5507f3c3d6fSHasso Tepper int alignment; 5517f3c3d6fSHasso Tepper unsigned long offset; 5527f3c3d6fSHasso Tepper int i; 5537f3c3d6fSHasso Tepper int byte_count; 5547f3c3d6fSHasso Tepper int page_count; 5557f3c3d6fSHasso Tepper unsigned long *temp_pagelist; 5564250aa95Szrj struct drm_buf **temp_buflist; 5577f3c3d6fSHasso Tepper 5587f3c3d6fSHasso Tepper count = request->count; 5594cd92098Szrj order = order_base_2(request->size); 5607f3c3d6fSHasso Tepper size = 1 << order; 5617f3c3d6fSHasso Tepper 5627f3c3d6fSHasso Tepper DRM_DEBUG("count=%d, size=%d (%d), order=%d\n", 5637f3c3d6fSHasso Tepper request->count, request->size, size, order); 5647f3c3d6fSHasso Tepper 5657f3c3d6fSHasso Tepper alignment = (request->flags & _DRM_PAGE_ALIGN) 5667f3c3d6fSHasso Tepper ? round_page(size) : size; 5677f3c3d6fSHasso Tepper page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 5687f3c3d6fSHasso Tepper total = PAGE_SIZE << page_order; 5697f3c3d6fSHasso Tepper 5707f3c3d6fSHasso Tepper entry = &dma->bufs[order]; 5717f3c3d6fSHasso Tepper 5725a3b77d5SFrançois Tigeot entry->buflist = kmalloc(count * sizeof(*entry->buflist), M_DRM, 573f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK | M_ZERO); 5745a3b77d5SFrançois Tigeot entry->seglist = kmalloc(count * sizeof(*entry->seglist), M_DRM, 575f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK | M_ZERO); 5767f3c3d6fSHasso Tepper 5777f3c3d6fSHasso Tepper /* Keep the original pagelist until we know all the allocations 5787f3c3d6fSHasso Tepper * have succeeded 5797f3c3d6fSHasso Tepper */ 5805718399fSFrançois Tigeot temp_pagelist = kmalloc((dma->page_count + (count << page_order)) * 581f8677ba6SMatthew Dillon sizeof(*dma->pagelist), 582f8677ba6SMatthew Dillon M_DRM, M_WAITOK | M_NULLOK); 5837f3c3d6fSHasso Tepper 5847f3c3d6fSHasso Tepper if (entry->buflist == NULL || entry->seglist == NULL || 5857f3c3d6fSHasso Tepper temp_pagelist == NULL) { 5865a3b77d5SFrançois Tigeot drm_free(temp_pagelist, M_DRM); 5875a3b77d5SFrançois Tigeot drm_free(entry->seglist, M_DRM); 5885a3b77d5SFrançois Tigeot drm_free(entry->buflist, M_DRM); 589b922632fSImre Vadász return -ENOMEM; 5907f3c3d6fSHasso Tepper } 5917f3c3d6fSHasso Tepper 5927f3c3d6fSHasso Tepper memcpy(temp_pagelist, dma->pagelist, dma->page_count * 5937f3c3d6fSHasso Tepper sizeof(*dma->pagelist)); 5947f3c3d6fSHasso Tepper 5957f3c3d6fSHasso Tepper DRM_DEBUG("pagelist: %d entries\n", 5967f3c3d6fSHasso Tepper dma->page_count + (count << page_order)); 5977f3c3d6fSHasso Tepper 5987f3c3d6fSHasso Tepper entry->buf_size = size; 5997f3c3d6fSHasso Tepper entry->page_order = page_order; 6007f3c3d6fSHasso Tepper byte_count = 0; 6017f3c3d6fSHasso Tepper page_count = 0; 6027f3c3d6fSHasso Tepper 6037f3c3d6fSHasso Tepper while (entry->buf_count < count) { 6045718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 605b31e9d59SFrançois Tigeot dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000); 6065718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 607b31e9d59SFrançois Tigeot 608b31e9d59SFrançois Tigeot if (!dmah) { 6097f3c3d6fSHasso Tepper /* Set count correctly so we free the proper amount. */ 6107f3c3d6fSHasso Tepper entry->buf_count = count; 6117f3c3d6fSHasso Tepper entry->seg_count = count; 6127f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 6135a3b77d5SFrançois Tigeot drm_free(temp_pagelist, M_DRM); 614b31e9d59SFrançois Tigeot return -ENOMEM; 6157f3c3d6fSHasso Tepper } 6167f3c3d6fSHasso Tepper 6177f3c3d6fSHasso Tepper entry->seglist[entry->seg_count++] = dmah; 6187f3c3d6fSHasso Tepper for (i = 0; i < (1 << page_order); i++) { 619b31e9d59SFrançois Tigeot DRM_DEBUG("page %d @ 0x%08lx\n", 6207f3c3d6fSHasso Tepper dma->page_count + page_count, 621b31e9d59SFrançois Tigeot (unsigned long)dmah->vaddr + PAGE_SIZE * i); 622b31e9d59SFrançois Tigeot temp_pagelist[dma->page_count + page_count++] 623b31e9d59SFrançois Tigeot = (unsigned long)dmah->vaddr + PAGE_SIZE * i; 6247f3c3d6fSHasso Tepper } 6257f3c3d6fSHasso Tepper for (offset = 0; 6267f3c3d6fSHasso Tepper offset + size <= total && entry->buf_count < count; 6277f3c3d6fSHasso Tepper offset += alignment, ++entry->buf_count) { 6287f3c3d6fSHasso Tepper buf = &entry->buflist[entry->buf_count]; 6297f3c3d6fSHasso Tepper buf->idx = dma->buf_count + entry->buf_count; 6307f3c3d6fSHasso Tepper buf->total = alignment; 6317f3c3d6fSHasso Tepper buf->order = order; 6327f3c3d6fSHasso Tepper buf->used = 0; 6337f3c3d6fSHasso Tepper buf->offset = (dma->byte_count + byte_count + offset); 6347f3c3d6fSHasso Tepper buf->address = ((char *)dmah->vaddr + offset); 6357f3c3d6fSHasso Tepper buf->bus_address = dmah->busaddr + offset; 6367f3c3d6fSHasso Tepper buf->next = NULL; 6377f3c3d6fSHasso Tepper buf->pending = 0; 6387f3c3d6fSHasso Tepper buf->file_priv = NULL; 6397f3c3d6fSHasso Tepper 640ba55f2f5SFrançois Tigeot buf->dev_priv_size = dev->driver->dev_priv_size; 6415718399fSFrançois Tigeot buf->dev_private = kmalloc(buf->dev_priv_size, 642f8677ba6SMatthew Dillon M_DRM, 643f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK | 644f8677ba6SMatthew Dillon M_ZERO); 6457f3c3d6fSHasso Tepper if (buf->dev_private == NULL) { 6467f3c3d6fSHasso Tepper /* Set count correctly so we free the proper amount. */ 6477f3c3d6fSHasso Tepper entry->buf_count = count; 6487f3c3d6fSHasso Tepper entry->seg_count = count; 6497f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 6505a3b77d5SFrançois Tigeot drm_free(temp_pagelist, M_DRM); 651b922632fSImre Vadász return -ENOMEM; 6527f3c3d6fSHasso Tepper } 6537f3c3d6fSHasso Tepper 6547f3c3d6fSHasso Tepper DRM_DEBUG("buffer %d @ %p\n", 6557f3c3d6fSHasso Tepper entry->buf_count, buf->address); 6567f3c3d6fSHasso Tepper } 6577f3c3d6fSHasso Tepper byte_count += PAGE_SIZE << page_order; 6587f3c3d6fSHasso Tepper } 6597f3c3d6fSHasso Tepper 6605718399fSFrançois Tigeot temp_buflist = krealloc(dma->buflist, 661b3705d71SHasso Tepper (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 662f8677ba6SMatthew Dillon M_DRM, M_WAITOK | M_NULLOK); 6637f3c3d6fSHasso Tepper if (temp_buflist == NULL) { 6647f3c3d6fSHasso Tepper /* Free the entry because it isn't valid */ 6657f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 6665a3b77d5SFrançois Tigeot drm_free(temp_pagelist, M_DRM); 667b922632fSImre Vadász return -ENOMEM; 6687f3c3d6fSHasso Tepper } 6697f3c3d6fSHasso Tepper dma->buflist = temp_buflist; 6707f3c3d6fSHasso Tepper 6717f3c3d6fSHasso Tepper for (i = 0; i < entry->buf_count; i++) { 6727f3c3d6fSHasso Tepper dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 6737f3c3d6fSHasso Tepper } 6747f3c3d6fSHasso Tepper 6757f3c3d6fSHasso Tepper /* No allocations failed, so now we can replace the orginal pagelist 6767f3c3d6fSHasso Tepper * with the new one. 6777f3c3d6fSHasso Tepper */ 6785a3b77d5SFrançois Tigeot drm_free(dma->pagelist, M_DRM); 6797f3c3d6fSHasso Tepper dma->pagelist = temp_pagelist; 6807f3c3d6fSHasso Tepper 6817f3c3d6fSHasso Tepper dma->buf_count += entry->buf_count; 6827f3c3d6fSHasso Tepper dma->seg_count += entry->seg_count; 6837f3c3d6fSHasso Tepper dma->page_count += entry->seg_count << page_order; 6847f3c3d6fSHasso Tepper dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); 6857f3c3d6fSHasso Tepper 6867f3c3d6fSHasso Tepper request->count = entry->buf_count; 6877f3c3d6fSHasso Tepper request->size = size; 6887f3c3d6fSHasso Tepper 6897f3c3d6fSHasso Tepper return 0; 6907f3c3d6fSHasso Tepper 6917f3c3d6fSHasso Tepper } 6927f3c3d6fSHasso Tepper 693b3705d71SHasso Tepper static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) 6947f3c3d6fSHasso Tepper { 6954250aa95Szrj struct drm_device_dma *dma = dev->dma; 6964250aa95Szrj struct drm_buf_entry *entry; 6974250aa95Szrj struct drm_buf *buf; 6987f3c3d6fSHasso Tepper unsigned long offset; 6997f3c3d6fSHasso Tepper unsigned long agp_offset; 7007f3c3d6fSHasso Tepper int count; 7017f3c3d6fSHasso Tepper int order; 7027f3c3d6fSHasso Tepper int size; 7037f3c3d6fSHasso Tepper int alignment; 7047f3c3d6fSHasso Tepper int page_order; 7057f3c3d6fSHasso Tepper int total; 7067f3c3d6fSHasso Tepper int byte_count; 7077f3c3d6fSHasso Tepper int i; 7084250aa95Szrj struct drm_buf **temp_buflist; 7097f3c3d6fSHasso Tepper 7107f3c3d6fSHasso Tepper count = request->count; 7114cd92098Szrj order = order_base_2(request->size); 7127f3c3d6fSHasso Tepper size = 1 << order; 7137f3c3d6fSHasso Tepper 7147f3c3d6fSHasso Tepper alignment = (request->flags & _DRM_PAGE_ALIGN) 7157f3c3d6fSHasso Tepper ? round_page(size) : size; 7167f3c3d6fSHasso Tepper page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 7177f3c3d6fSHasso Tepper total = PAGE_SIZE << page_order; 7187f3c3d6fSHasso Tepper 7197f3c3d6fSHasso Tepper byte_count = 0; 7207f3c3d6fSHasso Tepper agp_offset = request->agp_start; 7217f3c3d6fSHasso Tepper 7227f3c3d6fSHasso Tepper DRM_DEBUG("count: %d\n", count); 7237f3c3d6fSHasso Tepper DRM_DEBUG("order: %d\n", order); 7247f3c3d6fSHasso Tepper DRM_DEBUG("size: %d\n", size); 7257f3c3d6fSHasso Tepper DRM_DEBUG("agp_offset: %ld\n", agp_offset); 7267f3c3d6fSHasso Tepper DRM_DEBUG("alignment: %d\n", alignment); 7277f3c3d6fSHasso Tepper DRM_DEBUG("page_order: %d\n", page_order); 7287f3c3d6fSHasso Tepper DRM_DEBUG("total: %d\n", total); 7297f3c3d6fSHasso Tepper 7307f3c3d6fSHasso Tepper entry = &dma->bufs[order]; 7317f3c3d6fSHasso Tepper 7325a3b77d5SFrançois Tigeot entry->buflist = kmalloc(count * sizeof(*entry->buflist), M_DRM, 733f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK | M_ZERO); 7347f3c3d6fSHasso Tepper if (entry->buflist == NULL) 735b922632fSImre Vadász return -ENOMEM; 7367f3c3d6fSHasso Tepper 7377f3c3d6fSHasso Tepper entry->buf_size = size; 7387f3c3d6fSHasso Tepper entry->page_order = page_order; 7397f3c3d6fSHasso Tepper 7407f3c3d6fSHasso Tepper offset = 0; 7417f3c3d6fSHasso Tepper 7427f3c3d6fSHasso Tepper while (entry->buf_count < count) { 7437f3c3d6fSHasso Tepper buf = &entry->buflist[entry->buf_count]; 7447f3c3d6fSHasso Tepper buf->idx = dma->buf_count + entry->buf_count; 7457f3c3d6fSHasso Tepper buf->total = alignment; 7467f3c3d6fSHasso Tepper buf->order = order; 7477f3c3d6fSHasso Tepper buf->used = 0; 7487f3c3d6fSHasso Tepper 7497f3c3d6fSHasso Tepper buf->offset = (dma->byte_count + offset); 7507f3c3d6fSHasso Tepper buf->bus_address = agp_offset + offset; 75199f70504SFrançois Tigeot buf->address = (void *)(agp_offset + offset + dev->sg->vaddr); 7527f3c3d6fSHasso Tepper buf->next = NULL; 7537f3c3d6fSHasso Tepper buf->pending = 0; 7547f3c3d6fSHasso Tepper buf->file_priv = NULL; 7557f3c3d6fSHasso Tepper 756ba55f2f5SFrançois Tigeot buf->dev_priv_size = dev->driver->dev_priv_size; 7575a3b77d5SFrançois Tigeot buf->dev_private = kmalloc(buf->dev_priv_size, M_DRM, 758f8677ba6SMatthew Dillon M_WAITOK | M_NULLOK | M_ZERO); 7597f3c3d6fSHasso Tepper if (buf->dev_private == NULL) { 7607f3c3d6fSHasso Tepper /* Set count correctly so we free the proper amount. */ 7617f3c3d6fSHasso Tepper entry->buf_count = count; 7627f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 763b922632fSImre Vadász return -ENOMEM; 7647f3c3d6fSHasso Tepper } 7657f3c3d6fSHasso Tepper 7667f3c3d6fSHasso Tepper DRM_DEBUG("buffer %d @ %p\n", 7677f3c3d6fSHasso Tepper entry->buf_count, buf->address); 7687f3c3d6fSHasso Tepper 7697f3c3d6fSHasso Tepper offset += alignment; 7707f3c3d6fSHasso Tepper entry->buf_count++; 7717f3c3d6fSHasso Tepper byte_count += PAGE_SIZE << page_order; 7727f3c3d6fSHasso Tepper } 7737f3c3d6fSHasso Tepper 7747f3c3d6fSHasso Tepper DRM_DEBUG("byte_count: %d\n", byte_count); 7757f3c3d6fSHasso Tepper 7765718399fSFrançois Tigeot temp_buflist = krealloc(dma->buflist, 777b3705d71SHasso Tepper (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 778f8677ba6SMatthew Dillon M_DRM, M_WAITOK | M_NULLOK); 7797f3c3d6fSHasso Tepper if (temp_buflist == NULL) { 7807f3c3d6fSHasso Tepper /* Free the entry because it isn't valid */ 7817f3c3d6fSHasso Tepper drm_cleanup_buf_error(dev, entry); 782b922632fSImre Vadász return -ENOMEM; 7837f3c3d6fSHasso Tepper } 7847f3c3d6fSHasso Tepper dma->buflist = temp_buflist; 7857f3c3d6fSHasso Tepper 7867f3c3d6fSHasso Tepper for (i = 0; i < entry->buf_count; i++) { 7877f3c3d6fSHasso Tepper dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 7887f3c3d6fSHasso Tepper } 7897f3c3d6fSHasso Tepper 7907f3c3d6fSHasso Tepper dma->buf_count += entry->buf_count; 7917f3c3d6fSHasso Tepper dma->byte_count += byte_count; 7927f3c3d6fSHasso Tepper 7937f3c3d6fSHasso Tepper DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 7947f3c3d6fSHasso Tepper DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); 7957f3c3d6fSHasso Tepper 7967f3c3d6fSHasso Tepper request->count = entry->buf_count; 7977f3c3d6fSHasso Tepper request->size = size; 7987f3c3d6fSHasso Tepper 7997f3c3d6fSHasso Tepper dma->flags = _DRM_DMA_USE_SG; 8007f3c3d6fSHasso Tepper 8017f3c3d6fSHasso Tepper return 0; 8027f3c3d6fSHasso Tepper } 8037f3c3d6fSHasso Tepper 804df4baf3dSFrançois Tigeot /** 805df4baf3dSFrançois Tigeot * Add AGP buffers for DMA transfers. 806df4baf3dSFrançois Tigeot * 807df4baf3dSFrançois Tigeot * \param dev struct drm_device to which the buffers are to be added. 808df4baf3dSFrançois Tigeot * \param request pointer to a struct drm_buf_desc describing the request. 809df4baf3dSFrançois Tigeot * \return zero on success or a negative number on failure. 810df4baf3dSFrançois Tigeot * 811df4baf3dSFrançois Tigeot * After some sanity checks creates a drm_buf structure for each buffer and 812df4baf3dSFrançois Tigeot * reallocates the buffer list of the same size order to accommodate the new 813df4baf3dSFrançois Tigeot * buffers. 814df4baf3dSFrançois Tigeot */ 8151b13d190SFrançois Tigeot int drm_legacy_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) 8167f3c3d6fSHasso Tepper { 8177f3c3d6fSHasso Tepper int order, ret; 8187f3c3d6fSHasso Tepper 8197f3c3d6fSHasso Tepper if (request->count < 0 || request->count > 4096) 820b922632fSImre Vadász return -EINVAL; 8217f3c3d6fSHasso Tepper 8224cd92098Szrj order = order_base_2(request->size); 8237f3c3d6fSHasso Tepper if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 824b922632fSImre Vadász return -EINVAL; 8257f3c3d6fSHasso Tepper 8265718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 827b3705d71SHasso Tepper 8287f3c3d6fSHasso Tepper /* No more allocations after first buffer-using ioctl. */ 8297f3c3d6fSHasso Tepper if (dev->buf_use != 0) { 8305718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 831b922632fSImre Vadász return -EBUSY; 8327f3c3d6fSHasso Tepper } 8337f3c3d6fSHasso Tepper /* No more than one allocation per order */ 8347f3c3d6fSHasso Tepper if (dev->dma->bufs[order].buf_count != 0) { 8355718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 836b922632fSImre Vadász return -ENOMEM; 8377f3c3d6fSHasso Tepper } 8387f3c3d6fSHasso Tepper 8397f3c3d6fSHasso Tepper ret = drm_do_addbufs_agp(dev, request); 8407f3c3d6fSHasso Tepper 8415718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 8427f3c3d6fSHasso Tepper 8437f3c3d6fSHasso Tepper return ret; 8447f3c3d6fSHasso Tepper } 8457f3c3d6fSHasso Tepper 8461b13d190SFrançois Tigeot static int drm_legacy_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request) 8477f3c3d6fSHasso Tepper { 8487f3c3d6fSHasso Tepper int order, ret; 8497f3c3d6fSHasso Tepper 850c6f73aabSFrançois Tigeot if (!capable(CAP_SYS_ADMIN)) 851b922632fSImre Vadász return -EACCES; 8527f3c3d6fSHasso Tepper 8537f3c3d6fSHasso Tepper if (request->count < 0 || request->count > 4096) 854b922632fSImre Vadász return -EINVAL; 8557f3c3d6fSHasso Tepper 8564cd92098Szrj order = order_base_2(request->size); 8577f3c3d6fSHasso Tepper if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 858b922632fSImre Vadász return -EINVAL; 8597f3c3d6fSHasso Tepper 8605718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 861b3705d71SHasso Tepper 8627f3c3d6fSHasso Tepper /* No more allocations after first buffer-using ioctl. */ 8637f3c3d6fSHasso Tepper if (dev->buf_use != 0) { 8645718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 865b922632fSImre Vadász return -EBUSY; 8667f3c3d6fSHasso Tepper } 8677f3c3d6fSHasso Tepper /* No more than one allocation per order */ 8687f3c3d6fSHasso Tepper if (dev->dma->bufs[order].buf_count != 0) { 8695718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 870b922632fSImre Vadász return -ENOMEM; 8717f3c3d6fSHasso Tepper } 8727f3c3d6fSHasso Tepper 8737f3c3d6fSHasso Tepper ret = drm_do_addbufs_sg(dev, request); 8747f3c3d6fSHasso Tepper 8755718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 8767f3c3d6fSHasso Tepper 8777f3c3d6fSHasso Tepper return ret; 8787f3c3d6fSHasso Tepper } 8797f3c3d6fSHasso Tepper 8801b13d190SFrançois Tigeot int drm_legacy_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) 8817f3c3d6fSHasso Tepper { 8827f3c3d6fSHasso Tepper int order, ret; 8837f3c3d6fSHasso Tepper 884c6f73aabSFrançois Tigeot if (!capable(CAP_SYS_ADMIN)) 885b922632fSImre Vadász return -EACCES; 8867f3c3d6fSHasso Tepper 8877f3c3d6fSHasso Tepper if (request->count < 0 || request->count > 4096) 888b922632fSImre Vadász return -EINVAL; 8897f3c3d6fSHasso Tepper 8904cd92098Szrj order = order_base_2(request->size); 8917f3c3d6fSHasso Tepper if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 892b922632fSImre Vadász return -EINVAL; 8937f3c3d6fSHasso Tepper 8945718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 895b3705d71SHasso Tepper 8967f3c3d6fSHasso Tepper /* No more allocations after first buffer-using ioctl. */ 8977f3c3d6fSHasso Tepper if (dev->buf_use != 0) { 8985718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 899b922632fSImre Vadász return -EBUSY; 9007f3c3d6fSHasso Tepper } 9017f3c3d6fSHasso Tepper /* No more than one allocation per order */ 9027f3c3d6fSHasso Tepper if (dev->dma->bufs[order].buf_count != 0) { 9035718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 904b922632fSImre Vadász return -ENOMEM; 9057f3c3d6fSHasso Tepper } 9067f3c3d6fSHasso Tepper 9077f3c3d6fSHasso Tepper ret = drm_do_addbufs_pci(dev, request); 9087f3c3d6fSHasso Tepper 9095718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 9107f3c3d6fSHasso Tepper 9117f3c3d6fSHasso Tepper return ret; 9127f3c3d6fSHasso Tepper } 9137f3c3d6fSHasso Tepper 914df4baf3dSFrançois Tigeot /** 915df4baf3dSFrançois Tigeot * Add buffers for DMA transfers (ioctl). 916df4baf3dSFrançois Tigeot * 917df4baf3dSFrançois Tigeot * \param inode device inode. 918df4baf3dSFrançois Tigeot * \param file_priv DRM file private. 919df4baf3dSFrançois Tigeot * \param cmd command. 920df4baf3dSFrançois Tigeot * \param arg pointer to a struct drm_buf_desc request. 921df4baf3dSFrançois Tigeot * \return zero on success or a negative number on failure. 922df4baf3dSFrançois Tigeot * 923df4baf3dSFrançois Tigeot * According with the memory type specified in drm_buf_desc::flags and the 924df4baf3dSFrançois Tigeot * build options, it dispatches the call either to addbufs_agp(), 925df4baf3dSFrançois Tigeot * addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent 926df4baf3dSFrançois Tigeot * PCI memory respectively. 927df4baf3dSFrançois Tigeot */ 9281b13d190SFrançois Tigeot int drm_legacy_addbufs(struct drm_device *dev, void *data, 929df4baf3dSFrançois Tigeot struct drm_file *file_priv) 9307f3c3d6fSHasso Tepper { 931b3705d71SHasso Tepper struct drm_buf_desc *request = data; 9327f3c3d6fSHasso Tepper int err; 9337f3c3d6fSHasso Tepper 9347f3c3d6fSHasso Tepper if (request->flags & _DRM_AGP_BUFFER) 9351b13d190SFrançois Tigeot err = drm_legacy_addbufs_agp(dev, request); 9367f3c3d6fSHasso Tepper else if (request->flags & _DRM_SG_BUFFER) 9371b13d190SFrançois Tigeot err = drm_legacy_addbufs_sg(dev, request); 9387f3c3d6fSHasso Tepper else 9391b13d190SFrançois Tigeot err = drm_legacy_addbufs_pci(dev, request); 9407f3c3d6fSHasso Tepper 9417f3c3d6fSHasso Tepper return err; 9427f3c3d6fSHasso Tepper } 9437f3c3d6fSHasso Tepper 944df4baf3dSFrançois Tigeot /** 945df4baf3dSFrançois Tigeot * Get information about the buffer mappings. 946df4baf3dSFrançois Tigeot * 947df4baf3dSFrançois Tigeot * This was originally mean for debugging purposes, or by a sophisticated 948df4baf3dSFrançois Tigeot * client library to determine how best to use the available buffers (e.g., 949df4baf3dSFrançois Tigeot * large buffers can be used for image transfer). 950df4baf3dSFrançois Tigeot * 951df4baf3dSFrançois Tigeot * \param inode device inode. 952df4baf3dSFrançois Tigeot * \param file_priv DRM file private. 953df4baf3dSFrançois Tigeot * \param cmd command. 954df4baf3dSFrançois Tigeot * \param arg pointer to a drm_buf_info structure. 955df4baf3dSFrançois Tigeot * \return zero on success or a negative number on failure. 956df4baf3dSFrançois Tigeot * 95724edb884SFrançois Tigeot * Increments drm_device::buf_use while holding the drm_device::buf_lock 958df4baf3dSFrançois Tigeot * lock, preventing of allocating more buffers after this call. Information 959df4baf3dSFrançois Tigeot * about each requested buffer is then copied into user space. 960df4baf3dSFrançois Tigeot */ 9611b13d190SFrançois Tigeot int drm_legacy_infobufs(struct drm_device *dev, void *data, 962df4baf3dSFrançois Tigeot struct drm_file *file_priv) 9637f3c3d6fSHasso Tepper { 96424edb884SFrançois Tigeot struct drm_device_dma *dma = dev->dma; 965b3705d71SHasso Tepper struct drm_buf_info *request = data; 9667f3c3d6fSHasso Tepper int i; 9677f3c3d6fSHasso Tepper int count; 9687f3c3d6fSHasso Tepper 96924edb884SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_MODESET)) 97024edb884SFrançois Tigeot return -EINVAL; 97124edb884SFrançois Tigeot 97224edb884SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) 97324edb884SFrançois Tigeot return -EINVAL; 97424edb884SFrançois Tigeot 97524edb884SFrançois Tigeot if (!dma) 97624edb884SFrançois Tigeot return -EINVAL; 97724edb884SFrançois Tigeot 97824edb884SFrançois Tigeot spin_lock(&dev->buf_lock); 97924edb884SFrançois Tigeot if (atomic_read(&dev->buf_alloc)) { 98024edb884SFrançois Tigeot spin_unlock(&dev->buf_lock); 98124edb884SFrançois Tigeot return -EBUSY; 98224edb884SFrançois Tigeot } 9837f3c3d6fSHasso Tepper ++dev->buf_use; /* Can't allocate more after this call */ 98424edb884SFrançois Tigeot spin_unlock(&dev->buf_lock); 9857f3c3d6fSHasso Tepper 9867f3c3d6fSHasso Tepper for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 987b3705d71SHasso Tepper if (dma->bufs[i].buf_count) 988b3705d71SHasso Tepper ++count; 9897f3c3d6fSHasso Tepper } 9907f3c3d6fSHasso Tepper 9917f3c3d6fSHasso Tepper DRM_DEBUG("count = %d\n", count); 9927f3c3d6fSHasso Tepper 9937f3c3d6fSHasso Tepper if (request->count >= count) { 9947f3c3d6fSHasso Tepper for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 9957f3c3d6fSHasso Tepper if (dma->bufs[i].buf_count) { 99624edb884SFrançois Tigeot struct drm_buf_desc __user *to = 99724edb884SFrançois Tigeot &request->list[count]; 99824edb884SFrançois Tigeot struct drm_buf_entry *from = &dma->bufs[i]; 99924edb884SFrançois Tigeot if (copy_to_user(&to->count, 100024edb884SFrançois Tigeot &from->buf_count, 100124edb884SFrançois Tigeot sizeof(from->buf_count)) || 100224edb884SFrançois Tigeot copy_to_user(&to->size, 100324edb884SFrançois Tigeot &from->buf_size, 100424edb884SFrançois Tigeot sizeof(from->buf_size)) || 100524edb884SFrançois Tigeot copy_to_user(&to->low_mark, 100624edb884SFrançois Tigeot &from->low_mark, 100724edb884SFrançois Tigeot sizeof(from->low_mark)) || 100824edb884SFrançois Tigeot copy_to_user(&to->high_mark, 100924edb884SFrançois Tigeot &from->high_mark, 101024edb884SFrançois Tigeot sizeof(from->high_mark))) 101124edb884SFrançois Tigeot return -EFAULT; 10127f3c3d6fSHasso Tepper 10137f3c3d6fSHasso Tepper DRM_DEBUG("%d %d %d %d %d\n", 101424edb884SFrançois Tigeot i, 101524edb884SFrançois Tigeot dma->bufs[i].buf_count, 10167f3c3d6fSHasso Tepper dma->bufs[i].buf_size, 101724edb884SFrançois Tigeot dma->bufs[i].low_mark, 101824edb884SFrançois Tigeot dma->bufs[i].high_mark); 10197f3c3d6fSHasso Tepper ++count; 10207f3c3d6fSHasso Tepper } 10217f3c3d6fSHasso Tepper } 10227f3c3d6fSHasso Tepper } 10237f3c3d6fSHasso Tepper request->count = count; 10247f3c3d6fSHasso Tepper 102524edb884SFrançois Tigeot return 0; 10267f3c3d6fSHasso Tepper } 10277f3c3d6fSHasso Tepper 1028df4baf3dSFrançois Tigeot /** 1029df4baf3dSFrançois Tigeot * Specifies a low and high water mark for buffer allocation 1030df4baf3dSFrançois Tigeot * 1031df4baf3dSFrançois Tigeot * \param inode device inode. 1032df4baf3dSFrançois Tigeot * \param file_priv DRM file private. 1033df4baf3dSFrançois Tigeot * \param cmd command. 1034df4baf3dSFrançois Tigeot * \param arg a pointer to a drm_buf_desc structure. 1035df4baf3dSFrançois Tigeot * \return zero on success or a negative number on failure. 1036df4baf3dSFrançois Tigeot * 1037df4baf3dSFrançois Tigeot * Verifies that the size order is bounded between the admissible orders and 1038df4baf3dSFrançois Tigeot * updates the respective drm_device_dma::bufs entry low and high water mark. 1039df4baf3dSFrançois Tigeot * 1040df4baf3dSFrançois Tigeot * \note This ioctl is deprecated and mostly never used. 1041df4baf3dSFrançois Tigeot */ 10421b13d190SFrançois Tigeot int drm_legacy_markbufs(struct drm_device *dev, void *data, 1043df4baf3dSFrançois Tigeot struct drm_file *file_priv) 10447f3c3d6fSHasso Tepper { 104524edb884SFrançois Tigeot struct drm_device_dma *dma = dev->dma; 1046b3705d71SHasso Tepper struct drm_buf_desc *request = data; 10477f3c3d6fSHasso Tepper int order; 104824edb884SFrançois Tigeot struct drm_buf_entry *entry; 104924edb884SFrançois Tigeot 105024edb884SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_MODESET)) 105124edb884SFrançois Tigeot return -EINVAL; 105224edb884SFrançois Tigeot 105324edb884SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) 105424edb884SFrançois Tigeot return -EINVAL; 105524edb884SFrançois Tigeot 105624edb884SFrançois Tigeot if (!dma) 105724edb884SFrançois Tigeot return -EINVAL; 10587f3c3d6fSHasso Tepper 10597f3c3d6fSHasso Tepper DRM_DEBUG("%d, %d, %d\n", 10607f3c3d6fSHasso Tepper request->size, request->low_mark, request->high_mark); 10614cd92098Szrj order = order_base_2(request->size); 106224edb884SFrançois Tigeot if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 106324edb884SFrançois Tigeot return -EINVAL; 106424edb884SFrançois Tigeot entry = &dma->bufs[order]; 10657f3c3d6fSHasso Tepper 106624edb884SFrançois Tigeot if (request->low_mark < 0 || request->low_mark > entry->buf_count) 106724edb884SFrançois Tigeot return -EINVAL; 106824edb884SFrançois Tigeot if (request->high_mark < 0 || request->high_mark > entry->buf_count) 106924edb884SFrançois Tigeot return -EINVAL; 10707f3c3d6fSHasso Tepper 107124edb884SFrançois Tigeot entry->low_mark = request->low_mark; 107224edb884SFrançois Tigeot entry->high_mark = request->high_mark; 10737f3c3d6fSHasso Tepper 10747f3c3d6fSHasso Tepper return 0; 10757f3c3d6fSHasso Tepper } 10767f3c3d6fSHasso Tepper 1077df4baf3dSFrançois Tigeot /** 1078df4baf3dSFrançois Tigeot * Unreserve the buffers in list, previously reserved using drmDMA. 1079df4baf3dSFrançois Tigeot * 1080df4baf3dSFrançois Tigeot * \param inode device inode. 1081df4baf3dSFrançois Tigeot * \param file_priv DRM file private. 1082df4baf3dSFrançois Tigeot * \param cmd command. 1083df4baf3dSFrançois Tigeot * \param arg pointer to a drm_buf_free structure. 1084df4baf3dSFrançois Tigeot * \return zero on success or a negative number on failure. 1085df4baf3dSFrançois Tigeot * 1086df4baf3dSFrançois Tigeot * Calls free_buffer() for each used buffer. 1087df4baf3dSFrançois Tigeot * This function is primarily used for debugging. 1088df4baf3dSFrançois Tigeot */ 10891b13d190SFrançois Tigeot int drm_legacy_freebufs(struct drm_device *dev, void *data, 1090df4baf3dSFrançois Tigeot struct drm_file *file_priv) 10917f3c3d6fSHasso Tepper { 10924250aa95Szrj struct drm_device_dma *dma = dev->dma; 1093b3705d71SHasso Tepper struct drm_buf_free *request = data; 10947f3c3d6fSHasso Tepper int i; 10957f3c3d6fSHasso Tepper int idx; 10964250aa95Szrj struct drm_buf *buf; 10977f3c3d6fSHasso Tepper int retcode = 0; 10987f3c3d6fSHasso Tepper 10997f3c3d6fSHasso Tepper DRM_DEBUG("%d\n", request->count); 11007f3c3d6fSHasso Tepper 11015718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 11027f3c3d6fSHasso Tepper for (i = 0; i < request->count; i++) { 1103c6f73aabSFrançois Tigeot if (copy_from_user(&idx, &request->list[i], sizeof(idx))) { 1104b922632fSImre Vadász retcode = -EFAULT; 11057f3c3d6fSHasso Tepper break; 11067f3c3d6fSHasso Tepper } 11077f3c3d6fSHasso Tepper if (idx < 0 || idx >= dma->buf_count) { 11087f3c3d6fSHasso Tepper DRM_ERROR("Index %d (of %d max)\n", 11097f3c3d6fSHasso Tepper idx, dma->buf_count - 1); 1110b922632fSImre Vadász retcode = -EINVAL; 11117f3c3d6fSHasso Tepper break; 11127f3c3d6fSHasso Tepper } 11137f3c3d6fSHasso Tepper buf = dma->buflist[idx]; 11147f3c3d6fSHasso Tepper if (buf->file_priv != file_priv) { 11157f3c3d6fSHasso Tepper DRM_ERROR("Process %d freeing buffer not owned\n", 11167f3c3d6fSHasso Tepper DRM_CURRENTPID); 1117b922632fSImre Vadász retcode = -EINVAL; 11187f3c3d6fSHasso Tepper break; 11197f3c3d6fSHasso Tepper } 11201b13d190SFrançois Tigeot drm_legacy_free_buffer(dev, buf); 11217f3c3d6fSHasso Tepper } 11225718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 11237f3c3d6fSHasso Tepper 11247f3c3d6fSHasso Tepper return retcode; 11257f3c3d6fSHasso Tepper } 11267f3c3d6fSHasso Tepper 1127df4baf3dSFrançois Tigeot /** 1128df4baf3dSFrançois Tigeot * Maps all of the DMA buffers into client-virtual space (ioctl). 1129df4baf3dSFrançois Tigeot * 1130df4baf3dSFrançois Tigeot * \param inode device inode. 1131df4baf3dSFrançois Tigeot * \param file_priv DRM file private. 1132df4baf3dSFrançois Tigeot * \param cmd command. 1133df4baf3dSFrançois Tigeot * \param arg pointer to a drm_buf_map structure. 1134df4baf3dSFrançois Tigeot * \return zero on success or a negative number on failure. 1135df4baf3dSFrançois Tigeot * 1136df4baf3dSFrançois Tigeot * Maps the AGP, SG or PCI buffer region with vm_mmap(), and copies information 1137df4baf3dSFrançois Tigeot * about each buffer into user space. For PCI buffers, it calls vm_mmap() with 1138df4baf3dSFrançois Tigeot * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls 1139df4baf3dSFrançois Tigeot * drm_mmap_dma(). 1140df4baf3dSFrançois Tigeot */ 11411b13d190SFrançois Tigeot int drm_legacy_mapbufs(struct drm_device *dev, void *data, 1142df4baf3dSFrançois Tigeot struct drm_file *file_priv) 11437f3c3d6fSHasso Tepper { 11444250aa95Szrj struct drm_device_dma *dma = dev->dma; 11457f3c3d6fSHasso Tepper int retcode = 0; 11467f3c3d6fSHasso Tepper const int zero = 0; 11477f3c3d6fSHasso Tepper vm_offset_t address; 11487f3c3d6fSHasso Tepper struct vmspace *vms; 11497f3c3d6fSHasso Tepper vm_ooffset_t foff; 11507f3c3d6fSHasso Tepper vm_size_t size; 11517f3c3d6fSHasso Tepper vm_offset_t vaddr; 1152b3705d71SHasso Tepper struct drm_buf_map *request = data; 11537f3c3d6fSHasso Tepper int i; 11547f3c3d6fSHasso Tepper 11557f3c3d6fSHasso Tepper vms = DRM_CURPROC->td_proc->p_vmspace; 11567f3c3d6fSHasso Tepper 11575718399fSFrançois Tigeot spin_lock(&dev->dma_lock); 11587f3c3d6fSHasso Tepper dev->buf_use++; /* Can't allocate more after this call */ 11595718399fSFrançois Tigeot spin_unlock(&dev->dma_lock); 11607f3c3d6fSHasso Tepper 11617f3c3d6fSHasso Tepper if (request->count < dma->buf_count) 11627f3c3d6fSHasso Tepper goto done; 11637f3c3d6fSHasso Tepper 1164*53e4e524Szrj if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP)) || 1165b3705d71SHasso Tepper (drm_core_check_feature(dev, DRIVER_SG) && 1166b3705d71SHasso Tepper (dma->flags & _DRM_DMA_USE_SG))) { 11677f3c3d6fSHasso Tepper drm_local_map_t *map = dev->agp_buffer_map; 11687f3c3d6fSHasso Tepper 11697f3c3d6fSHasso Tepper if (map == NULL) { 1170b922632fSImre Vadász retcode = -EINVAL; 11717f3c3d6fSHasso Tepper goto done; 11727f3c3d6fSHasso Tepper } 11737f3c3d6fSHasso Tepper size = round_page(map->size); 117499f70504SFrançois Tigeot foff = (unsigned long)map->handle; 11757f3c3d6fSHasso Tepper } else { 11767f3c3d6fSHasso Tepper size = round_page(dma->byte_count), 11777f3c3d6fSHasso Tepper foff = 0; 11787f3c3d6fSHasso Tepper } 11797f3c3d6fSHasso Tepper 11807f3c3d6fSHasso Tepper vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); 1181b922632fSImre Vadász retcode = -vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1182b3705d71SHasso Tepper VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, 1183b3705d71SHasso Tepper SLIST_FIRST(&dev->devnode->si_hlist), foff); 11847f3c3d6fSHasso Tepper if (retcode) 11857f3c3d6fSHasso Tepper goto done; 11867f3c3d6fSHasso Tepper 11877f3c3d6fSHasso Tepper request->virtual = (void *)vaddr; 11887f3c3d6fSHasso Tepper 11897f3c3d6fSHasso Tepper for (i = 0; i < dma->buf_count; i++) { 1190c6f73aabSFrançois Tigeot if (copy_to_user(&request->list[i].idx, 11917f3c3d6fSHasso Tepper &dma->buflist[i]->idx, sizeof(request->list[0].idx))) { 1192b922632fSImre Vadász retcode = -EFAULT; 11937f3c3d6fSHasso Tepper goto done; 11947f3c3d6fSHasso Tepper } 1195c6f73aabSFrançois Tigeot if (copy_to_user(&request->list[i].total, 11967f3c3d6fSHasso Tepper &dma->buflist[i]->total, sizeof(request->list[0].total))) { 1197b922632fSImre Vadász retcode = -EFAULT; 11987f3c3d6fSHasso Tepper goto done; 11997f3c3d6fSHasso Tepper } 1200c6f73aabSFrançois Tigeot if (copy_to_user(&request->list[i].used, &zero, 12017f3c3d6fSHasso Tepper sizeof(zero))) { 1202b922632fSImre Vadász retcode = -EFAULT; 12037f3c3d6fSHasso Tepper goto done; 12047f3c3d6fSHasso Tepper } 12057f3c3d6fSHasso Tepper address = vaddr + dma->buflist[i]->offset; /* *** */ 1206c6f73aabSFrançois Tigeot if (copy_to_user(&request->list[i].address, &address, 12077f3c3d6fSHasso Tepper sizeof(address))) { 1208b922632fSImre Vadász retcode = -EFAULT; 12097f3c3d6fSHasso Tepper goto done; 12107f3c3d6fSHasso Tepper } 12117f3c3d6fSHasso Tepper } 12127f3c3d6fSHasso Tepper done: 12137f3c3d6fSHasso Tepper request->count = dma->buf_count; 12147f3c3d6fSHasso Tepper DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode); 12157f3c3d6fSHasso Tepper 12167f3c3d6fSHasso Tepper return retcode; 12177f3c3d6fSHasso Tepper } 12181b13d190SFrançois Tigeot 12191b13d190SFrançois Tigeot int drm_legacy_dma_ioctl(struct drm_device *dev, void *data, 12201b13d190SFrançois Tigeot struct drm_file *file_priv) 12211b13d190SFrançois Tigeot { 12221b13d190SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_MODESET)) 12231b13d190SFrançois Tigeot return -EINVAL; 12241b13d190SFrançois Tigeot 12251b13d190SFrançois Tigeot if (dev->driver->dma_ioctl) 12261b13d190SFrançois Tigeot return dev->driver->dma_ioctl(dev, data, file_priv); 12271b13d190SFrançois Tigeot else 12281b13d190SFrançois Tigeot return -EINVAL; 12291b13d190SFrançois Tigeot } 12301b13d190SFrançois Tigeot 12311b13d190SFrançois Tigeot struct drm_local_map *drm_legacy_getsarea(struct drm_device *dev) 12321b13d190SFrançois Tigeot { 12331b13d190SFrançois Tigeot struct drm_map_list *entry; 12341b13d190SFrançois Tigeot 12351b13d190SFrançois Tigeot list_for_each_entry(entry, &dev->maplist, head) { 12361b13d190SFrançois Tigeot if (entry->map && entry->map->type == _DRM_SHM && 12371b13d190SFrançois Tigeot (entry->map->flags & _DRM_CONTAINS_LOCK)) { 12381b13d190SFrançois Tigeot return entry->map; 12391b13d190SFrançois Tigeot } 12401b13d190SFrançois Tigeot } 12411b13d190SFrançois Tigeot return NULL; 12421b13d190SFrançois Tigeot } 12431b13d190SFrançois Tigeot EXPORT_SYMBOL(drm_legacy_getsarea); 1244