ioport.c

来自「linux 内核源代码」· C语言 代码 · 共 875 行 · 第 1/2 页

C
875
字号
		panic("sbus_dma_sync_single: 0x%x\n", ba);	va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */	/*	 * XXX This bogosity will be fixed with the iommu rewrite coming soon	 * to a kernel near you. - Anton	 */	/* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */#endif}void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction){#if 0	unsigned long va;	struct resource *res;	/* We do not need the resource, just print a message if invalid. */	res = _sparc_find_resource(&_sparc_dvma, ba);	if (res == NULL)		panic("sbus_dma_sync_single: 0x%x\n", ba);	va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */	/*	 * XXX This bogosity will be fixed with the iommu rewrite coming soon	 * to a kernel near you. - Anton	 */	/* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */#endif}void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction){	printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n");}void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction){	printk("sbus_dma_sync_sg_for_device: not implemented yet\n");}/* Support code for sbus_init().  *//* * XXX This functions appears to be a distorted version of * prom_sbus_ranges_init(), with all sun4d stuff cut away. * Ask DaveM what is going on here, how is sun4d supposed to work... XXX *//* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus){	int parent_node = pn->node;	if (sparc_cpu_model == sun4d) {		struct linux_prom_ranges iounit_ranges[PROMREG_MAX];		int num_iounit_ranges, len;		len = prom_getproperty(parent_node, "ranges",				       (char *) iounit_ranges,				       sizeof (iounit_ranges));		if (len != -1) {			num_iounit_ranges =				(len / sizeof(struct linux_prom_ranges));			prom_adjust_ranges(sbus->sbus_ranges,					   sbus->num_sbus_ranges,					   iounit_ranges, num_iounit_ranges);		}	}}void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp){#ifndef CONFIG_SUN4	struct device_node *parent = dp->parent;	if (sparc_cpu_model != sun4d &&	    parent != NULL &&	    !strcmp(parent->name, "iommu")) {		extern void iommu_init(int iommu_node, struct sbus_bus *sbus);		iommu_init(parent->node, sbus);	}	if (sparc_cpu_model == sun4d) {		extern void iounit_init(int sbi_node, int iounit_node,					struct sbus_bus *sbus);		iounit_init(dp->node, parent->node, sbus);	}#endif}void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp){	if (sparc_cpu_model == sun4d) {		struct device_node *parent = dp->parent;		sbus->devid = of_getintprop_default(parent, "device-id", 0);		sbus->board = of_getintprop_default(parent, "board#", 0);	}}int __init sbus_arch_preinit(void){	extern void register_proc_sparc_ioport(void);	register_proc_sparc_ioport();#ifdef CONFIG_SUN4	{		extern void sun4_dvma_init(void);		sun4_dvma_init();	}	return 1;#else	return 0;#endif}void __init sbus_arch_postinit(void){	if (sparc_cpu_model == sun4d) {		extern void sun4d_init_sbi_irq(void);		sun4d_init_sbi_irq();	}}#endif /* CONFIG_SBUS */#ifdef CONFIG_PCI/* Allocate and map kernel buffer using consistent mode DMA for a device. * hwdev should be valid struct pci_dev pointer for PCI devices. */void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba){	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;	unsigned long va;	struct resource *res;	int order;	if (len == 0) {		return NULL;	}	if (len > 256*1024) {			/* __get_free_pages() limit */		return NULL;	}	order = get_order(len_total);	va = __get_free_pages(GFP_KERNEL, order);	if (va == 0) {		printk("pci_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT);		return NULL;	}	if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {		free_pages(va, order);		printk("pci_alloc_consistent: no core\n");		return NULL;	}	if (allocate_resource(&_sparc_dvma, res, len_total,	    _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) {		printk("pci_alloc_consistent: cannot occupy 0x%lx", len_total);		free_pages(va, order);		kfree(res);		return NULL;	}	mmu_inval_dma_area(va, len_total);#if 0/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %lx\n",  (long)va, (long)res->start, (long)virt_to_phys(va), len_total);#endif	sparc_mapiorange(0, virt_to_phys(va), res->start, len_total);	*pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */	return (void *) res->start;}/* Free and unmap a consistent DMA buffer. * cpu_addr is what was returned from pci_alloc_consistent, * size must be the same as what as passed into pci_alloc_consistent, * and likewise dma_addr must be the same as what *dma_addrp was set to. * * References to the memory and mappings associated with cpu_addr/dma_addr * past this call are illegal. */void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba){	struct resource *res;	unsigned long pgp;	if ((res = _sparc_find_resource(&_sparc_dvma,	    (unsigned long)p)) == NULL) {		printk("pci_free_consistent: cannot free %p\n", p);		return;	}	if (((unsigned long)p & (PAGE_SIZE-1)) != 0) {		printk("pci_free_consistent: unaligned va %p\n", p);		return;	}	n = (n + PAGE_SIZE-1) & PAGE_MASK;	if ((res->end-res->start)+1 != n) {		printk("pci_free_consistent: region 0x%lx asked 0x%lx\n",		    (long)((res->end-res->start)+1), (long)n);		return;	}	pgp = (unsigned long) phys_to_virt(ba);	/* bus_to_virt actually */	mmu_inval_dma_area(pgp, n);	sparc_unmapiorange((unsigned long)p, n);	release_resource(res);	kfree(res);	free_pages(pgp, get_order(n));}/* Map a single buffer of the indicated size for DMA in streaming mode. * The 32-bit bus address to use is returned. * * Once the device is given the dma address, the device owns this memory * until either pci_unmap_single or pci_dma_sync_single_* is performed. */dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,    int direction){	BUG_ON(direction == PCI_DMA_NONE);	/* IIep is write-through, not flushing. */	return virt_to_phys(ptr);}/* Unmap a single streaming mode DMA translation.  The dma_addr and size * must match what was provided for in a previous pci_map_single call.  All * other usages are undefined. * * After this call, reads by the cpu to the buffer are guaranteed to see * whatever the device wrote there. */void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size,    int direction){	BUG_ON(direction == PCI_DMA_NONE);	if (direction != PCI_DMA_TODEVICE) {		mmu_inval_dma_area((unsigned long)phys_to_virt(ba),		    (size + PAGE_SIZE-1) & PAGE_MASK);	}}/* * Same as pci_map_single, but with pages. */dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,			unsigned long offset, size_t size, int direction){	BUG_ON(direction == PCI_DMA_NONE);	/* IIep is write-through, not flushing. */	return page_to_phys(page) + offset;}void pci_unmap_page(struct pci_dev *hwdev,			dma_addr_t dma_address, size_t size, int direction){	BUG_ON(direction == PCI_DMA_NONE);	/* mmu_inval_dma_area XXX */}/* Map a set of buffers described by scatterlist in streaming * mode for DMA.  This is the scather-gather version of the * above pci_map_single interface.  Here the scatter gather list * elements are each tagged with the appropriate dma address * and length.  They are obtained via sg_dma_{address,length}(SG). * * NOTE: An implementation may be able to use a smaller number of *       DMA address/length pairs than there are SG table elements. *       (for example via virtual mapping capabilities) *       The routine returns the number of addr/length pairs actually *       used, at most nents. * * Device ownership issues as mentioned above for pci_map_single are * the same here. */int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,    int direction){	struct scatterlist *sg;	int n;	BUG_ON(direction == PCI_DMA_NONE);	/* IIep is write-through, not flushing. */	for_each_sg(sgl, sg, nents, n) {		BUG_ON(page_address(sg_page(sg)) == NULL);		sg->dvma_address = virt_to_phys(sg_virt(sg));		sg->dvma_length = sg->length;	}	return nents;}/* Unmap a set of streaming mode DMA translations. * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,    int direction){	struct scatterlist *sg;	int n;	BUG_ON(direction == PCI_DMA_NONE);	if (direction != PCI_DMA_TODEVICE) {		for_each_sg(sgl, sg, nents, n) {			BUG_ON(page_address(sg_page(sg)) == NULL);			mmu_inval_dma_area(			    (unsigned long) page_address(sg_page(sg)),			    (sg->length + PAGE_SIZE-1) & PAGE_MASK);		}	}}/* Make physical memory consistent for a single * streaming mode DMA translation before or after a transfer. * * If you perform a pci_map_single() but wish to interrogate the * buffer using the cpu, yet do not wish to teardown the PCI dma * mapping, you must call this function before doing so.  At the * next point you give the PCI dma address back to the card, you * must first perform a pci_dma_sync_for_device, and then the * device again owns the buffer. */void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction){	BUG_ON(direction == PCI_DMA_NONE);	if (direction != PCI_DMA_TODEVICE) {		mmu_inval_dma_area((unsigned long)phys_to_virt(ba),		    (size + PAGE_SIZE-1) & PAGE_MASK);	}}void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction){	BUG_ON(direction == PCI_DMA_NONE);	if (direction != PCI_DMA_TODEVICE) {		mmu_inval_dma_area((unsigned long)phys_to_virt(ba),		    (size + PAGE_SIZE-1) & PAGE_MASK);	}}/* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. * * The same as pci_dma_sync_single_* but for a scatter-gather list, * same rules and usage. */void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, int direction){	struct scatterlist *sg;	int n;	BUG_ON(direction == PCI_DMA_NONE);	if (direction != PCI_DMA_TODEVICE) {		for_each_sg(sgl, sg, nents, n) {			BUG_ON(page_address(sg_page(sg)) == NULL);			mmu_inval_dma_area(			    (unsigned long) page_address(sg_page(sg)),			    (sg->length + PAGE_SIZE-1) & PAGE_MASK);		}	}}void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, int direction){	struct scatterlist *sg;	int n;	BUG_ON(direction == PCI_DMA_NONE);	if (direction != PCI_DMA_TODEVICE) {		for_each_sg(sgl, sg, nents, n) {			BUG_ON(page_address(sg_page(sg)) == NULL);			mmu_inval_dma_area(			    (unsigned long) page_address(sg_page(sg)),			    (sg->length + PAGE_SIZE-1) & PAGE_MASK);		}	}}#endif /* CONFIG_PCI */#ifdef CONFIG_PROC_FSstatic int_sparc_io_get_info(char *buf, char **start, off_t fpos, int length, int *eof,    void *data){	char *p = buf, *e = buf + length;	struct resource *r;	const char *nm;	for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) {		if (p + 32 >= e)	/* Better than nothing */			break;		if ((nm = r->name) == 0) nm = "???";		p += sprintf(p, "%016llx-%016llx: %s\n",				(unsigned long long)r->start,				(unsigned long long)r->end, nm);	}	return p-buf;}#endif /* CONFIG_PROC_FS *//* * This is a version of find_resource and it belongs to kernel/resource.c. * Until we have agreement with Linus and Martin, it lingers here. * * XXX Too slow. Can have 8192 DVMA pages on sun4m in the worst case. * This probably warrants some sort of hashing. */struct resource *_sparc_find_resource(struct resource *root, unsigned long hit){        struct resource *tmp;	for (tmp = root->child; tmp != 0; tmp = tmp->sibling) {		if (tmp->start <= hit && tmp->end >= hit)			return tmp;	}	return NULL;}void register_proc_sparc_ioport(void){#ifdef CONFIG_PROC_FS	create_proc_read_entry("io_map",0,NULL,_sparc_io_get_info,&sparc_iomap);	create_proc_read_entry("dvma_map",0,NULL,_sparc_io_get_info,&_sparc_dvma);#endif}

⌨️ 快捷键说明

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