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

📄 sba_iommu.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
	/*  	** 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);#if DELAYED_RESOURCE_CNT > 0	spin_lock_init(&ioc->saved_lock);#endif	/* 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;#ifdef CONFIG_PCI	sac->dev.bus = &pci_bus_type;#endif	ioc->sac_only_dev = sac;}static void __initioc_zx1_init(struct ioc *ioc){	unsigned long rope_config;	unsigned int i;	if (ioc->rev < 0x20)		panic(PFX "IOC 2.0 or later required for IOMMU support\n");	/* 38 bit memory controller + extra bit for range displaced by MMIO */	ioc->dma_mask = (0x1UL << 39) - 1;	/*	** 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 tg3 on bcm5701.	*/	for (i=0; i<(8*8); i+=8) {		rope_config = READ_REG(ioc->ioc_hpa + IOC_ROPE0_CFG + i);		rope_config &= ~IOC_ROPE_AO;		WRITE_REG(rope_config, ioc->ioc_hpa + IOC_ROPE0_CFG + i);	}}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 },	{ SX1000_IOC_ID, "sx1000", NULL },};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 */	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);		}	}	iovp_size = (1 << iovp_shift);	iovp_mask = ~(iovp_size - 1);	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);	if ((long) ~iovp_mask > (long) ia64_max_iommu_merge_mask)		ia64_max_iommu_merge_mask = ~iovp_mask;	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));#ifdef CONFIG_NUMA	if (ioc->node != MAX_NUMNODES)		seq_printf(s, "NUMA node       : %d\n", ioc->node);#endif	seq_printf(s, "IOVA size       : %ld MB\n", ((ioc->pdir_size >> 3) * iovp_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->pdir_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/IOVA page)\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", NULL);	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_domain_nr(bus), bus->number);}#ifdef CONFIG_NUMAstatic void __initsba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle){	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};	union acpi_object *obj;	acpi_handle phandle;	unsigned int node;	ioc->node = MAX_NUMNODES;	/*	 * Check for a _PXM on this node first.  We don't typically see	 * one here, so we'll end up getting it from the parent.	 */	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PXM", NULL, &buffer))) {		if (ACPI_FAILURE(acpi_get_parent(handle, &phandle)))			return;		/* Reset the acpi buffer */		buffer.length = ACPI_ALLOCATE_BUFFER;		buffer.pointer = NULL;		if (ACPI_FAILURE(acpi_evaluate_object(phandle, "_PXM", NULL,		                                      &buffer)))			return;	}	if (!buffer.length || !buffer.pointer)		return;	obj = buffer.pointer;	if (obj->type != ACPI_TYPE_INTEGER ||	    obj->integer.value >= MAX_PXM_DOMAINS) {		acpi_os_free(buffer.pointer);		return;	}	node = pxm_to_nid_map[obj->integer.value];	acpi_os_free(buffer.pointer);	if (node >= MAX_NUMNODES || !node_online(node))		return;	ioc->node = node;	return;}#else#define sba_map_ioc_to_node(ioc, handle)#endifstatic 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 = hp_acpi_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;		/* zx1 based systems default to kernel page size iommu pages */		if (!iovp_shift)			iovp_shift = min(PAGE_SHIFT, 16);	}	ACPI_MEM_FREE(dev_info);	/*	 * default anything not caught above or specified on cmdline to 4k	 * iommu page size	 */	if (!iovp_shift)		iovp_shift = 12;	ioc = ioc_init(hpa, device->handle);	if (!ioc)		return 1;	/* setup NUMA node association */	sba_map_ioc_to_node(ioc, device->handle);	return 0;}static struct acpi_driver acpi_sba_ioc_driver = {	.name		= "IOC IOMMU Driver",	.ids		= "HWP0001,HWP0004",	.ops		= {		.add	= acpi_sba_ioc_add,	},};static int __initsba_init(void){	acpi_bus_register_driver(&acpi_sba_ioc_driver);	if (!ioc_list)		return 0;#ifdef CONFIG_PCI	{		struct pci_bus *b = NULL;		while ((b = pci_find_next_bus(b)) != NULL)			sba_connect_bus(b);	}#endif#ifdef CONFIG_PROC_FS	ioc_proc_init();#endif	return 0;}subsys_initcall(sba_init); /* must be initialized after ACPI etc., but before any drivers... */extern void dig_setup(char**);/* * MAX_DMA_ADDRESS needs to be setup prior to paging_init to do any good, * so we use the platform_setup hook to fix it up. */void __initsba_setup(char **cmdline_p){	MAX_DMA_ADDRESS = ~0UL;	dig_setup(cmdline_p);}static int __initnosbagart(char *str){	reserve_sba_gart = 0;	return 1;}intsba_dma_supported (struct device *dev, u64 mask){	/* make sure it's at least 32bit capable */	return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL);}intsba_dma_mapping_error (dma_addr_t dma_addr){	return 0;}__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_dma_mapping_error);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 + -