diff options
author | Eric Anholt <anholt@freebsd.org> | 2005-02-05 08:00:14 +0000 |
---|---|---|
committer | Eric Anholt <anholt@freebsd.org> | 2005-02-05 08:00:14 +0000 |
commit | 080a547d4d42d42e08a525aca9a62b5ece7616d5 (patch) | |
tree | 6996ba882ce26098fb69ba336969d88aa47dc39c /bsd-core/drm_bufs.c | |
parent | 270ca5f3cee387c10a06a4d58e50c5d0e1cea837 (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.c | 254 |
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; } |