linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Richard Lee <superlibj8301@gmail.com>
To: linux-mm@kvack.org, linux@arm.linux.org.uk,
	linux-arm-kernel@lists.infradead.org, arnd@arndb.de,
	robherring2@gmail.com
Cc: lauraa@codeaurora.org, akpm@linux-foundation.org,
	d.hatayama@jp.fujitsu.com, zhangyanfei@cn.fujitsu.com,
	liwanp@linux.vnet.ibm.com, iamjoonsoo.kim@lge.com,
	hannes@cmpxchg.org, linux-kernel@vger.kernel.org,
	Richard Lee <superlibj8301@gmail.com>
Subject: [PATCHv2 1/2] mm/vmalloc: Add IO mapping space reused interface support.
Date: Wed, 14 May 2014 16:18:51 +0800	[thread overview]
Message-ID: <1400055532-13134-2-git-send-email-superlibj8301@gmail.com> (raw)
In-Reply-To: <1400055532-13134-1-git-send-email-superlibj8301@gmail.com>

For the IO mapping, the same physical address space maybe
mapped more than one time, for example, in some SoCs:
  - 0x20001000 ~ 0x20001400 --> 1KB for Dev1
  - 0x20001400 ~ 0x20001800 --> 1KB for Dev2
  and the page size is 4KB.

Then both Dev1 and Dev2 will do ioremap operations, and the IO
vmalloc area's virtual address will be aligned down to 4KB, and
the size will be aligned up to 4KB. That's to say, only one
4KB size's vmalloc area could contain Dev1 and Dev2 IO mapping area
at the same time.

For this case, we can ioremap only one time, and the later ioremap
operation will just return the exist vmalloc area.

Signed-off-by: Richard Lee <superlibj8301@gmail.com>
---
 include/linux/vmalloc.h |  5 +++
 mm/vmalloc.c            | 82 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+)

diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 4b8a891..a53b70f 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -1,6 +1,7 @@
 #ifndef _LINUX_VMALLOC_H
 #define _LINUX_VMALLOC_H
 
+#include <linux/atomic.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -34,6 +35,7 @@ struct vm_struct {
 	struct page		**pages;
 	unsigned int		nr_pages;
 	phys_addr_t		phys_addr;
+	atomic_t		used;
 	const void		*caller;
 };
 
@@ -100,6 +102,9 @@ static inline size_t get_vm_area_size(const struct vm_struct *area)
 	return area->size - PAGE_SIZE;
 }
 
+extern struct vm_struct *find_vm_area_paddr(phys_addr_t paddr, size_t size,
+				     unsigned long *offset,
+				     unsigned long flags);
 extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
 extern struct vm_struct *get_vm_area_caller(unsigned long size,
 					unsigned long flags, const void *caller);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index bf233b2..cf0093c 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1293,6 +1293,7 @@ static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
 	vm->addr = (void *)va->va_start;
 	vm->size = va->va_end - va->va_start;
 	vm->caller = caller;
+	atomic_set(&vm->used, 1);
 	va->vm = vm;
 	va->flags |= VM_VM_AREA;
 	spin_unlock(&vmap_area_lock);
@@ -1383,6 +1384,84 @@ struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
 				  NUMA_NO_NODE, GFP_KERNEL, caller);
 }
 
+static int vm_area_used_inc(struct vm_struct *area)
+{
+	if (!(area->flags & VM_IOREMAP))
+		return -EINVAL;
+
+	atomic_add(1, &area->used);
+
+	return atomic_read(&va->vm->used);
+}
+
+static int vm_area_used_dec(const void *addr)
+{
+	struct vmap_area *va;
+
+	va = find_vmap_area((unsigned long)addr);
+	if (!va || !(va->flags & VM_VM_AREA))
+		return 0;
+
+	if (!(va->vm->flags & VM_IOREMAP))
+		return 0;
+
+	atomic_sub(1, &va->vm->used);
+
+	return atomic_read(&va->vm->used);
+}
+
+/**
+ *	find_vm_area_paddr  -  find a continuous kernel virtual area using the
+ *			physical addreess.
+ *	@paddr:		base physical address
+ *	@size:		size of the physical area range
+ *	@offset:	the start offset of the vm area
+ *	@flags:		%VM_IOREMAP for I/O mappings
+ *
+ *	Search for the kernel VM area, whoes physical address starting at
+ *	@paddr, and if the exsit VM area's size is large enough, then return
+ *	it with increasing the 'used' counter, or return NULL.
+ */
+struct vm_struct *find_vm_area_paddr(phys_addr_t paddr, size_t size,
+				     unsigned long *offset,
+				     unsigned long flags)
+{
+	struct vmap_area *va;
+	int off;
+
+	if (!(flags & VM_IOREMAP))
+		return NULL;
+
+	size = PAGE_ALIGN((paddr & ~PAGE_MASK) + size);
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(va, &vmap_area_list, list) {
+		phys_addr_t phys_addr;
+
+		if (!va || !(va->flags & VM_VM_AREA) || !va->vm)
+			continue;
+
+		if (!(va->vm->flags & VM_IOREMAP))
+			continue;
+
+		phys_addr = va->vm->phys_addr;
+
+		off = (paddr & PAGE_MASK) - (phys_addr & PAGE_MASK);
+		if (off < 0)
+			continue;
+
+		if (off + size <= va->vm->size - PAGE_SIZE) {
+			*offset = off + (paddr & ~PAGE_MASK);
+			vm_area_used_inc(va->vm);
+			rcu_read_unlock();
+			return va->vm;
+		}
+	}
+	rcu_read_unlock();
+
+	return NULL;
+}
+
 /**
  *	find_vm_area  -  find a continuous kernel virtual area
  *	@addr:		base address
@@ -1443,6 +1522,9 @@ static void __vunmap(const void *addr, int deallocate_pages)
 			addr))
 		return;
 
+	if (vm_area_used_dec(addr))
+		return;
+
 	area = remove_vm_area(addr);
 	if (unlikely(!area)) {
 		WARN(1, KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n",
-- 
1.8.4

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

  reply	other threads:[~2014-05-14  9:07 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-05-14  8:18 [PATCHv2 0/2] Add IO mapping space reused support Richard Lee
2014-05-14  8:18 ` Richard Lee [this message]
2014-05-14 16:06   ` [PATCHv2 1/2] mm/vmalloc: Add IO mapping space reused interface support Rob Herring
2014-05-15  3:46     ` Richard Lee
2014-05-14 22:56   ` Andrew Morton
2014-05-15  7:55     ` Richard Lee
2014-05-14  8:18 ` [PATCHv2 2/2] ARM: ioremap: Add IO mapping space reused support Richard Lee

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1400055532-13134-2-git-send-email-superlibj8301@gmail.com \
    --to=superlibj8301@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=arnd@arndb.de \
    --cc=d.hatayama@jp.fujitsu.com \
    --cc=hannes@cmpxchg.org \
    --cc=iamjoonsoo.kim@lge.com \
    --cc=lauraa@codeaurora.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux@arm.linux.org.uk \
    --cc=liwanp@linux.vnet.ibm.com \
    --cc=robherring2@gmail.com \
    --cc=zhangyanfei@cn.fujitsu.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).