diff options
Diffstat (limited to 'drivers/gpu/drm/drm_bufs.c')
| -rw-r--r-- | drivers/gpu/drm/drm_bufs.c | 346 | 
1 files changed, 97 insertions, 249 deletions
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 3e257a50bf5..68175b54504 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -36,8 +36,9 @@  #include <linux/vmalloc.h>  #include <linux/slab.h>  #include <linux/log2.h> +#include <linux/export.h>  #include <asm/shmparam.h> -#include "drmP.h" +#include <drm/drmP.h>  static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,  						  struct drm_local_map *map) @@ -46,10 +47,11 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,  	list_for_each_entry(entry, &dev->maplist, head) {  		/*  		 * Because the kernel-userspace ABI is fixed at a 32-bit offset -		 * while PCI resources may live above that, we ignore the map -		 * offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS. -		 * It is assumed that each driver will have only one resource of -		 * each type. +		 * while PCI resources may live above that, we only compare the +		 * lower 32 bits of the map offset for maps of type +		 * _DRM_FRAMEBUFFER or _DRM_REGISTERS. +		 * It is assumed that if a driver have more than one resource +		 * of each type, the lower 32 bits are different.  		 */  		if (!entry->map ||  		    map->type != entry->map->type || @@ -59,9 +61,12 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,  		case _DRM_SHM:  			if (map->flags != _DRM_CONTAINS_LOCK)  				break; +			return entry;  		case _DRM_REGISTERS:  		case _DRM_FRAME_BUFFER: -			return entry; +			if ((entry->map->offset & 0xffffffff) == +			    (map->offset & 0xffffffff)) +				return entry;  		default: /* Make gcc happy */  			;  		} @@ -183,9 +188,6 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,  			return -EINVAL;  		}  #endif -#ifdef __alpha__ -		map->offset += dev->hose->mem_space->start; -#endif  		/* Some drivers preinitialize some maps, without the X Server  		 * needing to be aware of it.  Therefore, we just return success  		 * when the server tries to create a duplicate map. @@ -205,15 +207,17 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,  			return 0;  		} -		if (drm_core_has_MTRR(dev)) { -			if (map->type == _DRM_FRAME_BUFFER || -			    (map->flags & _DRM_WRITE_COMBINING)) { -				map->mtrr = mtrr_add(map->offset, map->size, -						     MTRR_TYPE_WRCOMB, 1); -			} +		if (map->type == _DRM_FRAME_BUFFER || +		    (map->flags & _DRM_WRITE_COMBINING)) { +			map->mtrr = +				arch_phys_wc_add(map->offset, map->size);  		}  		if (map->type == _DRM_REGISTERS) { -			map->handle = ioremap(map->offset, map->size); +			if (map->flags & _DRM_WRITE_COMBINING) +				map->handle = ioremap_wc(map->offset, +							 map->size); +			else +				map->handle = ioremap(map->offset, map->size);  			if (!map->handle) {  				kfree(map);  				return -ENOMEM; @@ -237,7 +241,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,  		}  		map->handle = vmalloc_user(map->size);  		DRM_DEBUG("%lu %d %p\n", -			  map->size, drm_order(map->size), map->handle); +			  map->size, order_base_2(map->size), map->handle);  		if (!map->handle) {  			kfree(map);  			return -ENOMEM; @@ -257,7 +261,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,  		struct drm_agp_mem *entry;  		int valid = 0; -		if (!drm_core_has_AGP(dev)) { +		if (!dev->agp) {  			kfree(map);  			return -EINVAL;  		} @@ -299,9 +303,6 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,  		break;  	} -	case _DRM_GEM: -		DRM_ERROR("tried to addmap GEM object\n"); -		break;  	case _DRM_SCATTER_GATHER:  		if (!dev->sg) {  			kfree(map); @@ -362,7 +363,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,  		list->master = dev->primary->master;  	*maplist = list;  	return 0; -	} +}  int drm_addmap(struct drm_device * dev, resource_size_t offset,  	       unsigned int size, enum drm_map_type type, @@ -408,6 +409,15 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data,  	/* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */  	map->handle = (void *)(unsigned long)maplist->user_token; + +	/* +	 * It appears that there are no users of this value whatsoever -- +	 * drmAddMap just discards it.  Let's not encourage its use. +	 * (Keeping drm_addmap_core's returned mtrr value would be wrong -- +	 *  it's not a real mtrr index anymore.) +	 */ +	map->mtrr = -1; +  	return 0;  } @@ -449,11 +459,7 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)  		iounmap(map->handle);  		/* FALLTHROUGH */  	case _DRM_FRAME_BUFFER: -		if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { -			int retcode; -			retcode = mtrr_del(map->mtrr, map->offset, map->size); -			DRM_DEBUG("mtrr_del=%d\n", retcode); -		} +		arch_phys_wc_del(map->mtrr);  		break;  	case _DRM_SHM:  		vfree(map->handle); @@ -474,9 +480,6 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)  		dmah.size = map->size;  		__drm_pci_free(dev, &dmah);  		break; -	case _DRM_GEM: -		DRM_ERROR("tried to rmmap GEM object\n"); -		break;  	}  	kfree(map); @@ -618,7 +621,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)  		return -EINVAL;  	count = request->count; -	order = drm_order(request->size); +	order = order_base_2(request->size);  	size = 1 << order;  	alignment = (request->flags & _DRM_PAGE_ALIGN) @@ -639,8 +642,6 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)  	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)  		return -EINVAL; -	if (dev->queue_count) -		return -EBUSY;	/* Not while in use */  	/* Make sure buffers are located in AGP memory that we own */  	valid = 0; @@ -655,13 +656,13 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)  		DRM_DEBUG("zone invalid\n");  		return -EINVAL;  	} -	spin_lock(&dev->count_lock); +	spin_lock(&dev->buf_lock);  	if (dev->buf_use) { -		spin_unlock(&dev->count_lock); +		spin_unlock(&dev->buf_lock);  		return -EBUSY;  	}  	atomic_inc(&dev->buf_alloc); -	spin_unlock(&dev->count_lock); +	spin_unlock(&dev->buf_lock);  	mutex_lock(&dev->struct_mutex);  	entry = &dma->bufs[order]; @@ -702,7 +703,6 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)  		buf->next = NULL;  		buf->waiting = 0;  		buf->pending = 0; -		init_waitqueue_head(&buf->dma_wait);  		buf->file_priv = NULL;  		buf->dev_priv_size = dev->driver->dev_priv_size; @@ -791,29 +791,27 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)  		return -EPERM;  	count = request->count; -	order = drm_order(request->size); +	order = order_base_2(request->size);  	size = 1 << order; -	DRM_DEBUG("count=%d, size=%d (%d), order=%d, queue_count=%d\n", -		  request->count, request->size, size, order, dev->queue_count); +	DRM_DEBUG("count=%d, size=%d (%d), order=%d\n", +		  request->count, request->size, size, order);  	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)  		return -EINVAL; -	if (dev->queue_count) -		return -EBUSY;	/* Not while in use */  	alignment = (request->flags & _DRM_PAGE_ALIGN)  	    ? PAGE_ALIGN(size) : size;  	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;  	total = PAGE_SIZE << page_order; -	spin_lock(&dev->count_lock); +	spin_lock(&dev->buf_lock);  	if (dev->buf_use) { -		spin_unlock(&dev->count_lock); +		spin_unlock(&dev->buf_lock);  		return -EBUSY;  	}  	atomic_inc(&dev->buf_alloc); -	spin_unlock(&dev->count_lock); +	spin_unlock(&dev->buf_lock);  	mutex_lock(&dev->struct_mutex);  	entry = &dma->bufs[order]; @@ -902,7 +900,6 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)  			buf->next = NULL;  			buf->waiting = 0;  			buf->pending = 0; -			init_waitqueue_head(&buf->dma_wait);  			buf->file_priv = NULL;  			buf->dev_priv_size = dev->driver->dev_priv_size; @@ -996,7 +993,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request  		return -EPERM;  	count = request->count; -	order = drm_order(request->size); +	order = order_base_2(request->size);  	size = 1 << order;  	alignment = (request->flags & _DRM_PAGE_ALIGN) @@ -1017,16 +1014,14 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request  	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)  		return -EINVAL; -	if (dev->queue_count) -		return -EBUSY;	/* Not while in use */ -	spin_lock(&dev->count_lock); +	spin_lock(&dev->buf_lock);  	if (dev->buf_use) { -		spin_unlock(&dev->count_lock); +		spin_unlock(&dev->buf_lock);  		return -EBUSY;  	}  	atomic_inc(&dev->buf_alloc); -	spin_unlock(&dev->count_lock); +	spin_unlock(&dev->buf_lock);  	mutex_lock(&dev->struct_mutex);  	entry = &dma->bufs[order]; @@ -1069,7 +1064,6 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request  		buf->next = NULL;  		buf->waiting = 0;  		buf->pending = 0; -		init_waitqueue_head(&buf->dma_wait);  		buf->file_priv = NULL;  		buf->dev_priv_size = dev->driver->dev_priv_size; @@ -1127,164 +1121,6 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request  	return 0;  } -static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request) -{ -	struct drm_device_dma *dma = dev->dma; -	struct drm_buf_entry *entry; -	struct drm_buf *buf; -	unsigned long offset; -	unsigned long agp_offset; -	int count; -	int order; -	int size; -	int alignment; -	int page_order; -	int total; -	int byte_count; -	int i; -	struct drm_buf **temp_buflist; - -	if (!drm_core_check_feature(dev, DRIVER_FB_DMA)) -		return -EINVAL; - -	if (!dma) -		return -EINVAL; - -	if (!capable(CAP_SYS_ADMIN)) -		return -EPERM; - -	count = request->count; -	order = drm_order(request->size); -	size = 1 << order; - -	alignment = (request->flags & _DRM_PAGE_ALIGN) -	    ? PAGE_ALIGN(size) : size; -	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; -	total = PAGE_SIZE << page_order; - -	byte_count = 0; -	agp_offset = request->agp_start; - -	DRM_DEBUG("count:      %d\n", count); -	DRM_DEBUG("order:      %d\n", order); -	DRM_DEBUG("size:       %d\n", size); -	DRM_DEBUG("agp_offset: %lu\n", agp_offset); -	DRM_DEBUG("alignment:  %d\n", alignment); -	DRM_DEBUG("page_order: %d\n", page_order); -	DRM_DEBUG("total:      %d\n", total); - -	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) -		return -EINVAL; -	if (dev->queue_count) -		return -EBUSY;	/* Not while in use */ - -	spin_lock(&dev->count_lock); -	if (dev->buf_use) { -		spin_unlock(&dev->count_lock); -		return -EBUSY; -	} -	atomic_inc(&dev->buf_alloc); -	spin_unlock(&dev->count_lock); - -	mutex_lock(&dev->struct_mutex); -	entry = &dma->bufs[order]; -	if (entry->buf_count) { -		mutex_unlock(&dev->struct_mutex); -		atomic_dec(&dev->buf_alloc); -		return -ENOMEM;	/* May only call once for each order */ -	} - -	if (count < 0 || count > 4096) { -		mutex_unlock(&dev->struct_mutex); -		atomic_dec(&dev->buf_alloc); -		return -EINVAL; -	} - -	entry->buflist = kzalloc(count * sizeof(*entry->buflist), -				GFP_KERNEL); -	if (!entry->buflist) { -		mutex_unlock(&dev->struct_mutex); -		atomic_dec(&dev->buf_alloc); -		return -ENOMEM; -	} - -	entry->buf_size = size; -	entry->page_order = page_order; - -	offset = 0; - -	while (entry->buf_count < count) { -		buf = &entry->buflist[entry->buf_count]; -		buf->idx = dma->buf_count + entry->buf_count; -		buf->total = alignment; -		buf->order = order; -		buf->used = 0; - -		buf->offset = (dma->byte_count + offset); -		buf->bus_address = agp_offset + offset; -		buf->address = (void *)(agp_offset + offset); -		buf->next = NULL; -		buf->waiting = 0; -		buf->pending = 0; -		init_waitqueue_head(&buf->dma_wait); -		buf->file_priv = NULL; - -		buf->dev_priv_size = dev->driver->dev_priv_size; -		buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL); -		if (!buf->dev_private) { -			/* Set count correctly so we free the proper amount. */ -			entry->buf_count = count; -			drm_cleanup_buf_error(dev, entry); -			mutex_unlock(&dev->struct_mutex); -			atomic_dec(&dev->buf_alloc); -			return -ENOMEM; -		} - -		DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); - -		offset += alignment; -		entry->buf_count++; -		byte_count += PAGE_SIZE << page_order; -	} - -	DRM_DEBUG("byte_count: %d\n", byte_count); - -	temp_buflist = krealloc(dma->buflist, -				(dma->buf_count + entry->buf_count) * -				sizeof(*dma->buflist), GFP_KERNEL); -	if (!temp_buflist) { -		/* Free the entry because it isn't valid */ -		drm_cleanup_buf_error(dev, entry); -		mutex_unlock(&dev->struct_mutex); -		atomic_dec(&dev->buf_alloc); -		return -ENOMEM; -	} -	dma->buflist = temp_buflist; - -	for (i = 0; i < entry->buf_count; i++) { -		dma->buflist[i + dma->buf_count] = &entry->buflist[i]; -	} - -	dma->buf_count += entry->buf_count; -	dma->seg_count += entry->seg_count; -	dma->page_count += byte_count >> PAGE_SHIFT; -	dma->byte_count += byte_count; - -	DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); -	DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); - -	mutex_unlock(&dev->struct_mutex); - -	request->count = entry->buf_count; -	request->size = size; - -	dma->flags = _DRM_DMA_USE_FB; - -	atomic_dec(&dev->buf_alloc); -	return 0; -} - -  /**   * Add buffers for DMA transfers (ioctl).   * @@ -1305,6 +1141,9 @@ int drm_addbufs(struct drm_device *dev, void *data,  	struct drm_buf_desc *request = data;  	int ret; +	if (drm_core_check_feature(dev, DRIVER_MODESET)) +		return -EINVAL; +  	if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))  		return -EINVAL; @@ -1316,7 +1155,7 @@ int drm_addbufs(struct drm_device *dev, void *data,  	if (request->flags & _DRM_SG_BUFFER)  		ret = drm_addbufs_sg(dev, request);  	else if (request->flags & _DRM_FB_BUFFER) -		ret = drm_addbufs_fb(dev, request); +		ret = -EINVAL;  	else  		ret = drm_addbufs_pci(dev, request); @@ -1336,7 +1175,7 @@ int drm_addbufs(struct drm_device *dev, void *data,   * \param arg pointer to a drm_buf_info structure.   * \return zero on success or a negative number on failure.   * - * Increments drm_device::buf_use while holding the drm_device::count_lock + * Increments drm_device::buf_use while holding the drm_device::buf_lock   * lock, preventing of allocating more buffers after this call. Information   * about each requested buffer is then copied into user space.   */ @@ -1348,19 +1187,22 @@ int drm_infobufs(struct drm_device *dev, void *data,  	int i;  	int count; +	if (drm_core_check_feature(dev, DRIVER_MODESET)) +		return -EINVAL; +  	if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))  		return -EINVAL;  	if (!dma)  		return -EINVAL; -	spin_lock(&dev->count_lock); +	spin_lock(&dev->buf_lock);  	if (atomic_read(&dev->buf_alloc)) { -		spin_unlock(&dev->count_lock); +		spin_unlock(&dev->buf_lock);  		return -EBUSY;  	}  	++dev->buf_use;		/* Can't allocate more after this call */ -	spin_unlock(&dev->count_lock); +	spin_unlock(&dev->buf_lock);  	for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {  		if (dma->bufs[i].buf_count) @@ -1427,6 +1269,9 @@ int drm_markbufs(struct drm_device *dev, void *data,  	int order;  	struct drm_buf_entry *entry; +	if (drm_core_check_feature(dev, DRIVER_MODESET)) +		return -EINVAL; +  	if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))  		return -EINVAL; @@ -1435,7 +1280,7 @@ int drm_markbufs(struct drm_device *dev, void *data,  	DRM_DEBUG("%d, %d, %d\n",  		  request->size, request->low_mark, request->high_mark); -	order = drm_order(request->size); +	order = order_base_2(request->size);  	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)  		return -EINVAL;  	entry = &dma->bufs[order]; @@ -1472,6 +1317,9 @@ int drm_freebufs(struct drm_device *dev, void *data,  	int idx;  	struct drm_buf *buf; +	if (drm_core_check_feature(dev, DRIVER_MODESET)) +		return -EINVAL; +  	if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))  		return -EINVAL; @@ -1508,8 +1356,8 @@ int drm_freebufs(struct drm_device *dev, void *data,   * \param arg pointer to a drm_buf_map structure.   * \return zero on success or a negative number on failure.   * - * Maps the AGP, SG or PCI buffer region with do_mmap(), and copies information - * about each buffer into user space. For PCI buffers, it calls do_mmap() with + * Maps the AGP, SG or PCI buffer region with vm_mmap(), and copies information + * about each buffer into user space. For PCI buffers, it calls vm_mmap() with   * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls   * drm_mmap_dma().   */ @@ -1524,26 +1372,27 @@ int drm_mapbufs(struct drm_device *dev, void *data,  	struct drm_buf_map *request = data;  	int i; +	if (drm_core_check_feature(dev, DRIVER_MODESET)) +		return -EINVAL; +  	if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))  		return -EINVAL;  	if (!dma)  		return -EINVAL; -	spin_lock(&dev->count_lock); +	spin_lock(&dev->buf_lock);  	if (atomic_read(&dev->buf_alloc)) { -		spin_unlock(&dev->count_lock); +		spin_unlock(&dev->buf_lock);  		return -EBUSY;  	}  	dev->buf_use++;		/* Can't allocate more after this call */ -	spin_unlock(&dev->count_lock); +	spin_unlock(&dev->buf_lock);  	if (request->count >= dma->buf_count) { -		if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) +		if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP))  		    || (drm_core_check_feature(dev, DRIVER_SG) -			&& (dma->flags & _DRM_DMA_USE_SG)) -		    || (drm_core_check_feature(dev, DRIVER_FB_DMA) -			&& (dma->flags & _DRM_DMA_USE_FB))) { +			&& (dma->flags & _DRM_DMA_USE_SG))) {  			struct drm_local_map *map = dev->agp_buffer_map;  			unsigned long token = dev->agp_buffer_token; @@ -1551,18 +1400,14 @@ int drm_mapbufs(struct drm_device *dev, void *data,  				retcode = -EINVAL;  				goto done;  			} -			down_write(¤t->mm->mmap_sem); -			virtual = do_mmap(file_priv->filp, 0, map->size, +			virtual = vm_mmap(file_priv->filp, 0, map->size,  					  PROT_READ | PROT_WRITE,  					  MAP_SHARED,  					  token); -			up_write(¤t->mm->mmap_sem);  		} else { -			down_write(¤t->mm->mmap_sem); -			virtual = do_mmap(file_priv->filp, 0, dma->byte_count, +			virtual = vm_mmap(file_priv->filp, 0, dma->byte_count,  					  PROT_READ | PROT_WRITE,  					  MAP_SHARED, 0); -			up_write(¤t->mm->mmap_sem);  		}  		if (virtual > -1024UL) {  			/* Real error */ @@ -1604,25 +1449,28 @@ int drm_mapbufs(struct drm_device *dev, void *data,  	return retcode;  } -/** - * Compute size order.  Returns the exponent of the smaller power of two which - * is greater or equal to given number. - * - * \param size size. - * \return order. - * - * \todo Can be made faster. - */ -int drm_order(unsigned long size) +int drm_dma_ioctl(struct drm_device *dev, void *data, +		  struct drm_file *file_priv)  { -	int order; -	unsigned long tmp; +	if (drm_core_check_feature(dev, DRIVER_MODESET)) +		return -EINVAL; -	for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++) ; +	if (dev->driver->dma_ioctl) +		return dev->driver->dma_ioctl(dev, data, file_priv); +	else +		return -EINVAL; +} -	if (size & (size - 1)) -		++order; +struct drm_local_map *drm_getsarea(struct drm_device *dev) +{ +	struct drm_map_list *entry; -	return order; +	list_for_each_entry(entry, &dev->maplist, head) { +		if (entry->map && entry->map->type == _DRM_SHM && +		    (entry->map->flags & _DRM_CONTAINS_LOCK)) { +			return entry->map; +		} +	} +	return NULL;  } -EXPORT_SYMBOL(drm_order); +EXPORT_SYMBOL(drm_getsarea);  | 
