It has been some time...

So, here's is my latest cut at latest AGP support for UniNorth.

It consists of 2 patches:

 - uninorth_agp.diff

This one can probably be merged as-is, it adds support for the UniNorth
chipset to the AGP driver backend

 - mac_r128_drm.diff

That one cannot be merged as-is. The implementation of ioremap_agp probably
need to be re-done in a less platform-specific way, I beleive the existing
implementation for other broken HW (was it for ia64 or x86/64, I don't
remember) should work provided the flags are set properly for PPC.

This only concerns drm_memory.h. Other patches should not affect existing
working code.

I will do the same for radeon once it have been tested a bit here.

The patch relies on the arch code providing the "agp_special_page". This
is not in Linus tree, but that is not a problem for now. I will get that
specific change merged as soon as we are in sync on the rest of the code.

Note that it doesn't work correctly with all chipsets yet (the Rage M3
loves to lockup) with XFree 4.1. I beleive the problem is specific to
that chip and possibly not related to those AGP fixes as other r128
cards seem to work properly.

Regards,
Ben.
diff -urN linuxppc_2_4_devel/drivers/char/Config.in 
linuxppc_benh_stable/drivers/char/Config.in
--- linuxppc_2_4_devel/drivers/char/Config.in   Sat Nov 10 12:23:51 2001
+++ linuxppc_benh_stable/drivers/char/Config.in Sat Nov 10 12:14:33 2001
@@ -221,6 +221,9 @@
    bool '  Generic SiS support' CONFIG_AGP_SIS
    bool '  ALI chipset support' CONFIG_AGP_ALI
    bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
+   if [ "$CONFIG_ALL_PPC" = "y" ]; then
+     bool '  Apple UniNorth support' CONFIG_AGP_UNINORTH
+   fi
 fi
 
 source drivers/char/drm/Config.in
diff -urN linuxppc_2_4_devel/drivers/char/agp/agpgart_be.c 
linuxppc_benh_stable/drivers/char/agp/agpgart_be.c
--- linuxppc_2_4_devel/drivers/char/agp/agpgart_be.c    Sat Nov 10 12:23:59 2001
+++ linuxppc_benh_stable/drivers/char/agp/agpgart_be.c  Sat Nov 10 20:25:59 2001
@@ -44,6 +44,10 @@
 #include <asm/io.h>
 #include <asm/page.h>
 
+#ifdef CONFIG_AGP_UNINORTH
+#include <asm/uninorth.h>
+#endif
+
 #include <linux/agp_backend.h>
 #include "agp.h"
 
@@ -69,7 +73,7 @@
 {
 #if defined(__i386__) || defined(__x86_64__)
        asm volatile ("wbinvd":::"memory");
-#elif defined(__alpha__) || defined(__ia64__) || defined(__sparc__)
+#elif defined(__alpha__) || defined(__ia64__) || defined(__sparc__) || defined 
+(__powerpc__)
        /* ??? I wonder if we'll really need to flush caches, or if the
           core logic can manage to keep the system coherent.  The ARM
           speaks only of using `cflush' to get things in memory in
@@ -3424,6 +3428,404 @@
 
 #endif /* CONFIG_AGP_SWORKS */
 
+#ifdef CONFIG_AGP_UNINORTH
+
+static int uninorth_fetch_size(void)
+{
+       int i;
+       u32 temp;
+       aper_size_info_32 *values;
+
+       pci_read_config_dword(agp_bridge.dev, UNI_N_CFG_GART_BASE, &temp);
+       temp &= ~(0xfffff000);
+       values = A_SIZE_32(agp_bridge.aperture_sizes);
+
+       for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+               if (temp == values[i].size_value) {
+                       agp_bridge.previous_size =
+                           agp_bridge.current_size = (void *) (values + i);
+                       agp_bridge.aperture_size_idx = i;
+                       return values[i].size;
+               }
+       }
+
+       agp_bridge.previous_size =
+           agp_bridge.current_size = (void *) (values + 1);
+       agp_bridge.aperture_size_idx = 1;
+       return values[1].size;
+
+       return 0;
+}
+
+static void uninorth_tlbflush(agp_memory * mem)
+{
+       pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL,
+                       UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL);
+       pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL,
+                       UNI_N_CFG_GART_ENABLE);
+       pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL,
+                       UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_2xRESET);
+       pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL,
+                       UNI_N_CFG_GART_ENABLE);
+}
+
+static void uninorth_cleanup(void)
+{
+       pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL,
+                       UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL);
+       pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL,
+                       0);
+       pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL,
+                       UNI_N_CFG_GART_2xRESET);
+       pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL,
+                       0);
+}
+
+static int uninorth_configure(void)
+{
+       aper_size_info_32 *current_size;
+       
+       current_size = A_SIZE_32(agp_bridge.current_size);
+
+       printk("agp: configuring for size idx: %d\n", current_size->size_value);
+       
+       /* aperture size and gatt addr */
+       pci_write_config_dword(agp_bridge.dev,
+               UNI_N_CFG_GART_BASE,
+               (agp_bridge.gatt_bus_addr & 0xfffff000)
+                       | current_size->size_value);
+
+       /* HACK ALERT
+        * UniNorth seem to be buggy enough not to handle properly when
+        * the AGP aperture isn't mapped at bus physical address 0
+        */
+       agp_bridge.gart_bus_addr = 0;
+       pci_write_config_dword(agp_bridge.dev,
+               UNI_N_CFG_AGP_BASE, agp_bridge.gart_bus_addr);
+       
+       return 0;
+}
+
+static unsigned long uninorth_mask_memory(unsigned long addr, int type)
+{
+       return addr;/* | agp_bridge.masks[0].mask;*/
+}
+
+static int uninorth_insert_memory(agp_memory * mem,
+                                    off_t pg_start, int type)
+{
+       int i, j, num_entries;
+       void *temp;
+
+       temp = agp_bridge.current_size;
+       num_entries = A_SIZE_32(temp)->num_entries;
+
+       if (type != 0 || mem->type != 0) {
+               /* The generic routines know nothing of memory types */
+               return -EINVAL;
+       }
+       if ((pg_start + mem->page_count) > num_entries) {
+               return -EINVAL;
+       }
+       j = pg_start;
+
+       while (j < (pg_start + mem->page_count)) {
+               if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
+                       return -EBUSY;
+               }
+               j++;
+       }
+
+       if (mem->is_flushed == FALSE) {
+               CACHE_FLUSH();
+               mem->is_flushed = TRUE;
+       }
+       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+               agp_bridge.gatt_table[j] = cpu_to_le32((mem->memory[i] & 0xfffff000) | 
+0x00000001UL);
+               flush_dcache_range(__va(mem->memory[i]), __va(mem->memory[i])+0x1000);
+       }
+       (void)in_le32((volatile u32*)&agp_bridge.gatt_table[pg_start]);
+       mb();
+       flush_dcache_range((unsigned long)&agp_bridge.gatt_table[pg_start], 
+               (unsigned long)&agp_bridge.gatt_table[pg_start + mem->page_count]);
+
+       agp_bridge.tlb_flush(mem);
+       return 0;
+}
+
+static void uninorth_agp_enable(u32 mode)
+{
+       struct pci_dev *device = NULL;
+       u32 command, scratch, cap_id;
+       u8 cap_ptr;
+
+       pci_read_config_dword(agp_bridge.dev,
+                             agp_bridge.capndx + 4,
+                             &command);
+
+       /*
+        * PASS1: go throu all devices that claim to be
+        *        AGP devices and collect their data.
+        */
+
+       while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
+                                       device)) != NULL) {
+               pci_read_config_dword(device, 0x04, &scratch);
+
+               if (!(scratch & 0x00100000))
+                       continue;
+
+               pci_read_config_byte(device, 0x34, &cap_ptr);
+
+               if (cap_ptr != 0x00) {
+                       do {
+                               pci_read_config_dword(device,
+                                                     cap_ptr, &cap_id);
+
+                               if ((cap_id & 0xff) != 0x02)
+                                       cap_ptr = (cap_id >> 8) & 0xff;
+                       }
+                       while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
+               }
+               if (cap_ptr != 0x00) {
+                       /*
+                        * Ok, here we have a AGP device. Disable impossible 
+                        * settings, and adjust the readqueue to the minimum.
+                        */
+
+                       pci_read_config_dword(device, cap_ptr + 4, &scratch);
+
+                       /* adjust RQ depth */
+                       command =
+                           ((command & ~0xff000000) |
+                            min_t(u32, (mode & 0xff000000),
+                                min_t(u32, (command & 0xff000000),
+                                    (scratch & 0xff000000))));
+
+                       /* disable SBA if it's not supported */
+                       if (!((command & 0x00000200) &&
+                             (scratch & 0x00000200) &&
+                             (mode & 0x00000200)))
+                               command &= ~0x00000200;
+
+                       /* disable FW if it's not supported */
+                       if (!((command & 0x00000010) &&
+                             (scratch & 0x00000010) &&
+                             (mode & 0x00000010)))
+                               command &= ~0x00000010;
+
+                       if (!((command & 4) &&
+                             (scratch & 4) &&
+                             (mode & 4)))
+                               command &= ~0x00000004;
+
+                       if (!((command & 2) &&
+                             (scratch & 2) &&
+                             (mode & 2)))
+                               command &= ~0x00000002;
+
+                       if (!((command & 1) &&
+                             (scratch & 1) &&
+                             (mode & 1)))
+                               command &= ~0x00000001;
+               }
+       }
+       /*
+        * PASS2: Figure out the 4X/2X/1X setting and enable the
+        *        target (our motherboard chipset).
+        */
+
+       if (command & 4) {
+               command &= ~3;  /* 4X */
+       }
+       if (command & 2) {
+               command &= ~5;  /* 2X */
+       }
+       if (command & 1) {
+               command &= ~6;  /* 1X */
+       }
+       command |= 0x00000100;
+
+       uninorth_tlbflush(NULL);
+
+       do {
+               pci_write_config_dword(agp_bridge.dev,
+                                      agp_bridge.capndx + 8,
+                                      command);
+               pci_read_config_dword(agp_bridge.dev,
+                                      agp_bridge.capndx + 8,
+                                      &scratch);
+       } while((scratch & 0x100) == 0);
+
+       /*
+        * PASS3: Go throu all AGP devices and update the
+        *        command registers.
+        */
+
+       while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
+                                       device)) != NULL) {
+               pci_read_config_dword(device, 0x04, &scratch);
+
+               if (!(scratch & 0x00100000))
+                       continue;
+
+               pci_read_config_byte(device, 0x34, &cap_ptr);
+
+               if (cap_ptr != 0x00) {
+                       do {
+                               pci_read_config_dword(device,
+                                                     cap_ptr, &cap_id);
+
+                               if ((cap_id & 0xff) != 0x02)
+                                       cap_ptr = (cap_id >> 8) & 0xff;
+                       }
+                       while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
+               }
+               if (cap_ptr != 0x00)
+                       pci_write_config_dword(device, cap_ptr + 8, command);
+       }
+
+       uninorth_tlbflush(NULL);
+}
+
+static int uninorth_create_gatt_table(void)
+{
+       char *table;
+       char *table_end;
+       int size;
+       int page_order;
+       int num_entries;
+       int i;
+       void *temp;
+       struct page *page;
+
+       /* The generic routines can't handle 2 level gatt's */
+       if (agp_bridge.size_type == LVL2_APER_SIZE) {
+               return -EINVAL;
+       }
+
+       table = NULL;
+       i = agp_bridge.aperture_size_idx;
+       temp = agp_bridge.current_size;
+       size = page_order = num_entries = 0;
+
+       do {
+               size = A_SIZE_32(temp)->size;
+               page_order = A_SIZE_32(temp)->page_order;
+               num_entries = A_SIZE_32(temp)->num_entries;
+
+               table = (char *) __get_free_pages(GFP_KERNEL, page_order);
+
+               if (table == NULL) {
+                       i++;
+                       agp_bridge.current_size = A_IDX32();
+               } else {
+                       agp_bridge.aperture_size_idx = i;
+               }
+       } while ((table == NULL) &&
+                        (i < agp_bridge.num_aperture_sizes));
+
+       if (table == NULL) {
+               return -ENOMEM;
+       }
+       table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
+
+       for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
+               set_bit(PG_reserved, &page->flags);
+
+       agp_bridge.gatt_table_real = (unsigned long *) table;
+       agp_bridge.gatt_table = (unsigned long *)table;
+       agp_bridge.gatt_bus_addr = virt_to_phys(table);
+
+       for (i = 0; i < num_entries; i++) {
+               agp_bridge.gatt_table[i] =
+                   (unsigned long) agp_bridge.scratch_page;
+       }
+
+       flush_dcache_range((unsigned long)table, (unsigned long)table_end);
+
+       return 0;
+}
+
+static int uninorth_free_gatt_table(void)
+{
+       int page_order;
+       char *table, *table_end;
+       void *temp;
+       struct page *page;
+
+       temp = agp_bridge.current_size;
+       page_order = A_SIZE_32(temp)->page_order;
+
+       /* Do not worry about freeing memory, because if this is
+        * called, then all agp memory is deallocated and removed
+        * from the table.
+        */
+
+       table = (char *) agp_bridge.gatt_table_real;
+       table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
+
+       for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
+               clear_bit(PG_reserved, &page->flags);
+
+       free_pages((unsigned long) agp_bridge.gatt_table_real, page_order);
+
+       return 0;
+}
+
+/* Setup function */
+static gatt_mask uninorth_masks[] =
+{
+       {0x00000000, 0}
+};
+
+static aper_size_info_32 uninorth_sizes[7] =
+{
+#if 0 /* Not sure uninorth supports that high aperture sizes */
+       {256, 65536, 6, 64},
+       {128, 32768, 5, 32},
+       {64, 16384, 4, 16},
+#endif 
+       {32, 8192, 3, 8},
+       {16, 4096, 2, 4},
+       {8, 2048, 1, 2},
+       {4, 1024, 0, 1}
+};
+
+static int __init uninorth_setup (struct pci_dev *pdev)
+{
+       agp_bridge.masks = uninorth_masks;
+       agp_bridge.num_of_masks = 1;
+       agp_bridge.aperture_sizes = (void *)uninorth_sizes;
+       agp_bridge.size_type = U32_APER_SIZE;
+       agp_bridge.num_aperture_sizes = 4; //7;
+       agp_bridge.dev_private_data = NULL;
+       agp_bridge.needs_scratch_page = FALSE;
+       agp_bridge.configure = uninorth_configure;
+       agp_bridge.fetch_size = uninorth_fetch_size;
+       agp_bridge.cleanup = uninorth_cleanup;
+       agp_bridge.tlb_flush = uninorth_tlbflush;
+       agp_bridge.mask_memory = uninorth_mask_memory;
+       agp_bridge.agp_enable = uninorth_agp_enable;
+       agp_bridge.cache_flush = global_cache_flush;
+       agp_bridge.create_gatt_table = uninorth_create_gatt_table;
+       agp_bridge.free_gatt_table = uninorth_free_gatt_table;
+       agp_bridge.insert_memory = uninorth_insert_memory;
+       agp_bridge.remove_memory = agp_generic_remove_memory;
+       agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+       agp_bridge.free_by_type = agp_generic_free_by_type;
+       agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+       agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
+       agp_bridge.cant_use_aperture = 1;
+
+       return 0;
+       
+       (void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_UNINORTH */
 
 /* per-chipset initialization data.
  * note -- all chipsets for a single vendor MUST be grouped together
@@ -3710,6 +4112,26 @@
                "Generic",
                via_generic_setup },
 #endif /* CONFIG_AGP_VIA */
+#ifdef CONFIG_AGP_UNINORTH
+       { PCI_DEVICE_ID_APPLE_UNI_N_AGP,
+               PCI_VENDOR_ID_APPLE,
+               APPLE_UNINORTH,
+               "Apple",
+               "UniNorth",
+               uninorth_setup },
+       { PCI_DEVICE_ID_APPLE_UNI_N_AGP_P,
+               PCI_VENDOR_ID_APPLE,
+               APPLE_UNINORTH,
+               "Apple",
+               "UniNorth/Pangea",
+               uninorth_setup },
+       { PCI_DEVICE_ID_APPLE_UNI_N_AGP15,
+               PCI_VENDOR_ID_APPLE,
+               APPLE_UNINORTH,
+               "Apple",
+               "UniNorth 1.5",
+               uninorth_setup },
+#endif /* CONFIG_AGP_UNINORTH */
 
        { 0, }, /* dummy final entry, always present */
 };
diff -urN linuxppc_2_4_devel/include/linux/agp_backend.h 
linuxppc_benh_stable/include/linux/agp_backend.h
--- linuxppc_2_4_devel/include/linux/agp_backend.h      Sat Nov 10 12:22:41 2001
+++ linuxppc_benh_stable/include/linux/agp_backend.h    Sat Nov 10 12:13:11 2001
@@ -74,7 +74,8 @@
        ALI_GENERIC,
        SVWRKS_HE,
        SVWRKS_LE,
-       SVWRKS_GENERIC
+       SVWRKS_GENERIC,
+       APPLE_UNINORTH
 };
 
 typedef struct _agp_version {
diff -urN linuxppc_2_4_devel/include/linux/pci_ids.h 
linuxppc_benh_stable/include/linux/pci_ids.h
--- linuxppc_2_4_devel/include/linux/pci_ids.h  Sat Nov 10 12:22:44 2001
+++ linuxppc_benh_stable/include/linux/pci_ids.h        Sat Nov 10 12:13:16 2001
@@ -651,6 +651,8 @@
 #define PCI_DEVICE_ID_APPLE_KL_USB     0x0019
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP  0x0020
 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P        0x0027
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15        0x002d
 #define PCI_DEVICE_ID_APPLE_UNI_N_FW2  0x0030
 
 #define PCI_VENDOR_ID_YAMAHA           0x1073
diff -urN linuxppc_2_4_devel/drivers/char/drm/drmP.h 
linuxppc_benh_stable/drivers/char/drm/drmP.h
--- linuxppc_2_4_devel/drivers/char/drm/drmP.h  Sat Nov 10 12:23:58 2001
+++ linuxppc_benh_stable/drivers/char/drm/drmP.h        Sat Nov 10 20:38:35 2001
@@ -375,6 +375,15 @@
                        DRM(ioremapfree)( (map)->handle, (map)->size ); \
        } while (0)
 
+#define DRM_IOREMAPAGP(map, dev)                                               \
+       (map)->handle = DRM(ioremap_agp)( (map)->offset, (map)->size, (dev) )
+
+#define DRM_IOREMAPAGPFREE(map)                                                \
+       do {                                                            \
+               if ( (map)->handle && (map)->size )                     \
+                       DRM(ioremap_agp_free)( (map)->handle, (map)->size );    \
+       } while (0)
+
 #define DRM_FIND_MAP(_map, _o)                                         \
 do {                                                                   \
        struct list_head *_list;                                        \
@@ -828,6 +837,9 @@
                                     int area);
 extern void         *DRM(ioremap)(unsigned long offset, unsigned long size);
 extern void         DRM(ioremapfree)(void *pt, unsigned long size);
+
+extern void         *DRM(ioremap_agp)(unsigned long offset, unsigned long size, 
+drm_device_t *dev);
+extern void         DRM(ioremap_agp_free)(void *pt, unsigned long size);
 
 #if __REALLY_HAVE_AGP
 extern agp_memory    *DRM(alloc_agp)(int pages, u32 type);
diff -urN linuxppc_2_4_devel/drivers/char/drm/drm_memory.h 
linuxppc_benh_stable/drivers/char/drm/drm_memory.h
--- linuxppc_2_4_devel/drivers/char/drm/drm_memory.h    Sat Nov 10 12:23:59 2001
+++ linuxppc_benh_stable/drivers/char/drm/drm_memory.h  Sat Nov 10 20:45:29 2001
@@ -329,6 +329,107 @@
        return pt;
 }
 
+/* PPC specific routine used by ioremap_agp, to be replaced by some
+ * more generic implementation
+ */
+extern int map_page(unsigned long va, unsigned long pa, int flags);
+
+void *DRM(ioremap_agp)(unsigned long offset, unsigned long size, drm_device_t *dev)
+{
+       void *pt;
+       struct vm_struct *area;
+       struct drm_agp_mem *agpmem;
+       unsigned int flags = 
+_PAGE_NO_CACHE|_PAGE_KERNEL|_PAGE_PRESENT|_PAGE_RW|_PAGE_DIRTY;
+       int err, i;
+               
+       printk("drm: ioremap_agp, offset: 0x%08lx, size: 0x%08lx\n", offset, size);
+       
+#if __REALLY_HAVE_AGP
+       if (!size) {
+               DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+                             "Mapping 0 bytes at 0x%08lx\n", offset);
+               return NULL;
+       }
+
+       if (!dev->agp || !dev->agp->cant_use_aperture)
+               return DRM(ioremap)(offset, size);
+
+       /* XXX This has to be changed into something more generic
+        * this implementation is really only valid on PPC
+        */
+       area = get_vm_area(size, VM_IOREMAP);
+       if (area == 0) {
+               spin_lock(&DRM(mem_lock));
+               ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count;
+               spin_unlock(&DRM(mem_lock));
+               printk("->NULL\n");
+               return NULL;
+       }
+       pt = (void *)VMALLOC_VMADDR(area->addr);
+       err = 0;
+       for (i = 0; i < size && err == 0; i += PAGE_SIZE) {
+               unsigned long baddr = offset + i;
+               unsigned long index;
+               
+                /*
+                 * 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) {
+                       printk("drm: not matching AGP page in ioremap_agp\n");
+                       err = 1;
+                       break;
+               }
+               index = (baddr - agpmem->bound) >> PAGE_SHIFT;
+               err = map_page(((unsigned long)pt)+i, agpmem->memory->memory[index], 
+flags);
+       }
+       if (err) {
+               vfree((void *)pt);
+               spin_lock(&DRM(mem_lock));
+               ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count;
+               spin_unlock(&DRM(mem_lock));
+               printk("->NULL\n");
+               return NULL;
+       }
+               
+       spin_lock(&DRM(mem_lock));
+       ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count;
+       DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size;
+       spin_unlock(&DRM(mem_lock));
+       printk("->pt=0x%p\n", pt);
+       return pt;
+#else
+       return NULL;
+#endif
+}
+
+void DRM(ioremap_agp_free)(void *pt, unsigned long size)
+{
+       int alloc_count;
+       int free_count;
+
+       if (!pt)
+               DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+                             "Attempt to free NULL pointer\n");
+       else
+               vfree(pt);
+
+       spin_lock(&DRM(mem_lock));
+       DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_freed += size;
+       free_count  = ++DRM(mem_stats)[DRM_MEM_MAPPINGS].free_count;
+       alloc_count =   DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count;
+       spin_unlock(&DRM(mem_lock));
+       if (free_count > alloc_count) {
+               DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+                             "Excess frees: %d frees, %d allocs\n",
+                             free_count, alloc_count);
+       }
+}
+
 void DRM(ioremapfree)(void *pt, unsigned long size)
 {
        int alloc_count;
diff -urN linuxppc_2_4_devel/drivers/char/drm/drm_vm.h 
linuxppc_benh_stable/drivers/char/drm/drm_vm.h
--- linuxppc_2_4_devel/drivers/char/drm/drm_vm.h        Sat Nov 10 12:23:59 2001
+++ linuxppc_benh_stable/drivers/char/drm/drm_vm.h      Sat Nov 10 20:44:07 2001
@@ -462,7 +462,13 @@
 
        if ( !priv->authenticated ) return -EACCES;
 
-       if (!VM_OFFSET(vma)) return DRM(mmap_dma)(filp, vma);
+       /* We check for "dma". On Apple's UniNorth, it's valid to have
+        * the AGP mapped at physical address 0
+        * --BenH.
+        */
+       if (!VM_OFFSET(vma) && (!dev->agp ||
+           dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE))
+               return DRM(mmap_dma)(filp, vma);
 
                                /* A sequential search of a linked list is
                                   fine here because: 1) there will only be
@@ -502,16 +508,21 @@
 
        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;
+               if (!dev->agp)
+                       return -ENODEV;
+               if (dev->agp->cant_use_aperture) {
+                       /*
+                        * 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()
+                        */
+#if defined(__powerpc__)
+                       pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
 #endif
+                       vma->vm_ops = &DRM(vm_ops);
+                       break;
+               }
                 /* fall through to _DRM_FRAME_BUFFER... */        
        case _DRM_FRAME_BUFFER:
        case _DRM_REGISTERS:
diff -urN linuxppc_2_4_devel/drivers/char/drm/r128_cce.c 
linuxppc_benh_stable/drivers/char/drm/r128_cce.c
--- linuxppc_2_4_devel/drivers/char/drm/r128_cce.c      Sat Nov 10 12:23:58 2001
+++ linuxppc_benh_stable/drivers/char/drm/r128_cce.c    Sat Nov 10 20:44:47 2001
@@ -38,6 +38,10 @@
 
 #define R128_FIFO_DEBUG                0
 
+#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC)
+extern unsigned long agp_special_page;
+#endif 
+
 
 /* CCE microcode (from ATI) */
 static u32 r128_cce_microcode[] = {
@@ -341,6 +345,14 @@
        SET_RING_HEAD( &dev_priv->ring, 0 );
 
        if ( !dev_priv->is_pci ) {
+#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC)
+               if (_machine == _MACH_Pmac) {
+                       dev_priv->ring.head = (__volatile__ u32 *) agp_special_page;
+                       SET_RING_HEAD( &dev_priv->ring, 0 );
+                       R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
+                                   __pa( dev_priv->ring.head ) );
+               } else
+#endif         
                R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
                            dev_priv->ring_rptr->offset );
        } else {
@@ -550,9 +562,9 @@
                                     init->sarea_priv_offset);
 
        if ( !dev_priv->is_pci ) {
-               DRM_IOREMAP( dev_priv->cce_ring );
-               DRM_IOREMAP( dev_priv->ring_rptr );
-               DRM_IOREMAP( dev_priv->buffers );
+               DRM_IOREMAPAGP( dev_priv->cce_ring, dev );
+               DRM_IOREMAPAGP( dev_priv->ring_rptr, dev );
+               DRM_IOREMAPAGP( dev_priv->buffers, dev );
                if(!dev_priv->cce_ring->handle ||
                   !dev_priv->ring_rptr->handle ||
                   !dev_priv->buffers->handle) {
@@ -624,10 +636,11 @@
                drm_r128_private_t *dev_priv = dev->dev_private;
 
                if ( !dev_priv->is_pci ) {
-                       DRM_IOREMAPFREE( dev_priv->cce_ring );
-                       DRM_IOREMAPFREE( dev_priv->ring_rptr );
-                       DRM_IOREMAPFREE( dev_priv->buffers );
-               } else {
+                       DRM_IOREMAPAGPFREE( dev_priv->cce_ring );
+                       DRM_IOREMAPAGPFREE( dev_priv->ring_rptr );
+                       DRM_IOREMAPAGPFREE( dev_priv->buffers );
+               }
+               else {
                        if (!DRM(ati_pcigart_cleanup)( dev,
                                                dev_priv->phys_pci_gart,
                                                dev_priv->bus_pci_gart ))
diff -urN linuxppc_2_4_devel/drivers/char/drm/r128_drv.h 
linuxppc_benh_stable/drivers/char/drm/r128_drv.h
--- linuxppc_2_4_devel/drivers/char/drm/r128_drv.h      Sat Nov 10 12:23:58 2001
+++ linuxppc_benh_stable/drivers/char/drm/r128_drv.h    Sat Nov 10 20:38:19 2001
@@ -34,8 +34,13 @@
 #ifndef __R128_DRV_H__
 #define __R128_DRV_H__
 
+#ifdef __powerpc__
+#define GET_RING_HEAD( ring )          in_le32((volatile u32 *)(ring)->head)
+#define SET_RING_HEAD( ring, val )     out_le32((volatile u32 *)(ring)->head, (val) )
+#else
 #define GET_RING_HEAD( ring )          le32_to_cpu( *(ring)->head )
 #define SET_RING_HEAD( ring, val )     *(ring)->head = cpu_to_le32( val )
+#endif
 
 typedef struct drm_r128_freelist {
        unsigned int age;
@@ -397,6 +402,9 @@
        wmb();                                                          \
        R128_DEREF(reg) = val;                                          \
 } while (0)
+#elif defined (__powerpc__)
+#define R128_READ(reg)         in_le32( (volatile u32 *)R128_ADDR( reg ) )
+#define R128_WRITE(reg,val)    out_le32( (volatile u32 *)R128_ADDR( reg ), (val) )
 #else
 #define R128_READ(reg)         le32_to_cpu( R128_DEREF( reg ) )
 #define R128_WRITE(reg,val)                                            \
@@ -418,6 +426,9 @@
        wmb();                                                          \
        R128_DEREF8(reg) = val;                                         \
 } while (0)
+#elif defined (__powerpc__)
+#define R128_READ8(reg)                in_8( (volatile u8 *)R128_ADDR(reg) )
+#define R128_WRITE8(reg,val)   out_8( (volatile u8 *)R128_ADDR(reg), val )
 #else
 #define R128_READ8(reg)                R128_DEREF8( reg )
 #define R128_WRITE8(reg,val)   do { R128_DEREF8( reg ) = val; } while (0)
@@ -493,8 +504,11 @@
  * Ring control
  */
 
+#ifdef __powerpc__
+#define r128_flush_write_combine()     (void)in_le32(ring)
+#else
 #define r128_flush_write_combine()     mb()
-
+#endif
 
 #define R128_VERBOSE   0
 

Reply via email to