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

📄 ioport.c

📁 linux-2.6.15.6
💻 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/dma.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 __iomem *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz);static void __iomem *_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 = {	.name = "sparc_dvma", .start = DVMA_VADDR, .end = DVMA_END - 1};/* This points to the start of I/O mappings, cluable from outside. *//*ext*/ struct resource sparc_iomap = {	.name = "sparc_iomap", .start = IOBASE_VADDR, .end = IOBASE_END - 1};/* * 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 __iomem *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(volatile void __iomem *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);	}}/* */void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset,    unsigned long size, char *name){	return _sparc_alloc_io(phyres->flags & 0xF,	    phyres->start + offset, size, name);}/* */void sbus_iounmap(volatile void __iomem *addr, unsigned long size){	iounmap(addr);}/* * Meat of mapping */static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,    unsigned long size, char *name){	static int printed_full;	struct xresource *xres;	struct resource *res;	char *tack;	int tlen;	void __iomem *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);	}	strlcpy(tack, name, XNMLN+1);	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 __iomem *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz){	unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);	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();	}	pa &= PAGE_MASK;	sparc_mapiorange(bus, pa, res->start, res->end - res->start + 1);	return (void __iomem *) (res->start + offset);}/* * Comlimentary to _sparc_ioremap(). */static void _sparc_free_io(struct resource *res){	unsigned long plen;	plen = res->end - res->start + 1;	if ((plen & (PAGE_SIZE-1)) != 0) BUG();	sparc_unmapiorange(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);	if ((va = __get_free_pages(GFP_KERNEL|__GFP_COMP, order)) == 0)		goto err_nopages;	if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL)		goto err_nomem;	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);		goto err_nova;	}	mmu_inval_dma_area(va, len_total);	// XXX The mmu_map_dma_area does this for us below, see comments.	// sparc_mapiorange(0, virt_to_phys(va), res->start, len_total);	/*	 * XXX That's where sdev would be used. Currently we load	 * all iommu tables with the same translations.	 */	if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0)		goto err_noiommu;	return (void *)res->start;err_noiommu:	release_resource(res);err_nova:	free_pages(va, order);err_nomem:	kfree(res);err_nopages:	return NULL;}void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba){	struct resource *res;	struct page *pgv;	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 */	pgv = mmu_translate_dvma(ba);	mmu_unmap_dma_area(ba, n);	__free_pages(pgv, 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. */dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction){	/* 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;	}	return mmu_get_scsi_one(va, len, sdev->bus);}void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction){	mmu_release_scsi_one(ba, n, sdev->bus);}int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction){	mmu_get_scsi_sgl(sg, n, sdev->bus);	/*	 * XXX sparc64 can return a partial length here. sun4c should do this	 * but it currently panics if it can't fulfill the request - Anton	 */	return n;}void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction){	mmu_release_scsi_sgl(sg, n, sdev->bus);}/* */void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction){#if 0	unsigned long va;

⌨️ 快捷键说明

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