summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/Makefile.kernel4
-rw-r--r--linux-core/ati_pcigart.c95
-rw-r--r--linux-core/drmP.h12
-rw-r--r--linux-core/drm_ioctl.c4
-rw-r--r--linux-core/drm_scatter.c42
-rw-r--r--linux-core/drm_vm.c71
6 files changed, 199 insertions, 29 deletions
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel
index 97b507ee..e2630989 100644
--- a/linux-core/Makefile.kernel
+++ b/linux-core/Makefile.kernel
@@ -3,9 +3,7 @@
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
O_TARGET := drm.o
-export-objs := gamma_drv.o tdfx_drv.o r128_drv.o mga_drv.o i810_drv.o \
- ffb_drv.o
-list-multi := gamma.o tdfx.o r128.o mga.o i810.o ffb.o
+list-multi := gamma.o tdfx.o r128.o mga.o i810.o ffb.o radeon.o
gamma-objs := gamma_drv.o gamma_dma.o
tdfx-objs := tdfx_drv.o
diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c
index 93c5148f..99d17ee7 100644
--- a/linux-core/ati_pcigart.c
+++ b/linux-core/ati_pcigart.c
@@ -72,8 +72,6 @@ static void DRM(ati_free_pcigart_table)( unsigned long address )
int i;
DRM_DEBUG( "%s\n", __FUNCTION__ );
- if ( !address ) return;
-
page = virt_to_page( address );
for ( i = 0 ; i <= ATI_PCIGART_TABLE_PAGES ; i++, page++ ) {
@@ -84,24 +82,45 @@ static void DRM(ati_free_pcigart_table)( unsigned long address )
free_pages( address, ATI_PCIGART_TABLE_ORDER );
}
-unsigned long DRM(ati_pcigart_init)( drm_device_t *dev )
+int DRM(ati_pcigart_init)( drm_device_t *dev,
+ unsigned long *addr,
+ dma_addr_t *bus_addr)
{
drm_sg_mem_t *entry = dev->sg;
- unsigned long address;
+ unsigned long address = 0;
unsigned long pages;
- u32 *pci_gart, page_base;
- int i, j;
+ u32 *pci_gart, page_base, bus_address = 0;
+ int i, j, ret = 0;
if ( !entry ) {
DRM_ERROR( "no scatter/gather memory!\n" );
- return 0;
+ goto done;
}
address = DRM(ati_alloc_pcigart_table)();
if ( !address ) {
DRM_ERROR( "cannot allocate PCI GART page!\n" );
- return 0;
+ goto done;
+ }
+
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
+ if ( !dev->pdev ) {
+ DRM_ERROR( "PCI device unknown!\n" );
+ goto done;
+ }
+
+ bus_address = pci_map_single(dev->pdev, (void *)address,
+ ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
+ PCI_DMA_TODEVICE);
+ if (bus_address == 0) {
+ DRM_ERROR( "unable to map PCIGART pages!\n" );
+ DRM(ati_free_pcigart_table)( address );
+ address = 0;
+ goto done;
}
+#else
+ bus_address = virt_to_bus( (void *)address );
+#endif
pci_gart = (u32 *)address;
@@ -111,28 +130,78 @@ unsigned long DRM(ati_pcigart_init)( drm_device_t *dev )
memset( pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32) );
for ( i = 0 ; i < pages ; i++ ) {
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
+ /* we need to support large memory configurations */
+ entry->busaddr[i] = pci_map_single(dev->pdev,
+ entry->pagelist[i]->virtual,
+ PAGE_SIZE,
+ PCI_DMA_TODEVICE);
+ if (entry->busaddr[i] == 0) {
+ DRM_ERROR( "unable to map PCIGART pages!\n" );
+ DRM(ati_pcigart_cleanup)( dev, address, bus_address );
+ address = 0;
+ bus_address = 0;
+ goto done;
+ }
+ page_base = (u32) entry->busaddr[i];
+#else
page_base = virt_to_bus( entry->pagelist[i]->virtual );
+#endif
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
*pci_gart++ = cpu_to_le32( page_base );
page_base += ATI_PCIGART_PAGE_SIZE;
}
}
+ ret = 1;
+
#if __i386__
asm volatile ( "wbinvd" ::: "memory" );
#else
mb();
#endif
- return address;
+done:
+ *addr = address;
+ *bus_addr = bus_address;
+ return ret;
}
-int DRM(ati_pcigart_cleanup)( unsigned long address )
+int DRM(ati_pcigart_cleanup)( drm_device_t *dev,
+ unsigned long addr,
+ dma_addr_t bus_addr)
{
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
+ drm_sg_mem_t *entry = dev->sg;
+ unsigned long pages;
+ int i;
- if ( address ) {
- DRM(ati_free_pcigart_table)( address );
+ /* we need to support large memory configurations */
+ if ( !entry ) {
+ DRM_ERROR( "no scatter/gather memory!\n" );
+ return 0;
+ }
+
+ if ( bus_addr ) {
+ pci_unmap_single(dev->pdev, bus_addr,
+ ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
+ PCI_DMA_TODEVICE);
+
+ pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES )
+ ? entry->pages : ATI_MAX_PCIGART_PAGES;
+
+ for ( i = 0 ; i < pages ; i++ ) {
+ if ( !entry->busaddr[i] ) break;
+ pci_unmap_single(dev->pdev, entry->busaddr[i],
+ PAGE_SIZE, PCI_DMA_TODEVICE);
+ }
+ }
+
+#endif
+
+ if ( addr ) {
+ DRM(ati_free_pcigart_table)( addr );
}
- return 0;
+ return 1;
}
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 3b282685..8e2ecd16 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -624,6 +624,9 @@ typedef struct drm_sg_mem {
void *virtual;
int pages;
struct page **pagelist;
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
+ dma_addr_t *busaddr;
+#endif
} drm_sg_mem_t;
typedef struct drm_sigdata {
@@ -715,6 +718,7 @@ typedef struct drm_device {
drm_agp_head_t *agp;
#endif
#ifdef __alpha__
+ struct pci_dev *pdev;
#if LINUX_VERSION_CODE < 0x020403
struct pci_controler *hose;
#else
@@ -1018,8 +1022,12 @@ extern int DRM(sg_free)(struct inode *inode, struct file *filp,
#endif
/* ATI PCIGART support (ati_pcigart.h) */
-extern unsigned long DRM(ati_pcigart_init)(drm_device_t *dev);
-extern int DRM(ati_pcigart_cleanup)(unsigned long address);
+extern int DRM(ati_pcigart_init)(drm_device_t *dev,
+ unsigned long *addr,
+ dma_addr_t *bus_addr);
+extern int DRM(ati_pcigart_cleanup)(drm_device_t *dev,
+ unsigned long addr,
+ dma_addr_t bus_addr);
#endif /* __KERNEL__ */
#endif
diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c
index 4712cbd3..e0c87d2d 100644
--- a/linux-core/drm_ioctl.c
+++ b/linux-core/drm_ioctl.c
@@ -114,8 +114,10 @@ int DRM(setunique)(struct inode *inode, struct file *filp,
if (*p) break;
pci_dev = pci_find_slot(b, PCI_DEVFN(d,f));
- if (pci_dev)
+ if (pci_dev) {
+ dev->pdev = pci_dev;
dev->hose = pci_dev->sysdata;
+ }
} while(0);
#endif
diff --git a/linux-core/drm_scatter.c b/linux-core/drm_scatter.c
index c1c9f7e8..5654c8cb 100644
--- a/linux-core/drm_scatter.c
+++ b/linux-core/drm_scatter.c
@@ -47,12 +47,17 @@ void DRM(sg_cleanup)( drm_sg_mem_t *entry )
vfree( entry->virtual );
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
+ DRM(free)( entry->busaddr,
+ entry->pages * sizeof(*entry->busaddr),
+ DRM_MEM_PAGES );
+#endif
DRM(free)( entry->pagelist,
- entry->pages * sizeof(*entry->pagelist),
- DRM_MEM_PAGES );
+ entry->pages * sizeof(*entry->pagelist),
+ DRM_MEM_PAGES );
DRM(free)( entry,
- sizeof(*entry),
- DRM_MEM_SGLISTS );
+ sizeof(*entry),
+ DRM_MEM_SGLISTS );
}
int DRM(sg_alloc)( struct inode *inode, struct file *filp,
@@ -93,16 +98,35 @@ int DRM(sg_alloc)( struct inode *inode, struct file *filp,
DRM(free)( entry, sizeof(*entry), DRM_MEM_SGLISTS );
return -ENOMEM;
}
- memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
+
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
+ entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr),
+ DRM_MEM_PAGES );
+ if ( !entry->busaddr ) {
+ DRM(free)( entry->pagelist,
+ entry->pages * sizeof(*entry->pagelist),
+ DRM_MEM_PAGES );
+ DRM(free)( entry,
+ sizeof(*entry),
+ DRM_MEM_SGLISTS );
+ return -ENOMEM;
+ }
+ memset( (void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr) );
+#endif
entry->virtual = vmalloc_32( pages << PAGE_SHIFT );
if ( !entry->virtual ) {
+#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400)
+ DRM(free)( entry->busaddr,
+ entry->pages * sizeof(*entry->busaddr),
+ DRM_MEM_PAGES );
+#endif
DRM(free)( entry->pagelist,
- entry->pages * sizeof(*entry->pagelist),
- DRM_MEM_PAGES );
+ entry->pages * sizeof(*entry->pagelist),
+ DRM_MEM_PAGES );
DRM(free)( entry,
- sizeof(*entry),
- DRM_MEM_SGLISTS );
+ sizeof(*entry),
+ DRM_MEM_SGLISTS );
return -ENOMEM;
}
diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c
index d8e77f79..2a5ee146 100644
--- a/linux-core/drm_vm.c
+++ b/linux-core/drm_vm.c
@@ -67,6 +67,64 @@ struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
int write_access)
#endif
{
+#if defined(__alpha__) && __REALLY_HAVE_AGP
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_map_t *map = NULL;
+ drm_map_list_t *r_list;
+ struct list_head *list;
+
+ /*
+ * Find the right map
+ */
+ list_for_each(list, &dev->maplist->head) {
+ r_list = (drm_map_list_t *)list;
+ map = r_list->map;
+ if (!map) continue;
+ if (map->offset == VM_OFFSET(vma)) break;
+ }
+
+ if (map && map->type == _DRM_AGP) {
+ unsigned long offset = address - vma->vm_start;
+ unsigned long baddr = VM_OFFSET(vma) + offset;
+ struct drm_agp_mem *agpmem;
+ struct page *page;
+
+ /*
+ * Make it a bus-relative address
+ */
+ baddr -= dev->hose->mem_space->start;
+
+ /*
+ * It's AGP memory - find the real physical page to map
+ */
+ for(agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) {
+ if (agpmem->bound <= baddr &&
+ agpmem->bound + agpmem->pages * PAGE_SIZE > baddr)
+ break;
+ }
+
+ if (!agpmem) {
+ /*
+ * Oops - no memory found
+ */
+ return NOPAGE_SIGBUS; /* couldn't find it */
+ }
+
+ /*
+ * Get the page, inc the use count, and return it
+ */
+ offset = (baddr - agpmem->bound) >> PAGE_SHIFT;
+ agpmem->memory->memory[offset] &= ~1UL; /* HACK */
+ page = virt_to_page(__va(agpmem->memory->memory[offset]));
+#if 0
+DRM_ERROR("baddr = 0x%lx page = 0x%lx, offset = 0x%lx\n",
+ baddr, __va(agpmem->memory->memory[offset]), offset);
+#endif
+ get_page(page);
+ return page;
+ }
+#endif
return NOPAGE_SIGBUS; /* Disallow mremap */
}
@@ -434,9 +492,20 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
}
switch (map->type) {
+ case _DRM_AGP:
+#if defined(__alpha__)
+ /*
+ * On Alpha we can't talk to bus dma address from the
+ * CPU, so for memory of type DRM_AGP, we'll deal with
+ * sorting out the real physical pages and mappings
+ * in nopage()
+ */
+ vma->vm_ops = &DRM(vm_ops);
+ break;
+#endif
+ /* fall through to _DRM_FRAME_BUFFER... */
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
- case _DRM_AGP:
if (VM_OFFSET(vma) >= __pa(high_memory)) {
#if defined(__i386__)
if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {