diff options
| author | Dave Jones <davej@redhat.com> | 2005-03-11 13:11:50 -0500 |
|---|---|---|
| committer | Dave Jones <davej@redhat.com> | 2005-03-11 13:11:50 -0500 |
| commit | 5f7435968f50615831b44ea5c1b5034a3e407d32 (patch) | |
| tree | bb0aae3f095f6b0c2570bac390f8d9cf641427b7 | |
| parent | e8a542874606691df2d754c2a37153085a4b64ae (diff) | |
[AGPGART] SGI TIO support.
From: Mike Werner
Signed-off-by: Dave Jones <davej@redhat.com>
| -rw-r--r-- | drivers/char/agp/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/char/agp/Makefile | 2 | ||||
| -rw-r--r-- | drivers/char/agp/sgi-agp.c | 331 |
3 files changed, 339 insertions, 1 deletions
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 2b15c4ce84f0..67765afadbff 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -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. + diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index dbe8758474df..d33a22f2fa0b 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -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 index 000000000000..4b3eda267976 --- /dev/null +++ b/drivers/char/agp/sgi-agp.c @@ -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"); |
