diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 5c2c08c3..7aab8f7a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -23,12 +23,12 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * + * * Authors: Rickard E. (Rik) Faith * Kevin E. Martin * * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.17 2000/09/24 13:51:32 alanh Exp $ - * + * */ #ifdef XFree86Server @@ -119,7 +119,7 @@ void drmFree(void *pt) static char *drmStrdup(const char *s) { char *retval = NULL; - + if (s) { retval = _DRM_MALLOC(strlen(s)+1); strcpy(retval, s); @@ -213,7 +213,7 @@ int drmAvailable(void) drmVersionPtr version; int retval = 0; int fd; - + if (!access("/proc/dri/0", R_OK)) return 1; sprintf(dev_name, "/dev/dri-temp-%d", getpid()); @@ -408,7 +408,7 @@ drmVersionPtr drmGetVersion(int fd) version->date = NULL; version->desc_len = 0; version->desc = NULL; - + if (ioctl(fd, DRM_IOCTL_VERSION, version)) { drmFreeKernelVersion(version); return NULL; @@ -421,7 +421,7 @@ drmVersionPtr drmGetVersion(int fd) version->date = drmMalloc(version->date_len + 1); if (version->desc_len) version->desc = drmMalloc(version->desc_len + 1); - + if (ioctl(fd, DRM_IOCTL_VERSION, version)) { drmFreeKernelVersion(version); return NULL; @@ -503,7 +503,7 @@ int drmAddMap(int fd, map.offset = offset; #ifdef __alpha__ /* Make sure we add the bus_base to all but shm */ - if (type != DRM_SHM) + if (type != DRM_SHM) map.offset += BUS_BASE; #endif map.size = size; @@ -519,14 +519,14 @@ int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, int agp_offset) { drm_buf_desc_t request; - + request.count = count; request.size = size; request.low_mark = 0; request.high_mark = 0; request.flags = flags; request.agp_start = agp_offset; - + if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno; return request.count; } @@ -542,16 +542,16 @@ int drmMarkBufs(int fd, double low, double high) if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return -EINVAL; if (!info.count) return -EINVAL; - + if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) return -ENOMEM; - + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { int retval = -errno; drmFree(info.list); return retval; } - + for (i = 0; i < info.count; i++) { info.list[i].low_mark = low * info.list[i].count; info.list[i].high_mark = high * info.list[i].count; @@ -562,7 +562,7 @@ int drmMarkBufs(int fd, double low, double high) } } drmFree(info.list); - + return 0; } @@ -630,7 +630,7 @@ drmBufInfoPtr drmGetBufInfo(int fd) if (info.count) { if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) return NULL; - + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { drmFree(info.list); return NULL; @@ -657,7 +657,7 @@ drmBufMapPtr drmMapBufs(int fd) drm_buf_map_t bufs; drmBufMapPtr retval; int i; - + bufs.count = 0; bufs.list = NULL; if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) return NULL; @@ -689,7 +689,7 @@ drmBufMapPtr drmMapBufs(int fd) int drmUnmapBufs(drmBufMapPtr bufs) { int i; - + for (i = 0; i < bufs->count; i++) { munmap(bufs->list[i].address, bufs->list[i].total); } @@ -712,7 +712,7 @@ int drmDMA(int fd, drmDMAReqPtr request) dma.request_sizes = request->request_sizes; if (ioctl(fd, DRM_IOCTL_DMA, &dma)) return -errno; request->granted_count = dma.granted_count; - + return 0; } @@ -728,7 +728,7 @@ int drmGetLock(int fd, drmContext context, drmLockFlags flags) if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; - + while (ioctl(fd, DRM_IOCTL_LOCK, &lock)) ; return 0; @@ -827,7 +827,7 @@ int drmGetContextFlags(int fd, drmContext context, drmContextFlagsPtr flags) if (ctx.flags & _DRM_CONTEXT_2DONLY) *flags |= DRM_CONTEXT_2DONLY; return 0; } - + int drmDestroyContext(int fd, drmContext handle) { drm_ctx_t ctx; @@ -989,6 +989,28 @@ unsigned int drmAgpDeviceId(int fd) return i.id_device; } +int drmScatterGatherAlloc(int fd, unsigned long size, unsigned long *handle) +{ + drm_scatter_gather_t sg; + + *handle = 0; + sg.size = size; + sg.handle = 0; + if (ioctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) return -errno; + *handle = sg.handle; + return 0; +} + +int drmScatterGatherFree(int fd, unsigned long handle) +{ + drm_scatter_gather_t sg; + + sg.size = 0; + sg.handle = handle; + if (ioctl(fd, DRM_IOCTL_SG_FREE, &sg)) return -errno; + return 0; +} + int drmError(int err, const char *label) { switch (err) { @@ -1074,7 +1096,7 @@ void *drmGetContextTag(int fd, drmContext context) { drmHashEntry *entry = drmGetEntry(fd); void *value; - + if (drmHashLookup(entry->tagTable, context, &value)) return NULL; return value; @@ -1108,7 +1130,7 @@ static void drmSIGIOHandler(int interrupt, void *closure) #if 0 fprintf(stderr, "Got %s\n", buf); #endif - + for (pt = buf; *pt != ' '; ++pt); /* Find first space */ ++pt; old = strtol(pt, &pt, 0); @@ -1141,7 +1163,7 @@ int drmRemoveSIGIOHandler(int fd) drmHashEntry *entry = drmGetEntry(fd); entry->f = NULL; - + return xf86RemoveSIGIOHandler(fd); } #endif diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 9fe0038f..42e13846 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -32,7 +32,7 @@ export-objs := $(patsubst %.o,%_drv.o,$(module-list)) # lib-objs := init.o memory.o proc.o auth.o context.o drawable.o bufs.o -lib-objs += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o +lib-objs += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o scatter.o ifeq ($(CONFIG_AGP),y) lib-objs += agpsupport.o @@ -45,7 +45,7 @@ endif gamma-objs := gamma_drv.o gamma_dma.o tdfx-objs := tdfx_drv.o tdfx_context.o r128-objs := r128_drv.o r128_cce.o r128_context.o r128_bufs.o \ - r128_state.o + r128_state.o r128_pcigart.o radeon-objs := radeon_drv.o radeon_cp.o radeon_context.o radeon_bufs.o \ radeon_state.o ffb-objs := ffb_drv.o ffb_context.o diff --git a/linux-core/drmP.h b/linux-core/drmP.h index affeae70..5dca6ca6 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -109,6 +109,8 @@ #define DRM_MEM_TOTALAGP 16 #define DRM_MEM_BOUNDAGP 17 #define DRM_MEM_CTXBITMAP 18 +#define DRM_MEM_SG 19 +#define DRM_MEM_SGLISTS 20 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) @@ -480,7 +482,8 @@ typedef struct drm_device_dma { unsigned long *pagelist; unsigned long byte_count; enum { - _DRM_DMA_USE_AGP = 0x01 + _DRM_DMA_USE_AGP = 0x01, + _DRM_DMA_USE_SG = 0x02 } flags; /* DMA support */ @@ -512,6 +515,13 @@ typedef struct drm_agp_head { } drm_agp_head_t; #endif +typedef struct drm_sg_mem { + unsigned long handle; + void *virtual; + int pages; + struct page **pagelist; +} drm_sg_mem_t; + typedef struct drm_sigdata { int context; drm_hw_lock_t *lock; @@ -599,6 +609,7 @@ typedef struct drm_device { #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) drm_agp_head_t *agp; #endif + drm_sg_mem_t *sg; /* Scatter / gather memory */ unsigned long *ctx_bitmap; void *dev_private; drm_sigdata_t sigdata; /* For block_all_signals */ @@ -639,6 +650,9 @@ extern unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma, extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern unsigned long drm_vm_sg_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); #else /* Return type changed in 2.3.23 */ extern struct page *drm_vm_nopage(struct vm_area_struct *vma, @@ -653,6 +667,9 @@ extern struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma, extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); #endif extern void drm_vm_open(struct vm_area_struct *vma); extern void drm_vm_close(struct vm_area_struct *vma); @@ -831,5 +848,14 @@ extern int drm_agp_free_memory(agp_memory *handle); extern int drm_agp_bind_memory(agp_memory *handle, off_t start); extern int drm_agp_unbind_memory(agp_memory *handle); #endif + + /* Scatter/gather memory supprt (scatter.c) */ +extern int drm_sg_alloc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_sg_free(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +#define page_to_pfn( page ) ((unsigned long)((page)-mem_map)) + #endif #endif diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index cf258925..977be8ea 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -107,6 +107,8 @@ static drm_ioctl_desc_t r128_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, #endif + [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { drm_sg_alloc, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { drm_sg_free, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_cce_init, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_START)] = { r128_cce_start, 1, 1 }, @@ -309,6 +311,12 @@ static int r128_takedown(drm_device_t *dev) /* Do nothing here, because this is all handled in the AGP/GART driver. */ break; + case _DRM_SCATTER_GATHER: + if(dev->sg) { + drm_sg_cleanup(dev->sg); + dev->sg = NULL; + } + break; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); } diff --git a/linux/Makefile.kernel b/linux/Makefile.kernel index 9fe0038f..42e13846 100644 --- a/linux/Makefile.kernel +++ b/linux/Makefile.kernel @@ -32,7 +32,7 @@ export-objs := $(patsubst %.o,%_drv.o,$(module-list)) # lib-objs := init.o memory.o proc.o auth.o context.o drawable.o bufs.o -lib-objs += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o +lib-objs += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o scatter.o ifeq ($(CONFIG_AGP),y) lib-objs += agpsupport.o @@ -45,7 +45,7 @@ endif gamma-objs := gamma_drv.o gamma_dma.o tdfx-objs := tdfx_drv.o tdfx_context.o r128-objs := r128_drv.o r128_cce.o r128_context.o r128_bufs.o \ - r128_state.o + r128_state.o r128_pcigart.o radeon-objs := radeon_drv.o radeon_cp.o radeon_context.o radeon_bufs.o \ radeon_state.o ffb-objs := ffb_drv.o ffb_context.o diff --git a/linux/Makefile.linux b/linux/Makefile.linux index 862bb6c3..3422c161 100644 --- a/linux/Makefile.linux +++ b/linux/Makefile.linux @@ -46,12 +46,12 @@ # *** Setup # **** End of SMP/MODVERSIONS detection - +CC= gcc MODS= gamma.o tdfx.o r128.o radeon.o LIBS= libdrm.a DRMOBJS= init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ - lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o + lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o scatter.o DRMHEADERS= drm.h drmP.h compat-pre24.h GAMMAOBJS= gamma_drv.o gamma_dma.o @@ -141,7 +141,8 @@ MGAHEADERS= mga_drv.h $(DRMHEADERS) I810OBJS= i810_drv.o i810_dma.o i810_bufs.o i810_context.o I810HEADERS= i810_drv.h $(DRMHEADERS) -R128OBJS= r128_drv.o r128_cce.o r128_bufs.o r128_context.o r128_state.o +R128OBJS= r128_drv.o r128_cce.o r128_bufs.o r128_context.o r128_state.o \ + r128_pcigart.o R128HEADERS= r128_drv.h r128_drm.h $(DRMHEADERS) RADEONOBJS= radeon_drv.o radeon_cp.o radeon_bufs.o radeon_context.o \ diff --git a/linux/bufs.c b/linux/bufs.c index 28e0eb5f..127ef142 100644 --- a/linux/bufs.c +++ b/linux/bufs.c @@ -111,6 +111,10 @@ int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd, map->offset = map->offset + dev->agp->base; break; #endif + case _DRM_SCATTER_GATHER: + if(!dev->sg) return -EINVAL; + map->offset = map->offset + dev->sg->handle; + break; default: drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -EINVAL; diff --git a/linux/drm.h b/linux/drm.h index dc3d262d..f657eab9 100644 --- a/linux/drm.h +++ b/linux/drm.h @@ -124,10 +124,11 @@ typedef struct drm_control { } drm_control_t; typedef enum drm_map_type { - _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ - _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2, /* shared, cached */ - _DRM_AGP = 3 /* AGP/GART */ + _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /* no caching, no core dump */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3, /* AGP/GART */ + _DRM_SCATTER_GATHER = 4 /* Scatter/gather memory for PCI DMA */ } drm_map_type_t; typedef enum drm_map_flags { @@ -192,7 +193,8 @@ typedef struct drm_buf_desc { int high_mark; /* High water mark */ enum { _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ - _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ + _DRM_AGP_BUFFER = 0x02, /* Buffer is in agp space */ + _DRM_SG_BUFFER = 0x04 /* Scatter/gather memory buffer */ } flags; unsigned long agp_start; /* Start address of where the agp buffers * are in the agp aperture */ @@ -298,6 +300,11 @@ typedef struct drm_agp_info { unsigned short id_device; } drm_agp_info_t; +typedef struct drm_scatter_gather { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for mapping / unmapping */ +} drm_scatter_gather_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) #define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) @@ -345,6 +352,9 @@ typedef struct drm_agp_info { #define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) #define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) +#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t) +#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t) + /* Mga specific ioctls */ #define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) #define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t) diff --git a/linux/drmP.h b/linux/drmP.h index affeae70..5dca6ca6 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -109,6 +109,8 @@ #define DRM_MEM_TOTALAGP 16 #define DRM_MEM_BOUNDAGP 17 #define DRM_MEM_CTXBITMAP 18 +#define DRM_MEM_SG 19 +#define DRM_MEM_SGLISTS 20 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) @@ -480,7 +482,8 @@ typedef struct drm_device_dma { unsigned long *pagelist; unsigned long byte_count; enum { - _DRM_DMA_USE_AGP = 0x01 + _DRM_DMA_USE_AGP = 0x01, + _DRM_DMA_USE_SG = 0x02 } flags; /* DMA support */ @@ -512,6 +515,13 @@ typedef struct drm_agp_head { } drm_agp_head_t; #endif +typedef struct drm_sg_mem { + unsigned long handle; + void *virtual; + int pages; + struct page **pagelist; +} drm_sg_mem_t; + typedef struct drm_sigdata { int context; drm_hw_lock_t *lock; @@ -599,6 +609,7 @@ typedef struct drm_device { #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) drm_agp_head_t *agp; #endif + drm_sg_mem_t *sg; /* Scatter / gather memory */ unsigned long *ctx_bitmap; void *dev_private; drm_sigdata_t sigdata; /* For block_all_signals */ @@ -639,6 +650,9 @@ extern unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma, extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern unsigned long drm_vm_sg_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); #else /* Return type changed in 2.3.23 */ extern struct page *drm_vm_nopage(struct vm_area_struct *vma, @@ -653,6 +667,9 @@ extern struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma, extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); #endif extern void drm_vm_open(struct vm_area_struct *vma); extern void drm_vm_close(struct vm_area_struct *vma); @@ -831,5 +848,14 @@ extern int drm_agp_free_memory(agp_memory *handle); extern int drm_agp_bind_memory(agp_memory *handle, off_t start); extern int drm_agp_unbind_memory(agp_memory *handle); #endif + + /* Scatter/gather memory supprt (scatter.c) */ +extern int drm_sg_alloc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_sg_free(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +#define page_to_pfn( page ) ((unsigned long)((page)-mem_map)) + #endif #endif diff --git a/linux/memory.c b/linux/memory.c index 261fb34a..6128010c 100644 --- a/linux/memory.c +++ b/linux/memory.c @@ -66,6 +66,8 @@ static drm_mem_stats_t drm_mem_stats[] = { [DRM_MEM_TOTALAGP] = { "totalagp" }, [DRM_MEM_BOUNDAGP] = { "boundagp" }, [DRM_MEM_CTXBITMAP] = { "ctxbitmap"}, + [DRM_MEM_SG] = { "sg dma" }, + [DRM_MEM_SGLISTS] = { "sglist" }, { NULL, 0, } /* Last entry must be null */ }; diff --git a/linux/proc.c b/linux/proc.c index ca062a09..c18ed688 100644 --- a/linux/proc.c +++ b/linux/proc.c @@ -165,9 +165,9 @@ static int _drm_vm_info(char *buf, char **start, off_t offset, int len, drm_device_t *dev = (drm_device_t *)data; drm_map_t *map; /* Hardcoded from _DRM_FRAME_BUFFER, - _DRM_REGISTERS, _DRM_SHM, and - _DRM_AGP. */ - const char *types[] = { "FB", "REG", "SHM", "AGP" }; + _DRM_REGISTERS, _DRM_SHM, + _DRM_AGP, and _DRM_SCATTER_GATHER. */ + const char *types[] = { "FB", "REG", "SHM", "AGP", "SG" }; const char *type; int i; @@ -178,7 +178,7 @@ static int _drm_vm_info(char *buf, char **start, off_t offset, int len, "address mtrr\n\n"); for (i = 0; i < dev->map_count; i++) { map = dev->maplist[i]; - if (map->type < 0 || map->type > 3) type = "??"; + if (map->type < 0 || map->type > 4) type = "??"; else type = types[map->type]; DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", i, @@ -411,7 +411,7 @@ static int _drm_vma_info(char *buf, char **start, off_t offset, int len, pte = pte_offset(pmd, i); if (pte_present(*pte)) { address = __pa(pte_page(*pte)) - + (i & (PAGE_SIZE-1)); + /*+ (i & (PAGE_SIZE-1));*/ DRM_PROC_PRINT(" 0x%08lx -> 0x%08lx" " %c%c%c%c%c\n", i, diff --git a/linux/r128_bufs.c b/linux/r128_bufs.c index a060749e..39b09ed0 100644 --- a/linux/r128_bufs.c +++ b/linux/r128_bufs.c @@ -74,7 +74,7 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, total = PAGE_SIZE << page_order; byte_count = 0; - agp_offset = dev->agp->base + request.agp_start; + agp_offset = request.agp_start; DRM_DEBUG("count: %d\n", count); DRM_DEBUG("order: %d\n", order); @@ -125,7 +125,8 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, buf->order = order; buf->used = 0; buf->offset = (dma->byte_count + offset); - buf->address = (void *)(agp_offset + offset); + buf->bus_address = agp_offset + offset; + buf->address = (void *)(agp_offset + dev->agp->base + offset); buf->next = NULL; buf->waiting = 0; buf->pending = 0; @@ -185,6 +186,152 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, } #endif +int r128_addbufs_sg(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *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; + + if (!dma) return -EINVAL; + + if (copy_from_user(&request, + (drm_buf_desc_t *)arg, + sizeof(request))) + return -EFAULT; + + 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: %ld\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); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->buf_size = size; + entry->page_order = page_order; + offset = 0; + + for (offset = 0; + entry->buf_count < count; + offset += alignment, ++entry->buf_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 + dev->sg->handle + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_priv_size = sizeof(drm_r128_buf_priv_t); + buf->dev_private = drm_alloc(sizeof(drm_r128_buf_priv_t), + DRM_MEM_BUFS); + memset(buf->dev_private, 0, buf->dev_priv_size); + +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + + byte_count += PAGE_SIZE << page_order; + + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + + DRM_DEBUG("byte_count: %d\n", byte_count); + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; + + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + if (copy_to_user((drm_buf_desc_t *)arg, + &request, + sizeof(request))) + return -EFAULT; + dma->flags = _DRM_DMA_USE_SG; + + atomic_dec(&dev->buf_alloc); + return 0; +} + int r128_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -193,7 +340,7 @@ int r128_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, drm_r128_private_t *dev_priv = dev->dev_private; drm_buf_desc_t request; - if (!dev_priv || dev_priv->is_pci) return -EINVAL; + if (!dev_priv) return -EINVAL; if (copy_from_user(&request, (drm_buf_desc_t *)arg, @@ -201,8 +348,14 @@ int r128_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, return -EFAULT; #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + if (dev_priv->is_pci && (request.flags & _DRM_AGP_BUFFER)) + return -EINVAL; + if (!dev_priv->is_pci && (request.flags & _DRM_SG_BUFFER)) + return -EINVAL; if (request.flags & _DRM_AGP_BUFFER) return r128_addbufs_agp(inode, filp, cmd, arg); + if (request.flags & _DRM_SG_BUFFER) + return r128_addbufs_sg(inode, filp, cmd, arg); else #endif return -EINVAL; @@ -222,7 +375,7 @@ int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, drm_buf_map_t request; int i; - if (!dma || !dev_priv || dev_priv->is_pci) return -EINVAL; + if (!dma || !dev_priv) return -EINVAL; DRM_DEBUG("\n"); @@ -240,7 +393,8 @@ int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, return -EFAULT; if (request.count >= dma->buf_count) { - if (dma->flags & _DRM_DMA_USE_AGP) { + if (dma->flags & _DRM_DMA_USE_AGP || + dma->flags & _DRM_DMA_USE_SG) { drm_map_t *map; map = dev_priv->buffers; diff --git a/linux/r128_cce.c b/linux/r128_cce.c index 6df2b45a..ae681828 100644 --- a/linux/r128_cce.c +++ b/linux/r128_cce.c @@ -37,6 +37,7 @@ #include #define R128_FIFO_DEBUG 0 +#define DEBUG_RING_AFTER_INIT 0 /* CCE microcode (from ATI) */ @@ -128,6 +129,12 @@ static void r128_status( drm_r128_private_t *dev_priv ) (unsigned int)R128_READ( R128_PM4_MICRO_CNTL ) ); printk( "PM4_BUFFER_CNTL = 0x%08x\n", (unsigned int)R128_READ( R128_PM4_BUFFER_CNTL ) ); + printk( "PM4_BUFFER_DL_WPTR = 0x%08x\n", + (unsigned int)R128_READ( R128_PM4_BUFFER_DL_WPTR ) ); + printk( "PM4_BUFFER_DL_RPTR = 0x%08x\n", + (unsigned int)R128_READ( R128_PM4_BUFFER_DL_RPTR ) ); + printk( "*ring.head = 0x%08x\n", + (unsigned int)*dev_priv->ring.head ); } #endif @@ -228,7 +235,13 @@ static int r128_do_cce_idle( drm_r128_private_t *dev_priv ) int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { - if ( *dev_priv->ring.head == dev_priv->ring.tail ) { +#if 0 + if ( R128_READ( R128_PM4_BUFFER_DL_WPTR ) == + R128_READ( R128_PM4_BUFFER_DL_RPTR ) ) +#else + if ( *dev_priv->ring.head == dev_priv->ring.tail ) +#endif + { int pm4stat = R128_READ( R128_PM4_STAT ); if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size ) && @@ -241,7 +254,7 @@ static int r128_do_cce_idle( drm_r128_private_t *dev_priv ) } #if R128_FIFO_DEBUG - DRM_ERROR( "failed!\n" ); + DRM_ERROR( "cce idle failed!\n" ); r128_status( dev_priv ); #endif return -EBUSY; @@ -335,7 +348,11 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev ) /* The manual (p. 2) says this address is in "VM space". This * means it's an offset from the start of AGP space. */ - ring_start = dev_priv->cce_ring->offset - dev->agp->base; + if ( !dev_priv->is_pci ) { + ring_start = dev_priv->cce_ring->offset - dev->agp->base; + } else { + ring_start = dev_priv->cce_ring->offset - dev->sg->handle; + } R128_WRITE( R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET ); R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); @@ -343,8 +360,23 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev ) /* DL_RPTR_ADDR is a physical address in AGP space. */ *dev_priv->ring.head = 0; - R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, - dev_priv->ring_rptr->offset ); + if ( !dev_priv->is_pci ) { + R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, + dev_priv->ring_rptr->offset ); + } else { + drm_sg_mem_t *entry = dev->sg; + unsigned long tmp_ofs, page_ofs; + + tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle; + page_ofs = tmp_ofs >> PAGE_SHIFT; + + R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, + virt_to_bus(entry->pagelist[page_ofs]->virtual)); + + DRM_INFO( "ring rptr: offset=0x%08lx handle=0x%08lx\n", + virt_to_bus(entry->pagelist[page_ofs]->virtual), + entry->handle + tmp_ofs ); + } /* Set watermark control */ R128_WRITE( R128_PM4_BUFFER_WM_CNTL, @@ -379,7 +411,8 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) * Fail here so we can remove all checks for PCI cards around * the CCE ring code. */ - if ( dev_priv->is_pci ) { + + if ( dev_priv->is_pci && !dev->sg) { drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; return -EINVAL; @@ -390,10 +423,12 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT ) { drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; + printk("USec timeout is screwed\n"); return -EINVAL; } dev_priv->cce_mode = init->cce_mode; + dev_priv->cce_secure = init->cce_secure; /* GH: Simple idle check. */ @@ -409,6 +444,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) ( init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM ) ) { drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; + printk("CCE mode is screwed\n"); return -EINVAL; } @@ -479,9 +515,25 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DO_IOREMAP( dev_priv->cce_ring ); - DO_IOREMAP( dev_priv->ring_rptr ); - DO_IOREMAP( dev_priv->buffers ); + if(dev_priv->is_pci) { + printk("dev->sg->virtual (cce_ring): %p\n", dev->sg->virtual); + + dev_priv->cce_ring->handle = + (void *)dev_priv->cce_ring->offset; + printk("cce_ring : %p\n", dev_priv->cce_ring->handle); + + dev_priv->ring_rptr->handle = + (void *)dev_priv->ring_rptr->offset; + printk("ring_rptr : %p\n", dev_priv->ring_rptr->handle); + + dev_priv->buffers->handle = (void *)dev_priv->buffers->offset; + printk("buffers : %p\n", dev_priv->buffers->handle); + } else { + DO_IOREMAP( dev_priv->cce_ring ); + DO_IOREMAP( dev_priv->ring_rptr ); + DO_IOREMAP( dev_priv->buffers ); + } + #if 0 if ( !dev_priv->is_pci ) { DO_IOREMAP( dev_priv->agp_textures ); @@ -507,10 +559,83 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) R128_WRITE( R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch ); + if ( dev_priv->is_pci && r128_pcigart_init( dev ) < 0) { + DRM_ERROR( "failed to init PCIGART!\n" ); + drm_free( dev_priv, sizeof(*dev_priv), + DRM_MEM_DRIVER ); + dev->dev_private = NULL; + return -EINVAL; + } + + printk("Initializing ring buffer\n"); r128_cce_init_ring_buffer( dev ); + printk("Initializing microcode\n"); r128_cce_load_microcode( dev_priv ); + printk("Reseting engine\n"); r128_do_engine_reset( dev ); + printk("Waiting for idle\n"); + r128_do_wait_for_idle( dev_priv ); + + { + printk( "GUI_STAT = 0x%08x\n", + (unsigned int)R128_READ( R128_GUI_STAT ) ); + printk( "PM4_STAT = 0x%08x\n", + (unsigned int)R128_READ( R128_PM4_STAT ) ); + printk( "PM4_BUFFER_DL_WPTR = 0x%08x\n", + (unsigned int)R128_READ( R128_PM4_BUFFER_DL_WPTR ) ); + printk( "PM4_BUFFER_DL_RPTR = 0x%08x\n", + (unsigned int)R128_READ( R128_PM4_BUFFER_DL_RPTR ) ); + printk( "PM4_MICRO_CNTL = 0x%08x\n", + (unsigned int)R128_READ( R128_PM4_MICRO_CNTL ) ); + printk( "PM4_BUFFER_CNTL = 0x%08x\n", + (unsigned int)R128_READ( R128_PM4_BUFFER_CNTL ) ); + printk( "PM4_BUFFER_OFFSET = 0x%08x\n", + (unsigned int)R128_READ( R128_PM4_BUFFER_OFFSET ) ); + printk( "PM4_BUFFER_DL_RPTR_ADDR = 0x%08x\n", + (unsigned int)R128_READ( R128_PM4_BUFFER_DL_RPTR_ADDR )); + printk( "PCI_GART_PAGE = 0x%08x\n", + (unsigned int)R128_READ( R128_PCI_GART_PAGE ) ); + printk( "BM_CHUNK_0_VAL = 0x%08x\n", + (unsigned int)R128_READ( R128_BM_CHUNK_0_VAL ) ); + } + +#ifdef DEBUG_RING_AFTER_INIT + { + int last_dispatch; + RING_LOCALS; + + r128_do_cce_start( dev_priv ); + + printk("Doing a test write to dispatch register\n"); + + BEGIN_RING( 2 ); + OUT_RING( CCE_PACKET0( R128_LAST_DISPATCH_REG, 0 ) ); + OUT_RING( 0xcafebabe ); + ADVANCE_RING(); + + r128_do_cce_flush( dev_priv ); + r128_do_cce_idle( dev_priv ); + last_dispatch = R128_READ( R128_LAST_DISPATCH_REG ); + printk("last_dispatch = 0x%x\n", last_dispatch); + + BEGIN_RING( 2 ); + OUT_RING( CCE_PACKET0( R128_LAST_DISPATCH_REG, 0 ) ); + OUT_RING( 0 ); + ADVANCE_RING(); + + r128_do_cce_flush( dev_priv ); + r128_do_cce_idle( dev_priv ); + last_dispatch = R128_READ( R128_LAST_DISPATCH_REG ); + printk("last_dispatch 2 = 0x%x\n", last_dispatch); + + r128_do_wait_for_idle( dev_priv ); + r128_do_engine_reset( dev ); + r128_do_wait_for_idle( dev_priv ); + } +#endif + + printk("Returning zero\n"); return 0; } @@ -519,9 +644,11 @@ static int r128_do_cleanup_cce( drm_device_t *dev ) if ( dev->dev_private ) { drm_r128_private_t *dev_priv = dev->dev_private; - DO_IOREMAPFREE( dev_priv->cce_ring ); - DO_IOREMAPFREE( dev_priv->ring_rptr ); - DO_IOREMAPFREE( dev_priv->buffers ); + if(!dev_priv->is_pci) { + DO_IOREMAPFREE( dev_priv->cce_ring ); + DO_IOREMAPFREE( dev_priv->ring_rptr ); + DO_IOREMAPFREE( dev_priv->buffers ); + } #if 0 if ( !dev_priv->is_pci ) { DO_IOREMAPFREE( dev_priv->agp_textures ); diff --git a/linux/r128_drv.c b/linux/r128_drv.c index cf258925..977be8ea 100644 --- a/linux/r128_drv.c +++ b/linux/r128_drv.c @@ -107,6 +107,8 @@ static drm_ioctl_desc_t r128_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, #endif + [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { drm_sg_alloc, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { drm_sg_free, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_cce_init, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_START)] = { r128_cce_start, 1, 1 }, @@ -309,6 +311,12 @@ static int r128_takedown(drm_device_t *dev) /* Do nothing here, because this is all handled in the AGP/GART driver. */ break; + case _DRM_SCATTER_GATHER: + if(dev->sg) { + drm_sg_cleanup(dev->sg); + dev->sg = NULL; + } + break; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); } diff --git a/linux/r128_drv.h b/linux/r128_drv.h index 08ef5dc9..62eb9bd4 100644 --- a/linux/r128_drv.h +++ b/linux/r128_drv.h @@ -59,6 +59,7 @@ typedef struct drm_r128_private { int cce_mode; int cce_fifo_size; + int cce_secure; int cce_running; drm_r128_freelist_t *head; @@ -90,6 +91,9 @@ typedef struct drm_r128_private { u32 depth_pitch_offset_c; u32 span_pitch_offset_c; + void *pci_gart_page; + unsigned long phys_pci_gart_page; + drm_map_t *sarea; drm_map_t *fb; drm_map_t *mmio; @@ -216,6 +220,11 @@ extern int r128_context_switch_complete(drm_device_t *dev, int new); #define R128_AUX3_SC_TOP 0x168c #define R128_AUX3_SC_BOTTOM 0x1690 +#define R128_BM_CHUNK_0_VAL 0x0a18 +# define R128_BM_PTR_FORCE_TO_PCI (1 << 21) +# define R128_BM_PM4_RD_FORCE_TO_PCI (1 << 22) +# define R128_BM_GLOBAL_FORCE_TO_PCI (1 << 23) + #define R128_BRUSH_DATA0 0x1480 #define R128_BUS_CNTL 0x0030 # define R128_BUS_MASTER_DIS (1 << 6) @@ -275,6 +284,7 @@ extern int r128_context_switch_complete(drm_device_t *dev, int new); # define R128_PC_FLUSH_ALL 0x00ff # define R128_PC_BUSY (1 << 31) +#define R128_PCI_GART_PAGE 0x017c #define R128_PRIM_TEX_CNTL_C 0x1cb0 #define R128_SCALE_3D_CNTL 0x1a00 diff --git a/linux/r128_pcigart.c b/linux/r128_pcigart.c new file mode 100644 index 00000000..54ca8f0e --- /dev/null +++ b/linux/r128_pcigart.c @@ -0,0 +1,156 @@ +/* r128_pcigart.c -- Rage 128 PCI GART support -*- linux-c -*- + * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com + * + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Gareth Hughes + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "r128_drv.h" + +#include /* For task queue support */ +#include + + + + +static unsigned long r128_alloc_pages( void ) +{ + unsigned long address; + unsigned long addr_end; + struct page *page; + + DRM_INFO( "%s\n", __FUNCTION__ ); + + address = __get_free_pages( GFP_KERNEL, 3 ); + if ( address == 0UL ) { + return 0; + } + + addr_end = address + ((PAGE_SIZE * (1 << 3)) - 1); + for (page = virt_to_page(address); + page <= virt_to_page(addr_end); + page++) { + atomic_inc( &page->count ); + SetPageReserved( page ); + } + + DRM_INFO( "%s: returning 0x%08lx\n", __FUNCTION__, address ); + return address; +} + +static void r128_free_pages( unsigned long address ) +{ + unsigned long addr_end; + struct page *page; + + DRM_INFO( "%s\n", __FUNCTION__ ); + if ( !address ) return; + + addr_end = address + ((PAGE_SIZE * (1 << 3)) - 1); + + for (page = virt_to_page(address); + page <= virt_to_page(addr_end); + page++) { + atomic_dec( &page->count ); + ClearPageReserved( page ); + } + + free_pages( address , 3 ); +} + +int r128_pcigart_init( drm_device_t *dev ) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + drm_sg_mem_t *entry = dev->sg; + unsigned long address; + unsigned long pages; + u32 *pci_gart; + int i; + DRM_INFO( "%s\n", __FUNCTION__ ); + +#if 0 + dev_priv->phys_pci_gart_page = 0; + dev_priv->pci_gart_page = NULL; + + return 0; +#endif + + if ( !entry ) { + DRM_ERROR( "no scatter/gather memory!\n" ); + return -EINVAL; + } + + /* 32 MB aperture is the largest size */ + pages = ( entry->pages <= 8192 ) + ? entry->pages : 8192; + + address = r128_alloc_pages(); + + + if ( !address ) { + DRM_ERROR( "cannot allocate PCI GART page!\n" ); + return -ENOMEM; + } + + dev_priv->pci_gart_page = dev_priv->phys_pci_gart_page = address; + + DRM_INFO( "%s: phys=0x%08lx virt=%p\n", + __FUNCTION__, dev_priv->phys_pci_gart_page, + dev_priv->pci_gart_page ); + + pci_gart = (u32 *)dev_priv->pci_gart_page; + + for ( i = 0; i < 8192 ; i++) pci_gart[i] = 0; + for ( i = 0 ; i < pages ; i++ ) { + pci_gart[i] = virt_to_bus( entry->pagelist[i]->virtual ); + } + + DRM_INFO( "%s: writing PCI_GART_PAGE...\n", __FUNCTION__ ); + R128_WRITE( R128_PCI_GART_PAGE, virt_to_bus((void *)address) ); + DRM_INFO( "%s: writing PCI_GART_PAGE... done.\n", __FUNCTION__ ); + + asm volatile ( "wbinvd" ::: "memory" ); + + return 0; +} + +int r128_pcigart_cleanup( drm_device_t *dev ) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + DRM_INFO( "%s\n", __FUNCTION__ ); +#if 0 + if ( dev_priv->pci_gart_page ) { + iounmap( dev_priv->pci_gart_page ); + } +#endif + if ( dev_priv->phys_pci_gart_page ) { + r128_free_pages( dev_priv->phys_pci_gart_page ); + } + + return 0; +} diff --git a/linux/r128_state.c b/linux/r128_state.c index ba003929..1a86747c 100644 --- a/linux/r128_state.c +++ b/linux/r128_state.c @@ -613,7 +613,10 @@ static void r128_cce_dispatch_vertex( drm_device_t *dev, drm_r128_buf_priv_t *buf_priv = buf->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; int format = sarea_priv->vc_format; + int offset = buf->bus_address; +/* int offset = dev_priv->buffers->offset + buf->offset - dev->agp->base; + */ int size = buf->used; int prim = buf_priv->prim; int i = 0; @@ -705,8 +708,7 @@ static void r128_cce_dispatch_indirect( drm_device_t *dev, r128_update_ring_snapshot( dev_priv ); if ( start != end ) { - int offset = (dev_priv->buffers->offset - dev->agp->base - + buf->offset + start); + int offset = (buf->bus_address + start); int dwords = (end - start + 3) / sizeof(u32); /* Indirect buffer data must be an even number of @@ -766,11 +768,12 @@ static void r128_cce_dispatch_indices( drm_device_t *dev, int start, int end, int count ) { + drm_device_dma_t *dma = dev->dma; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_buf_priv_t *buf_priv = buf->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; int format = sarea_priv->vc_format; - int offset = dev_priv->buffers->offset - dev->agp->base; + int offset; int prim = buf_priv->prim; u32 *data; int dwords; @@ -778,6 +781,10 @@ static void r128_cce_dispatch_indices( drm_device_t *dev, RING_LOCALS; DRM_DEBUG( "indices: s=%d e=%d c=%d\n", start, end, count ); + if(dma->flags == _DRM_DMA_USE_SG) + offset = dev_priv->buffers->offset - dev->sg->handle; + else offset = dev_priv->buffers->offset - dev->agp->base; + r128_update_ring_snapshot( dev_priv ); if ( 0 ) @@ -1449,7 +1456,7 @@ int r128_cce_vertex( struct inode *inode, struct file *filp, DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); return -EINVAL; } - if ( !dev_priv || dev_priv->is_pci ) { + if ( !dev_priv ) { DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); return -EINVAL; } @@ -1512,7 +1519,7 @@ int r128_cce_indices( struct inode *inode, struct file *filp, DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); return -EINVAL; } - if ( !dev_priv || dev_priv->is_pci ) { + if ( !dev_priv ) { DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); return -EINVAL; } diff --git a/linux/scatter.c b/linux/scatter.c new file mode 100644 index 00000000..c5521098 --- /dev/null +++ b/linux/scatter.c @@ -0,0 +1,211 @@ +/* scatter.c -- IOCTLs to manage scatter/gather memory -*- linux-c -*- + * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com + * + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Gareth Hughes + * + */ + +#define __NO_VERSION__ +#include +#include "drmP.h" +#include + +#define DEBUG_SCATTER 1 + +static void drm_sg_cleanup( drm_sg_mem_t *entry ) +{ + int i; + + for ( i = 0 ; i < entry->pages ; i++ ) { + ClearPageReserved( entry->pagelist[i] ); + } + + vfree( entry->virtual ); + + drm_free( entry->pagelist, + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + drm_free( entry, + sizeof(*entry), + DRM_MEM_SGLISTS ); +} + +static inline long usec( void ) +{ + struct timeval tv; + + do_gettimeofday( &tv ); + + return (tv.tv_sec & 0x7ff) * 1000000 + tv.tv_usec; +} + +int drm_sg_alloc( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_scatter_gather_t request; + drm_sg_mem_t *entry; + unsigned long pages; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int i, j; + DRM_INFO( "%s\n", __FUNCTION__ ); + + if ( dev->sg ) return -EINVAL; + + if ( copy_from_user( &request, + (drm_scatter_gather_t *)arg, + sizeof(request) ) ) + return -EFAULT; + + entry = drm_alloc( sizeof(*entry), DRM_MEM_SGLISTS ); + if ( !entry ) return -ENOMEM; + + memset( entry, 0, sizeof(*entry) ); + + pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; + DRM_DEBUG( "sg size=%ld pages=%ld\n", request.size, pages ); + + entry->pages = pages; + entry->pagelist = drm_alloc( pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + if ( !entry->pagelist ) { + drm_free( entry, sizeof(*entry), DRM_MEM_SGLISTS ); + return -ENOMEM; + } + + /* FIXME: We should really have a kernel call for this... + */ + entry->virtual = __vmalloc( (pages << PAGE_SHIFT), + GFP_KERNEL, + PAGE_KERNEL); + if ( !entry->virtual ) { + drm_free( entry->pagelist, + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + drm_free( entry, + sizeof(*entry), + DRM_MEM_SGLISTS ); + return -ENOMEM; + } + + /* This also forces the mapping of COW pages, so our page list + * will be valid. Please don't remove it... + */ + memset( entry->virtual, 0, pages << PAGE_SHIFT ); + + entry->handle = (unsigned long)entry->virtual; + + DRM_DEBUG( "sg alloc handle = %08lx\n", entry->handle ); + DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual ); + + for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) { + pgd = pgd_offset_k( i ); + pmd = pmd_offset( pgd, i ); + pte = pte_offset( pmd, i ); + + entry->pagelist[j]= pte_page( *pte ); + SetPageReserved( entry->pagelist[j] ); + + if ( j < 16 ) { + DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", + i, j, + (unsigned long)entry->pagelist[j]->virtual); + } + } + + request.handle = entry->handle; + + if ( copy_to_user( (drm_scatter_gather_t *)arg, + &request, + sizeof(request) ) ) { + drm_sg_cleanup( entry ); + return -EFAULT; + } + + dev->sg = entry; + +#ifdef DEBUG_SCATTER + /* Verify that each page points to its virtual address, and vice + * versa. + */ + { + int error = 0; + + for(i = 0; i < pages; i++) { + unsigned long *tmp; + + tmp = (unsigned long *)entry->pagelist[i]->virtual; + for(j = 0; j < PAGE_SIZE / sizeof(unsigned long); j++, tmp++) { + *tmp = 0xcafebabe; + } + tmp = (unsigned long *)((u8 *)entry->virtual + + (PAGE_SIZE * i)); + for(j = 0; j < PAGE_SIZE / sizeof(unsigned long); j++, tmp++) { + if(*tmp != 0xcafebabe && error == 0) { + error = 1; + printk("Scatter allocation error, pagelist" + " does not match virtual mapping\n"); + } + } + tmp = (unsigned long *)entry->pagelist[i]->virtual; + for(j = 0; j < PAGE_SIZE / sizeof(unsigned long); j++, tmp++) { + *tmp = 0; + } + } + if(error == 0) printk("Scatter allocation matches pagelist\n"); + } +#endif + + return 0; +} + +int drm_sg_free( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_scatter_gather_t request; + drm_sg_mem_t *entry; + + if ( copy_from_user( &request, + (drm_scatter_gather_t *)arg, + sizeof(request) ) ) + return -EFAULT; + + entry = dev->sg; + dev->sg = NULL; + + if ( !entry || entry->handle != request.handle ) return -EINVAL; + + DRM_INFO( "sg free virtual = %p\n", entry->virtual ); + + drm_sg_cleanup( entry ); + + return 0; +} diff --git a/linux/vm.c b/linux/vm.c index 964921b4..843427ba 100644 --- a/linux/vm.c +++ b/linux/vm.c @@ -56,6 +56,12 @@ struct vm_operations_struct drm_vm_dma_ops = { close: drm_vm_close, }; +struct vm_operations_struct drm_vm_sg_ops = { + nopage: drm_vm_sg_nopage, + open: drm_vm_open, + close: drm_vm_close, +}; + #if LINUX_VERSION_CODE < 0x020317 unsigned long drm_vm_nopage(struct vm_area_struct *vma, unsigned long address, @@ -172,6 +178,49 @@ struct page *drm_vm_dma_nopage(struct vm_area_struct *vma, #endif } +#if LINUX_VERSION_CODE < 0x020317 +unsigned long drm_vm_sg_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#else + /* Return type changed in 2.3.23 */ +struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#endif +{ +#if LINUX_VERSION_CODE >= 0x020300 + drm_map_t *map = (drm_map_t *)vma->vm_private_data; +#else + drm_map_t *map = (drm_map_t *)vma->vm_pte; +#endif + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; + drm_sg_mem_t *entry = dev->sg; + unsigned long offset; + unsigned long map_offset; + unsigned long page_offset; + struct page *page; + + if (!entry) return NOPAGE_SIGBUS; /* Error */ + if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ + if (!entry->pagelist) return NOPAGE_OOM ; /* Nothing allocated */ + + + offset = address - vma->vm_start; + map_offset = map->offset - dev->sg->handle; + page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT); + page = entry->pagelist[page_offset]; + atomic_inc(&page->count); /* Dec. by kernel */ + + +#if LINUX_VERSION_CODE < 0x020317 + return (unsigned long)virt_to_phys(page->virtual); +#else + return page; +#endif +} + void drm_vm_open(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; @@ -311,6 +360,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) #endif } + if (map->type == _DRM_SCATTER_GATHER) { + DRM_DEBUG("%s: scatter/gather\n", __FUNCTION__); + DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", + vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + } + switch (map->type) { case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: @@ -354,6 +409,15 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) DRM_KERNEL advisory is supported. */ vma->vm_flags |= VM_LOCKED; break; + case _DRM_SCATTER_GATHER: + vma->vm_ops = &drm_vm_sg_ops; +#if LINUX_VERSION_CODE >= 0x020300 + vma->vm_private_data = (void *)map; +#else + vma->vm_pte = (unsigned long)map; +#endif + vma->vm_flags |= VM_LOCKED; + break; default: return -EINVAL; /* This should never happen. */ } @@ -366,5 +430,9 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) #endif vma->vm_file = filp; /* Needed for drm_vm_open() */ drm_vm_open(vma); + + if(map->type == _DRM_SCATTER_GATHER) { + DRM_DEBUG("%s: scatter/gather done.\n", __FUNCTION__); + } return 0; } diff --git a/shared-core/drm.h b/shared-core/drm.h index dc3d262d..f657eab9 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -124,10 +124,11 @@ typedef struct drm_control { } drm_control_t; typedef enum drm_map_type { - _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ - _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2, /* shared, cached */ - _DRM_AGP = 3 /* AGP/GART */ + _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /* no caching, no core dump */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3, /* AGP/GART */ + _DRM_SCATTER_GATHER = 4 /* Scatter/gather memory for PCI DMA */ } drm_map_type_t; typedef enum drm_map_flags { @@ -192,7 +193,8 @@ typedef struct drm_buf_desc { int high_mark; /* High water mark */ enum { _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ - _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ + _DRM_AGP_BUFFER = 0x02, /* Buffer is in agp space */ + _DRM_SG_BUFFER = 0x04 /* Scatter/gather memory buffer */ } flags; unsigned long agp_start; /* Start address of where the agp buffers * are in the agp aperture */ @@ -298,6 +300,11 @@ typedef struct drm_agp_info { unsigned short id_device; } drm_agp_info_t; +typedef struct drm_scatter_gather { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for mapping / unmapping */ +} drm_scatter_gather_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) #define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) @@ -345,6 +352,9 @@ typedef struct drm_agp_info { #define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) #define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) +#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t) +#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t) + /* Mga specific ioctls */ #define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) #define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t) diff --git a/shared/drm.h b/shared/drm.h index dc3d262d..f657eab9 100644 --- a/shared/drm.h +++ b/shared/drm.h @@ -124,10 +124,11 @@ typedef struct drm_control { } drm_control_t; typedef enum drm_map_type { - _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ - _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2, /* shared, cached */ - _DRM_AGP = 3 /* AGP/GART */ + _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /* no caching, no core dump */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3, /* AGP/GART */ + _DRM_SCATTER_GATHER = 4 /* Scatter/gather memory for PCI DMA */ } drm_map_type_t; typedef enum drm_map_flags { @@ -192,7 +193,8 @@ typedef struct drm_buf_desc { int high_mark; /* High water mark */ enum { _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ - _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ + _DRM_AGP_BUFFER = 0x02, /* Buffer is in agp space */ + _DRM_SG_BUFFER = 0x04 /* Scatter/gather memory buffer */ } flags; unsigned long agp_start; /* Start address of where the agp buffers * are in the agp aperture */ @@ -298,6 +300,11 @@ typedef struct drm_agp_info { unsigned short id_device; } drm_agp_info_t; +typedef struct drm_scatter_gather { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for mapping / unmapping */ +} drm_scatter_gather_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) #define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) @@ -345,6 +352,9 @@ typedef struct drm_agp_info { #define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) #define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) +#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t) +#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t) + /* Mga specific ioctls */ #define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) #define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t)