Index: oldkernel/linux/Documentation/Configure.help diff -u linux/Documentation/Configure.help:1.8 linux/Documentation/Configure.help:1.9 --- linux/Documentation/Configure.help:1.8 Thu Jun 1 17:01:59 2000 +++ linux/Documentation/Configure.help Thu Jun 1 17:12:56 2000 @@ -9369,6 +9369,20 @@ sampling), then say Y here, and read Documentation/rtc.txt for details. +AGP/GART support +CONFIG_AGP + This provides a kernel interface (/dev/agpgart) for programming AGP + transfers on motherboards that support them. Primarily, this is used + for hardware-accelerated 3d graphics, though any other AGP device + could take advantage of it. + + If you have a 3d-capable AGP video card say 'M' or 'Y' here. + Otherwise, say 'N'. + + You will also have to indicate support for your specific chipset. + Consult the output of lspci, your motherboard manual, or the inside + of your computer if unsure what to choose. Multiple selections are ok. + Tadpole ANA H8 Support CONFIG_H8 The Hitachi H8/337 is a microcontroller used to deal with the power Index: oldkernel/linux/arch/i386/mm/ioremap.c diff -u linux/arch/i386/mm/ioremap.c:1.1.1.1 linux/arch/i386/mm/ioremap.c:1.2 --- linux/arch/i386/mm/ioremap.c:1.1.1.1 Wed May 31 12:33:53 2000 +++ linux/arch/i386/mm/ioremap.c Thu Jun 1 17:12:57 2000 @@ -110,7 +110,18 @@ * Don't allow anybody to remap normal RAM that we're using.. */ if (phys_addr < virt_to_phys(high_memory)) - return NULL; + { + char *temp_addr, *temp_end; + int i; + + temp_addr = __va(phys_addr); + temp_end = temp_addr + (size - 1); + + for(i = MAP_NR(temp_addr); i < MAP_NR(temp_end); i++) { + if(!PageReserved(mem_map + i)) + return NULL; + } + } /* * Mappings have to be page-aligned Index: oldkernel/linux/drivers/char/Config.in diff -u linux/drivers/char/Config.in:1.2 linux/drivers/char/Config.in:1.3 --- linux/drivers/char/Config.in:1.2 Thu Jun 1 17:01:59 2000 +++ linux/drivers/char/Config.in Thu Jun 1 17:12:57 2000 @@ -62,7 +62,7 @@ bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK fi fi - + bool 'Mouse Support (not serial mice)' CONFIG_MOUSE if [ "$CONFIG_MOUSE" = "y" ]; then mainmenu_option next_comment @@ -118,6 +118,18 @@ bool 'Tadpole ANA H8 Support' CONFIG_H8 fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate '/dev/agpgart (AGP Support) (EXPERIMENTAL)' CONFIG_AGP + if [ "$CONFIG_AGP" != "n" ]; then + bool ' Intel 440LX/BX/GX support' CONFIG_AGP_INTEL + bool ' Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810 + bool ' VIA VP3/MVP3/Apollo Pro support' CONFIG_AGP_VIA + bool ' AMD Irongate support' CONFIG_AGP_AMD + bool ' Generic SiS support' CONFIG_AGP_SIS + bool ' ALI M1541 support' CONFIG_AGP_ALI + fi +fi + mainmenu_option next_comment comment 'Video For Linux' Index: oldkernel/linux/drivers/char/Makefile diff -u linux/drivers/char/Makefile:1.3 linux/drivers/char/Makefile:1.4 --- linux/drivers/char/Makefile:1.3 Thu Jun 1 17:01:59 2000 +++ linux/drivers/char/Makefile Thu Jun 1 17:12:57 2000 @@ -360,6 +360,17 @@ endif endif +ifeq ($(CONFIG_AGP),y) +L_OBJS += agp/agp.o +ALL_SUB_DIRS += agp +SUB_DIRS += agp +else + ifeq ($(CONFIG_AGP),m) + ALL_SUB_DIRS += agp + MOD_SUB_DIRS += agp + endif +endif + ifeq ($(CONFIG_VIDEO_DEV),y) LX_OBJS += videodev.o else Index: oldkernel/linux/drivers/char/agp/Makefile diff -u /dev/null linux/drivers/char/agp/Makefile:1.1 --- /dev/null Mon Jul 31 21:14:58 2000 +++ linux/drivers/char/agp/Makefile Thu Jun 1 17:12:57 2000 @@ -0,0 +1,22 @@ +# +# Makefile for the agpgart device driver. This driver adds a user +# space ioctl interface to use agp memory. It also adds a kernel interface +# that other drivers could use to manipulate agp memory. + +O_TARGET := agp.o + +ifeq ($(CONFIG_AGP),y) + O_OBJS += agpgart_fe.o + OX_OBJS += agpgart_be.o +else + ifeq ($(CONFIG_AGP), m) + MI_OBJS += agpgart_fe.o + MIX_OBJS += agpgart_be.o + M_OBJS += agpgart.o + endif +endif + +include $(TOPDIR)/Rules.make + +agpgart.o: agpgart_be.o agpgart_fe.o + $(LD) $(LD_RFLAG) -r -o $@ agpgart_be.o agpgart_fe.o Index: oldkernel/linux/drivers/char/agp/agp.h diff -u /dev/null linux/drivers/char/agp/agp.h:1.1 --- /dev/null Mon Jul 31 21:14:58 2000 +++ linux/drivers/char/agp/agp.h Thu Jun 1 17:12:57 2000 @@ -0,0 +1,254 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 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 + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS 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. + * + */ + +#ifndef _AGP_BACKEND_PRIV_H +#define _AGP_BACKEND_PRIV_H 1 + +enum aper_size_type { + U8_APER_SIZE, + U16_APER_SIZE, + U32_APER_SIZE, + FIXED_APER_SIZE +}; + +typedef struct _gatt_mask { + unsigned long mask; + u32 type; + /* totally device specific, for integrated chipsets that + * might have different types of memory masks. For other + * devices this will probably be ignored */ +} gatt_mask; + +typedef struct _aper_size_info_8 { + int size; + int num_entries; + int page_order; + u8 size_value; +} aper_size_info_8; + +typedef struct _aper_size_info_16 { + int size; + int num_entries; + int page_order; + u16 size_value; +} aper_size_info_16; + +typedef struct _aper_size_info_32 { + int size; + int num_entries; + int page_order; + u32 size_value; +} aper_size_info_32; + +typedef struct _aper_size_info_fixed { + int size; + int num_entries; + int page_order; +} aper_size_info_fixed; + +struct agp_bridge_data { + agp_version *version; + void *aperture_sizes; + void *previous_size; + void *current_size; + void *dev_private_data; + struct pci_dev *dev; + gatt_mask *masks; + unsigned long *gatt_table; + unsigned long *gatt_table_real; + unsigned long scratch_page; + unsigned long gart_bus_addr; + unsigned long gatt_bus_addr; + u32 mode; + enum chipset_type type; + enum aper_size_type size_type; + u32 *key_list; + atomic_t current_memory_agp; + atomic_t agp_in_use; + int max_memory_agp; /* in number of pages */ + int needs_scratch_page; + int aperture_size_idx; + int num_aperture_sizes; + int num_of_masks; + int capndx; + + /* Links to driver specific functions */ + + int (*fetch_size) (void); + int (*configure) (void); + void (*agp_enable) (u32); + void (*cleanup) (void); + void (*tlb_flush) (agp_memory *); + unsigned long (*mask_memory) (unsigned long, int); + void (*cache_flush) (void); + int (*create_gatt_table) (void); + int (*free_gatt_table) (void); + int (*insert_memory) (agp_memory *, off_t, int); + int (*remove_memory) (agp_memory *, off_t, int); + agp_memory *(*alloc_by_type) (size_t, int); + void (*free_by_type) (agp_memory *); +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 3, 0) +#define OUTREG32(mmap, addr, val) *(volatile u32 *)(mmap + (addr)) = (val) +#define OUTREG16(mmap, addr, val) *(volatile u16 *)(mmap + (addr)) = (val) +#define OUTREG8 (mmap, addr, val) *(volatile u8 *) (mmap + (addr)) = (val) + +#define INREG32(mmap, addr) *(volatile u32 *)(mmap + (addr)) +#define INREG16(mmap, addr) *(volatile u16 *)(mmap + (addr)) +#define INREG8 (mmap, addr) *(volatile u8 *) (mmap + (addr)) +#else +#define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr)) +#define OUTREG16(mmap, addr, val) __raw_writew((val), (mmap)+(addr)) +#define OUTREG8 (mmap, addr, val) __raw_writeb((val), (mmap)+(addr)) + +#define INREG32(mmap, addr) __raw_readl((mmap)+(addr)) +#define INREG16(mmap, addr) __raw_readw((mmap)+(addr)) +#define INREG8 (mmap, addr) __raw_readb((mmap)+(addr)) +#endif + +#define CACHE_FLUSH agp_bridge.cache_flush +#define A_SIZE_8(x) ((aper_size_info_8 *) x) +#define A_SIZE_16(x) ((aper_size_info_16 *) x) +#define A_SIZE_32(x) ((aper_size_info_32 *) x) +#define A_SIZE_FIX(x) ((aper_size_info_fixed *) x) +#define A_IDX8() (A_SIZE_8(agp_bridge.aperture_sizes) + i) +#define A_IDX16() (A_SIZE_16(agp_bridge.aperture_sizes) + i) +#define A_IDX32() (A_SIZE_32(agp_bridge.aperture_sizes) + i) +#define A_IDXFIX() (A_SIZE_FIX(agp_bridge.aperture_sizes) + i) +#define MAXKEY (4096 * 32) + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +#define AGPGART_MODULE_NAME "agpgart" +#define PFX AGPGART_MODULE_NAME ": " + +#define PGE_EMPTY(p) (!(p) || (p) == (unsigned long) agp_bridge.scratch_page) + +#ifndef PCI_DEVICE_ID_VIA_82C691_0 +#define PCI_DEVICE_ID_VIA_82C691_0 0x0691 +#endif +#ifndef PCI_DEVICE_ID_VIA_82C691_1 +#define PCI_DEVICE_ID_VIA_82C691_1 0x8691 +#endif +#ifndef PCI_DEVICE_ID_VIA_8501_0 +#define PCI_DEVICE_ID_VIA_8501_0 0x0501 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_0 +#define PCI_DEVICE_ID_INTEL_810_0 0x7120 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_DC100_0 +#define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_E_0 +#define PCI_DEVICE_ID_INTEL_810_E_0 0x7124 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82443GX_0 +#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_1 +#define PCI_DEVICE_ID_INTEL_810_1 0x7121 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_DC100_1 +#define PCI_DEVICE_ID_INTEL_810_DC100_1 0x7123 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_E_1 +#define PCI_DEVICE_ID_INTEL_810_E_1 0x7125 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82443GX_1 +#define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1 +#endif +#ifndef PCI_DEVICE_ID_AMD_IRONGATE_0 +#define PCI_DEVICE_ID_AMD_IRONGATE_0 0x7006 +#endif +#ifndef PCI_VENDOR_ID_AL +#define PCI_VENDOR_ID_AL 0x10b9 +#endif +#ifndef PCI_DEVICE_ID_AL_M1541_0 +#define PCI_DEVICE_ID_AL_M1541_0 0x1541 +#endif + +/* intel register */ +#define INTEL_APBASE 0x10 +#define INTEL_APSIZE 0xb4 +#define INTEL_ATTBASE 0xb8 +#define INTEL_AGPCTRL 0xb0 +#define INTEL_NBXCFG 0x50 +#define INTEL_ERRSTS 0x91 + +/* intel i810 registers */ +#define I810_GMADDR 0x10 +#define I810_MMADDR 0x14 +#define I810_PTE_BASE 0x10000 +#define I810_PTE_MAIN_UNCACHED 0x00000000 +#define I810_PTE_LOCAL 0x00000002 +#define I810_PTE_VALID 0x00000001 +#define I810_SMRAM_MISCC 0x70 +#define I810_GFX_MEM_WIN_SIZE 0x00010000 +#define I810_GFX_MEM_WIN_32M 0x00010000 +#define I810_GMS 0x000000c0 +#define I810_GMS_DISABLE 0x00000000 +#define I810_PGETBL_CTL 0x2020 +#define I810_PGETBL_ENABLED 0x00000001 +#define I810_DRAM_CTL 0x3000 +#define I810_DRAM_ROW_0 0x00000001 +#define I810_DRAM_ROW_0_SDRAM 0x00000001 + +/* VIA register */ +#define VIA_APBASE 0x10 +#define VIA_GARTCTRL 0x80 +#define VIA_APSIZE 0x84 +#define VIA_ATTBASE 0x88 + +/* SiS registers */ +#define SIS_APBASE 0x10 +#define SIS_ATTBASE 0x90 +#define SIS_APSIZE 0x94 +#define SIS_TLBCNTRL 0x97 +#define SIS_TLBFLUSH 0x98 + +/* AMD registers */ +#define AMD_APBASE 0x10 +#define AMD_MMBASE 0x14 +#define AMD_APSIZE 0xac +#define AMD_MODECNTL 0xb0 +#define AMD_MODECNTL2 0xb2 +#define AMD_GARTENABLE 0x02 /* In mmio region (16-bit register) */ +#define AMD_ATTBASE 0x04 /* In mmio region (32-bit register) */ +#define AMD_TLBFLUSH 0x0c /* In mmio region (32-bit register) */ +#define AMD_CACHEENTRY 0x10 /* In mmio region (32-bit register) */ + +/* ALi registers */ +#define ALI_APBASE 0x10 +#define ALI_AGPCTRL 0xb8 +#define ALI_ATTBASE 0xbc +#define ALI_TLBCTRL 0xc0 + +#endif /* _AGP_BACKEND_PRIV_H */ Index: oldkernel/linux/drivers/char/agp/agpgart_be.c diff -u /dev/null linux/drivers/char/agp/agpgart_be.c:1.1 --- /dev/null Mon Jul 31 21:14:58 2000 +++ linux/drivers/char/agp/agpgart_be.c Thu Jun 1 17:12:57 2000 @@ -0,0 +1,2161 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 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 + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + +MODULE_AUTHOR("Jeff Hartmann "); +MODULE_PARM(agp_try_unsupported, "1i"); +EXPORT_SYMBOL(agp_free_memory); +EXPORT_SYMBOL(agp_allocate_memory); +EXPORT_SYMBOL(agp_copy_info); +EXPORT_SYMBOL(agp_bind_memory); +EXPORT_SYMBOL(agp_unbind_memory); +EXPORT_SYMBOL(agp_enable); +EXPORT_SYMBOL(agp_backend_acquire); +EXPORT_SYMBOL(agp_backend_release); + +static void flush_cache(void); + +static struct agp_bridge_data agp_bridge; +static int agp_try_unsupported __initdata = 0; + + +static inline void flush_cache(void) +{ +#if defined(__i386__) + asm volatile ("wbinvd":::"memory"); +#elif defined(__alpha__) + /* ??? 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 + preparation for power failure. + + If we do need to call `cflush', we'll need a target page, + as we can only flush one page at a time. */ + mb(); +#else +#error "Please define flush_cache." +#endif +} + +#ifdef __SMP__ +static atomic_t cpus_waiting; + +static void ipi_handler(void *null) +{ + flush_cache(); + atomic_dec(&cpus_waiting); + while (atomic_read(&cpus_waiting) > 0) + barrier(); +} + +static void smp_flush_cache(void) +{ + atomic_set(&cpus_waiting, smp_num_cpus - 1); + if (smp_call_function(ipi_handler, NULL, 1, 0) != 0) + panic(PFX "timed out waiting for the other CPUs!\n"); + flush_cache(); + while (atomic_read(&cpus_waiting) > 0) + barrier(); +} +#define global_cache_flush smp_flush_cache +#else /* __SMP__ */ +#define global_cache_flush flush_cache +#endif /* __SMP__ */ + +int agp_backend_acquire(void) +{ + atomic_inc(&agp_bridge.agp_in_use); + + if (atomic_read(&agp_bridge.agp_in_use) != 1) { + atomic_dec(&agp_bridge.agp_in_use); + return -EBUSY; + } + MOD_INC_USE_COUNT; + return 0; +} + +void agp_backend_release(void) +{ + atomic_dec(&agp_bridge.agp_in_use); + MOD_DEC_USE_COUNT; +} + +/* + * Basic Page Allocation Routines - + * These routines handle page allocation + * and by default they reserve the allocated + * memory. They also handle incrementing the + * current_memory_agp value, Which is checked + * against a maximum value. + */ + +static unsigned long agp_alloc_page(void) +{ + void *pt; + + pt = (void *) __get_free_page(GFP_KERNEL); + if (pt == NULL) { + return 0; + } + atomic_inc(&mem_map[MAP_NR(pt)].count); + set_bit(PG_locked, &mem_map[MAP_NR(pt)].flags); + atomic_inc(&agp_bridge.current_memory_agp); + return (unsigned long) pt; +} + +static void agp_destroy_page(unsigned long page) +{ + void *pt = (void *) page; + + if (pt == NULL) { + return; + } + atomic_dec(&mem_map[MAP_NR(pt)].count); + clear_bit(PG_locked, &mem_map[MAP_NR(pt)].flags); + wake_up(&mem_map[MAP_NR(pt)].wait); + free_page((unsigned long) pt); + atomic_dec(&agp_bridge.current_memory_agp); +} + +/* End Basic Page Allocation Routines */ + +/* + * Generic routines for handling agp_memory structures - + * They use the basic page allocation routines to do the + * brunt of the work. + */ + + +static void agp_free_key(int key) +{ + + if (key < 0) { + return; + } + if (key < MAXKEY) { + clear_bit(key, agp_bridge.key_list); + } +} + +static int agp_get_key(void) +{ + int bit; + + bit = find_first_zero_bit(agp_bridge.key_list, MAXKEY); + if (bit < MAXKEY) { + set_bit(bit, agp_bridge.key_list); + return bit; + } + return -1; +} + +static agp_memory *agp_create_memory(int scratch_pages) +{ + agp_memory *new; + + new = kmalloc(sizeof(agp_memory), GFP_KERNEL); + + if (new == NULL) { + return NULL; + } + memset(new, 0, sizeof(agp_memory)); + new->key = agp_get_key(); + + if (new->key < 0) { + kfree(new); + return NULL; + } + new->memory = vmalloc(PAGE_SIZE * scratch_pages); + + if (new->memory == NULL) { + agp_free_key(new->key); + kfree(new); + return NULL; + } + new->num_scratch_pages = scratch_pages; + return new; +} + +void agp_free_memory(agp_memory * curr) +{ + int i; + + if (curr == NULL) { + return; + } + if (curr->is_bound == TRUE) { + agp_unbind_memory(curr); + } + if (curr->type != 0) { + agp_bridge.free_by_type(curr); + return; + } + if (curr->page_count != 0) { + for (i = 0; i < curr->page_count; i++) { + curr->memory[i] &= ~(0x00000fff); + agp_destroy_page((unsigned long) + phys_to_virt(curr->memory[i])); + } + } + agp_free_key(curr->key); + vfree(curr->memory); + kfree(curr); + MOD_DEC_USE_COUNT; +} + +#define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long)) + +agp_memory *agp_allocate_memory(size_t page_count, u32 type) +{ + int scratch_pages; + agp_memory *new; + int i; + + if ((atomic_read(&agp_bridge.current_memory_agp) + page_count) > + agp_bridge.max_memory_agp) { + return NULL; + } + + if (type != 0) { + new = agp_bridge.alloc_by_type(page_count, type); + return new; + } + /* We always increase the module count, since free auto-decrements + * it + */ + + MOD_INC_USE_COUNT; + + scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE; + + new = agp_create_memory(scratch_pages); + + if (new == NULL) { + MOD_DEC_USE_COUNT; + return NULL; + } + for (i = 0; i < page_count; i++) { + new->memory[i] = agp_alloc_page(); + + if (new->memory[i] == 0) { + /* Free this structure */ + agp_free_memory(new); + return NULL; + } + new->memory[i] = + agp_bridge.mask_memory( + virt_to_phys((void *) new->memory[i]), + type); + new->page_count++; + } + + return new; +} + +/* End - Generic routines for handling agp_memory structures */ + +static int agp_return_size(void) +{ + int current_size; + void *temp; + + temp = agp_bridge.current_size; + + switch (agp_bridge.size_type) { + case U8_APER_SIZE: + current_size = A_SIZE_8(temp)->size; + break; + case U16_APER_SIZE: + current_size = A_SIZE_16(temp)->size; + break; + case U32_APER_SIZE: + current_size = A_SIZE_32(temp)->size; + break; + case FIXED_APER_SIZE: + current_size = A_SIZE_FIX(temp)->size; + break; + default: + current_size = 0; + break; + } + + return current_size; +} + +/* Routine to copy over information structure */ + +void agp_copy_info(agp_kern_info * info) +{ + memset(info, 0, sizeof(agp_kern_info)); + info->version.major = agp_bridge.version->major; + info->version.minor = agp_bridge.version->minor; + info->device = agp_bridge.dev; + info->chipset = agp_bridge.type; + info->mode = agp_bridge.mode; + info->aper_base = agp_bridge.gart_bus_addr; + info->aper_size = agp_return_size(); + info->max_memory = agp_bridge.max_memory_agp; + info->current_memory = atomic_read(&agp_bridge.current_memory_agp); +} + +/* End - Routine to copy over information structure */ + +/* + * Routines for handling swapping of agp_memory into the GATT - + * These routines take agp_memory and insert them into the GATT. + * They call device specific routines to actually write to the GATT. + */ + +int agp_bind_memory(agp_memory * curr, off_t pg_start) +{ + int ret_val; + + if ((curr == NULL) || (curr->is_bound == TRUE)) { + return -EINVAL; + } + if (curr->is_flushed == FALSE) { + CACHE_FLUSH(); + curr->is_flushed = TRUE; + } + ret_val = agp_bridge.insert_memory(curr, pg_start, curr->type); + + if (ret_val != 0) { + return ret_val; + } + curr->is_bound = TRUE; + curr->pg_start = pg_start; + return 0; +} + +int agp_unbind_memory(agp_memory * curr) +{ + int ret_val; + + if (curr == NULL) { + return -EINVAL; + } + if (curr->is_bound != TRUE) { + return -EINVAL; + } + ret_val = agp_bridge.remove_memory(curr, curr->pg_start, curr->type); + + if (ret_val != 0) { + return ret_val; + } + curr->is_bound = FALSE; + curr->pg_start = 0; + return 0; +} + +/* End - Routines for handling swapping of agp_memory into the GATT */ + +/* + * Driver routines - start + * Currently this module supports the + * i810, 440lx, 440bx, 440gx, via vp3, via mvp3, + * amd irongate, ALi M1541 and generic support for the + * SiS chipsets. + */ + +/* Generic Agp routines - Start */ + +static void agp_generic_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((mode & 0xff000000), + min((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; + + pci_write_config_dword(agp_bridge.dev, + agp_bridge.capndx + 8, + command); + + /* + * 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); + } +} + +static int agp_generic_create_gatt_table(void) +{ + char *table; + char *table_end; + int size; + int page_order; + int num_entries; + int i; + void *temp; + + table = NULL; + i = agp_bridge.aperture_size_idx; + temp = agp_bridge.current_size; + size = page_order = num_entries = 0; + + if (agp_bridge.size_type != FIXED_APER_SIZE) { + do { + switch (agp_bridge.size_type) { + case U8_APER_SIZE: + size = A_SIZE_8(temp)->size; + page_order = + A_SIZE_8(temp)->page_order; + num_entries = + A_SIZE_8(temp)->num_entries; + break; + case U16_APER_SIZE: + size = A_SIZE_16(temp)->size; + page_order = A_SIZE_16(temp)->page_order; + num_entries = A_SIZE_16(temp)->num_entries; + break; + case U32_APER_SIZE: + size = A_SIZE_32(temp)->size; + page_order = A_SIZE_32(temp)->page_order; + num_entries = A_SIZE_32(temp)->num_entries; + break; + /* This case will never really happen. */ + case FIXED_APER_SIZE: + default: + size = page_order = num_entries = 0; + break; + } + + table = (char *) __get_free_pages(GFP_KERNEL, + page_order); + + if (table == NULL) { + i++; + switch (agp_bridge.size_type) { + case U8_APER_SIZE: + agp_bridge.current_size = A_IDX8(); + break; + case U16_APER_SIZE: + agp_bridge.current_size = A_IDX16(); + break; + case U32_APER_SIZE: + agp_bridge.current_size = A_IDX32(); + break; + /* This case will never really + * happen. + */ + case FIXED_APER_SIZE: + default: + agp_bridge.current_size = + agp_bridge.current_size; + break; + } + } else { + agp_bridge.aperture_size_idx = i; + } + } while ((table == NULL) && + (i < agp_bridge.num_aperture_sizes)); + } else { + size = ((aper_size_info_fixed *) temp)->size; + page_order = ((aper_size_info_fixed *) temp)->page_order; + num_entries = ((aper_size_info_fixed *) temp)->num_entries; + table = (char *) __get_free_pages(GFP_KERNEL, page_order); + } + + if (table == NULL) { + return -ENOMEM; + } + table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); + + for (i = MAP_NR(table); i < MAP_NR(table_end); i++) { + set_bit(PG_reserved, &mem_map[i].flags); + } + + agp_bridge.gatt_table_real = (unsigned long *) table; + CACHE_FLUSH(); + agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table), + (PAGE_SIZE * (1 << page_order))); + CACHE_FLUSH(); + + if (agp_bridge.gatt_table == NULL) { + for (i = MAP_NR(table); i < MAP_NR(table_end); i++) { + clear_bit(PG_reserved, &mem_map[i].flags); + } + + free_pages((unsigned long) table, page_order); + + return -ENOMEM; + } + agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real); + + for (i = 0; i < num_entries; i++) { + agp_bridge.gatt_table[i] = + (unsigned long) agp_bridge.scratch_page; + } + + return 0; +} + +static int agp_generic_free_gatt_table(void) +{ + int i; + int page_order; + char *table, *table_end; + void *temp; + + temp = agp_bridge.current_size; + + switch (agp_bridge.size_type) { + case U8_APER_SIZE: + page_order = A_SIZE_8(temp)->page_order; + break; + case U16_APER_SIZE: + page_order = A_SIZE_16(temp)->page_order; + break; + case U32_APER_SIZE: + page_order = A_SIZE_32(temp)->page_order; + break; + case FIXED_APER_SIZE: + page_order = A_SIZE_FIX(temp)->page_order; + break; + default: + page_order = 0; + break; + } + + /* Do not worry about freeing memory, because if this is + * called, then all agp memory is deallocated and removed + * from the table. + */ + + iounmap(agp_bridge.gatt_table); + table = (char *) agp_bridge.gatt_table_real; + table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); + + for (i = MAP_NR(table); i < MAP_NR(table_end); i++) { + clear_bit(PG_reserved, &mem_map[i].flags); + } + + free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); + return 0; +} + +static int agp_generic_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, num_entries; + void *temp; + + temp = agp_bridge.current_size; + + switch (agp_bridge.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; + default: + num_entries = 0; + break; + } + + 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] = mem->memory[i]; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static int agp_generic_remove_memory(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + + if (type != 0 || mem->type != 0) { + /* The generic routines know nothing of memory types */ + return -EINVAL; + } + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + agp_bridge.gatt_table[i] = + (unsigned long) agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static agp_memory *agp_generic_alloc_by_type(size_t page_count, int type) +{ + return NULL; +} + +static void agp_generic_free_by_type(agp_memory * curr) +{ + if (curr->memory != NULL) { + vfree(curr->memory); + } + agp_free_key(curr->key); + kfree(curr); +} + +void agp_enable(u32 mode) +{ + agp_bridge.agp_enable(mode); +} + +/* End - Generic Agp routines */ + +#ifdef CONFIG_AGP_I810 +static aper_size_info_fixed intel_i810_sizes[] = +{ + {64, 16384, 4}, + /* The 32M mode still requires a 64k gatt */ + {32, 8192, 4} +}; + +#define AGP_DCACHE_MEMORY 1 +#define AGP_PHYS_MEMORY 2 + +static gatt_mask intel_i810_masks[] = +{ + {I810_PTE_VALID, 0}, + {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY}, + {I810_PTE_VALID, 0} +}; + +static struct _intel_i810_private { + struct pci_dev *i810_dev; /* device one */ + volatile u8 *registers; + int num_dcache_entries; +} intel_i810_private; + +static int intel_i810_fetch_size(void) +{ + u32 smram_miscc; + aper_size_info_fixed *values; + + pci_read_config_dword(agp_bridge.dev, I810_SMRAM_MISCC, &smram_miscc); + values = A_SIZE_FIX(agp_bridge.aperture_sizes); + + if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { + printk(KERN_WARNING PFX "i810 is disabled\n"); + return 0; + } + if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + 1); + agp_bridge.aperture_size_idx = 1; + return values[1].size; + } else { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values); + agp_bridge.aperture_size_idx = 0; + return values[0].size; + } + + return 0; +} + +static int intel_i810_configure(void) +{ + aper_size_info_fixed *current_size; + u32 temp; + int i; + + current_size = A_SIZE_FIX(agp_bridge.current_size); + + pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); + temp &= 0xfff80000; + + intel_i810_private.registers = + (volatile u8 *) ioremap(temp, 128 * 4096); + + if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL) + & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { + /* This will need to be dynamically assigned */ + printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); + intel_i810_private.num_dcache_entries = 1024; + } + pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, + agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED); + CACHE_FLUSH(); + + if (agp_bridge.needs_scratch_page == TRUE) { + for (i = 0; i < current_size->num_entries; i++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (i * 4), + agp_bridge.scratch_page); + } + } + return 0; +} + +static void intel_i810_cleanup(void) +{ + OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0); + iounmap((void *) intel_i810_private.registers); +} + +static void intel_i810_tlbflush(agp_memory * mem) +{ + return; +} + +static void intel_i810_agp_enable(u32 mode) +{ + return; +} + +static int intel_i810_insert_entries(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_FIX(temp)->num_entries; + + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + for (j = pg_start; j < (pg_start + mem->page_count); j++) { + if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { + return -EBUSY; + } + } + + if (type != 0 || mem->type != 0) { + if ((type == AGP_DCACHE_MEMORY) && + (mem->type == AGP_DCACHE_MEMORY)) { + /* special insert */ + CACHE_FLUSH(); + for (i = pg_start; + i < (pg_start + mem->page_count); i++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (i * 4), + (i * 4096) | I810_PTE_LOCAL | + I810_PTE_VALID); + } + CACHE_FLUSH(); + agp_bridge.tlb_flush(mem); + return 0; + } + if((type == AGP_PHYS_MEMORY) && + (mem->type == AGP_PHYS_MEMORY)) { + goto insert; + } + return -EINVAL; + } + +insert: + CACHE_FLUSH(); + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (j * 4), mem->memory[i]); + } + CACHE_FLUSH(); + + agp_bridge.tlb_flush(mem); + return 0; +} + +static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (i * 4), + agp_bridge.scratch_page); + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) +{ + agp_memory *new; + + if (type == AGP_DCACHE_MEMORY) { + if (pg_count != intel_i810_private.num_dcache_entries) { + return NULL; + } + new = agp_create_memory(1); + + if (new == NULL) { + return NULL; + } + new->type = AGP_DCACHE_MEMORY; + new->page_count = pg_count; + new->num_scratch_pages = 0; + vfree(new->memory); + MOD_INC_USE_COUNT; + return new; + } + if(type == AGP_PHYS_MEMORY) { + /* The I810 requires a physical address to program + * it's mouse pointer into hardware. However the + * Xserver still writes to it through the agp + * aperture + */ + if (pg_count != 1) { + return NULL; + } + new = agp_create_memory(1); + + if (new == NULL) { + return NULL; + } + MOD_INC_USE_COUNT; + new->memory[0] = agp_alloc_page(); + + if (new->memory[0] == 0) { + /* Free this structure */ + agp_free_memory(new); + return NULL; + } + new->memory[0] = + agp_bridge.mask_memory( + virt_to_phys((void *) new->memory[0]), + type); + new->page_count = 1; + new->num_scratch_pages = 1; + new->type = AGP_PHYS_MEMORY; + new->physical = virt_to_phys((void *) new->memory[0]); + return new; + } + + return NULL; +} + +static void intel_i810_free_by_type(agp_memory * curr) +{ + agp_free_key(curr->key); + if(curr->type == AGP_PHYS_MEMORY) { + agp_destroy_page((unsigned long) + phys_to_virt(curr->memory[0])); + vfree(curr->memory); + } + kfree(curr); + MOD_DEC_USE_COUNT; +} + +static unsigned long intel_i810_mask_memory(unsigned long addr, int type) +{ + /* Type checking must be done elsewhere */ + return addr | agp_bridge.masks[type].mask; +} + +static int __init intel_i810_setup(struct pci_dev *i810_dev) +{ + intel_i810_private.i810_dev = i810_dev; + + agp_bridge.masks = intel_i810_masks; + agp_bridge.num_of_masks = 2; + agp_bridge.aperture_sizes = (void *) intel_i810_sizes; + agp_bridge.size_type = FIXED_APER_SIZE; + agp_bridge.num_aperture_sizes = 2; + agp_bridge.dev_private_data = (void *) &intel_i810_private; + agp_bridge.needs_scratch_page = TRUE; + agp_bridge.configure = intel_i810_configure; + agp_bridge.fetch_size = intel_i810_fetch_size; + agp_bridge.cleanup = intel_i810_cleanup; + agp_bridge.tlb_flush = intel_i810_tlbflush; + agp_bridge.mask_memory = intel_i810_mask_memory; + agp_bridge.agp_enable = intel_i810_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = intel_i810_insert_entries; + agp_bridge.remove_memory = intel_i810_remove_entries; + agp_bridge.alloc_by_type = intel_i810_alloc_by_type; + agp_bridge.free_by_type = intel_i810_free_by_type; + + return 0; +} + +#endif /* CONFIG_AGP_I810 */ + +#ifdef CONFIG_AGP_INTEL + +static int intel_fetch_size(void) +{ + int i; + u16 temp; + aper_size_info_16 *values; + + pci_read_config_word(agp_bridge.dev, INTEL_APSIZE, &temp); + values = A_SIZE_16(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; + } + } + + return 0; +} + +static void intel_tlbflush(agp_memory * mem) +{ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2200); + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); +} + +static void intel_cleanup(void) +{ + u16 temp; + aper_size_info_16 *previous_size; + + previous_size = A_SIZE_16(agp_bridge.previous_size); + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); + pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, + previous_size->size_value); +} + +static int intel_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_16 *current_size; + + current_size = A_SIZE_16(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); + + /* paccfg/nbxcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, + (temp2 & ~(1 << 10)) | (1 << 9)); + /* clear any possible error conditions */ + pci_write_config_byte(agp_bridge.dev, INTEL_ERRSTS + 1, 7); + return 0; +} + +static unsigned long intel_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + + +/* Setup function */ +static gatt_mask intel_generic_masks[] = +{ + {0x00000017, 0} +}; + +static aper_size_info_16 intel_generic_sizes[7] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 32}, + {64, 16384, 4, 48}, + {32, 8192, 3, 56}, + {16, 4096, 2, 60}, + {8, 2048, 1, 62}, + {4, 1024, 0, 63} +}; + +static int __init intel_generic_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_generic_sizes; + agp_bridge.size_type = U16_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_configure; + agp_bridge.fetch_size = intel_fetch_size; + agp_bridge.cleanup = intel_cleanup; + agp_bridge.tlb_flush = intel_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_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; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_INTEL */ + +#ifdef CONFIG_AGP_VIA + +static int via_fetch_size(void) +{ + int i; + u8 temp; + aper_size_info_8 *values; + + values = A_SIZE_8(agp_bridge.aperture_sizes); + pci_read_config_byte(agp_bridge.dev, VIA_APSIZE, &temp); + 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; + } + } + + return 0; +} + +static int via_configure(void) +{ + u32 temp; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, VIA_APSIZE, + current_size->size_value); + /* address to map too */ + pci_read_config_dword(agp_bridge.dev, VIA_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* GART control register */ + pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f); + + /* attbase - aperture GATT base */ + pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE, + (agp_bridge.gatt_bus_addr & 0xfffff000) | 3); + return 0; +} + +static void via_cleanup(void) +{ + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE, 0); + pci_write_config_byte(agp_bridge.dev, VIA_APSIZE, + previous_size->size_value); +} + +static void via_tlbflush(agp_memory * mem) +{ + pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000008f); + pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f); +} + +static unsigned long via_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + +static aper_size_info_8 via_generic_sizes[7] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 128}, + {64, 16384, 4, 192}, + {32, 8192, 3, 224}, + {16, 4096, 2, 240}, + {8, 2048, 1, 248}, + {4, 1024, 0, 252} +}; + +static gatt_mask via_generic_masks[] = +{ + {0x00000000, 0} +}; + +static int __init via_generic_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = via_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) via_generic_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = via_configure; + agp_bridge.fetch_size = via_fetch_size; + agp_bridge.cleanup = via_cleanup; + agp_bridge.tlb_flush = via_tlbflush; + agp_bridge.mask_memory = via_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_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; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_VIA */ + +#ifdef CONFIG_AGP_SIS + +static int sis_fetch_size(void) +{ + u8 temp_size; + int i; + aper_size_info_8 *values; + + pci_read_config_byte(agp_bridge.dev, SIS_APSIZE, &temp_size); + values = A_SIZE_8(agp_bridge.aperture_sizes); + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if ((temp_size == values[i].size_value) || + ((temp_size & ~(0x03)) == + (values[i].size_value & ~(0x03)))) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + + +static void sis_tlbflush(agp_memory * mem) +{ + pci_write_config_byte(agp_bridge.dev, SIS_TLBFLUSH, 0x02); +} + +static int sis_configure(void) +{ + u32 temp; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + pci_write_config_byte(agp_bridge.dev, SIS_TLBCNTRL, 0x05); + pci_read_config_dword(agp_bridge.dev, SIS_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + pci_write_config_dword(agp_bridge.dev, SIS_ATTBASE, + agp_bridge.gatt_bus_addr); + pci_write_config_byte(agp_bridge.dev, SIS_APSIZE, + current_size->size_value); + return 0; +} + +static void sis_cleanup(void) +{ + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_write_config_byte(agp_bridge.dev, SIS_APSIZE, + (previous_size->size_value & ~(0x03))); +} + +static unsigned long sis_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + +static aper_size_info_8 sis_generic_sizes[7] = +{ + {256, 65536, 6, 99}, + {128, 32768, 5, 83}, + {64, 16384, 4, 67}, + {32, 8192, 3, 51}, + {16, 4096, 2, 35}, + {8, 2048, 1, 19}, + {4, 1024, 0, 3} +}; + +static gatt_mask sis_generic_masks[] = +{ + {0x00000000, 0} +}; + +static int __init sis_generic_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = sis_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) sis_generic_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = sis_configure; + agp_bridge.fetch_size = sis_fetch_size; + agp_bridge.cleanup = sis_cleanup; + agp_bridge.tlb_flush = sis_tlbflush; + agp_bridge.mask_memory = sis_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_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; + + return 0; +} + +#endif /* CONFIG_AGP_SIS */ + +#ifdef CONFIG_AGP_AMD + +static struct _amd_irongate_private { + volatile u8 *registers; +} amd_irongate_private; + +static int amd_irongate_fetch_size(void) +{ + int i; + u32 temp; + aper_size_info_32 *values; + + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = (temp & 0x0000000e); + 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; + } + } + + return 0; +} + +static int amd_irongate_configure(void) +{ + aper_size_info_32 *current_size; + unsigned long addr; + u32 temp; + u16 enable_reg; + + current_size = A_SIZE_32(agp_bridge.current_size); + + /* Get the memory mapped registers */ + pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp); + temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); + amd_irongate_private.registers = (volatile u8 *) ioremap(temp, 4096); + + /* Write out the address of the gatt table */ + OUTREG32(amd_irongate_private.registers, AMD_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* Write the Sync register */ + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80); + + /* Set indexing mode */ + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x02); + + /* Write the enable register */ + enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); + enable_reg = (enable_reg | 0x0004); + OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); + + /* Write out the size register */ + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = (((temp & ~(0x0000000e)) | current_size->size_value) + | 0x00000001); + pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp); + + /* Flush the tlb */ + OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); + + /* Get the address for the gart region */ + pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); + addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +#ifdef __alpha__ + /* ??? Presumably what is wanted is the bus address as seen + from the CPU side, since it appears that this value is + exported to userland via an ioctl. The terminology below + is confused, mixing `physical address' with `bus address', + as x86 folk are wont to do. */ + addr = virt_to_phys(ioremap(addr, 0)); +#endif + agp_bridge.gart_bus_addr = addr; + return 0; +} + +static void amd_irongate_cleanup(void) +{ + aper_size_info_32 *previous_size; + u32 temp; + u16 enable_reg; + + previous_size = A_SIZE_32(agp_bridge.previous_size); + + enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); + enable_reg = (enable_reg & ~(0x0004)); + OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); + + /* Write back the previous size and disable gart translation */ + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = ((temp & ~(0x0000000f)) | previous_size->size_value); + pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp); + iounmap((void *) amd_irongate_private.registers); +} + +/* + * This routine could be implemented by taking the addresses + * written to the GATT, and flushing them individually. However + * currently it just flushes the whole table. Which is probably + * more efficent, since agp_memory blocks can be a large number of + * entries. + */ + +static void amd_irongate_tlbflush(agp_memory * temp) +{ + OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); +} + +static unsigned long amd_irongate_mask_memory(unsigned long addr, int type) +{ + /* Only type 0 is supported by the irongate */ + + return addr | agp_bridge.masks[0].mask; +} + +static aper_size_info_32 amd_irongate_sizes[7] = +{ + {2048, 524288, 9, 0x0000000c}, + {1024, 262144, 8, 0x0000000a}, + {512, 131072, 7, 0x00000008}, + {256, 65536, 6, 0x00000006}, + {128, 32768, 5, 0x00000004}, + {64, 16384, 4, 0x00000002}, + {32, 8192, 3, 0x00000000} +}; + +static gatt_mask amd_irongate_masks[] = +{ + {0x00000001, 0} +}; + +static int __init amd_irongate_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = amd_irongate_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; + agp_bridge.size_type = U32_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = (void *) &amd_irongate_private; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = amd_irongate_configure; + agp_bridge.fetch_size = amd_irongate_fetch_size; + agp_bridge.cleanup = amd_irongate_cleanup; + agp_bridge.tlb_flush = amd_irongate_tlbflush; + agp_bridge.mask_memory = amd_irongate_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_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; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_AMD */ + +#ifdef CONFIG_AGP_ALI + +static int ali_fetch_size(void) +{ + int i; + u32 temp; + aper_size_info_32 *values; + + pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp); + temp &= ~(0xfffffff0); + 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; + } + } + + return 0; +} + +static void ali_tlbflush(agp_memory * mem) +{ + u32 temp; + + pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, + ((temp & 0xffffff00) | 0x00000090)); + pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, + ((temp & 0xffffff00) | 0x00000010)); +} + +static void ali_cleanup(void) +{ + aper_size_info_32 *previous_size; + u32 temp; + + previous_size = A_SIZE_32(agp_bridge.previous_size); + + pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, + ((temp & 0xffffff00) | 0x00000090)); + pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, + previous_size->size_value); +} + +static int ali_configure(void) +{ + u32 temp; + aper_size_info_32 *current_size; + + current_size = A_SIZE_32(agp_bridge.current_size); + + /* aperture size and gatt addr */ + pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, + agp_bridge.gatt_bus_addr | current_size->size_value); + + /* tlb control */ + pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, + ((temp & 0xffffff00) | 0x00000010)); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + return 0; +} + +static unsigned long ali_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + + +/* Setup function */ +static gatt_mask ali_generic_masks[] = +{ + {0x00000000, 0} +}; + +static aper_size_info_32 ali_generic_sizes[7] = +{ + {256, 65536, 6, 10}, + {128, 32768, 5, 9}, + {64, 16384, 4, 8}, + {32, 8192, 3, 7}, + {16, 4096, 2, 6}, + {8, 2048, 1, 4}, + {4, 1024, 0, 3} +}; + +static int __init ali_generic_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = ali_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) ali_generic_sizes; + agp_bridge.size_type = U32_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = ali_configure; + agp_bridge.fetch_size = ali_fetch_size; + agp_bridge.cleanup = ali_cleanup; + agp_bridge.tlb_flush = ali_tlbflush; + agp_bridge.mask_memory = ali_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_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; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_ALI */ + + +/* per-chipset initialization data. + * note -- all chipsets for a single vendor MUST be grouped together + */ +static struct { + unsigned short device_id; /* first, to make table easier to read */ + unsigned short vendor_id; + enum chipset_type chipset; + const char *vendor_name; + const char *chipset_name; + int (*chipset_setup) (struct pci_dev *pdev); +} agp_bridge_info[] __initdata = { + +#ifdef CONFIG_AGP_ALI + { PCI_DEVICE_ID_AL_M1541_0, + PCI_VENDOR_ID_AL, + ALI_M1541, + "Ali", + "M1541", + ali_generic_setup }, + { 0, + PCI_VENDOR_ID_AL, + ALI_GENERIC, + "Ali", + "Generic", + ali_generic_setup }, +#endif /* CONFIG_AGP_ALI */ + +#ifdef CONFIG_AGP_AMD + { PCI_DEVICE_ID_AMD_IRONGATE_0, + PCI_VENDOR_ID_AMD, + AMD_IRONGATE, + "AMD", + "Irongate", + amd_irongate_setup }, + { 0, + PCI_VENDOR_ID_AMD, + AMD_GENERIC, + "AMD", + "Generic", + amd_irongate_setup }, +#endif /* CONFIG_AGP_AMD */ + +#ifdef CONFIG_AGP_INTEL + { PCI_DEVICE_ID_INTEL_82443LX_0, + PCI_VENDOR_ID_INTEL, + INTEL_LX, + "Intel", + "440LX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_82443BX_0, + PCI_VENDOR_ID_INTEL, + INTEL_BX, + "Intel", + "440BX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_82443GX_0, + PCI_VENDOR_ID_INTEL, + INTEL_GX, + "Intel", + "440GX", + intel_generic_setup }, + { 0, + PCI_VENDOR_ID_INTEL, + INTEL_GENERIC, + "Intel", + "Generic", + intel_generic_setup }, +#endif /* CONFIG_AGP_INTEL */ + +#ifdef CONFIG_AGP_SIS + { 0, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "Generic", + sis_generic_setup }, +#endif /* CONFIG_AGP_SIS */ + +#ifdef CONFIG_AGP_VIA + { PCI_DEVICE_ID_VIA_8501_0, + PCI_VENDOR_ID_VIA, + VIA_MVP4, + "Via", + "MVP4", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_82C597_0, + PCI_VENDOR_ID_VIA, + VIA_VP3, + "Via", + "VP3", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_82C598_0, + PCI_VENDOR_ID_VIA, + VIA_MVP3, + "Via", + "MVP3", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_82C691_0, + PCI_VENDOR_ID_VIA, + VIA_APOLLO_PRO, + "Via", + "Apollo Pro", + via_generic_setup }, + { 0, + PCI_VENDOR_ID_VIA, + VIA_GENERIC, + "Via", + "Generic", + via_generic_setup }, +#endif /* CONFIG_AGP_VIA */ + + { 0, }, /* dummy final entry, always present */ +}; + + +/* scan table above for supported devices */ +static int __init agp_lookup_host_bridge (struct pci_dev *pdev) +{ + int i; + + for (i = 0; i < arraysize (agp_bridge_info); i++) + if (pdev->vendor == agp_bridge_info[i].vendor_id) + break; + + if (i >= arraysize (agp_bridge_info)) { + printk (KERN_DEBUG PFX "unsupported bridge\n"); + return -ENODEV; + } + + while ((i < arraysize (agp_bridge_info)) && + (agp_bridge_info[i].vendor_id == pdev->vendor)) { + if (pdev->device == agp_bridge_info[i].device_id) { + printk (KERN_INFO PFX "Detected %s %s chipset\n", + agp_bridge_info[i].vendor_name, + agp_bridge_info[i].chipset_name); + agp_bridge.type = agp_bridge_info[i].chipset; + return agp_bridge_info[i].chipset_setup (pdev); + } + + i++; + } + + i--; /* point to vendor generic entry (device_id == 0) */ + + /* try init anyway, if user requests it AND + * there is a 'generic' bridge entry for this vendor */ + if (agp_try_unsupported && agp_bridge_info[i].device_id == 0) { + printk(KERN_WARNING PFX "Trying generic %s routines" + " for device id: %x\n", + agp_bridge_info[i].vendor_name, pdev->device); + agp_bridge.type = agp_bridge_info[i].chipset; + return agp_bridge_info[i].chipset_setup (pdev); + } + + printk(KERN_ERR PFX "Unsupported %s chipset," + " you might want to try " + "agp_try_unsupported=1.\n", + agp_bridge_info[i].vendor_name); + return -ENODEV; +} + + +/* Supported Device Scanning routine */ + +static int __init agp_find_supported_device(void) +{ + struct pci_dev *dev = NULL; + u8 cap_ptr = 0x00; + u32 cap_id, scratch; + + if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL) + return -ENODEV; + + agp_bridge.dev = dev; + + /* Need to test for I810 here */ +#ifdef CONFIG_AGP_I810 + if (dev->vendor == PCI_VENDOR_ID_INTEL) { + struct pci_dev *i810_dev; + + switch (dev->device) { + case PCI_DEVICE_ID_INTEL_810_0: + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_810_1, + NULL); + if (i810_dev == NULL) { + printk(KERN_ERR PFX "Detected an Intel i810," + " but could not find the secondary" + " device.\n"); + return -ENODEV; + } + printk(KERN_INFO PFX "Detected an Intel " + "i810 Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i810_setup (i810_dev); + + case PCI_DEVICE_ID_INTEL_810_DC100_0: + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_810_DC100_1, + NULL); + if (i810_dev == NULL) { + printk(KERN_ERR PFX "Detected an Intel i810 " + "DC100, but could not find the " + "secondary device.\n"); + return -ENODEV; + } + printk(KERN_INFO PFX "Detected an Intel i810 " + "DC100 Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i810_setup(i810_dev); + + case PCI_DEVICE_ID_INTEL_810_E_0: + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_810_E_1, + NULL); + if (i810_dev == NULL) { + printk(KERN_ERR PFX "Detected an Intel i810 E" + ", but could not find the secondary " + "device.\n"); + return -ENODEV; + } + printk(KERN_INFO PFX "Detected an Intel i810 E " + "Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i810_setup(i810_dev); + + default: + break; + } + } +#endif /* CONFIG_AGP_I810 */ + + /* find capndx */ + pci_read_config_dword(dev, 0x04, &scratch); + if (!(scratch & 0x00100000)) + return -ENODEV; + + pci_read_config_byte(dev, 0x34, &cap_ptr); + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(dev, 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) + return -ENODEV; + agp_bridge.capndx = cap_ptr; + + /* Fill in the mode register */ + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + 4, + &agp_bridge.mode); + + /* probe for known chipsets */ + return agp_lookup_host_bridge (dev); +} + +struct agp_max_table { + int mem; + int agp; +}; + +static struct agp_max_table maxes_table[9] __initdata = +{ + {0, 0}, + {32, 4}, + {64, 28}, + {128, 96}, + {256, 204}, + {512, 440}, + {1024, 942}, + {2048, 1920}, + {4096, 3932} +}; + +static int __init agp_find_max (void) +{ + long memory, index, result; + + memory = virt_to_phys(high_memory) >> 20; + index = 1; + + while ((memory > maxes_table[index].mem) && + (index < 8)) { + index++; + } + + result = maxes_table[index - 1].agp + + ( (memory - maxes_table[index - 1].mem) * + (maxes_table[index].agp - maxes_table[index - 1].agp)) / + (maxes_table[index].mem - maxes_table[index - 1].mem); + + printk(KERN_INFO PFX "Maximum main memory to use " + "for agp memory: %ldM\n", result); + result = result << (20 - PAGE_SHIFT); + return result; +} + +#define AGPGART_VERSION_MAJOR 0 +#define AGPGART_VERSION_MINOR 99 + +static agp_version agp_current_version = +{ + AGPGART_VERSION_MAJOR, + AGPGART_VERSION_MINOR +}; + +static int __init agp_backend_initialize(void) +{ + int size_value, rc, got_gatt=0, got_keylist=0; + + memset(&agp_bridge, 0, sizeof(struct agp_bridge_data)); + agp_bridge.type = NOT_SUPPORTED; + agp_bridge.max_memory_agp = agp_find_max(); + agp_bridge.version = &agp_current_version; + + rc = agp_find_supported_device(); + if (rc) { + /* not KERN_ERR because error msg should have already printed */ + printk(KERN_DEBUG PFX "no supported devices found.\n"); + return rc; + } + + if (agp_bridge.needs_scratch_page == TRUE) { + agp_bridge.scratch_page = agp_alloc_page(); + + if (agp_bridge.scratch_page == 0) { + printk(KERN_ERR PFX "unable to get memory for " + "scratch page.\n"); + return -ENOMEM; + } + agp_bridge.scratch_page = + virt_to_phys((void *) agp_bridge.scratch_page); + agp_bridge.scratch_page = + agp_bridge.mask_memory(agp_bridge.scratch_page, 0); + } + + size_value = agp_bridge.fetch_size(); + + if (size_value == 0) { + printk(KERN_ERR PFX "unable to detrimine aperture size.\n"); + rc = -EINVAL; + goto err_out; + } + if (agp_bridge.create_gatt_table()) { + printk(KERN_ERR PFX "unable to get memory for graphics " + "translation table.\n"); + rc = -ENOMEM; + goto err_out; + } + got_gatt = 1; + + agp_bridge.key_list = vmalloc(PAGE_SIZE * 4); + if (agp_bridge.key_list == NULL) { + printk(KERN_ERR PFX "error allocating memory for key lists.\n"); + rc = -ENOMEM; + goto err_out; + } + got_keylist = 1; + + /* FIXME vmalloc'd memory not guaranteed contiguous */ + memset(agp_bridge.key_list, 0, PAGE_SIZE * 4); + + if (agp_bridge.configure()) { + printk(KERN_ERR PFX "error configuring host chipset.\n"); + rc = -EINVAL; + goto err_out; + } + + printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n", + size_value, agp_bridge.gart_bus_addr); + + return 0; + +err_out: + if (agp_bridge.needs_scratch_page == TRUE) { + agp_bridge.scratch_page &= ~(0x00000fff); + agp_destroy_page((unsigned long) + phys_to_virt(agp_bridge.scratch_page)); + } + if (got_gatt) + agp_bridge.free_gatt_table(); + if (got_keylist) + vfree(agp_bridge.key_list); + return rc; +} + + +/* cannot be __exit b/c as it could be called from __init code */ +static void agp_backend_cleanup(void) +{ + agp_bridge.cleanup(); + agp_bridge.free_gatt_table(); + vfree(agp_bridge.key_list); + + if (agp_bridge.needs_scratch_page == TRUE) { + agp_bridge.scratch_page &= ~(0x00000fff); + agp_destroy_page((unsigned long) + phys_to_virt(agp_bridge.scratch_page)); + } +} + +extern int agp_frontend_initialize(void); +extern void agp_frontend_cleanup(void); + +int agp_initialize (void) +{ + int ret_val; + + printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Jeff Hartmann\n", + AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR); + + ret_val = agp_backend_initialize(); + if (ret_val) + return ret_val; + + ret_val = agp_frontend_initialize(); + if (ret_val) { + agp_backend_cleanup(); + return ret_val; + } + + return 0; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 3, 0) \ + || (LINUX_VERSION_CODE < KERNEL_VERSION (2, 3, 0) && defined MODULE) +#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 3, 0) && defined MODULE +int init_module(void) +#else +static int __init agp_init(void) +#endif +{ + return agp_initialize (); +} +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 3, 0) \ + || (LINUX_VERSION_CODE < KERNEL_VERSION (2, 3, 0) && defined MODULE) +#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 3, 0) && defined MODULE +void cleanup_module (void) +#else +static void __exit agp_cleanup(void) +#endif +{ + agp_frontend_cleanup(); + agp_backend_cleanup(); +} +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 3, 0) +module_init(agp_init); +module_exit(agp_cleanup); +#else +#ifndef MODULE +__initfunc(void agp_setup(char *str, int *ints)) +{ + if (!strcmp(str,"agp_try_unsupported")) + agp_try_unsupported = ints[1]; +} +#endif +#endif Index: oldkernel/linux/drivers/char/agp/agpgart_fe.c diff -u /dev/null linux/drivers/char/agp/agpgart_fe.c:1.1 --- /dev/null Mon Jul 31 21:14:58 2000 +++ linux/drivers/char/agp/agpgart_fe.c Thu Jun 1 17:12:57 2000 @@ -0,0 +1,1109 @@ +/* + * AGPGART module frontend version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * 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 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 + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS 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. + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "agp.h" + +static struct agp_front_data agp_fe; + +static agp_memory *agp_find_mem_by_key(int key) +{ + agp_memory *curr; + + if (agp_fe.current_controller == NULL) { + return NULL; + } + curr = agp_fe.current_controller->pool; + + while (curr != NULL) { + if (curr->key == key) { + return curr; + } + curr = curr->next; + } + + return NULL; +} + +static void agp_remove_from_pool(agp_memory * temp) +{ + agp_memory *prev; + agp_memory *next; + + /* Check to see if this is even in the memory pool */ + + if (agp_find_mem_by_key(temp->key) != NULL) { + next = temp->next; + prev = temp->prev; + + if (prev != NULL) { + prev->next = next; + if (next != NULL) { + next->prev = prev; + } + } else { + /* This is the first item on the list */ + if (next != NULL) { + next->prev = NULL; + } + agp_fe.current_controller->pool = next; + } + } +} + +/* + * Routines for managing each client's segment list - + * These routines handle adding and removing segments + * to each auth'ed client. + */ + +static agp_segment_priv *agp_find_seg_in_client(const agp_client * client, + unsigned long offset, + int size, pgprot_t page_prot) +{ + agp_segment_priv *seg; + int num_segments, pg_start, pg_count, i; + + pg_start = offset / 4096; + pg_count = size / 4096; + seg = *(client->segments); + num_segments = client->num_segments; + + for (i = 0; i < client->num_segments; i++) { + if ((seg[i].pg_start == pg_start) && + (seg[i].pg_count == pg_count) && + (pgprot_val(seg[i].prot) == pgprot_val(page_prot))) { + return seg + i; + } + } + + return NULL; +} + +static void agp_remove_seg_from_client(agp_client * client) +{ + if (client->segments != NULL) { + if (*(client->segments) != NULL) { + kfree(*(client->segments)); + } + kfree(client->segments); + } +} + +static void agp_add_seg_to_client(agp_client * client, + agp_segment_priv ** seg, int num_segments) +{ + agp_segment_priv **prev_seg; + + prev_seg = client->segments; + + if (prev_seg != NULL) { + agp_remove_seg_from_client(client); + } + client->num_segments = num_segments; + client->segments = seg; +} + +/* Originally taken from linux/mm/mmap.c from the array + * protection_map. + * The original really should be exported to modules, or + * some routine which does the conversion for you + */ + +static const pgprot_t my_protect_map[16] = +{ + __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, + __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 +}; + +static pgprot_t agp_convert_mmap_flags(int prot) +{ +#define _trans(x,bit1,bit2) \ +((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0) + + unsigned long prot_bits; + pgprot_t temp; + + prot_bits = _trans(prot, PROT_READ, VM_READ) | + _trans(prot, PROT_WRITE, VM_WRITE) | + _trans(prot, PROT_EXEC, VM_EXEC); + + prot_bits |= VM_SHARED; + + temp = my_protect_map[prot_bits & 0x0000000f]; + + return temp; +} + +static int agp_create_segment(agp_client * client, agp_region * region) +{ + agp_segment_priv **ret_seg; + agp_segment_priv *seg; + agp_segment *user_seg; + int i; + + seg = kmalloc((sizeof(agp_segment_priv) * region->seg_count), + GFP_KERNEL); + if (seg == NULL) { + kfree(region->seg_list); + return -ENOMEM; + } + memset(seg, 0, (sizeof(agp_segment_priv) * region->seg_count)); + user_seg = region->seg_list; + + for (i = 0; i < region->seg_count; i++) { + seg[i].pg_start = user_seg[i].pg_start; + seg[i].pg_count = user_seg[i].pg_count; + seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot); + } + ret_seg = kmalloc(sizeof(void *), GFP_KERNEL); + if (ret_seg == NULL) { + kfree(region->seg_list); + kfree(seg); + return -ENOMEM; + } + *ret_seg = seg; + kfree(region->seg_list); + agp_add_seg_to_client(client, ret_seg, region->seg_count); + return 0; +} + +/* End - Routines for managing each client's segment list */ + +/* This function must only be called when current_controller != NULL */ +static void agp_insert_into_pool(agp_memory * temp) +{ + agp_memory *prev; + + prev = agp_fe.current_controller->pool; + + if (prev != NULL) { + prev->prev = temp; + temp->next = prev; + } + agp_fe.current_controller->pool = temp; +} + + +/* File private list routines */ + +agp_file_private *agp_find_private(pid_t pid) +{ + agp_file_private *curr; + + curr = agp_fe.file_priv_list; + + while (curr != NULL) { + if (curr->my_pid == pid) { + return curr; + } + curr = curr->next; + } + + return NULL; +} + +void agp_insert_file_private(agp_file_private * priv) +{ + agp_file_private *prev; + + prev = agp_fe.file_priv_list; + + if (prev != NULL) { + prev->prev = priv; + } + priv->next = prev; + agp_fe.file_priv_list = priv; +} + +void agp_remove_file_private(agp_file_private * priv) +{ + agp_file_private *next; + agp_file_private *prev; + + next = priv->next; + prev = priv->prev; + + if (prev != NULL) { + prev->next = next; + + if (next != NULL) { + next->prev = prev; + } + } else { + if (next != NULL) { + next->prev = NULL; + } + agp_fe.file_priv_list = next; + } +} + +/* End - File flag list routines */ + +/* + * Wrappers for agp_free_memory & agp_allocate_memory + * These make sure that internal lists are kept updated. + */ +static void agp_free_memory_wrap(agp_memory * memory) +{ + agp_remove_from_pool(memory); + agp_free_memory(memory); +} + +static agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type) +{ + agp_memory *memory; + + memory = agp_allocate_memory(pg_count, type); +#if 0 + printk(KERN_DEBUG "memory : %p\n", memory); +#endif + if (memory == NULL) { + return NULL; + } + agp_insert_into_pool(memory); + return memory; +} + +/* Routines for managing the list of controllers - + * These routines manage the current controller, and the list of + * controllers + */ + +static agp_controller *agp_find_controller_by_pid(pid_t id) +{ + agp_controller *controller; + + controller = agp_fe.controllers; + + while (controller != NULL) { + if (controller->pid == id) { + return controller; + } + controller = controller->next; + } + + return NULL; +} + +static agp_controller *agp_create_controller(pid_t id) +{ + agp_controller *controller; + + controller = kmalloc(sizeof(agp_controller), GFP_KERNEL); + + if (controller == NULL) { + return NULL; + } + memset(controller, 0, sizeof(agp_controller)); + controller->pid = id; + + return controller; +} + +static int agp_insert_controller(agp_controller * controller) +{ + agp_controller *prev_controller; + + prev_controller = agp_fe.controllers; + controller->next = prev_controller; + + if (prev_controller != NULL) { + prev_controller->prev = controller; + } + agp_fe.controllers = controller; + + return 0; +} + +static void agp_remove_all_clients(agp_controller * controller) +{ + agp_client *client; + agp_client *temp; + + client = controller->clients; + + while (client) { + agp_file_private *priv; + + temp = client; + agp_remove_seg_from_client(temp); + priv = agp_find_private(temp->pid); + + if (priv != NULL) { + clear_bit(AGP_FF_IS_VALID, &priv->access_flags); + clear_bit(AGP_FF_IS_CLIENT, &priv->access_flags); + } + client = client->next; + kfree(temp); + } +} + +static void agp_remove_all_memory(agp_controller * controller) +{ + agp_memory *memory; + agp_memory *temp; + + memory = controller->pool; + + while (memory) { + temp = memory; + memory = memory->next; + agp_free_memory_wrap(temp); + } +} + +static int agp_remove_controller(agp_controller * controller) +{ + agp_controller *prev_controller; + agp_controller *next_controller; + + prev_controller = controller->prev; + next_controller = controller->next; + + if (prev_controller != NULL) { + prev_controller->next = next_controller; + if (next_controller != NULL) { + next_controller->prev = prev_controller; + } + } else { + if (next_controller != NULL) { + next_controller->prev = NULL; + } + agp_fe.controllers = next_controller; + } + + agp_remove_all_memory(controller); + agp_remove_all_clients(controller); + + if (agp_fe.current_controller == controller) { + agp_fe.current_controller = NULL; + agp_fe.backend_acquired = FALSE; + agp_backend_release(); + } + kfree(controller); + return 0; +} + +static void agp_controller_make_current(agp_controller * controller) +{ + agp_client *clients; + + clients = controller->clients; + + while (clients != NULL) { + agp_file_private *priv; + + priv = agp_find_private(clients->pid); + + if (priv != NULL) { + set_bit(AGP_FF_IS_VALID, &priv->access_flags); + set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); + } + clients = clients->next; + } + + agp_fe.current_controller = controller; +} + +static void agp_controller_release_current(agp_controller * controller, + agp_file_private * controller_priv) +{ + agp_client *clients; + + clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags); + clients = controller->clients; + + while (clients != NULL) { + agp_file_private *priv; + + priv = agp_find_private(clients->pid); + + if (priv != NULL) { + clear_bit(AGP_FF_IS_VALID, &priv->access_flags); + } + clients = clients->next; + } + + agp_fe.current_controller = NULL; + agp_fe.used_by_controller = FALSE; + agp_backend_release(); +} + +/* + * Routines for managing client lists - + * These routines are for managing the list of auth'ed clients. + */ + +static agp_client *agp_find_client_in_controller(agp_controller * controller, + pid_t id) +{ + agp_client *client; + + if (controller == NULL) { + return NULL; + } + client = controller->clients; + + while (client != NULL) { + if (client->pid == id) { + return client; + } + client = client->next; + } + + return NULL; +} + +static agp_controller *agp_find_controller_for_client(pid_t id) +{ + agp_controller *controller; + + controller = agp_fe.controllers; + + while (controller != NULL) { + if ((agp_find_client_in_controller(controller, id)) != NULL) { + return controller; + } + controller = controller->next; + } + + return NULL; +} + +static agp_client *agp_find_client_by_pid(pid_t id) +{ + agp_client *temp; + + if (agp_fe.current_controller == NULL) { + return NULL; + } + temp = agp_find_client_in_controller(agp_fe.current_controller, id); + return temp; +} + +static void agp_insert_client(agp_client * client) +{ + agp_client *prev_client; + + prev_client = agp_fe.current_controller->clients; + client->next = prev_client; + + if (prev_client != NULL) { + prev_client->prev = client; + } + agp_fe.current_controller->clients = client; + agp_fe.current_controller->num_clients++; +} + +static agp_client *agp_create_client(pid_t id) +{ + agp_client *new_client; + + new_client = kmalloc(sizeof(agp_client), GFP_KERNEL); + + if (new_client == NULL) { + return NULL; + } + memset(new_client, 0, sizeof(agp_client)); + new_client->pid = id; + agp_insert_client(new_client); + return new_client; +} + +static int agp_remove_client(pid_t id) +{ + agp_client *client; + agp_client *prev_client; + agp_client *next_client; + agp_controller *controller; + + controller = agp_find_controller_for_client(id); + + if (controller == NULL) { + return -EINVAL; + } + client = agp_find_client_in_controller(controller, id); + + if (client == NULL) { + return -EINVAL; + } + prev_client = client->prev; + next_client = client->next; + + if (prev_client != NULL) { + prev_client->next = next_client; + if (next_client != NULL) { + next_client->prev = prev_client; + } + } else { + if (next_client != NULL) { + next_client->prev = NULL; + } + controller->clients = next_client; + } + + controller->num_clients--; + agp_remove_seg_from_client(client); + kfree(client); + return 0; +} + +/* End - Routines for managing client lists */ + +/* File Operations */ + +static int agp_mmap(struct file *file, struct vm_area_struct *vma) +{ + int size; + int current_size; + unsigned long offset; + agp_client *client; + agp_file_private *priv = (agp_file_private *) file->private_data; + agp_kern_info kerninfo; + + AGP_LOCK(); + + if (agp_fe.backend_acquired != TRUE) { + AGP_UNLOCK(); + return -EPERM; + } + if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags))) { + AGP_UNLOCK(); + return -EPERM; + } + agp_copy_info(&kerninfo); + size = vma->vm_end - vma->vm_start; + current_size = kerninfo.aper_size; + current_size = current_size * 0x100000; +#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 3, 0) + offset = vma->vm_offset; +#else + offset = vma->vm_pgoff << PAGE_SHIFT; +#endif + + if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { + if ((size + offset) > current_size) { + AGP_UNLOCK(); + return -EINVAL; + } + client = agp_find_client_by_pid(current->pid); + + if (client == NULL) { + AGP_UNLOCK(); + return -EPERM; + } + if (!agp_find_seg_in_client(client, offset, + size, vma->vm_page_prot)) { + AGP_UNLOCK(); + return -EINVAL; + } + if (remap_page_range(vma->vm_start, + (kerninfo.aper_base + offset), + size, vma->vm_page_prot)) { + AGP_UNLOCK(); + return -EAGAIN; + } + AGP_UNLOCK(); + return 0; + } + if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { + if (size != current_size) { + AGP_UNLOCK(); + return -EINVAL; + } + if (remap_page_range(vma->vm_start, kerninfo.aper_base, + size, vma->vm_page_prot)) { + AGP_UNLOCK(); + return -EAGAIN; + } + AGP_UNLOCK(); + return 0; + } + AGP_UNLOCK(); + return -EPERM; +} + +static int agp_release(struct inode *inode, struct file *file) +{ + agp_file_private *priv = (agp_file_private *) file->private_data; + + AGP_LOCK(); + + if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { + agp_controller *controller; + + controller = agp_find_controller_by_pid(priv->my_pid); + + if (controller != NULL) { + if (controller == agp_fe.current_controller) { + agp_controller_release_current(controller, + priv); + } + agp_remove_controller(controller); + } + } + if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { + agp_remove_client(priv->my_pid); + } + agp_remove_file_private(priv); + kfree(priv); + MOD_DEC_USE_COUNT; + AGP_UNLOCK(); + return 0; +} + +static int agp_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + agp_file_private *priv; + agp_client *client; + + AGP_LOCK(); + + if (minor != AGPGART_MINOR) { + AGP_UNLOCK(); + return -ENXIO; + } + priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL); + + if (priv == NULL) { + AGP_UNLOCK(); + return -ENOMEM; + } + memset(priv, 0, sizeof(agp_file_private)); + set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); + priv->my_pid = current->pid; + + if ((current->uid == 0) || (current->suid == 0)) { + /* Root priv, can be controller */ + set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags); + } + client = agp_find_client_by_pid(current->pid); + + if (client != NULL) { + set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); + set_bit(AGP_FF_IS_VALID, &priv->access_flags); + } + file->private_data = (void *) priv; + agp_insert_file_private(priv); + MOD_INC_USE_COUNT; + AGP_UNLOCK(); + return 0; +} + + +static long long agp_lseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static ssize_t agp_read(struct file *file, char *buf, + size_t count, loff_t * ppos) +{ + return -EINVAL; +} + +static ssize_t agp_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + return -EINVAL; +} + +static int agpioc_info_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_info userinfo; + agp_kern_info kerninfo; + + agp_copy_info(&kerninfo); + + userinfo.version.major = kerninfo.version.major; + userinfo.version.minor = kerninfo.version.minor; + userinfo.bridge_id = kerninfo.device->vendor | + (kerninfo.device->device << 16); + userinfo.agp_mode = kerninfo.mode; + userinfo.aper_base = kerninfo.aper_base; + userinfo.aper_size = kerninfo.aper_size; + userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; + userinfo.pg_used = kerninfo.current_memory; + + if (copy_to_user((void *) arg, &userinfo, sizeof(agp_info))) { + return -EFAULT; + } + return 0; +} + +static int agpioc_acquire_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_controller *controller; + if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags))) { + return -EPERM; + } + if (agp_fe.current_controller != NULL) { + return -EBUSY; + } + if ((agp_backend_acquire()) == 0) { + agp_fe.backend_acquired = TRUE; + } else { + return -EBUSY; + } + + controller = agp_find_controller_by_pid(priv->my_pid); + + if (controller != NULL) { + agp_controller_make_current(controller); + } else { + controller = agp_create_controller(priv->my_pid); + + if (controller == NULL) { + agp_fe.backend_acquired = FALSE; + agp_backend_release(); + return -ENOMEM; + } + agp_insert_controller(controller); + agp_controller_make_current(controller); + } + + set_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags); + set_bit(AGP_FF_IS_VALID, &priv->access_flags); + return 0; +} + +static int agpioc_release_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_controller_release_current(agp_fe.current_controller, priv); + return 0; +} + +static int agpioc_setup_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_setup mode; + + if (copy_from_user(&mode, (void *) arg, sizeof(agp_setup))) { + return -EFAULT; + } + agp_enable(mode.agp_mode); + return 0; +} + +static int agpioc_reserve_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_region reserve; + agp_client *client; + agp_file_private *client_priv; + + + if (copy_from_user(&reserve, (void *) arg, sizeof(agp_region))) { + return -EFAULT; + } + client = agp_find_client_by_pid(reserve.pid); + + if (reserve.seg_count == 0) { + /* remove a client */ + client_priv = agp_find_private(reserve.pid); + + if (client_priv != NULL) { + set_bit(AGP_FF_IS_CLIENT, + &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, + &client_priv->access_flags); + } + if (client == NULL) { + /* client is already removed */ + return 0; + } + return agp_remove_client(reserve.pid); + } else { + agp_segment *segment; + + segment = kmalloc((sizeof(agp_segment) * reserve.seg_count), + GFP_KERNEL); + + if (segment == NULL) { + return -ENOMEM; + } + if (copy_from_user(segment, (void *) reserve.seg_list, + GFP_KERNEL)) { + kfree(segment); + return -EFAULT; + } + reserve.seg_list = segment; + + if (client == NULL) { + /* Create the client and add the segment */ + client = agp_create_client(reserve.pid); + + if (client == NULL) { + kfree(segment); + return -ENOMEM; + } + client_priv = agp_find_private(reserve.pid); + + if (client_priv != NULL) { + set_bit(AGP_FF_IS_CLIENT, + &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, + &client_priv->access_flags); + } + return agp_create_segment(client, &reserve); + } else { + return agp_create_segment(client, &reserve); + } + } + /* Will never really happen */ + return -EINVAL; +} + +static int agpioc_protect_wrap(agp_file_private * priv, unsigned long arg) +{ + /* This function is not currently implemented */ + return -EINVAL; +} + +static int agpioc_allocate_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_memory *memory; + agp_allocate alloc; + + if (copy_from_user(&alloc, (void *) arg, sizeof(agp_allocate))) { + return -EFAULT; + } + memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); + + if (memory == NULL) { + return -ENOMEM; + } + alloc.key = memory->key; + alloc.physical = memory->physical; + + if (copy_to_user((void *) arg, &alloc, sizeof(agp_allocate))) { + agp_free_memory_wrap(memory); + return -EFAULT; + } + return 0; +} + +static int agpioc_deallocate_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_memory *memory; + + memory = agp_find_mem_by_key((int) arg); + + if (memory == NULL) { + return -EINVAL; + } + agp_free_memory_wrap(memory); + return 0; +} + +static int agpioc_bind_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_bind bind_info; + agp_memory *memory; + + if (copy_from_user(&bind_info, (void *) arg, sizeof(agp_bind))) { + return -EFAULT; + } + memory = agp_find_mem_by_key(bind_info.key); + + if (memory == NULL) { + return -EINVAL; + } + return agp_bind_memory(memory, bind_info.pg_start); +} + +static int agpioc_unbind_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_memory *memory; + agp_unbind unbind; + + if (copy_from_user(&unbind, (void *) arg, sizeof(agp_unbind))) { + return -EFAULT; + } + memory = agp_find_mem_by_key(unbind.key); + + if (memory == NULL) { + return -EINVAL; + } + return agp_unbind_memory(memory); +} + +static int agp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + agp_file_private *curr_priv = (agp_file_private *) file->private_data; + int ret_val = -ENOTTY; + + AGP_LOCK(); + + if ((agp_fe.current_controller == NULL) && + (cmd != AGPIOC_ACQUIRE)) { + ret_val = -EINVAL; + goto ioctl_out; + } + if ((agp_fe.backend_acquired != TRUE) && + (cmd != AGPIOC_ACQUIRE)) { + ret_val = -EBUSY; + goto ioctl_out; + } + if (cmd != AGPIOC_ACQUIRE) { + if (!(test_bit(AGP_FF_IS_CONTROLLER, + &curr_priv->access_flags))) { + ret_val = -EPERM; + goto ioctl_out; + } + /* Use the original pid of the controller, + * in case it's threaded */ + + if (agp_fe.current_controller->pid != curr_priv->my_pid) { + ret_val = -EBUSY; + goto ioctl_out; + } + } + switch (cmd) { + case AGPIOC_INFO: + { + ret_val = agpioc_info_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_ACQUIRE: + { + ret_val = agpioc_acquire_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_RELEASE: + { + ret_val = agpioc_release_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_SETUP: + { + ret_val = agpioc_setup_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_RESERVE: + { + ret_val = agpioc_reserve_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_PROTECT: + { + ret_val = agpioc_protect_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_ALLOCATE: + { + ret_val = agpioc_allocate_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_DEALLOCATE: + { + ret_val = agpioc_deallocate_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_BIND: + { + ret_val = agpioc_bind_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_UNBIND: + { + ret_val = agpioc_unbind_wrap(curr_priv, arg); + goto ioctl_out; + } + } + +ioctl_out: + AGP_UNLOCK(); + return ret_val; +} + +static struct file_operations agp_fops = +{ + llseek: agp_lseek, + read: agp_read, + write: agp_write, + ioctl: agp_ioctl, + mmap: agp_mmap, + open: agp_open, + release: agp_release, +}; + +static struct miscdevice agp_miscdev = +{ + AGPGART_MINOR, + AGPGART_MODULE_NAME, + &agp_fops +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 3, 0) +int +#else +int __init +#endif +agp_frontend_initialize(void) +{ + memset(&agp_fe, 0, sizeof(struct agp_front_data)); + AGP_LOCK_INIT(); + + if (misc_register(&agp_miscdev)) { + printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR); + return -EIO; + } + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 3, 0) +void +#else +void __exit +#endif +agp_frontend_cleanup(void) +{ + misc_deregister(&agp_miscdev); +} Index: oldkernel/linux/init/main.c diff -u linux/init/main.c:1.6 linux/init/main.c:1.7 --- linux/init/main.c:1.6 Thu Jun 1 16:48:05 2000 +++ linux/init/main.c Thu Jun 1 17:12:57 2000 @@ -377,6 +377,11 @@ extern void md_setup(char *str,int *ints) __init; #endif +#ifdef CONFIG_AGP +extern int agp_initialize (void); +extern void agp_setup(char *str, int *ints); +#endif + /* * Boot command-line arguments */ @@ -975,6 +980,9 @@ #ifdef CONFIG_BLK_CPQ_DA { "smart2=", cpqarray_setup }, #endif +#ifdef CONFIG_AGP + { "agp_try_unsupported=", agp_setup}, +#endif { 0, 0 } }; @@ -1409,6 +1417,9 @@ #endif #ifdef CONFIG_MAC nubus_init(); +#endif +#ifdef CONFIG_AGP + agp_initialize (); #endif /* Networking initialization needs a process context */