Sorta working (i.e., sometimes it works right) r128 pcigart implementation,

based on code from Gareth Hughes. Needs bug fixing before its ready for
    general use.
This commit is contained in:
Jeff Hartmann 2001-01-17 18:43:04 +00:00
parent 61c15f4a2d
commit e2117d5487
21 changed files with 935 additions and 75 deletions

View file

@ -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 <faith@valinux.com>
* Kevin E. Martin <martin@valinux.com>
*
* $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

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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 \

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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 */
};

View file

@ -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,

View file

@ -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;

View file

@ -37,6 +37,7 @@
#include <linux/delay.h>
#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 );

View file

@ -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);
}

View file

@ -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

156
linux/r128_pcigart.c Normal file
View file

@ -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 <gareth@valinux.com>
*
*/
#define __NO_VERSION__
#include "drmP.h"
#include "r128_drv.h"
#include <linux/interrupt.h> /* For task queue support */
#include <linux/delay.h>
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;
}

View file

@ -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;
}

211
linux/scatter.c Normal file
View file

@ -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 <gareth@valinux.com>
*
*/
#define __NO_VERSION__
#include <linux/config.h>
#include "drmP.h"
#include <linux/wrapper.h>
#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;
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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)