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

📄 sba_iommu.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
static voidsba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num){	/* lba_set_iregs() is in arch/parisc/kernel/lba_pci.c */	extern void lba_set_iregs(struct parisc_device *, u32, u32);	u32 iova_space_size, iova_space_mask;	int pdir_size, iov_order;	unsigned long physmem;	struct parisc_device *lba;	/*	** Determine IOVA Space size from memory size.	**	** Ideally, PCI drivers would register the maximum number	** of DMA they can have outstanding for each device they	** own.  Next best thing would be to guess how much DMA	** can be outstanding based on PCI Class/sub-class. Both	** methods still require some "extra" to support PCI	** Hot-Plug/Removal of PCI cards. (aka PCI OLARD).	**	** While we have 32-bits "IOVA" space, top two 2 bits are used	** for DMA hints - ergo only 30 bits max.	*/	physmem = num_physpages << PAGE_SHIFT;	iova_space_size = (u32) (physmem/(sba_mem_ratio*global_ioc_cnt));	/* limit IOVA space size to 1MB-1GB */	if (iova_space_size < 1024*1024) {		iova_space_size = 1024*1024;	}#ifdef __LP64__	else if (iova_space_size > 512*1024*1024) {		iova_space_size = 512*1024*1024;	}#endif	/*	** iova space must be log2() in size.	** thus, pdir/res_map will also be log2().	** PIRANHA BUG: Exception is when IO Pdir is 2MB (gets reduced)	*/	iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT));	ASSERT(iov_order <= (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */	ASSERT(iov_order >= (20 - IOVP_SHIFT));   /* iova_space_size >= 1MB */	iova_space_size = 1 << (iov_order + IOVP_SHIFT);	ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);	ASSERT(pdir_size < 4*1024*1024);   /* max pdir size == 2MB */	/* Verify it's a power of two */	ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT));	DBG_INIT("%s() hpa 0x%lx mem %dMB IOV %dMB (%d bits) PDIR size 0x%0x\n",		__FUNCTION__, ioc->ioc_hpa, (int) (physmem>>20),		iova_space_size>>20, iov_order + PAGE_SHIFT, pdir_size);	/* FIXME : DMA HINTs not used */	ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;	ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));	ioc->pdir_base = sba_alloc_pdir(pdir_size);	DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",		__FUNCTION__, ioc->pdir_base, pdir_size,		ioc->hint_shift_pdir, ioc->hint_mask_pdir);	ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base);	WRITE_REG64(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);	/* build IMASK for IOC and Elroy */	iova_space_mask =  0xffffffff;	iova_space_mask <<= (iov_order + PAGE_SHIFT);	/*	** On C3000 w/512MB mem, HP-UX 10.20 reports:	**     ibase=0, imask=0xFE000000, size=0x2000000.	*/	ioc->ibase = IOC_IOVA_SPACE_BASE | 1;	/* bit 0 == enable bit */	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.	*/	/*	** setup Elroy IBASE/IMASK registers as well.	*/	for (lba = sba->child; lba; lba = lba->sibling) {		int rope_num = (lba->hpa >> 13) & 0xf;		if (rope_num >> 3 == ioc_num)			lba_set_iregs(lba, ioc->ibase, ioc->imask);	}	/*	** Program the IOC's ibase and enable IOVA translation	*/	WRITE_REG(ioc->ibase, ioc->ioc_hpa+IOC_IBASE);	WRITE_REG(ioc->imask, ioc->ioc_hpa+IOC_IMASK);	/* Set I/O PDIR Page size to 4K */	WRITE_REG(0, ioc->ioc_hpa+IOC_TCNFG);	/*	** 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);	DBG_INIT("%s() DONE\n", __FUNCTION__);}/******************************************************************************   SBA initialization code (HW and SW)****   o identify SBA chip itself**   o initialize SBA chip modes (HardFail)**   o initialize SBA chip modes (HardFail)**   o FIXME: initialize DMA hints for reasonable defaults****************************************************************************/static voidsba_hw_init(struct sba_device *sba_dev){ 	int i;	int num_ioc;	u64 ioc_ctl;	ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);	DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",		__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);	ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC | IOC_CTRL_CE);	ioc_ctl |= IOC_CTRL_TC;	/* Astro: firmware enables this */	WRITE_REG(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL);#ifdef DEBUG_SBA_INIT	ioc_ctl = READ_REG64(sba_dev->sba_hpa+IOC_CTRL);	DBG_INIT(" 0x%Lx\n", ioc_ctl);#endif	if (IS_ASTRO(sba_dev->iodc)) {		/* PAT_PDC (L-class) also reports the same goofy base */		sba_dev->ioc[0].ioc_hpa = ASTRO_IOC_OFFSET;		num_ioc = 1;	} else {		sba_dev->ioc[0].ioc_hpa = sba_dev->ioc[1].ioc_hpa = 0;		num_ioc = 2;	}	sba_dev->num_ioc = num_ioc;	for (i = 0; i < num_ioc; i++) {		sba_dev->ioc[i].ioc_hpa += sba_dev->sba_hpa + IKE_IOC_OFFSET(i);		/*		** Make sure the box crashes if we get any errors on a rope.		*/		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL);		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL);		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL);		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL);		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL);		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL);		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL);		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);		/* flush out the writes */		READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);		sba_ioc_init(sba_dev->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;	for(i=0; i< sba_dev->num_ioc; i++) {		int res_size;#ifdef DEBUG_DMB_TRAP		extern void iterate_pages(unsigned long , unsigned long ,					  void (*)(pte_t * , unsigned long),					  unsigned long );		void set_data_memory_break(pte_t * , unsigned long);#endif		/* resource map size dictated by pdir_size */		res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */		/* Second part of PIRANHA BUG */		if (piranha_bad_128k) {			res_size -= (128*1024)/sizeof(u64);		}		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));#ifdef DEBUG_DMB_TRAP		iterate_pages( sba_dev->ioc[i].res_map, res_size,				set_data_memory_break, 0);#endif		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 */		sba_dev->ioc[i].res_hint = (unsigned long *)				&(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]);#ifdef ASSERT_PDIR_SANITY		/* Mark first bit busy - ie no IOVA 0 */		sba_dev->ioc[i].res_map[0] = 0x80;		sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL;#endif		/* Third (and last) part of PIRANHA BUG */		if (piranha_bad_128k) {			/* region from +1408K to +1536 is un-usable. */			int idx_start = (1408*1024/sizeof(u64)) >> 3;			int idx_end   = (1536*1024/sizeof(u64)) >> 3;			long *p_start = (long *) &(sba_dev->ioc[i].res_map[idx_start]);			long *p_end   = (long *) &(sba_dev->ioc[i].res_map[idx_end]);			/* mark that part of the io pdir busy */			while (p_start < p_end)				*p_start++ = -1;						}#ifdef DEBUG_DMB_TRAP		iterate_pages( sba_dev->ioc[i].res_map, res_size,				set_data_memory_break, 0);		iterate_pages( sba_dev->ioc[i].pdir_base, sba_dev->ioc[i].pdir_size,				set_data_memory_break, 0);#endif		DBG_INIT("%s() %d res_map %x %p\n",			__FUNCTION__, i, res_size, sba_dev->ioc[i].res_map);	}	sba_dev->sba_lock = SPIN_LOCK_UNLOCKED;	ioc_needs_fdc = boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC;#ifdef DEBUG_SBA_INIT	/*	 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set	 * (bit #61, big endian), we have to flush and sync every time	 * IO-PDIR is changed in Ike/Astro.	 */	if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) {		printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n");	} else {		printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n");	}#endif}#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",		sba_dev->name,		(sba_dev->hw_rev & 0x7) + 1,		(sba_dev->hw_rev & 0x18) >> 3		);	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));	/* KLUGE - unmap_sg calls unmap_single for each mapped page */	min = ioc->usingle_calls;	max = ioc->usingle_pages - ioc->usg_pages;	sprintf(buf, "%spci_unmap_single: %12ld calls  %12ld pages (avg %d/1000)\n",		buf, min, max,		(int) ((max * 1000)/min));	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));	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);}#if 0/* XXX too much output - exceeds 4k limit and needs to be re-written */static intsba_resource_map(char *buf, char **start, off_t offset, int len){	struct sba_device *sba_dev = sba_list;	struct ioc *ioc = &sba_dev->ioc[0];	/* FIXME: Mutli-IOC suppoer! */	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 /* 0 */#endif /* CONFIG_PROC_FS */static struct parisc_device_id sba_tbl[] = {	{ HPHW_IOA, HVERSION_REV_ANY_ID, ASTRO_RUNWAY_PORT, 0xb },	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_MERCED_PORT, 0xc },	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REO_MERCED_PORT, 0xc },	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REOG_MERCED_PORT, 0xc },/* These two entries commented out because we don't find them in a * buswalk yet.  If/when we do, they would cause us to think we had * many more SBAs then we really do. *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, ASTRO_ROPES_PORT, 0xc }, *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_ROPES_PORT, 0xc }, */	{ 0, }};int sba_driver_callback(struct parisc_device *);static struct parisc_driver sba_driver = {	name:		MODULE_NAME,	id_table:	sba_tbl,	probe:		sba_driver_callback,};/*** Determine if lba 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.*/intsba_driver_callback(struct parisc_device *dev){	struct sba_device *sba_dev;	u32 func_class;	int i;	char *version;#ifdef DEBUG_SBA_INIT	sba_dump_ranges(dev->hpa);#endif	/* Read HW Rev First */	func_class = READ_REG(dev->hpa + SBA_FCLASS);	if (IS_ASTRO(&dev->id)) {		unsigned long fclass;		static char astro_rev[]="Astro ?.?";		/* Astro is broken...Read HW Rev First */		fclass = READ_REG(dev->hpa);		astro_rev[6] = '1' + (char) (fclass & 0x7);		astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);		version = astro_rev;	} else if (IS_IKE(&dev->id)) {		static char ike_rev[]="Ike rev ?";		ike_rev[8] = '0' + (char) (func_class & 0xff);		version = ike_rev;	} else {		static char reo_rev[]="REO rev ?";		reo_rev[8] = '0' + (char) (func_class & 0xff);		version = reo_rev;	}	if (!global_ioc_cnt) {		global_ioc_cnt = count_parisc_driver(&sba_driver);		/* Only Astro has one IOC per SBA */		if (!IS_ASTRO(&dev->id))			global_ioc_cnt *= 2;	}	printk(KERN_INFO "%s found %s at 0x%lx\n",		MODULE_NAME, version, dev->hpa);#ifdef DEBUG_SBA_INIT	sba_dump_tlb(dev->hpa);#endif	sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);	if (NULL == sba_dev) {		printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n");		return(1);	}	dev->sysdata = (void *) sba_dev;	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->dev = dev;	sba_dev->hw_rev = func_class;	sba_dev->iodc = &dev->id;	sba_dev->name = dev->name;	sba_dev->sba_hpa = dev->hpa;  /* faster access */	sba_get_pat_resources(sba_dev);	sba_hw_init(sba_dev);	sba_common_init(sba_dev);	hppa_dma_ops = &sba_ops;#ifdef CONFIG_PROC_FS	if (IS_ASTRO(&dev->id)) {		create_proc_info_entry("Astro", 0, proc_runway_root, sba_proc_info);	} else if (IS_IKE(&dev->id)) {		create_proc_info_entry("Ike", 0, proc_runway_root, sba_proc_info);	} else {		create_proc_info_entry("Reo", 0, proc_runway_root, sba_proc_info);	}#if 0	create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map);#endif#endif	return 0;}/*** One time initialization to let the world know the SBA was found.** This is the only routine which is NOT static.** Must be called exactly once before pci_init().*/void __init sba_init(void){	register_parisc_driver(&sba_driver);}/** * sba_get_iommu - Assign the iommu pointer for the pci bus controller. * @dev: The parisc device. * * This function searches through the registerd IOMMU's and returns the * appropriate IOMMU data for the given parisc PCI controller. */void * sba_get_iommu(struct parisc_device *pci_hba){	struct sba_device *sba = (struct sba_device *) pci_hba->parent->sysdata;	char t = pci_hba->parent->id.hw_type;	int iocnum = (pci_hba->hw_path >> 3);	/* rope # */	if ((t!=HPHW_IOA) && (t!=HPHW_BCPORT))		BUG();	return &(sba->ioc[iocnum]);}

⌨️ 快捷键说明

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