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

📄 sba_iommu.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	** We program the next pdir index after we stop w/ a key for	** the GART code to handshake on.	*/	while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL)		agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP);	if (agp_found && reserve_sba_gart) {		printk(KERN_INFO PFX "reserving %dMb of IOVA space at 0x%lx for agpgart\n",			ioc->iov_size/2 >> 20, ioc->ibase + ioc->iov_size/2);		ioc->pdir_size /= 2;		((u64 *)ioc->pdir_base)[PDIR_INDEX(ioc->iov_size/2)] = ZX1_SBA_IOMMU_COOKIE;	}#ifdef FULL_VALID_PDIR	/*  	** Check to see if the spill page has been allocated, we don't need more than	** one across multiple SBAs.	*/	if (!prefetch_spill_page) {		char *spill_poison = "SBAIOMMU POISON";		int poison_size = 16;		void *poison_addr, *addr;		addr = (void *)__get_free_pages(GFP_KERNEL, get_order(iovp_size));		if (!addr)			panic(PFX "Couldn't allocate PDIR spill page\n");		poison_addr = addr;		for ( ; (u64) poison_addr < addr + iovp_size; poison_addr += poison_size)			memcpy(poison_addr, spill_poison, poison_size);		prefetch_spill_page = virt_to_phys(addr);		DBG_INIT("%s() prefetch spill addr: 0x%lx\n", __FUNCTION__, prefetch_spill_page);	}	/*  	** Set all the PDIR entries valid w/ the spill page as the target	*/	for (index = 0 ; index < (ioc->pdir_size / PDIR_ENTRY_SIZE) ; index++)		((u64 *)ioc->pdir_base)[index] = (0x80000000000000FF | prefetch_spill_page);#endif	/* Clear I/O TLB of any possible entries */	WRITE_REG(ioc->ibase | (get_iovp_order(ioc->iov_size) + iovp_shift), ioc->ioc_hpa + IOC_PCOM);	READ_REG(ioc->ioc_hpa + IOC_PCOM);	/* Enable IOVA translation */	WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa + IOC_IBASE);	READ_REG(ioc->ioc_hpa + IOC_IBASE);}static void __initioc_resource_init(struct ioc *ioc){	spin_lock_init(&ioc->res_lock);	/* resource map size dictated by pdir_size */	ioc->res_size = ioc->pdir_size / PDIR_ENTRY_SIZE; /* entries */	ioc->res_size >>= 3;  /* convert bit count to byte count */	DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size);	ioc->res_map = (char *) __get_free_pages(GFP_KERNEL,						 get_order(ioc->res_size));	if (!ioc->res_map)		panic(PFX "Couldn't allocate resource map\n");	memset(ioc->res_map, 0, ioc->res_size);	/* next available IOVP - circular search */	ioc->res_hint = (unsigned long *) ioc->res_map;#ifdef ASSERT_PDIR_SANITY	/* Mark first bit busy - ie no IOVA 0 */	ioc->res_map[0] = 0x1;	ioc->pdir_base[0] = 0x8000000000000000ULL | ZX1_SBA_IOMMU_COOKIE;#endif#ifdef FULL_VALID_PDIR	/* Mark the last resource used so we don't prefetch beyond IOVA space */	ioc->res_map[ioc->res_size - 1] |= 0x80UL; /* res_map is chars */	ioc->pdir_base[(ioc->pdir_size / PDIR_ENTRY_SIZE) - 1] = (0x80000000000000FF							      | prefetch_spill_page);#endif	DBG_INIT("%s() res_map %x %p\n", __FUNCTION__,		 ioc->res_size, (void *) ioc->res_map);}static void __initioc_sac_init(struct ioc *ioc){	struct pci_dev *sac = NULL;	struct pci_controller *controller = NULL;	/*	 * pci_alloc_coherent() must return a DMA address which is	 * SAC (single address cycle) addressable, so allocate a	 * pseudo-device to enforce that.	 */	sac = kmalloc(sizeof(*sac), GFP_KERNEL);	if (!sac)		panic(PFX "Couldn't allocate struct pci_dev");	memset(sac, 0, sizeof(*sac));	controller = kmalloc(sizeof(*controller), GFP_KERNEL);	if (!controller)		panic(PFX "Couldn't allocate struct pci_controller");	memset(controller, 0, sizeof(*controller));	controller->iommu = ioc;	sac->sysdata = controller;	sac->dma_mask = 0xFFFFFFFFUL;	ioc->sac_only_dev = sac;}static void __initioc_zx1_init(struct ioc *ioc){	if (ioc->rev < 0x20)		panic(PFX "IOC 2.0 or later required for IOMMU support\n");	ioc->dma_mask = 0xFFFFFFFFFFUL;	if (!iovp_shift) {		/* 64k is max iommu page size */		iovp_shift = min(PAGE_SHIFT, 16);		iovp_size = (1 << iovp_shift);		iovp_mask = ~(iovp_size - 1);	}}static void __initioc_sx1000_init(struct ioc *ioc){	if (!iovp_shift) {		iovp_shift = 12;	/* 4K for now */		iovp_size = (1 << iovp_shift);		iovp_mask = ~(iovp_size - 1);	}}typedef void (initfunc)(struct ioc *);struct ioc_iommu {	u32 func_id;	char *name;	initfunc *init;};static struct ioc_iommu ioc_iommu_info[] __initdata = {	{ ZX1_IOC_ID, "zx1", ioc_zx1_init },	{ REO_IOC_ID, "REO", ioc_sx1000_init },	{ SX1000_IOC_ID, "sx1000", ioc_sx1000_init },};static struct ioc * __initioc_init(u64 hpa, void *handle){	struct ioc *ioc;	struct ioc_iommu *info;	ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);	if (!ioc)		return NULL;	memset(ioc, 0, sizeof(*ioc));	ioc->next = ioc_list;	ioc_list = ioc;	ioc->handle = handle;	ioc->ioc_hpa = ioremap(hpa, 0x1000);	ioc->func_id = READ_REG(ioc->ioc_hpa + IOC_FUNC_ID);	ioc->rev = READ_REG(ioc->ioc_hpa + IOC_FCLASS) & 0xFFUL;	ioc->dma_mask = 0xFFFFFFFFFFFFFFFFUL;	/* conservative */	if (iovp_shift) {		iovp_size = (1 << iovp_shift);		iovp_mask = ~(iovp_size - 1);	}	for (info = ioc_iommu_info; info < ioc_iommu_info + ARRAY_SIZE(ioc_iommu_info); info++) {		if (ioc->func_id == info->func_id) {			ioc->name = info->name;			if (info->init)				(info->init)(ioc);		}	}	DBG_INIT("%s: PAGE_SIZE %ldK, iovp_size %ldK\n", __FUNCTION__,		PAGE_SIZE >> 10, iovp_size >> 10);	if (!ioc->name) {		ioc->name = kmalloc(24, GFP_KERNEL);		if (ioc->name)			sprintf((char *) ioc->name, "Unknown (%04x:%04x)",				ioc->func_id & 0xFFFF, (ioc->func_id >> 16) & 0xFFFF);		else			ioc->name = "Unknown";	}	ioc_iova_init(ioc);	ioc_resource_init(ioc);	ioc_sac_init(ioc);	printk(KERN_INFO PFX		"%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",		ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF,		hpa, ioc->iov_size >> 20, ioc->ibase);	return ioc;}/******************************************************************************   SBA initialization code (HW and SW)****   o identify SBA chip itself**   o FIXME: initialize DMA hints for reasonable defaults****************************************************************************/#ifdef CONFIG_PROC_FSstatic void *ioc_start(struct seq_file *s, loff_t *pos){	struct ioc *ioc;	loff_t n = *pos;	for (ioc = ioc_list; ioc; ioc = ioc->next)		if (!n--)			return ioc;	return NULL;}static void *ioc_next(struct seq_file *s, void *v, loff_t *pos){	struct ioc *ioc = v;	++*pos;	return ioc->next;}static voidioc_stop(struct seq_file *s, void *v){}static intioc_show(struct seq_file *s, void *v){	struct ioc *ioc = v;	unsigned long *res_ptr = (unsigned long *)ioc->res_map;	int i, used = 0;	seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n",		ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF));	seq_printf(s, "IOVA size       : %d MB\n", ioc->iov_size/(1024*1024));	seq_printf(s, "IOVA page size  : %ld kb\n", iovp_size/1024);	for (i = 0; i < (ioc->res_size / sizeof(unsigned long)); ++i, ++res_ptr)		used += hweight64(*res_ptr);	seq_printf(s, "PDIR size       : %d entries\n", ioc->res_size << 3);	seq_printf(s, "PDIR used       : %d entries\n", used);#ifdef PDIR_SEARCH_TIMING	{		unsigned long i = 0, avg = 0, min, max;		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;		seq_printf(s, "Bitmap search   : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",		           min, avg, max);	}#endif#ifndef ALLOW_IOV_BYPASS	 seq_printf(s, "IOVA bypass disabled\n");#endif	return 0;}static struct seq_operations ioc_seq_ops = {	.start = ioc_start,	.next  = ioc_next,	.stop  = ioc_stop,	.show  = ioc_show};static intioc_open(struct inode *inode, struct file *file){	return seq_open(file, &ioc_seq_ops);}static struct file_operations ioc_fops = {	.open    = ioc_open,	.read    = seq_read,	.llseek  = seq_lseek,	.release = seq_release};static void __initioc_proc_init(void){	struct proc_dir_entry *dir, *entry;	dir = proc_mkdir("bus/mckinley", 0);	if (!dir)		return;	entry = create_proc_entry(ioc_list->name, 0, dir);	if (entry)		entry->proc_fops = &ioc_fops;}#endifstatic voidsba_connect_bus(struct pci_bus *bus){	acpi_handle handle, parent;	acpi_status status;	struct ioc *ioc;	if (!PCI_CONTROLLER(bus))		panic(PFX "no sysdata on bus %d!\n", bus->number);	if (PCI_CONTROLLER(bus)->iommu)		return;	handle = PCI_CONTROLLER(bus)->acpi_handle;	if (!handle)		return;	/*	 * The IOC scope encloses PCI root bridges in the ACPI	 * namespace, so work our way out until we find an IOC we	 * claimed previously.	 */	do {		for (ioc = ioc_list; ioc; ioc = ioc->next)			if (ioc->handle == handle) {				PCI_CONTROLLER(bus)->iommu = ioc;				return;			}		status = acpi_get_parent(handle, &parent);		handle = parent;	} while (ACPI_SUCCESS(status));	printk(KERN_WARNING "No IOC for PCI Bus %04x:%02x in ACPI\n", PCI_SEGMENT(bus), bus->number);}extern acpi_status acpi_hp_csr_space (acpi_handle obj, u64 *csr_base, u64 *csr_length);static int __initacpi_sba_ioc_add(struct acpi_device *device){	struct ioc *ioc;	acpi_status status;	u64 hpa, length;	struct acpi_buffer buffer;	struct acpi_device_info *dev_info;	status = acpi_hp_csr_space(device->handle, &hpa, &length);	if (ACPI_FAILURE(status))		return 1;	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;	status = acpi_get_object_info(device->handle, &buffer);	if (ACPI_FAILURE(status))		return 1;	dev_info = buffer.pointer;	/*	 * For HWP0001, only SBA appears in ACPI namespace.  It encloses the PCI	 * root bridges, and its CSR space includes the IOC function.	 */	if (strncmp("HWP0001", dev_info->hardware_id.value, 7) == 0)		hpa += ZX1_IOC_OFFSET;	ACPI_MEM_FREE(dev_info);	ioc = ioc_init(hpa, device->handle);	if (!ioc)		return 1;	return 0;}static struct acpi_driver acpi_sba_ioc_driver = {	.name		= "IOC IOMMU Driver",	.ids		= "HWP0001,HWP0004",	.ops		= {		.add	= acpi_sba_ioc_add,	},};void __initsba_init(void){	acpi_bus_register_driver(&acpi_sba_ioc_driver);	if (!ioc_list)		return;#ifdef CONFIG_PCI	{		struct pci_bus *b = NULL;		pci_for_each_bus(b)			sba_connect_bus(b);	}#endif#ifdef CONFIG_PROC_FS	ioc_proc_init();#endif}static int __initnosbagart(char *str){	reserve_sba_gart = 0;	return 1;}intsba_dma_supported (struct pci_dev *dev, u64 mask){	/* make sure it's at least 32bit capable */	return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL);}__setup("nosbagart", nosbagart);static int __initsba_page_override(char *str){	unsigned long page_size;	page_size = memparse(str, &str);	switch (page_size) {		case 4096:		case 8192:		case 16384:		case 65536:			iovp_shift = ffs(page_size) - 1;			break;		default:			printk("%s: unknown/unsupported iommu page size %ld\n",			       __FUNCTION__, page_size);	}	return 1;}__setup("sbapagesize=",sba_page_override);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_supported);EXPORT_SYMBOL(sba_alloc_coherent);EXPORT_SYMBOL(sba_free_coherent);

⌨️ 快捷键说明

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