FreeBSD/sys/dev/drm2/drm_bufs.c
/**
 * Add AGP buffers for DMA transfers.
 *
 * \param dev struct drm_device to which the buffers are to be added.
 * \param request pointer to a struct drm_buf_desc describing the request.
 * \return zero on success or a negative number on failure.
 *
 * After some sanity checks creates a drm_buf structure for each buffer and
 * reallocates the buffer list of the same size order to accommodate the new
 * buffers.
 */
Add AGP buffers for DMA transfers.
\param dev struct drm_device to which the buffers are to be added.
\param request pointer to a struct drm_buf_desc describing the request.
\return zero on success or a negative number on failure.

After some sanity checks creates a drm_buf structure for each buffer and
reallocates the buffer list of the same size order to accommodate the new
buffers.
Add AGP buffers for DMA transfers . \ param dev struct drm_device to which the buffers are to be added . \ param request pointer to a struct drm_buf_desc describing the request . \ return zero on success or a negative number on failure . After some sanity checks creates a drm_buf structure for each buffer and reallocates the buffer list of the same size order to accommodate the new buffers .
int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
{
	struct drm_device_dma *dma = dev->dma;
	struct drm_buf_entry *entry;
	struct drm_agp_mem *agp_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, valid;
	struct drm_buf **temp_buflist;
	if (!dma)
		return -EINVAL;
	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 = dev->agp->base + 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: %lx\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;
	valid = 0;
	list_for_each_entry(agp_entry, &dev->agp->memory, head) {
		if ((agp_offset >= agp_entry->bound) &&
		    (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
			valid = 1;
			break;
		}
	}
	if (!list_empty(&dev->agp->memory) && !valid) {
		DRM_DEBUG("zone invalid\n");
		return -EINVAL;
	}
	mtx_lock(&dev->count_lock);
	if (dev->buf_use) {
		mtx_unlock(&dev->count_lock);
		return -EBUSY;
	}
	atomic_inc(&dev->buf_alloc);
	mtx_unlock(&dev->count_lock);
	DRM_LOCK(dev);
	entry = &dma->bufs[order];
	if (entry->buf_count) {
		DRM_UNLOCK(dev);
		atomic_dec(&dev->buf_alloc);
		return -ENOMEM;	
	}
	if (count < 0 || count > 4096) {
		DRM_UNLOCK(dev);
		atomic_dec(&dev->buf_alloc);
		return -EINVAL;
	}
	entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
	    M_NOWAIT | M_ZERO);
	if (!entry->buflist) {
		DRM_UNLOCK(dev);
		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;
		buf->file_priv = NULL;
		buf->dev_priv_size = dev->driver->dev_priv_size;
		buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS,
		    M_NOWAIT | M_ZERO);
		if (!buf->dev_private) {
			entry->buf_count = count;
			drm_cleanup_buf_error(dev, entry);
			DRM_UNLOCK(dev);
			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 = realloc(dma->buflist,
	    (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
	    DRM_MEM_BUFS, M_NOWAIT);
	if (!temp_buflist) {
		drm_cleanup_buf_error(dev, entry);
		DRM_UNLOCK(dev);
		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);
	DRM_UNLOCK(dev);
	request->count = entry->buf_count;
	request->size = size;
	dma->flags = _DRM_DMA_USE_AGP;
	atomic_dec(&dev->buf_alloc);
	return 0;
}
int drm_addbufs_agp ( struct drm_device * dev , struct drm_buf_desc * request ) { struct drm_device_dma * dma = dev -> dma ; struct drm_buf_entry * entry ; struct drm_agp_mem * agp_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 , valid ; struct drm_buf * * temp_buflist ; if ( ! dma ) return - EINVAL ; 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 = dev -> agp -> base + request -> agp_start ; DRM_DEBUG ( " \n " , count ) ; DRM_DEBUG ( " \n " , order ) ; DRM_DEBUG ( " \n " , size ) ; DRM_DEBUG ( " \n " , agp_offset ) ; DRM_DEBUG ( " \n " , alignment ) ; DRM_DEBUG ( " \n " , page_order ) ; DRM_DEBUG ( " \n " , total ) ; if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return - EINVAL ; valid = 0 ; list_for_each_entry ( agp_entry , & dev -> agp -> memory , head ) { if ( ( agp_offset >= agp_entry -> bound ) && ( agp_offset + total * count <= agp_entry -> bound + agp_entry -> pages * PAGE_SIZE ) ) { valid = 1 ; break ; } } if ( ! list_empty ( & dev -> agp -> memory ) && ! valid ) { DRM_DEBUG ( " \n " ) ; return - EINVAL ; } mtx_lock ( & dev -> count_lock ) ; if ( dev -> buf_use ) { mtx_unlock ( & dev -> count_lock ) ; return - EBUSY ; } atomic_inc ( & dev -> buf_alloc ) ; mtx_unlock ( & dev -> count_lock ) ; DRM_LOCK ( dev ) ; entry = & dma -> bufs [ order ] ; if ( entry -> buf_count ) { DRM_UNLOCK ( dev ) ; atomic_dec ( & dev -> buf_alloc ) ; return - ENOMEM ; } if ( count < 0 || count > 4096 ) { DRM_UNLOCK ( dev ) ; atomic_dec ( & dev -> buf_alloc ) ; return - EINVAL ; } entry -> buflist = malloc ( count * sizeof ( * entry -> buflist ) , DRM_MEM_BUFS , M_NOWAIT | M_ZERO ) ; if ( ! entry -> buflist ) { DRM_UNLOCK ( dev ) ; 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 ; buf -> file_priv = NULL ; buf -> dev_priv_size = dev -> driver -> dev_priv_size ; buf -> dev_private = malloc ( buf -> dev_priv_size , DRM_MEM_BUFS , M_NOWAIT | M_ZERO ) ; if ( ! buf -> dev_private ) { entry -> buf_count = count ; drm_cleanup_buf_error ( dev , entry ) ; DRM_UNLOCK ( dev ) ; atomic_dec ( & dev -> buf_alloc ) ; return - ENOMEM ; } DRM_DEBUG ( " \n " , entry -> buf_count , buf -> address ) ; offset += alignment ; entry -> buf_count ++ ; byte_count += PAGE_SIZE << page_order ; } DRM_DEBUG ( " \n " , byte_count ) ; temp_buflist = realloc ( dma -> buflist , ( dma -> buf_count + entry -> buf_count ) * sizeof ( * dma -> buflist ) , DRM_MEM_BUFS , M_NOWAIT ) ; if ( ! temp_buflist ) { drm_cleanup_buf_error ( dev , entry ) ; DRM_UNLOCK ( dev ) ; 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 ( " \n " , dma -> buf_count ) ; DRM_DEBUG ( " \n " , entry -> buf_count ) ; DRM_UNLOCK ( dev ) ; request -> count = entry -> buf_count ; request -> size = size ; dma -> flags = _DRM_DMA_USE_AGP ; atomic_dec ( & dev -> buf_alloc ) ; return 0 ; }
Add AGP buffers for DMA transfers.
Add AGP buffers for DMA transfers .
/* Make sure buffers are located in AGP memory that we own */ /* May only call once for each order */ /* Set count correctly so we free the proper amount. */ /* Free the entry because it isn't valid */