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

📄 sba_iommu.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	DBG_INIT(" base %p\n", pdir_base);	/* build IMASK for IOC and Elroy */	iova_space_mask =  0xffffffff;	iova_space_mask <<= (iov_order + PAGE_SHIFT);#ifdef CONFIG_IA64_HP_PROTO	/*	** REVISIT - this is a kludge, but we won't be supporting anything but	** zx1 2.0 or greater for real.  When fw is in shape, ibase will	** be preprogrammed w/ the IOVA hole base and imask will give us	** the size.	*/	if ((sba_dev->hw_rev & 0xFF) < 0x20) {		DBG_INIT("%s() Found SBA rev < 2.0, setting IOVA base to 0.  This device will not be supported in the future.\n", __FUNCTION__);		ioc->ibase = 0x0;	} else#endif	ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & 0xFFFFFFFEUL;	ioc->imask = iova_space_mask;	/* save it */	DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n",		__FUNCTION__, ioc->ibase, ioc->imask);	/*	** FIXME: Hint registers are programmed with default hint	** values during boot, so hints should be sane even if we	** can't reprogram them the way drivers want.	*/	WRITE_REG(ioc->imask, ioc->ioc_hpa+IOC_IMASK);	/*	** Setting the upper bits makes checking for bypass addresses	** a little faster later on.	*/	ioc->imask |= 0xFFFFFFFF00000000UL;	/* Set I/O PDIR Page size to system page size */	switch (PAGE_SHIFT) {		case 12: /* 4K */			tcnfg = 0;			break;		case 13: /* 8K */			tcnfg = 1;			break;		case 14: /* 16K */			tcnfg = 2;			break;		case 16: /* 64K */			tcnfg = 3;			break;	}	WRITE_REG(tcnfg, ioc->ioc_hpa+IOC_TCNFG);	/*	** Program the IOC's ibase and enable IOVA translation	** Bit zero == enable bit.	*/	WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa+IOC_IBASE);	/*	** Clear I/O TLB of any possible entries.	** (Yes. This is a bit paranoid...but so what)	*/	WRITE_REG(0 | 31, ioc->ioc_hpa+IOC_PCOM);	/*	** If an AGP device is present, only use half of the IOV space	** for PCI DMA.  Unfortunately we can't know ahead of time	** whether GART support will actually be used, for now we	** can just key on an AGP device found in the system.	** We program the next pdir index after we stop w/ a key for	** the GART code to handshake on.	*/	if (SBA_GET_AGP(sba_dev)) {		DBG_INIT("%s() AGP Device found, reserving 512MB for GART support\n", __FUNCTION__);		ioc->pdir_size /= 2;		((u64 *)pdir_base)[PDIR_INDEX(iova_space_size/2)] = 0x0000badbadc0ffeeULL;	}	DBG_INIT("%s() DONE\n", __FUNCTION__);}/******************************************************************************   SBA initialization code (HW and SW)****   o identify SBA chip itself**   o FIXME: initialize DMA hints for reasonable defaults****************************************************************************/static voidsba_hw_init(struct sba_device *sba_dev){ 	int i;	int num_ioc;	u64 dma_mask;	u32 func_id;	/*	** Identify the SBA so we can set the dma_mask.  We can make a virtual	** dma_mask of the memory subsystem such that devices not implmenting	** a full 64bit mask might still be able to bypass efficiently.	*/	func_id = READ_REG(sba_dev->sba_hpa + SBA_FUNC_ID);	if (func_id == ZX1_FUNC_ID_VALUE) {		dma_mask = 0xFFFFFFFFFFUL;	} else {		dma_mask = 0xFFFFFFFFFFFFFFFFUL;	}	DBG_INIT("%s(): ioc->dma_mask == 0x%lx\n", __FUNCTION__, dma_mask);		/*	** Leaving in the multiple ioc code from parisc for the future,	** currently there are no muli-ioc mckinley sbas	*/	sba_dev->ioc[0].ioc_hpa = SBA_IOC_OFFSET;	num_ioc = 1;	sba_dev->num_ioc = num_ioc;	for (i = 0; i < num_ioc; i++) {		sba_dev->ioc[i].dma_mask = dma_mask;		sba_dev->ioc[i].ioc_hpa += sba_dev->sba_hpa;		sba_ioc_init(sba_dev, &(sba_dev->ioc[i]), i);	}}static voidsba_common_init(struct sba_device *sba_dev){	int i;	/* add this one to the head of the list (order doesn't matter)	** This will be useful for debugging - especially if we get coredumps	*/	sba_dev->next = sba_list;	sba_list = sba_dev;	sba_count++;	for(i=0; i< sba_dev->num_ioc; i++) {		int res_size;		/* resource map size dictated by pdir_size */		res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */		res_size >>= 3;  /* convert bit count to byte count */		DBG_INIT("%s() res_size 0x%x\n",			__FUNCTION__, res_size);		sba_dev->ioc[i].res_size = res_size;		sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));		if (NULL == sba_dev->ioc[i].res_map)		{			panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ );		}		memset(sba_dev->ioc[i].res_map, 0, res_size);		/* next available IOVP - circular search */		if ((sba_dev->hw_rev & 0xFF) >= 0x20) {			sba_dev->ioc[i].res_hint = (unsigned long *)			    sba_dev->ioc[i].res_map;		} else {			u64 reserved_iov;						/* Yet another 1.x hack */			printk("zx1 1.x: Starting resource hint offset into IOV space to avoid initial zero value IOVA\n");			sba_dev->ioc[i].res_hint = (unsigned long *)			    &(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]);			sba_dev->ioc[i].res_map[0] = 0x1;			sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL;			for (reserved_iov = 0xA0000 ; reserved_iov < 0xC0000 ; reserved_iov += IOVP_SIZE) {				u64 *res_ptr = sba_dev->ioc[i].res_map;				int index = PDIR_INDEX(reserved_iov);				int res_word;				u64 mask;				res_word = (int)(index / BITS_PER_LONG);				mask =  0x1UL << (index - (res_word * BITS_PER_LONG));				res_ptr[res_word] |= mask;				sba_dev->ioc[i].pdir_base[PDIR_INDEX(reserved_iov)] = (0x80000000000000FFULL | reserved_iov);			}		}#ifdef ASSERT_PDIR_SANITY		/* Mark first bit busy - ie no IOVA 0 */		sba_dev->ioc[i].res_map[0] = 0x1;		sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL;#endif		DBG_INIT("%s() %d res_map %x %p\n", __FUNCTION__,		         i, res_size, (void *)sba_dev->ioc[i].res_map);	}	sba_dev->sba_lock = SPIN_LOCK_UNLOCKED;}#ifdef CONFIG_PROC_FSstatic int sba_proc_info(char *buf, char **start, off_t offset, int len){	struct sba_device *sba_dev = sba_list;	struct ioc *ioc = &sba_dev->ioc[0];	/* FIXME: Multi-IOC support! */	int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */	unsigned long i = 0, avg = 0, min, max;	sprintf(buf, "%s rev %d.%d\n",		"Hewlett Packard zx1 SBA",		((sba_dev->hw_rev >> 4) & 0xF),		(sba_dev->hw_rev & 0xF)		);	sprintf(buf, "%sIO PDIR size    : %d bytes (%d entries)\n",		buf,		(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */		total_pages);	sprintf(buf, "%sIO PDIR entries : %ld free  %ld used (%d%%)\n", buf,		total_pages - ioc->used_pages, ioc->used_pages,		(int) (ioc->used_pages * 100 / total_pages));		sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", 		buf, ioc->res_size, ioc->res_size << 3);   /* 8 bits per byte */	min = max = ioc->avg_search[0];	for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {		avg += ioc->avg_search[i];		if (ioc->avg_search[i] > max) max = ioc->avg_search[i];		if (ioc->avg_search[i] < min) min = ioc->avg_search[i];	}	avg /= SBA_SEARCH_SAMPLE;	sprintf(buf, "%s  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",		buf, min, avg, max);	sprintf(buf, "%spci_map_single(): %12ld calls  %12ld pages (avg %d/1000)\n",		buf, ioc->msingle_calls, ioc->msingle_pages,		(int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));#ifdef ALLOW_IOV_BYPASS	sprintf(buf, "%spci_map_single(): %12ld bypasses\n",	        buf, ioc->msingle_bypass);#endif	sprintf(buf, "%spci_unmap_single: %12ld calls  %12ld pages (avg %d/1000)\n",		buf, ioc->usingle_calls, ioc->usingle_pages,		(int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls));#ifdef ALLOW_IOV_BYPASS	sprintf(buf, "%spci_unmap_single: %12ld bypasses\n",	        buf, ioc->usingle_bypass);#endif	sprintf(buf, "%spci_map_sg()    : %12ld calls  %12ld pages (avg %d/1000)\n",		buf, ioc->msg_calls, ioc->msg_pages,		(int) ((ioc->msg_pages * 1000)/ioc->msg_calls));#ifdef ALLOW_IOV_BYPASS	sprintf(buf, "%spci_map_sg()    : %12ld bypasses\n",	        buf, ioc->msg_bypass);#endif	sprintf(buf, "%spci_unmap_sg()  : %12ld calls  %12ld pages (avg %d/1000)\n",		buf, ioc->usg_calls, ioc->usg_pages,		(int) ((ioc->usg_pages * 1000)/ioc->usg_calls));	return strlen(buf);}static intsba_resource_map(char *buf, char **start, off_t offset, int len){	struct ioc *ioc = sba_list->ioc;	/* FIXME: Multi-IOC support! */	unsigned int *res_ptr = (unsigned int *)ioc->res_map;	int i;	buf[0] = '\0';	for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) {		if ((i & 7) == 0)		    strcat(buf,"\n   ");		sprintf(buf, "%s %08x", buf, *res_ptr);	}	strcat(buf, "\n");	return strlen(buf);}#endif/*** Determine if sba should claim this chip (return 0) or not (return 1).** If so, initialize the chip and tell other partners in crime they** have work to do.*/void __init sba_init(void){	struct sba_device *sba_dev;	u32 func_id, hw_rev;	u32 *func_offset = NULL;	int i, agp_found = 0;	static char sba_rev[6];	struct pci_dev *device = NULL;	u64 hpa = 0;	if (!(device = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_SBA, NULL)))		return;	for (i = 0; i < PCI_NUM_RESOURCES; i++) {		if (pci_resource_flags(device, i) == IORESOURCE_MEM) {			hpa = ioremap(pci_resource_start(device, i),				pci_resource_len(device, i));			break;		}	}	func_id = READ_REG(hpa + SBA_FUNC_ID);	if (func_id == ZX1_FUNC_ID_VALUE) {		(void)strcpy(sba_rev, "zx1");		func_offset = zx1_func_offsets;	} else {		return;	}	/* Read HW Rev First */	hw_rev = READ_REG(hpa + SBA_FCLASS) & 0xFFUL;	/*	 * Not all revision registers of the chipset are updated on every	 * turn.  Must scan through all functions looking for the highest rev	 */	if (func_offset) {		for (i = 0 ; func_offset[i] != -1 ; i++) {			u32 func_rev;			func_rev = READ_REG(hpa + SBA_FCLASS + func_offset[i]) & 0xFFUL;			DBG_INIT("%s() func offset: 0x%x rev: 0x%x\n",			         __FUNCTION__, func_offset[i], func_rev);			if (func_rev > hw_rev)				hw_rev = func_rev;		}	}	printk(KERN_INFO "%s found %s %d.%d at %s, HPA 0x%lx\n", DRIVER_NAME,	       sba_rev, ((hw_rev >> 4) & 0xF), (hw_rev & 0xF),	       device->slot_name, hpa);	if ((hw_rev & 0xFF) < 0x20) {		printk(KERN_INFO "%s WARNING rev 2.0 or greater will be required for IO MMU support in the future\n", DRIVER_NAME);#ifndef CONFIG_IA64_HP_PROTO		panic("%s: CONFIG_IA64_HP_PROTO MUST be enabled to support SBA rev less than 2.0", DRIVER_NAME);#endif	}	sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);	if (NULL == sba_dev) {		printk(KERN_ERR DRIVER_NAME " - couldn't alloc sba_device\n");		return;	}	memset(sba_dev, 0, sizeof(struct sba_device));	for(i=0; i<MAX_IOC; i++)		spin_lock_init(&(sba_dev->ioc[i].res_lock));	sba_dev->hw_rev = hw_rev;	sba_dev->sba_hpa = hpa;	/*	 * We need to check for an AGP device, if we find one, then only	 * use part of the IOVA space for PCI DMA, the rest is for GART.	 * REVISIT for multiple IOC.	 */	pci_for_each_dev(device)		agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP);	if (agp_found && reserve_sba_gart)		SBA_SET_AGP(sba_dev);	sba_hw_init(sba_dev);	sba_common_init(sba_dev);#ifdef CONFIG_PROC_FS	{		struct proc_dir_entry * proc_mckinley_root;		proc_mckinley_root = proc_mkdir("bus/mckinley",0);		create_proc_info_entry(sba_rev, 0, proc_mckinley_root, sba_proc_info);		create_proc_info_entry("bitmap", 0, proc_mckinley_root, sba_resource_map);	}#endif}static int __initnosbagart (char *str){	reserve_sba_gart = 0;	return 1;}__setup("nosbagart",nosbagart);EXPORT_SYMBOL(sba_init);EXPORT_SYMBOL(sba_map_single);EXPORT_SYMBOL(sba_unmap_single);EXPORT_SYMBOL(sba_map_sg);EXPORT_SYMBOL(sba_unmap_sg);EXPORT_SYMBOL(sba_dma_address);EXPORT_SYMBOL(sba_alloc_consistent);EXPORT_SYMBOL(sba_free_consistent);/***  IA64 System Bus Adapter (SBA) I/O MMU manager****	(c) Copyright 2002 Alex Williamson**	(c) Copyright 2002 Hewlett-Packard Company****	Portions (c) 2000 Grant Grundler (from parisc I/O MMU code)**	Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code)****	This program is free software; you can redistribute it and/or modify**	it under the terms of the GNU General Public License as published by**      the Free Software Foundation; either version 2 of the License, or**      (at your option) any later version.****** This module initializes the IOC (I/O Controller) found on HP** McKinley machines and their successors.***/#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/pci.h>#include <linux/proc_fs.h>#include <asm/delay.h>		/* ia64_get_itc() */#include <asm/io.h>#include <asm/page.h>		/* PAGE_OFFSET */#include <asm/efi.h>#define DRIVER_NAME "SBA"#ifndef CONFIG_IA64_HP_PROTO#define ALLOW_IOV_BYPASS#endif#define ENABLE_MARK_CLEAN/*** The number of debug flags is a clue - this code is fragile.*/#undef DEBUG_SBA_INIT#undef DEBUG_SBA_RUN#undef DEBUG_SBA_RUN_SG#undef DEBUG_SBA_RESOURCE#undef ASSERT_PDIR_SANITY#undef DEBUG_LARGE_SG_ENTRIES#undef DEBUG_BYPASS#define SBA_INLINE	__inline__/* #define SBA_INLINE */#ifdef DEBUG_SBA_INIT#define DBG_INIT(x...)	printk(x)#else#define DBG_INIT(x...)#endif#ifdef DEBUG_SBA_RUN#define DBG_RUN(x...)	printk(x)

⌨️ 快捷键说明

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