]> git.neil.brown.name Git - history.git/commitdiff
[AGPGART] SGI TIO support.
authorDave Jones <davej@redhat.com>
Fri, 11 Mar 2005 18:11:50 +0000 (13:11 -0500)
committerDave Jones <davej@redhat.com>
Fri, 11 Mar 2005 18:11:50 +0000 (13:11 -0500)
From: Mike Werner
Signed-off-by: Dave Jones <davej@redhat.com>
drivers/char/agp/Kconfig
drivers/char/agp/Makefile
drivers/char/agp/sgi-agp.c [new file with mode: 0644]

index 2b15c4ce84f0f202e067daa9cd0da0e8e1732be4..67765afadbff97c99fc79e9403bbeb888453f759 100644 (file)
@@ -162,3 +162,10 @@ config AGP_EFFICEON
          You should say Y here if you use XFree86 3.3.6 or 4.x and want to
          use GLX or DRI.  If unsure, say Y.
 
+config AGP_SGI_TIOCA
+        tristate "SGI TIO chipset AGP support"
+        depends on AGP && (IA64_SGI_SN2 || IA64_GENERIC)
+        help
+          This option gives you AGP GART support for the SGI TIO chipset
+          for IA64 processors.
+
index dbe8758474df38778e1ceef71a0f77bd51a72368..d33a22f2fa0b9b2fa509517789884e119294851f 100644 (file)
@@ -11,8 +11,8 @@ obj-$(CONFIG_AGP_HP_ZX1)      += hp-agp.o
 obj-$(CONFIG_AGP_I460)         += i460-agp.o
 obj-$(CONFIG_AGP_INTEL)                += intel-agp.o
 obj-$(CONFIG_AGP_NVIDIA)       += nvidia-agp.o
+obj-$(CONFIG_AGP_SGI_TIOCA)    += sgi-agp.o
 obj-$(CONFIG_AGP_SIS)          += sis-agp.o
 obj-$(CONFIG_AGP_SWORKS)       += sworks-agp.o
 obj-$(CONFIG_AGP_UNINORTH)     += uninorth-agp.o
 obj-$(CONFIG_AGP_VIA)          += via-agp.o
-
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
new file mode 100644 (file)
index 0000000..4b3eda2
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+/*
+ * SGI TIOCA AGPGART routines.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/tioca_provider.h>
+#include "agp.h"
+
+extern int agp_memory_reserved;
+extern uint32_t tioca_gart_found;
+extern struct list_head tioca_list;
+static struct agp_bridge_data **sgi_tioca_agp_bridges;
+
+/*
+ * The aperature size and related information is set up at TIOCA init time.
+ * Values for this table will be extracted and filled in at
+ * sgi_tioca_fetch_size() time.
+ */
+
+static struct aper_size_info_fixed sgi_tioca_sizes[] = {
+       {0, 0, 0},
+};
+
+static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
+{
+       struct page *page;
+       int nid;
+       struct tioca_kernel *info =
+           (struct tioca_kernel *)bridge->dev_private_data;
+
+       nid = info->ca_closest_node;
+       page = alloc_pages_node(nid, GFP_KERNEL, 0);
+       if (page == NULL) {
+               return 0;
+       }
+
+       get_page(page);
+       SetPageLocked(page);
+       atomic_inc(&agp_bridge->current_memory_agp);
+       return page_address(page);
+}
+
+/*
+ * Flush GART tlb's.  Cannot selectively flush based on memory so the mem
+ * arg is ignored.
+ */
+
+static void sgi_tioca_tlbflush(struct agp_memory *mem)
+{
+       tioca_tlbflush(mem->bridge->dev_private_data);
+}
+
+/*
+ * Given an address of a host physical page, turn it into a valid gart
+ * entry.
+ */
+static unsigned long
+sgi_tioca_mask_memory(struct agp_bridge_data *bridge,
+                     unsigned long addr, int type)
+{
+       return tioca_physpage_to_gart(addr);
+}
+
+static void sgi_tioca_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+{
+       tioca_fastwrite_enable(bridge->dev_private_data);
+}
+
+/*
+ * sgi_tioca_configure() doesn't have anything to do since the base CA driver
+ * has alreay set up the GART.
+ */
+
+static int sgi_tioca_configure(void)
+{
+       return 0;
+}
+
+/*
+ * Determine gfx aperature size.  This has already been determined by the
+ * CA driver init, so just need to set agp_bridge values accordingly.
+ */
+
+static int sgi_tioca_fetch_size(void)
+{
+       struct tioca_kernel *info =
+           (struct tioca_kernel *)agp_bridge->dev_private_data;
+
+       sgi_tioca_sizes[0].size = info->ca_gfxap_size / MB(1);
+       sgi_tioca_sizes[0].num_entries = info->ca_gfxgart_entries;
+
+       return sgi_tioca_sizes[0].size;
+}
+
+static int sgi_tioca_create_gatt_table(struct agp_bridge_data *bridge)
+{
+       struct tioca_kernel *info =
+           (struct tioca_kernel *)bridge->dev_private_data;
+
+       bridge->gatt_table_real = (u32 *) info->ca_gfxgart;
+       bridge->gatt_table = bridge->gatt_table_real;
+       bridge->gatt_bus_addr = info->ca_gfxgart_base;
+
+       return 0;
+}
+
+static int sgi_tioca_free_gatt_table(struct agp_bridge_data *bridge)
+{
+       return 0;
+}
+
+static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
+                                  int type)
+{
+       int num_entries;
+       size_t i;
+       off_t j;
+       void *temp;
+       struct agp_bridge_data *bridge;
+
+       bridge = mem->bridge;
+       if (!bridge)
+               return -EINVAL;
+
+       temp = bridge->current_size;
+
+       switch (bridge->driver->size_type) {
+       case U8_APER_SIZE:
+               num_entries = A_SIZE_8(temp)->num_entries;
+               break;
+       case U16_APER_SIZE:
+               num_entries = A_SIZE_16(temp)->num_entries;
+               break;
+       case U32_APER_SIZE:
+               num_entries = A_SIZE_32(temp)->num_entries;
+               break;
+       case FIXED_APER_SIZE:
+               num_entries = A_SIZE_FIX(temp)->num_entries;
+               break;
+       case LVL2_APER_SIZE:
+               return -EINVAL;
+               break;
+       default:
+               num_entries = 0;
+               break;
+       }
+
+       num_entries -= agp_memory_reserved / PAGE_SIZE;
+       if (num_entries < 0)
+               num_entries = 0;
+
+       if (type != 0 || mem->type != 0) {
+               return -EINVAL;
+       }
+
+       if ((pg_start + mem->page_count) > num_entries)
+               return -EINVAL;
+
+       j = pg_start;
+
+       while (j < (pg_start + mem->page_count)) {
+               if (*(bridge->gatt_table + j))
+                       return -EBUSY;
+               j++;
+       }
+
+       if (mem->is_flushed == FALSE) {
+               bridge->driver->cache_flush();
+               mem->is_flushed = TRUE;
+       }
+
+       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+               *(bridge->gatt_table + j) =
+                   bridge->driver->mask_memory(bridge, mem->memory[i],
+                                               mem->type);
+       }
+
+       bridge->driver->tlb_flush(mem);
+       return 0;
+}
+
+static int sgi_tioca_remove_memory(struct agp_memory *mem, off_t pg_start,
+                                  int type)
+{
+       size_t i;
+       struct agp_bridge_data *bridge;
+
+       bridge = mem->bridge;
+       if (!bridge)
+               return -EINVAL;
+
+       if (type != 0 || mem->type != 0) {
+               return -EINVAL;
+       }
+
+       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+               *(bridge->gatt_table + i) = 0;
+       }
+
+       bridge->driver->tlb_flush(mem);
+       return 0;
+}
+
+static void sgi_tioca_cache_flush(void)
+{
+}
+
+/*
+ * Cleanup.  Nothing to do as the CA driver owns the GART.
+ */
+
+static void sgi_tioca_cleanup(void)
+{
+}
+
+static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev)
+{
+       struct agp_bridge_data *bridge;
+
+       list_for_each_entry(bridge, &agp_bridges, list) {
+               if (bridge->dev->bus == pdev->bus)
+                       break;
+       }
+       return bridge;
+}
+
+struct agp_bridge_driver sgi_tioca_driver = {
+       .owner = THIS_MODULE,
+       .size_type = U16_APER_SIZE,
+       .configure = sgi_tioca_configure,
+       .fetch_size = sgi_tioca_fetch_size,
+       .cleanup = sgi_tioca_cleanup,
+       .tlb_flush = sgi_tioca_tlbflush,
+       .mask_memory = sgi_tioca_mask_memory,
+       .agp_enable = sgi_tioca_agp_enable,
+       .cache_flush = sgi_tioca_cache_flush,
+       .create_gatt_table = sgi_tioca_create_gatt_table,
+       .free_gatt_table = sgi_tioca_free_gatt_table,
+       .insert_memory = sgi_tioca_insert_memory,
+       .remove_memory = sgi_tioca_remove_memory,
+       .alloc_by_type = agp_generic_alloc_by_type,
+       .free_by_type = agp_generic_free_by_type,
+       .agp_alloc_page = sgi_tioca_alloc_page,
+       .agp_destroy_page = agp_generic_destroy_page,
+       .cant_use_aperture = 1,
+       .needs_scratch_page = 0,
+       .num_aperture_sizes = 1,
+};
+
+static int __devinit agp_sgi_init(void)
+{
+       unsigned int j;
+       struct tioca_kernel *info;
+       struct pci_dev *pdev = NULL;
+
+       if (tioca_gart_found)
+               printk(KERN_INFO PFX "SGI TIO CA GART driver initialized.\n");
+       else
+               return 0;
+
+       sgi_tioca_agp_bridges =
+           (struct agp_bridge_data **)kmalloc(tioca_gart_found *
+                                              sizeof(struct agp_bridge_data *),
+                                              GFP_KERNEL);
+
+       j = 0;
+       list_for_each_entry(info, &tioca_list, ca_list) {
+               struct list_head *tmp;
+               list_for_each(tmp, info->ca_devices) {
+                       u8 cap_ptr;
+                       pdev = pci_dev_b(tmp);
+                       if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
+                               continue;
+                       cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+                       if (!cap_ptr)
+                               continue;
+               }
+               sgi_tioca_agp_bridges[j] = agp_alloc_bridge();
+               printk(KERN_INFO PFX "bridge %d = 0x%p\n", j,
+                      sgi_tioca_agp_bridges[j]);
+               if (sgi_tioca_agp_bridges[j]) {
+                       sgi_tioca_agp_bridges[j]->dev = pdev;
+                       sgi_tioca_agp_bridges[j]->dev_private_data = info;
+                       sgi_tioca_agp_bridges[j]->driver = &sgi_tioca_driver;
+                       sgi_tioca_agp_bridges[j]->gart_bus_addr =
+                           info->ca_gfxap_base;
+                       sgi_tioca_agp_bridges[j]->mode = (0x7D << 24) | /* 126 requests */
+                           (0x1 << 9) |        /* SBA supported */
+                           (0x1 << 5) |        /* 64-bit addresses supported */
+                           (0x1 << 4) |        /* FW supported */
+                           (0x1 << 3) |        /* AGP 3.0 mode */
+                           0x2;        /* 8x transfer only */
+                       sgi_tioca_agp_bridges[j]->current_size =
+                           sgi_tioca_agp_bridges[j]->previous_size =
+                           (void *)&sgi_tioca_sizes[0];
+                       agp_add_bridge(sgi_tioca_agp_bridges[j]);
+               }
+               j++;
+       }
+
+       agp_find_bridge = &sgi_tioca_find_bridge;
+       return 0;
+}
+
+static void __devexit agp_sgi_cleanup(void)
+{
+       if(sgi_tioca_agp_bridges)
+               kfree(sgi_tioca_agp_bridges);
+       sgi_tioca_agp_bridges=NULL;
+}
+
+module_init(agp_sgi_init);
+module_exit(agp_sgi_cleanup);
+
+MODULE_LICENSE("GPL and additional rights");