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

📄 ccio-dma.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 4 页
字号:
 * @hw_path: The hardware path of the ioc. * * This function searches the ioc_list for an ioc that matches * the provide hardware path. */static struct ioc * ccio_find_ioc(int hw_path){	int i;	struct ioc *ioc;	ioc = ioc_list;	for (i = 0; i < ioc_count; i++) {		if (ioc->hw_path == hw_path)			return ioc;		ioc = ioc->next;	}	return NULL;}/** * ccio_get_iommu - Find the iommu which controls this device * @dev: The parisc device. * * This function searches through the registerd IOMMU's and returns the * appropriate IOMMU for the device based upon the devices hardware path. */void * ccio_get_iommu(const struct parisc_device *dev){	dev = find_pa_parent_type(dev, HPHW_IOA);	if (!dev)		return NULL;	return ccio_find_ioc(dev->hw_path);}#define CUJO_20_STEP       0x10000000	/* inc upper nibble *//* Cujo 2.0 has a bug which will silently corrupt data being transferred * to/from certain pages.  To avoid this happening, we mark these pages * as `used', and ensure that nothing will try to allocate from them. */void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp){	unsigned int idx;	struct ioc *ioc = ccio_get_iommu(dev);	u8 *res_ptr;#ifdef CONFIG_PROC_FS	ioc->cujo20_bug = 1;#endif	res_ptr = ioc->res_map;	idx = PDIR_INDEX(iovp) >> 3;	while (idx < ioc->res_size) { 		res_ptr[idx] |= 0xff;		idx += PDIR_INDEX(CUJO_20_STEP) >> 3;	}}#if 0/* GRANT -  is this needed for U2 or not? *//*** Get the size of the I/O TLB for this I/O MMU.**** If spa_shift is non-zero (ie probably U2),** then calculate the I/O TLB size using spa_shift.**** Otherwise we are supposed to get the IODC entry point ENTRY TLB** and execute it. However, both U2 and Uturn firmware supplies spa_shift.** I think only Java (K/D/R-class too?) systems don't do this.*/static intccio_get_iotlb_size(struct parisc_device *dev){	if (dev->spa_shift == 0) {		panic("%s() : Can't determine I/O TLB size.\n", __FUNCTION__);	}	return (1 << dev->spa_shift);}#else/* Uturn supports 256 TLB entries */#define CCIO_CHAINID_SHIFT	8#define CCIO_CHAINID_MASK	0xff#endif /* 0 *//** * ccio_ioc_init - Initalize the I/O Controller * @ioc: The I/O Controller. * * Initalize the I/O Controller which includes setting up the * I/O Page Directory, the resource map, and initalizing the * U2/Uturn chip into virtual mode. */static voidccio_ioc_init(struct ioc *ioc){	int i, iov_order;	u32 iova_space_size;	unsigned long physmem;	/*	** 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).	*/	/* limit IOVA space size to 1MB-1GB */	physmem = num_physpages << PAGE_SHIFT;	if(physmem < (ccio_mem_ratio * 1024 * 1024)) {		iova_space_size = 1024 * 1024;#ifdef __LP64__	} else if(physmem > (ccio_mem_ratio * 512 * 1024 * 1024)) {		iova_space_size = 512 * 1024 * 1024;#endif	} else {		iova_space_size = (u32)(physmem / ccio_mem_ratio);	}	/*	** iova space must be log2() in size.	** thus, pdir/res_map will also be log2().	*/	/* We could use larger page sizes in order to *decrease* the number	** of mappings needed.  (ie 8k pages means 1/2 the mappings).	**	** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either	**   since the pages must also be physically contiguous - typically	**   this is the case under linux."	*/	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 = (iova_space_size / IOVP_SIZE) * sizeof(u64);	ASSERT(ioc->pdir_size < 4 * 1024 * 1024);   /* max pdir size < 4MB */	/* Verify it's a power of two */	ASSERT((1 << get_order(ioc->pdir_size)) == (ioc->pdir_size >> PAGE_SHIFT));	DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits) PDIR size 0x%0x",		__FUNCTION__, ioc->ioc_hpa, physmem>>20, iova_space_size>>20,		 iov_order + PAGE_SHIFT, ioc->pdir_size);	ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, 						 get_order(ioc->pdir_size));	if(NULL == ioc->pdir_base) {		panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);	}	memset(ioc->pdir_base, 0, ioc->pdir_size);	ASSERT((((unsigned long)ioc->pdir_base) & PAGE_MASK) == (unsigned long)ioc->pdir_base);	DBG_INIT(" base %p", ioc->pdir_base);	/* resource map size dictated by pdir_size */ 	ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3;	DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size);		ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, 					      get_order(ioc->res_size));	if(NULL == ioc->res_map) {		panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__);	}	memset(ioc->res_map, 0, ioc->res_size);	/* Initialize the res_hint to 16 */	ioc->res_hint = 16;	/* Initialize the spinlock */	spin_lock_init(&ioc->res_lock);	/*	** Chainid is the upper most bits of an IOVP used to determine	** which TLB entry an IOVP will use.	*/	ioc->chainid_shift = get_order(iova_space_size) + PAGE_SHIFT - CCIO_CHAINID_SHIFT;	DBG_INIT(" chainid_shift 0x%x\n", ioc->chainid_shift);	/*	** Initialize IOA hardware	*/	WRITE_U32(CCIO_CHAINID_MASK << ioc->chainid_shift, 		  &ioc->ioc_hpa->io_chain_id_mask);	WRITE_U32(virt_to_phys(ioc->pdir_base), 		  &ioc->ioc_hpa->io_pdir_base);	/*	** Go to "Virtual Mode"	*/	WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_hpa->io_control);	/*	** Initialize all I/O TLB entries to 0 (Valid bit off).	*/	WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_m);	WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_l);	for(i = 1 << CCIO_CHAINID_SHIFT; i ; i--) {		WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioc->chainid_shift)),			  &ioc->ioc_hpa->io_command);	}}static voidccio_init_resource(struct resource *res, char *name, unsigned long ioaddr){	int result;	res->flags = IORESOURCE_MEM;	res->start = (unsigned long)(signed) __raw_readl(ioaddr) << 16;	res->end = (unsigned long)(signed) (__raw_readl(ioaddr + 4) << 16) - 1;	if (res->end + 1 == res->start)		return;	res->name = name;	result = request_resource(&iomem_resource, res);	if (result < 0) {		printk(KERN_ERR 		       "%s: failed to claim CCIO bus address space (%p,%p)\n", 		       __FILE__, res->start, res->end);	}}static void __init ccio_init_resources(struct ioc *ioc){	struct resource *res = ioc->mmio_region;	char *name = kmalloc(14, GFP_KERNEL);	sprintf(name, "GSC Bus [%d/]", ioc->hw_path);	ccio_init_resource(res, name, (unsigned long)&ioc->ioc_hpa->io_io_low);	ccio_init_resource(res + 1, name,			(unsigned long)&ioc->ioc_hpa->io_io_low_hv);}static void expand_ioc_area(struct ioc *ioc, unsigned long size,		unsigned long min, unsigned long max, unsigned long align){#ifdef NASTY_HACK_FOR_K_CLASS	__raw_writel(0xfffff600, (unsigned long)&(ioc->ioc_hpa->io_io_high));	ioc->mmio_region[0].end = 0xf5ffffff;#endif}static struct resource *ccio_get_resource(struct ioc* ioc,		const struct parisc_device *dev){	if (!ioc) {		return &iomem_resource;	} else if ((ioc->mmio_region->start <= dev->hpa) &&			(dev->hpa < ioc->mmio_region->end)) {		return ioc->mmio_region;	} else if (((ioc->mmio_region + 1)->start <= dev->hpa) &&			(dev->hpa < (ioc->mmio_region + 1)->end)) {		return ioc->mmio_region + 1;	} else {		return NULL;	}}int ccio_allocate_resource(const struct parisc_device *dev,		struct resource *res, unsigned long size,		unsigned long min, unsigned long max, unsigned long align,		void (*alignf)(void *, struct resource *, unsigned long),		void *alignf_data){	struct ioc *ioc = ccio_get_iommu(dev);	struct resource *parent = ccio_get_resource(ioc, dev);	if (!parent)		return -EBUSY;	if (!allocate_resource(parent, res, size, min, max, align, alignf,			alignf_data))		return 0;	expand_ioc_area(ioc, size, min, max, align);	return allocate_resource(parent, res, size, min, max, align, alignf,			alignf_data);}int ccio_request_resource(const struct parisc_device *dev,		struct resource *res){	struct ioc *ioc = ccio_get_iommu(dev);	struct resource *parent = ccio_get_resource(ioc, dev);	return request_resource(parent, res);}/** * ccio_probe - Determine if ccio should claim this device. * @dev: The device which has been found * * Determine if ccio 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. */static int ccio_probe(struct parisc_device *dev){	int i;	struct ioc *ioc, **ioc_p = &ioc_list;		ioc = kmalloc(sizeof(struct ioc), GFP_KERNEL);	if (ioc == NULL) {		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");		return 1;	}	memset(ioc, 0, sizeof(struct ioc));	ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn";	printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa);	for (i = 0; i < ioc_count; i++) {		ioc_p = &(*ioc_p)->next;	}	*ioc_p = ioc;	ioc->hw_path = dev->hw_path;	ioc->ioc_hpa = (struct ioa_registers *)dev->hpa;	ccio_ioc_init(ioc);	ccio_init_resources(ioc);	hppa_dma_ops = &ccio_ops;	if (ioc_count == 0) {		/* XXX: Create separate entries for each ioc */		create_proc_read_entry(MODULE_NAME, S_IRWXU, proc_runway_root,				       ccio_proc_info, NULL);		create_proc_read_entry(MODULE_NAME"-bitmap", S_IRWXU,				       proc_runway_root, ccio_resource_map, NULL);	}	ioc_count++;	return 0;}struct pci_dev * ccio_get_fake(const struct parisc_device *dev){	struct ioc *ioc;	dev = find_pa_parent_type(dev, HPHW_IOA);	if(!dev)		return NULL;	ioc = ccio_find_ioc(dev->hw_path);	if(!ioc)		return NULL;	if(ioc->fake_pci_dev)		return ioc->fake_pci_dev;	ioc->fake_pci_dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);	if(ioc->fake_pci_dev == NULL) {		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");		return NULL;	}	memset(ioc->fake_pci_dev, 0, sizeof(struct pci_dev));	ioc->fake_pci_dev->sysdata = kmalloc(sizeof(struct pci_hba_data), GFP_KERNEL);	if(ioc->fake_pci_dev->sysdata == NULL) {		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");		return NULL;	}	HBA_DATA(ioc->fake_pci_dev->sysdata)->iommu = ioc;	return ioc->fake_pci_dev;}/* We *can't* support JAVA (T600). Venture there at your own risk. */static struct parisc_device_id ccio_tbl[] = {	{ HPHW_IOA, HVERSION_REV_ANY_ID, U2_IOA_RUNWAY, 0xb }, /* U2 */	{ HPHW_IOA, HVERSION_REV_ANY_ID, UTURN_IOA_RUNWAY, 0xb }, /* UTurn */	{ 0, }};static struct parisc_driver ccio_driver = {	name:		"U2/Uturn",	id_table:	ccio_tbl,	probe:		ccio_probe,};/** * ccio_init - ccio initalization procedure. * * Register this driver. */void __init ccio_init(void){	register_parisc_driver(&ccio_driver);}

⌨️ 快捷键说明

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