⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 generic.c

📁 h内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * AGPGART driver. * Copyright (C) 2002-2004 Dave Jones. * 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. * * TODO: * - Allocate more than order 0 pages to avoid too much linear map splitting. */#include <linux/config.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/pagemap.h>#include <linux/miscdevice.h>#include <linux/pm.h>#include <linux/agp_backend.h>#include <linux/vmalloc.h>#include <linux/mm.h>#include <asm/io.h>#include <asm/cacheflush.h>#include <asm/pgtable.h>#include "agp.h"__u32 *agp_gatt_table;int agp_memory_reserved;/* * Needed by the Nforce GART driver for the time being. Would be * nice to do this some other way instead of needing this export. */EXPORT_SYMBOL_GPL(agp_memory_reserved);#if defined(CONFIG_X86)int map_page_into_agp(struct page *page){	int i;	i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE);	global_flush_tlb();	return i;}EXPORT_SYMBOL_GPL(map_page_into_agp);int unmap_page_from_agp(struct page *page){	int i;	i = change_page_attr(page, 1, PAGE_KERNEL);	global_flush_tlb();	return i;}EXPORT_SYMBOL_GPL(unmap_page_from_agp);#endif/* * Generic routines for handling agp_memory structures - * They use the basic page allocation routines to do the brunt of the work. */void agp_free_key(int key){	if (key < 0)		return;	if (key < MAXKEY)		clear_bit(key, agp_bridge->key_list);}EXPORT_SYMBOL(agp_free_key);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;}struct agp_memory *agp_create_memory(int scratch_pages){	struct agp_memory *new;	new = kmalloc(sizeof(struct agp_memory), GFP_KERNEL);	if (new == NULL)		return NULL;	memset(new, 0, sizeof(struct 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;}EXPORT_SYMBOL(agp_create_memory);/** *	agp_free_memory - free memory associated with an agp_memory pointer. * *	@curr:		agp_memory pointer to be freed. * *	It is the only function that can be called when the backend is not owned *	by the caller.  (So it can free memory on client death.) */void agp_free_memory(struct agp_memory *curr){	size_t i;	if ((agp_bridge->type == NOT_SUPPORTED) || (curr == NULL))		return;	if (curr->is_bound == TRUE)		agp_unbind_memory(curr);	if (curr->type != 0) {		agp_bridge->driver->free_by_type(curr);		return;	}	if (curr->page_count != 0) {		for (i = 0; i < curr->page_count; i++) {			agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[i]));		}	}	agp_free_key(curr->key);	vfree(curr->memory);	kfree(curr);}EXPORT_SYMBOL(agp_free_memory);#define ENTRIES_PER_PAGE		(PAGE_SIZE / sizeof(unsigned long))/** *	agp_allocate_memory  -  allocate a group of pages of a certain type. * *	@page_count:	size_t argument of the number of pages *	@type:	u32 argument of the type of memory to be allocated. * *	Every agp bridge device will allow you to allocate AGP_NORMAL_MEMORY which *	maps to physical ram.  Any other type is device dependent. * *	It returns NULL whenever memory is unavailable. */struct agp_memory *agp_allocate_memory(size_t page_count, u32 type){	int scratch_pages;	struct agp_memory *new;	size_t i;	if (agp_bridge->type == NOT_SUPPORTED)		return NULL;	if ((atomic_read(&agp_bridge->current_memory_agp) + page_count) > agp_bridge->max_memory_agp)		return NULL;	if (type != 0) {		new = agp_bridge->driver->alloc_by_type(page_count, type);		return new;	}	scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;	new = agp_create_memory(scratch_pages);	if (new == NULL)		return NULL;	for (i = 0; i < page_count; i++) {		void *addr = agp_bridge->driver->agp_alloc_page();		if (addr == NULL) {			agp_free_memory(new);			return NULL;		}		new->memory[i] = virt_to_phys(addr);		new->page_count++;	}	flush_agp_mappings();	return new;}EXPORT_SYMBOL(agp_allocate_memory);/* 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->driver->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 LVL2_APER_SIZE:		current_size = A_SIZE_LVL2(temp)->size;		break;	case FIXED_APER_SIZE:		current_size = A_SIZE_FIX(temp)->size;		break;	default:		current_size = 0;		break;	}	current_size -= (agp_memory_reserved / (1024*1024));	if (current_size <0)		current_size = 0;	return current_size;}int agp_num_entries(void){	int num_entries;	void *temp;	temp = agp_bridge->current_size;	switch (agp_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 LVL2_APER_SIZE:		num_entries = A_SIZE_LVL2(temp)->num_entries;		break;	case FIXED_APER_SIZE:		num_entries = A_SIZE_FIX(temp)->num_entries;		break;	default:		num_entries = 0;		break;	}	num_entries -= agp_memory_reserved>>PAGE_SHIFT;	if (num_entries<0)		num_entries = 0;	return num_entries;}EXPORT_SYMBOL_GPL(agp_num_entries);/** *	agp_copy_info  -  copy bridge state information * *	@info:		agp_kern_info pointer.  The caller should insure that this pointer is valid.  * *	This function copies information about the agp bridge device and the state of *	the agp backend into an agp_kern_info pointer. */int agp_copy_info(struct agp_kern_info *info){	memset(info, 0, sizeof(struct agp_kern_info));	if (!agp_bridge || agp_bridge->type == NOT_SUPPORTED ||	    !agp_bridge->version) {		info->chipset = NOT_SUPPORTED;		return -EIO;	}	info->version.major = agp_bridge->version->major;	info->version.minor = agp_bridge->version->minor;	info->chipset = agp_bridge->type;	info->device = agp_bridge->dev;	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);	info->cant_use_aperture = agp_bridge->driver->cant_use_aperture;	info->vm_ops = agp_bridge->vm_ops;	info->page_mask = ~0UL;	return 0;}EXPORT_SYMBOL(agp_copy_info);/* 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. *//** *	agp_bind_memory  -  Bind an agp_memory structure into the GATT. * *	@curr:		agp_memory pointer *	@pg_start:	an offset into the graphics aperture translation table * *	It returns -EINVAL if the pointer == NULL. *	It returns -EBUSY if the area of the table requested is already in use. */int agp_bind_memory(struct agp_memory *curr, off_t pg_start){	int ret_val;	if ((agp_bridge->type == NOT_SUPPORTED) || (curr == NULL))		return -EINVAL;	if (curr->is_bound == TRUE) {		printk (KERN_INFO PFX "memory %p is already bound!\n", curr);		return -EINVAL;	}	if (curr->is_flushed == FALSE) {		agp_bridge->driver->cache_flush();		curr->is_flushed = TRUE;	}	ret_val = agp_bridge->driver->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;}EXPORT_SYMBOL(agp_bind_memory);/** *	agp_unbind_memory  -  Removes an agp_memory structure from the GATT * * @curr:	agp_memory pointer to be removed from the GATT. * * It returns -EINVAL if this piece of agp_memory is not currently bound to * the graphics aperture translation table or if the agp_memory pointer == NULL */int agp_unbind_memory(struct agp_memory *curr){	int ret_val;	if ((agp_bridge->type == NOT_SUPPORTED) || (curr == NULL))		return -EINVAL;	if (curr->is_bound != TRUE) {		printk (KERN_INFO PFX "memory %p was not bound!\n", curr);		return -EINVAL;	}	ret_val = agp_bridge->driver->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;}EXPORT_SYMBOL(agp_unbind_memory);/* End - Routines for handling swapping of agp_memory into the GATT *//* Generic Agp routines - Start */static void agp_v2_parse_one(u32 *mode, u32 *cmd, u32 *tmp){	/* disable SBA if it's not supported */	if (!((*cmd & AGPSTAT_SBA) && (*tmp & AGPSTAT_SBA) && (*mode & AGPSTAT_SBA)))		*cmd &= ~AGPSTAT_SBA;	/* Set speed */	if (!((*cmd & AGPSTAT2_4X) && (*tmp & AGPSTAT2_4X) && (*mode & AGPSTAT2_4X)))		*cmd &= ~AGPSTAT2_4X;	if (!((*cmd & AGPSTAT2_2X) && (*tmp & AGPSTAT2_2X) && (*mode & AGPSTAT2_2X)))		*cmd &= ~AGPSTAT2_2X;	if (!((*cmd & AGPSTAT2_1X) && (*tmp & AGPSTAT2_1X) && (*mode & AGPSTAT2_1X)))		*cmd &= ~AGPSTAT2_1X;	/* Now we know what mode it should be, clear out the unwanted bits. */	if (*cmd & AGPSTAT2_4X)		*cmd &= ~(AGPSTAT2_1X | AGPSTAT2_2X);	/* 4X */	if (*cmd & AGPSTAT2_2X)		*cmd &= ~(AGPSTAT2_1X | AGPSTAT2_4X);	/* 2X */	if (*cmd & AGPSTAT2_1X)		*cmd &= ~(AGPSTAT2_2X | AGPSTAT2_4X);	/* 1X */}/* * mode = requested mode. * cmd = PCI_AGP_STATUS from agp bridge. * tmp = PCI_AGP_STATUS from graphic card. */static void agp_v3_parse_one(u32 *mode, u32 *cmd, u32 *tmp){	u32 origcmd=*cmd, origtmp=*tmp;	/* ARQSZ - Set the value to the maximum one.	 * Don't allow the mode register to override values. */	*cmd = ((*cmd & ~AGPSTAT_ARQSZ) |		max_t(u32,(*cmd & AGPSTAT_ARQSZ),(*tmp & AGPSTAT_ARQSZ)));	/* Calibration cycle.	 * Don't allow the mode register to override values. */	*cmd = ((*cmd & ~AGPSTAT_CAL_MASK) |		min_t(u32,(*cmd & AGPSTAT_CAL_MASK),(*tmp & AGPSTAT_CAL_MASK)));	/* SBA *must* be supported for AGP v3 */	*cmd |= AGPSTAT_SBA;	/*	 * Set speed.	 * Check for invalid speeds. This can happen when applications	 * written before the AGP 3.0 standard pass AGP2.x modes to AGP3 hardware	 */	if (*mode & AGPSTAT_MODE_3_0) {		/*		 * Caller hasn't a clue what its doing. We are in 3.0 mode,		 * have been passed a 3.0 mode, but with 2.x speed bits set.		 * AGP2.x 4x -> AGP3.0 4x.		 */		if (*mode & AGPSTAT2_4X) {			printk (KERN_INFO PFX "%s passes broken AGP3 flags (%x). Fixed.\n",						current->comm, *mode);			*mode &= ~AGPSTAT2_4X;			*mode |= AGPSTAT3_4X;		}	} else {		/*		 * The caller doesn't know what they are doing. We are in 3.0 mode,		 * but have been passed an AGP 2.x mode.		 * Convert AGP 1x,2x,4x -> AGP 3.0 4x.		 */		printk (KERN_INFO PFX "%s passes broken AGP2 flags (%x) in AGP3 mode. Fixed.\n",					current->comm, *mode);		*mode &= ~(AGPSTAT2_4X | AGPSTAT2_2X | AGPSTAT2_1X);		*mode |= AGPSTAT3_4X;	}	if (*mode & AGPSTAT3_8X) {		if (!(*cmd & AGPSTAT3_8X)) {			*cmd &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);			*cmd |= AGPSTAT3_4X;			printk ("%s requested AGPx8 but bridge not capable.\n", current->comm);			return;		}		if (!(*tmp & AGPSTAT3_8X)) {			*cmd &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);			*cmd |= AGPSTAT3_4X;			printk ("%s requested AGPx8 but graphic card not capable.\n", current->comm);			return;		}		/* All set, bridge & device can do AGP x8*/		*cmd &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);		return;	} else {		/*		 * If we didn't specify AGPx8, we can only do x4.		 * If the hardware can't do x4, we're up shit creek, and never		 *  should have got this far.		 */		*cmd &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);		if ((*cmd & AGPSTAT3_4X) && (*tmp & AGPSTAT3_4X))			*cmd |= AGPSTAT3_4X;		else {			printk (KERN_INFO PFX "Badness. Don't know which AGP mode to set. "							"[cmd:%x tmp:%x fell back to:- cmd:%x tmp:%x]\n",							origcmd, origtmp, *cmd, *tmp);			if (!(*cmd & AGPSTAT3_4X))				printk (KERN_INFO PFX "Bridge couldn't do AGP x4.\n");			if (!(*tmp & AGPSTAT3_4X))				printk (KERN_INFO PFX "Graphic card couldn't do AGP x4.\n");		}	}}//FIXME: This doesn't smell right.//We need a function we pass an agp_device to.u32 agp_collect_device_status(u32 mode, u32 cmd){	struct pci_dev *device = NULL;	u8 cap_ptr;	u32 tmp;	u32 agp3;	for_each_pci_dev(device) {		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);		if (!cap_ptr)			continue;		//FIXME: We should probably skip anything here that		// isn't an AGP graphic card.		/*		 * Ok, here we have a AGP device. Disable impossible		 * settings, and adjust the readqueue to the minimum.		 */		pci_read_config_dword(device, cap_ptr+PCI_AGP_STATUS, &tmp);		/* adjust RQ depth */		cmd = ((cmd & ~AGPSTAT_RQ_DEPTH) |		     min_t(u32, (mode & AGPSTAT_RQ_DEPTH),

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -