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

📄 sba_iommu.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		err = request_resource(&iomem_resource, &(sba_dev->chip_resv));		WARN_ON(err < 0);		sba_dev->iommu_resv.name = "IOVA Space";		sba_dev->iommu_resv.start = 0x40000000UL;		sba_dev->iommu_resv.end   = 0x50000000UL - 1;		err = request_resource(&iomem_resource, &(sba_dev->iommu_resv));		WARN_ON(err < 0);	} else {		/* IKE, REO */		sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0));		sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1));		num_ioc = 2;		/* TODO - LOOKUP Ike/Stretch chipset mem map */	}	/* XXX: What about Reo Grande? */	sba_dev->num_ioc = num_ioc;	for (i = 0; i < num_ioc; i++) {		void __iomem *ioc_hpa = sba_dev->ioc[i].ioc_hpa;		unsigned int j;		for (j=0; j < sizeof(u64) * ROPES_PER_IOC; j+=sizeof(u64)) {			/*			 * Clear ROPE(N)_CONFIG AO bit.			 * Disables "NT Ordering" (~= !"Relaxed Ordering")			 * Overrides bit 1 in DMA Hint Sets.			 * Improves netperf UDP_STREAM by ~10% for bcm5701.			 */			if (IS_PLUTO(sba_dev->dev)) {				void __iomem *rope_cfg;				unsigned long cfg_val;				rope_cfg = ioc_hpa + IOC_ROPE0_CFG + j;				cfg_val = READ_REG(rope_cfg);				cfg_val &= ~IOC_ROPE_AO;				WRITE_REG(cfg_val, rope_cfg);			}			/*			** Make sure the box crashes on rope errors.			*/			WRITE_REG(HF_ENABLE, ioc_hpa + ROPE0_CTL + j);		}		/* flush out the last writes */		READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);		DBG_INIT("	ioc[%d] ROPE_CFG 0x%Lx  ROPE_DBG 0x%Lx\n",				i,				READ_REG(sba_dev->ioc[i].ioc_hpa + 0x40),				READ_REG(sba_dev->ioc[i].ioc_hpa + 0x50)			);		DBG_INIT("	STATUS_CONTROL 0x%Lx  FLUSH_CTRL 0x%Lx\n",				READ_REG(sba_dev->ioc[i].ioc_hpa + 0x108),				READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)			);		if (IS_PLUTO(sba_dev->dev)) {			sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i);		} else {			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("%s:%s() could not allocate resource map\n",			      __FILE__, __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);	}	spin_lock_init(&sba_dev->sba_lock);	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 (ioc_needs_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(struct seq_file *m, void *p){	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 */#ifdef SBA_COLLECT_STATS	unsigned long avg = 0, min, max;#endif	int i, len = 0;	len += seq_printf(m, "%s rev %d.%d\n",		sba_dev->name,		(sba_dev->hw_rev & 0x7) + 1,		(sba_dev->hw_rev & 0x18) >> 3		);	len += seq_printf(m, "IO PDIR size    : %d bytes (%d entries)\n",		(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */		total_pages);	len += seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n", 		ioc->res_size, ioc->res_size << 3);   /* 8 bits per byte */	len += seq_printf(m, "LMMIO_BASE/MASK/ROUTE %08x %08x %08x\n",		READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_BASE),		READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_MASK),		READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_ROUTE)		);	for (i=0; i<4; i++)		len += seq_printf(m, "DIR%d_BASE/MASK/ROUTE %08x %08x %08x\n", i,			READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_BASE  + i*0x18),			READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_MASK  + i*0x18),			READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_ROUTE + i*0x18)		);#ifdef SBA_COLLECT_STATS	len += seq_printf(m, "IO PDIR entries : %ld free  %ld used (%d%%)\n",		total_pages - ioc->used_pages, ioc->used_pages,		(int) (ioc->used_pages * 100 / total_pages));	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;	len += seq_printf(m, "  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",		min, avg, max);	len += seq_printf(m, "pci_map_single(): %12ld calls  %12ld pages (avg %d/1000)\n",		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;	len += seq_printf(m, "pci_unmap_single: %12ld calls  %12ld pages (avg %d/1000)\n",		min, max, (int) ((max * 1000)/min));	len += seq_printf(m, "pci_map_sg()    : %12ld calls  %12ld pages (avg %d/1000)\n",		ioc->msg_calls, ioc->msg_pages, 		(int) ((ioc->msg_pages * 1000)/ioc->msg_calls));	len += seq_printf(m, "pci_unmap_sg()  : %12ld calls  %12ld pages (avg %d/1000)\n",		ioc->usg_calls, ioc->usg_pages,		(int) ((ioc->usg_pages * 1000)/ioc->usg_calls));#endif	return 0;}static intsba_proc_open(struct inode *i, struct file *f){	return single_open(f, &sba_proc_info, NULL);}static const struct file_operations sba_proc_fops = {	.owner = THIS_MODULE,	.open = sba_proc_open,	.read = seq_read,	.llseek = seq_lseek,	.release = single_release,};static intsba_proc_bitmap_info(struct seq_file *m, void *p){	struct sba_device *sba_dev = sba_list;	struct ioc *ioc = &sba_dev->ioc[0];	/* FIXME: Multi-IOC support! */	unsigned int *res_ptr = (unsigned int *)ioc->res_map;	int i, len = 0;	for (i = 0; i < (ioc->res_size/sizeof(unsigned int)); ++i, ++res_ptr) {		if ((i & 7) == 0)			len += seq_printf(m, "\n   ");		len += seq_printf(m, " %08x", *res_ptr);	}	len += seq_printf(m, "\n");	return 0;}static intsba_proc_bitmap_open(struct inode *i, struct file *f){	return single_open(f, &sba_proc_bitmap_info, NULL);}static const struct file_operations sba_proc_bitmap_fops = {	.owner = THIS_MODULE,	.open = sba_proc_bitmap_open,	.read = seq_read,	.llseek = seq_lseek,	.release = single_release,};#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 },	{ HPHW_IOA, HVERSION_REV_ANY_ID, PLUTO_MCKINLEY_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 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.*/intsba_driver_callback(struct parisc_device *dev){	struct sba_device *sba_dev;	u32 func_class;	int i;	char *version;	void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE);	struct proc_dir_entry *info_entry, *bitmap_entry, *root;	sba_dump_ranges(sba_addr);	/* Read HW Rev First */	func_class = READ_REG(sba_addr + SBA_FCLASS);	if (IS_ASTRO(dev)) {		unsigned long fclass;		static char astro_rev[]="Astro ?.?";		/* Astro is broken...Read HW Rev First */		fclass = READ_REG(sba_addr);		astro_rev[6] = '1' + (char) (fclass & 0x7);		astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);		version = astro_rev;	} else if (IS_IKE(dev)) {		static char ike_rev[] = "Ike rev ?";		ike_rev[8] = '0' + (char) (func_class & 0xff);		version = ike_rev;	} else if (IS_PLUTO(dev)) {		static char pluto_rev[]="Pluto ?.?";		pluto_rev[6] = '0' + (char) ((func_class & 0xf0) >> 4); 		pluto_rev[8] = '0' + (char) (func_class & 0x0f); 		version = pluto_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);		/* Astro and Pluto have one IOC per SBA */		if ((!IS_ASTRO(dev)) || (!IS_PLUTO(dev)))			global_ioc_cnt *= 2;	}	printk(KERN_INFO "%s found %s at 0x%llx\n",		MODULE_NAME, version, (unsigned long long)dev->hpa.start);	sba_dev = kzalloc(sizeof(struct sba_device), GFP_KERNEL);	if (!sba_dev) {		printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n");		return -ENOMEM;	}	parisc_set_drvdata(dev, sba_dev);	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->name = dev->name;	sba_dev->sba_hpa = sba_addr;	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	switch (dev->id.hversion) {	case PLUTO_MCKINLEY_PORT:		root = proc_mckinley_root;		break;	case ASTRO_RUNWAY_PORT:	case IKE_MERCED_PORT:	default:		root = proc_runway_root;		break;	}	info_entry = create_proc_entry("sba_iommu", 0, root);	bitmap_entry = create_proc_entry("sba_iommu-bitmap", 0, root);	if (info_entry)		info_entry->proc_fops = &sba_proc_fops;	if (bitmap_entry)		bitmap_entry->proc_fops = &sba_proc_bitmap_fops;#endif	parisc_vmerge_boundary = IOVP_SIZE;	parisc_vmerge_max_size = IOVP_SIZE * BITS_PER_LONG;	parisc_has_iommu();	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. * * Returns the appropriate IOMMU data for the given parisc PCI controller. * This is cached and used later for PCI DMA Mapping. */void * sba_get_iommu(struct parisc_device *pci_hba){	struct parisc_device *sba_dev = parisc_parent(pci_hba);	struct sba_device *sba = sba_dev->dev.driver_data;	char t = sba_dev->id.hw_type;	int iocnum = (pci_hba->hw_path >> 3);	/* rope # */	WARN_ON((t != HPHW_IOA) && (t != HPHW_BCPORT));	return &(sba->ioc[iocnum]);}/** * sba_directed_lmmio - return first directed LMMIO range routed to rope * @pa_dev: The parisc device. * @r: resource PCI host controller wants start/end fields assigned. * * For the given parisc PCI controller, determine if any direct ranges * are routed down the corresponding rope. */void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r){	struct parisc_device *sba_dev = parisc_parent(pci_hba);	struct sba_device *sba = sba_dev->dev.driver_data;	char t = sba_dev->id.hw_type;	int i;	int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1));  /* rope # */	BUG_ON((t!=HPHW_IOA) && (t!=HPHW_BCPORT));	r->start = r->end = 0;	/* Astro has 4 directed ranges. Not sure about Ike/Pluto/et al */	for (i=0; i<4; i++) {		int base, size;		void __iomem *reg = sba->sba_hpa + i*0x18;		base = READ_REG32(reg + LMMIO_DIRECT0_BASE);		if ((base & 1) == 0)			continue;	/* not enabled */		size = READ_REG32(reg + LMMIO_DIRECT0_ROUTE);		if ((size & (ROPES_PER_IOC-1)) != rope)			continue;	/* directed down different rope */				r->start = (base & ~1UL) | PCI_F_EXTEND;		size = ~ READ_REG32(reg + LMMIO_DIRECT0_MASK);		r->end = r->start + size;	}}/** * sba_distributed_lmmio - return portion of distributed LMMIO range * @pa_dev: The parisc device. * @r: resource PCI host controller wants start/end fields assigned. * * For the given parisc PCI controller, return portion of distributed LMMIO * range. The distributed LMMIO is always present and it's just a question * of the base address and size of the range. */void sba_distributed_lmmio(struct parisc_device *pci_hba, struct resource *r ){	struct parisc_device *sba_dev = parisc_parent(pci_hba);	struct sba_device *sba = sba_dev->dev.driver_data;	char t = sba_dev->id.hw_type;	int base, size;	int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1));  /* rope # */	BUG_ON((t!=HPHW_IOA) && (t!=HPHW_BCPORT));	r->start = r->end = 0;	base = READ_REG32(sba->sba_hpa + LMMIO_DIST_BASE);	if ((base & 1) == 0) {		BUG();	/* Gah! Distr Range wasn't enabled! */		return;	}	r->start = (base & ~1UL) | PCI_F_EXTEND;	size = (~READ_REG32(sba->sba_hpa + LMMIO_DIST_MASK)) / ROPES_PER_IOC;	r->start += rope * (size + 1);	/* adjust base for this rope */	r->end = r->start + size;}

⌨️ 快捷键说明

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