aboutsummaryrefslogtreecommitdiff
path: root/bsd-core/drm_bufs.c
diff options
context:
space:
mode:
authorEric Anholt <anholt@freebsd.org>2005-02-05 08:00:14 +0000
committerEric Anholt <anholt@freebsd.org>2005-02-05 08:00:14 +0000
commit080a547d4d42d42e08a525aca9a62b5ece7616d5 (patch)
tree6996ba882ce26098fb69ba336969d88aa47dc39c /bsd-core/drm_bufs.c
parent270ca5f3cee387c10a06a4d58e50c5d0e1cea837 (diff)
- Implement drm_initmap, and extend it with the resource number to help
FreeBSD. Add drm_get_resource_{start|len} so linux-specific stuff doesn't need to be in shared code. - Fix mach64 build by using __DECONST to work around passing a const pointer to useracc, which is unfortunately not marked const. - Get rid of a lot of maplist code by not having dev->maplist be a pointer, and by sticking the link entries directly in drm_local_map_t rather than having a separate structure for the linked list. - Factor out map uninit and removal into its own routine, rather than duplicating in both drm_takedown() and drm_rmmap(). - Hook up more driver functions, and correct FreeBSD-specific bits of radeon_cp.c, making radeon work. - Baby steps towards using bus_space as we should.
Diffstat (limited to 'bsd-core/drm_bufs.c')
-rw-r--r--bsd-core/drm_bufs.c254
1 files changed, 193 insertions, 61 deletions
diff --git a/bsd-core/drm_bufs.c b/bsd-core/drm_bufs.c
index 26007a4d..0fefb8f5 100644
--- a/bsd-core/drm_bufs.c
+++ b/bsd-core/drm_bufs.c
@@ -48,19 +48,151 @@ int drm_order(unsigned long size)
return order;
}
+unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource)
+{
+ struct resource *bsr;
+ unsigned long offset;
+
+ resource = resource * 4 + 0x10;
+
+ bsr = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &resource,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (bsr == NULL) {
+ DRM_ERROR("Couldn't find resource 0x%x\n", resource);
+ return 0;
+ }
+
+ offset = rman_get_start(bsr);
+
+ bus_release_resource(dev->device, SYS_RES_MEMORY, resource, bsr);
+
+ return offset;
+}
+
+unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource)
+{
+ struct resource *bsr;
+ unsigned long len;
+
+ resource = resource * 4 + 0x10;
+
+ bsr = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &resource,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (bsr == NULL) {
+ DRM_ERROR("Couldn't find resource 0x%x\n", resource);
+ return ENOMEM;
+ }
+
+ len = rman_get_size(bsr);
+
+ bus_release_resource(dev->device, SYS_RES_MEMORY, resource, bsr);
+
+ return len;
+}
+
+int drm_initmap(drm_device_t *dev, unsigned long start, unsigned long len,
+ unsigned int resource, int type, int flags)
+{
+ drm_local_map_t *map;
+ struct resource *bsr;
+
+ if (type != _DRM_REGISTERS && type != _DRM_FRAME_BUFFER)
+ return EINVAL;
+ if (len == 0)
+ return EINVAL;
+
+ map = malloc(sizeof(*map), M_DRM, M_ZERO | M_NOWAIT);
+ if (map == NULL)
+ return ENOMEM;
+
+ map->rid = resource * 4 + 0x10;
+ bsr = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &map->rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (bsr == NULL) {
+ DRM_ERROR("Couldn't allocate %s resource\n",
+ ((type == _DRM_REGISTERS) ? "mmio" : "framebuffer"));
+ free(map, M_DRM);
+ return ENOMEM;
+ }
+
+ map->kernel_owned = 1;
+ map->type = type;
+ map->flags = flags;
+ map->bsr = bsr;
+ map->bst = rman_get_bustag(bsr);
+ map->bsh = rman_get_bushandle(bsr);
+ map->offset = start;
+ map->size = len;
+
+ if (type == _DRM_REGISTERS)
+ map->handle = rman_get_virtual(bsr);
+
+ DRM_DEBUG("initmap %d,0x%x@0x%lx/0x%lx\n", map->type, map->flags,
+ map->offset, map->size);
+
+ if (map->flags & _DRM_WRITE_COMBINING) {
+ int err;
+
+ err = drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC);
+ if (err == 0)
+ map->mtrr = 1;
+ }
+
+ DRM_LOCK();
+ TAILQ_INSERT_TAIL(&dev->maplist, map, link);
+ DRM_UNLOCK();
+
+ return 0;
+}
+
int drm_addmap(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_map_t request;
drm_local_map_t *map;
- drm_map_list_entry_t *list;
+ dma_addr_t bus_addr;
if (!(dev->flags & (FREAD|FWRITE)))
return DRM_ERR(EACCES); /* Require read/write */
DRM_COPY_FROM_USER_IOCTL( request, (drm_map_t *)data, sizeof(drm_map_t) );
- map = malloc(sizeof(*map), M_DRM, M_NOWAIT);
+ /* Only allow shared memory to be removable since we only keep enough
+ * book keeping information about shared memory to allow for removal
+ * when processes fork.
+ */
+ if ((request.flags & _DRM_REMOVABLE) && request.type != _DRM_SHM)
+ return EINVAL;
+ if ((request.offset & PAGE_MASK) || (request.size & PAGE_MASK))
+ return EINVAL;
+ if (request.offset + request.size < request.offset)
+ return EINVAL;
+
+ DRM_ERROR("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
+ request.offset, request.size, request.type);
+
+ /* Check if this is just another version of a kernel-allocated map, and
+ * just hand that back if so.
+ */
+ if (request.type == _DRM_REGISTERS || request.type == _DRM_FRAME_BUFFER)
+ {
+ DRM_LOCK();
+ TAILQ_FOREACH(map, &dev->maplist, link) {
+ if (map->kernel_owned && map->type == request.type &&
+ map->offset == request.offset) {
+ /* XXX: this size setting is questionable. */
+ map->size = request.size;
+ DRM_DEBUG("Found kernel map %d\n", request.type);
+ goto done;
+ }
+ }
+ DRM_UNLOCK();
+ }
+
+ /* Allocate a new map structure, fill it in, and do any type-specific
+ * initialization necessary.
+ */
+ map = malloc(sizeof(*map), M_DRM, M_ZERO | M_NOWAIT);
if ( !map )
return DRM_ERR(ENOMEM);
@@ -68,31 +200,10 @@ int drm_addmap(DRM_IOCTL_ARGS)
map->size = request.size;
map->type = request.type;
map->flags = request.flags;
- map->mtrr = 0;
- map->handle = 0;
-
- /* Only allow shared memory to be removable since we only keep enough
- * book keeping information about shared memory to allow for removal
- * when processes fork.
- */
- if ( (map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM ) {
- free(map, M_DRM);
- return DRM_ERR(EINVAL);
- }
- DRM_DEBUG( "offset = 0x%08lx, size = 0x%08lx, type = %d\n",
- map->offset, map->size, map->type );
- if ( (map->offset & PAGE_MASK) || (map->size & PAGE_MASK) ) {
- free(map, M_DRM);
- return DRM_ERR(EINVAL);
- }
- if (map->offset + map->size < map->offset) {
- free(map, M_DRM);
- return DRM_ERR(EINVAL);
- }
switch ( map->type ) {
case _DRM_REGISTERS:
- drm_core_ioremap(map, dev);
+ drm_ioremap(dev, map);
if (!(map->flags & _DRM_WRITE_COMBINING))
break;
/* FALLTHROUGH */
@@ -133,29 +244,34 @@ int drm_addmap(DRM_IOCTL_ARGS)
}
map->offset = map->offset + dev->sg->handle;
break;
-
+ case _DRM_CONSISTENT:
+ map->handle = drm_pci_alloc(dev, map->size, map->size,
+ 0xfffffffful, &bus_addr);
+ if (map->handle == NULL) {
+ free(map, M_DRM);
+ return ENOMEM;
+ }
+ map->offset = (unsigned long)bus_addr;
+ break;
default:
free(map, M_DRM);
return DRM_ERR(EINVAL);
}
- list = malloc(sizeof(*list), M_DRM, M_NOWAIT | M_ZERO);
- if (list == NULL) {
- free(map, M_DRM);
- return DRM_ERR(EINVAL);
- }
- list->map = map;
-
DRM_LOCK();
- TAILQ_INSERT_TAIL(dev->maplist, list, link);
- DRM_UNLOCK();
+ TAILQ_INSERT_TAIL(&dev->maplist, map, link);
+done:
+ /* Jumped to, with lock held, when a kernel map is found. */
request.offset = map->offset;
request.size = map->size;
request.type = map->type;
request.flags = map->flags;
request.mtrr = map->mtrr;
request.handle = map->handle;
+ DRM_UNLOCK();
+
+ DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", request.type, request.offset, request.size);
if ( request.type != _DRM_SHM ) {
request.handle = (void *)request.offset;
@@ -166,6 +282,44 @@ int drm_addmap(DRM_IOCTL_ARGS)
return 0;
}
+void drm_remove_map(drm_device_t *dev, drm_local_map_t *map)
+{
+ DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+
+ TAILQ_REMOVE(&dev->maplist, map, link);
+
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ if (map->bsr == NULL)
+ drm_ioremapfree(map);
+ /* FALLTHROUGH */
+ case _DRM_FRAME_BUFFER:
+ if (map->mtrr) {
+ int __unused retcode;
+
+ retcode = drm_mtrr_del(map->offset, map->size,
+ DRM_MTRR_WC);
+ DRM_DEBUG("mtrr_del = %d\n", retcode);
+ }
+ break;
+ case _DRM_SHM:
+ free(map->handle, M_DRM);
+ break;
+ case _DRM_AGP:
+ case _DRM_SCATTER_GATHER:
+ break;
+ case _DRM_CONSISTENT:
+ drm_pci_free(dev, map->size, map->handle, map->offset);
+ break;
+ }
+
+ if (map->bsr != NULL) {
+ bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid,
+ map->bsr);
+ }
+
+ free(map, M_DRM);
+}
/* Remove a map private from list and deallocate resources if the mapping
* isn't in use.
@@ -174,50 +328,28 @@ int drm_addmap(DRM_IOCTL_ARGS)
int drm_rmmap(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_map_list_entry_t *list;
drm_local_map_t *map;
drm_map_t request;
DRM_COPY_FROM_USER_IOCTL( request, (drm_map_t *)data, sizeof(request) );
DRM_LOCK();
- TAILQ_FOREACH(list, dev->maplist, link) {
- map = list->map;
+ TAILQ_FOREACH(map, &dev->maplist, link) {
if (map->handle == request.handle &&
map->flags & _DRM_REMOVABLE)
break;
}
/* No match found. */
- if (list == NULL) {
+ if (map == NULL) {
DRM_UNLOCK();
return DRM_ERR(EINVAL);
}
- TAILQ_REMOVE(dev->maplist, list, link);
- DRM_UNLOCK();
- free(list, M_DRM);
+ drm_remove_map(dev, map);
+
+ DRM_UNLOCK();
- switch (map->type) {
- case _DRM_REGISTERS:
- case _DRM_FRAME_BUFFER:
- if (map->mtrr) {
- int __unused retcode;
-
- retcode = drm_mtrr_del(map->offset, map->size,
- DRM_MTRR_WC);
- DRM_DEBUG("mtrr_del = %d\n", retcode);
- }
- drm_ioremapfree(map);
- break;
- case _DRM_SHM:
- free(map->handle, M_DRM);
- break;
- case _DRM_AGP:
- case _DRM_SCATTER_GATHER:
- break;
- }
- free(map, M_DRM);
return 0;
}