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

📄 ioport.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: ioport.c,v 1.45 2001/10/30 04:54:21 davem Exp $ * ioport.c:  Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * * 1996: sparc_free_io, 1999: ioremap()/iounmap() by Pete Zaitcev. * * 2000/01/29 * <rth> zait: as long as pci_alloc_consistent produces something addressable,  *	things are ok. * <zaitcev> rth: no, it is relevant, because get_free_pages returns you a *	pointer into the big page mapping * <rth> zait: so what? * <rth> zait: remap_it_my_way(virt_to_phys(get_free_page())) * <zaitcev> Hmm * <zaitcev> Suppose I did this remap_it_my_way(virt_to_phys(get_free_page())). *	So far so good. * <zaitcev> Now, driver calls pci_free_consistent(with result of *	remap_it_my_way()). * <zaitcev> How do you find the address to pass to free_pages()? * <rth> zait: walk the page tables?  It's only two or three level after all. * <rth> zait: you have to walk them anyway to remove the mapping. * <zaitcev> Hmm * <zaitcev> Sounds reasonable */#include <linux/config.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/pci.h>		/* struct pci_dev */#include <linux/proc_fs.h>#include <asm/io.h>#include <asm/vaddrs.h>#include <asm/oplib.h>#include <asm/page.h>#include <asm/pgalloc.h>#include <asm/pgtable.h>#define mmu_inval_dma_area(p, l)	/* Anton pulled it out for 2.4.0-xx */struct resource *_sparc_find_resource(struct resource *r, unsigned long);static void *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz);static void *_sparc_alloc_io(unsigned int busno, unsigned long phys,    unsigned long size, char *name);static void _sparc_free_io(struct resource *res);/* This points to the next to use virtual memory for DVMA mappings */static struct resource _sparc_dvma = {	"sparc_dvma", DVMA_VADDR, DVMA_END - 1};/* This points to the start of I/O mappings, cluable from outside. *//*ext*/ struct resource sparc_iomap = {	"sparc_iomap", IOBASE_VADDR, IOBASE_END - 1};/* * BTFIXUP would do as well but it seems overkill for the case. */static void (*_sparc_mapioaddr)(unsigned long pa, unsigned long va,    int bus, int ro);static void (*_sparc_unmapioaddr)(unsigned long va);/* * Our mini-allocator... * Boy this is gross! We need it because we must map I/O for * timers and interrupt controller before the kmalloc is available. */#define XNMLN  15#define XNRES  10	/* SS-10 uses 8 */struct xresource {	struct resource xres;	/* Must be first */	int xflag;		/* 1 == used */	char xname[XNMLN+1];};static struct xresource xresv[XNRES];static struct xresource *xres_alloc(void) {	struct xresource *xrp;	int n;	xrp = xresv;	for (n = 0; n < XNRES; n++) {		if (xrp->xflag == 0) {			xrp->xflag = 1;			return xrp;		}		xrp++;	}	return NULL;}static void xres_free(struct xresource *xrp) {	xrp->xflag = 0;}/* * These are typically used in PCI drivers * which are trying to be cross-platform. * * Bus type is always zero on IIep. */void *ioremap(unsigned long offset, unsigned long size){	char name[14];	sprintf(name, "phys_%08x", (u32)offset);	return _sparc_alloc_io(0, offset, size, name);}/* * Comlimentary to ioremap(). */void iounmap(void *virtual){	unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;	struct resource *res;	if ((res = _sparc_find_resource(&sparc_iomap, vaddr)) == NULL) {		printk("free_io/iounmap: cannot free %lx\n", vaddr);		return;	}	_sparc_free_io(res);	if ((char *)res >= (char*)xresv && (char *)res < (char *)&xresv[XNRES]) {		xres_free((struct xresource *)res);	} else {		kfree(res);	}}/* */unsigned long sbus_ioremap(struct resource *phyres, unsigned long offset,    unsigned long size, char *name){	return (unsigned long) _sparc_alloc_io(phyres->flags & 0xF,	    phyres->start + offset, size, name);}/* */void sbus_iounmap(unsigned long addr, unsigned long size){	iounmap((void *)addr);}/* * Meat of mapping */static void *_sparc_alloc_io(unsigned int busno, unsigned long phys,    unsigned long size, char *name){	static int printed_full = 0;	struct xresource *xres;	struct resource *res;	char *tack;	int tlen;	void *va;	/* P3 diag */	if (name == NULL) name = "???";	if ((xres = xres_alloc()) != 0) {		tack = xres->xname;		res = &xres->xres;	} else {		if (!printed_full) {			printk("ioremap: done with statics, switching to malloc\n");			printed_full = 1;		}		tlen = strlen(name);		tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL);		if (tack == NULL) return NULL;		memset(tack, 0, sizeof(struct resource));		res = (struct resource *) tack;		tack += sizeof (struct resource);	}	strncpy(tack, name, XNMLN);	tack[XNMLN] = 0;	res->name = tack;	va = _sparc_ioremap(res, busno, phys, size);	/* printk("ioremap(0x%x:%08lx[0x%lx])=%p\n", busno, phys, size, va); */ /* P3 diag */	return va;}/* */static void *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz){	unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);	unsigned long va;	unsigned int psz;	if (allocate_resource(&sparc_iomap, res,	    (offset + sz + PAGE_SIZE-1) & PAGE_MASK,	    sparc_iomap.start, sparc_iomap.end, PAGE_SIZE, NULL, NULL) != 0) {		/* Usually we cannot see printks in this case. */		prom_printf("alloc_io_res(%s): cannot occupy\n",		    (res->name != NULL)? res->name: "???");		prom_halt();	}	va = res->start;	pa &= PAGE_MASK;	for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {		(*_sparc_mapioaddr)(pa, va, bus, 0);		va += PAGE_SIZE;		pa += PAGE_SIZE;	}	/*	 * XXX Playing with implementation details here.	 * On sparc64 Ebus has resources with precise boundaries.	 * We share drivers with sparc64. Too clever drivers use	 * start of a resource instead of a base address.	 *	 * XXX-2 This may be not valid anymore, clean when	 * interface to sbus_ioremap() is resolved.	 */	res->start += offset;	res->end = res->start + sz - 1;		/* not strictly necessary.. */	return (void *) res->start;}/* * Comlimentary to _sparc_ioremap(). */static void _sparc_free_io(struct resource *res){	unsigned long plen;	plen = res->end - res->start + 1;	plen = (plen + PAGE_SIZE-1) & PAGE_MASK;	while (plen != 0) {		plen -= PAGE_SIZE;		(*_sparc_unmapioaddr)(res->start + plen);	}	release_resource(res);}#ifdef CONFIG_SBUSvoid sbus_set_sbus64(struct sbus_dev *sdev, int x) {	printk("sbus_set_sbus64: unsupported\n");}/* * Allocate a chunk of memory suitable for DMA. * Typically devices use them for control blocks. * CPU may access them without any explicit flushing. * * XXX Some clever people know that sdev is not used and supply NULL. Watch. */void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp){	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;	unsigned long va;	struct resource *res;	int order;	/* XXX why are some lenghts signed, others unsigned? */	if (len <= 0) {		return NULL;	}	/* XXX So what is maxphys for us and how do drivers know it? */	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 here may be flooding... Consider removal XXX.		 */		printk("sbus_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT);		return NULL;	}	if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {		free_pages(va, order);		printk("sbus_alloc_consistent: no core\n");		return NULL;	}	memset((char*)res, 0, sizeof(struct resource));	if (allocate_resource(&_sparc_dvma, res, len_total,	    _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) {		printk("sbus_alloc_consistent: cannot occupy 0x%lx", len_total);		free_pages(va, order);		kfree(res);		return NULL;	}	mmu_map_dma_area(va, res->start, len_total);	*dma_addrp = res->start;	return (void *)res->start;}void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba){	struct resource *res;	unsigned long pgp;	if ((res = _sparc_find_resource(&_sparc_dvma,	    (unsigned long)p)) == NULL) {		printk("sbus_free_consistent: cannot free %p\n", p);		return;	}	if (((unsigned long)p & (PAGE_SIZE-1)) != 0) {		printk("sbus_free_consistent: unaligned va %p\n", p);		return;	}	n = (n + PAGE_SIZE-1) & PAGE_MASK;	if ((res->end-res->start)+1 != n) {		printk("sbus_free_consistent: region 0x%lx asked 0x%lx\n",		    (long)((res->end-res->start)+1), n);		return;	}	release_resource(res);	kfree(res);	/* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */	pgp = (unsigned long) phys_to_virt(mmu_translate_dvma(ba));	mmu_unmap_dma_area(ba, n);	free_pages(pgp, get_order(n));}/* * Map a chunk of memory so that devices can see it. * CPU view of this memory may be inconsistent with * a device view and explicit flushing is necessary. */u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len, int direction){#if 0 /* This is the version that abuses consistent space */	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;	struct resource *res;	/* XXX why are some lenghts signed, others unsigned? */	if (len <= 0) {		return 0;	}	/* XXX So what is maxphys for us and how do drivers know it? */	if (len > 256*1024) {			/* __get_free_pages() limit */		return 0;	}	if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {		printk("sbus_map_single: no core\n");		return 0;	}	memset((char*)res, 0, sizeof(struct resource));	res->name = va; /* XXX */	if (allocate_resource(&_sparc_dvma, res, len_total,	    _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE) != 0) {		printk("sbus_map_single: cannot occupy 0x%lx", len);		kfree(res);		return 0;	}	mmu_map_dma_area(va, res->start, len_total);	mmu_flush_dma_area((unsigned long)va, len_total); /* in all contexts? */	return res->start;#endif#if 1 /* "trampoline" version */	/* XXX why are some lenghts signed, others unsigned? */	if (len <= 0) {		return 0;	}	/* XXX So what is maxphys for us and how do drivers know it? */	if (len > 256*1024) {			/* __get_free_pages() limit */

⌨️ 快捷键说明

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