Re: [PATCH v1 13/19] zsmalloc: factor page chain functionality out
On 2016/3/11 15:30, Minchan Kim wrote: For migration, we need to create sub-page chain of zspage dynamically so this patch factors it out from alloc_zspage. As a minor refactoring, it makes OBJ_ALLOCATED_TAG assign more clear in obj_malloc(it could be another patch but it's trivial so I want to put together in this patch). Signed-off-by: Minchan Kim--- mm/zsmalloc.c | 78 ++- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index bfc6a048afac..f86f8aaeb902 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -977,7 +977,9 @@ static void init_zspage(struct size_class *class, struct page *first_page) unsigned long off = 0; struct page *page = first_page; - VM_BUG_ON_PAGE(!is_first_page(first_page), first_page); + first_page->freelist = NULL; + INIT_LIST_HEAD(_page->lru); + set_zspage_inuse(first_page, 0); while (page) { struct page *next_page; @@ -1022,13 +1024,44 @@ static void init_zspage(struct size_class *class, struct page *first_page) set_freeobj(first_page, 0); } +static void create_page_chain(struct page *pages[], int nr_pages) +{ + int i; + struct page *page; + struct page *prev_page = NULL; + struct page *first_page = NULL; + + for (i = 0; i < nr_pages; i++) { + page = pages[i]; + + INIT_LIST_HEAD(>lru); + if (i == 0) { + SetPagePrivate(page); + set_page_private(page, 0); + first_page = page; + } + + if (i == 1) + set_page_private(first_page, (unsigned long)page); + if (i >= 1) + set_page_private(page, (unsigned long)first_page); + if (i >= 2) + list_add(>lru, _page->lru); + if (i == nr_pages - 1) + SetPagePrivate2(page); + + prev_page = page; + } +} + /* * Allocate a zspage for the given size class */ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) { - int i, error; + int i; struct page *first_page = NULL, *uninitialized_var(prev_page); + struct page *pages[ZS_MAX_PAGES_PER_ZSPAGE]; /* * Allocate individual pages and link them together as: @@ -1041,43 +1074,23 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) *uninitialized_var(prev_page) in alloc_zspage is not in use more. * (i.e. no other sub-page has this flag set) and PG_private_2 to * identify the last page. */ - error = -ENOMEM; for (i = 0; i < class->pages_per_zspage; i++) { struct page *page; page = alloc_page(flags); - if (!page) - goto cleanup; - - INIT_LIST_HEAD(>lru); - if (i == 0) { /* first page */ - page->freelist = NULL; - SetPagePrivate(page); - set_page_private(page, 0); - first_page = page; - set_zspage_inuse(page, 0); + if (!page) { + while (--i >= 0) + __free_page(pages[i]); + return NULL; } - if (i == 1) - set_page_private(first_page, (unsigned long)page); - if (i >= 1) - set_page_private(page, (unsigned long)first_page); - if (i >= 2) - list_add(>lru, _page->lru); - if (i == class->pages_per_zspage - 1)/* last page */ - SetPagePrivate2(page); - prev_page = page; + + pages[i] = page; } + create_page_chain(pages, class->pages_per_zspage); + first_page = pages[0]; init_zspage(class, first_page); - error = 0; /* Success */ - -cleanup: - if (unlikely(error) && first_page) { - free_zspage(first_page); - first_page = NULL; - } - return first_page; } @@ -1419,7 +1432,6 @@ static unsigned long obj_malloc(struct size_class *class, unsigned long m_offset; void *vaddr; - handle |= OBJ_ALLOCATED_TAG; obj = get_freeobj(first_page); objidx_to_page_and_ofs(class, first_page, obj, _page, _offset); @@ -1429,10 +1441,10 @@ static unsigned long obj_malloc(struct size_class *class, set_freeobj(first_page, link->next >> OBJ_ALLOCATED_TAG); if (!class->huge) /* record handle in the header of allocated chunk */ - link->handle = handle; + link->handle = handle | OBJ_ALLOCATED_TAG;
Re: [PATCH v1 13/19] zsmalloc: factor page chain functionality out
On 2016/3/11 15:30, Minchan Kim wrote: For migration, we need to create sub-page chain of zspage dynamically so this patch factors it out from alloc_zspage. As a minor refactoring, it makes OBJ_ALLOCATED_TAG assign more clear in obj_malloc(it could be another patch but it's trivial so I want to put together in this patch). Signed-off-by: Minchan Kim --- mm/zsmalloc.c | 78 ++- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index bfc6a048afac..f86f8aaeb902 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -977,7 +977,9 @@ static void init_zspage(struct size_class *class, struct page *first_page) unsigned long off = 0; struct page *page = first_page; - VM_BUG_ON_PAGE(!is_first_page(first_page), first_page); + first_page->freelist = NULL; + INIT_LIST_HEAD(_page->lru); + set_zspage_inuse(first_page, 0); while (page) { struct page *next_page; @@ -1022,13 +1024,44 @@ static void init_zspage(struct size_class *class, struct page *first_page) set_freeobj(first_page, 0); } +static void create_page_chain(struct page *pages[], int nr_pages) +{ + int i; + struct page *page; + struct page *prev_page = NULL; + struct page *first_page = NULL; + + for (i = 0; i < nr_pages; i++) { + page = pages[i]; + + INIT_LIST_HEAD(>lru); + if (i == 0) { + SetPagePrivate(page); + set_page_private(page, 0); + first_page = page; + } + + if (i == 1) + set_page_private(first_page, (unsigned long)page); + if (i >= 1) + set_page_private(page, (unsigned long)first_page); + if (i >= 2) + list_add(>lru, _page->lru); + if (i == nr_pages - 1) + SetPagePrivate2(page); + + prev_page = page; + } +} + /* * Allocate a zspage for the given size class */ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) { - int i, error; + int i; struct page *first_page = NULL, *uninitialized_var(prev_page); + struct page *pages[ZS_MAX_PAGES_PER_ZSPAGE]; /* * Allocate individual pages and link them together as: @@ -1041,43 +1074,23 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) *uninitialized_var(prev_page) in alloc_zspage is not in use more. * (i.e. no other sub-page has this flag set) and PG_private_2 to * identify the last page. */ - error = -ENOMEM; for (i = 0; i < class->pages_per_zspage; i++) { struct page *page; page = alloc_page(flags); - if (!page) - goto cleanup; - - INIT_LIST_HEAD(>lru); - if (i == 0) { /* first page */ - page->freelist = NULL; - SetPagePrivate(page); - set_page_private(page, 0); - first_page = page; - set_zspage_inuse(page, 0); + if (!page) { + while (--i >= 0) + __free_page(pages[i]); + return NULL; } - if (i == 1) - set_page_private(first_page, (unsigned long)page); - if (i >= 1) - set_page_private(page, (unsigned long)first_page); - if (i >= 2) - list_add(>lru, _page->lru); - if (i == class->pages_per_zspage - 1)/* last page */ - SetPagePrivate2(page); - prev_page = page; + + pages[i] = page; } + create_page_chain(pages, class->pages_per_zspage); + first_page = pages[0]; init_zspage(class, first_page); - error = 0; /* Success */ - -cleanup: - if (unlikely(error) && first_page) { - free_zspage(first_page); - first_page = NULL; - } - return first_page; } @@ -1419,7 +1432,6 @@ static unsigned long obj_malloc(struct size_class *class, unsigned long m_offset; void *vaddr; - handle |= OBJ_ALLOCATED_TAG; obj = get_freeobj(first_page); objidx_to_page_and_ofs(class, first_page, obj, _page, _offset); @@ -1429,10 +1441,10 @@ static unsigned long obj_malloc(struct size_class *class, set_freeobj(first_page, link->next >> OBJ_ALLOCATED_TAG); if (!class->huge) /* record handle in the header of allocated chunk */ - link->handle = handle; + link->handle = handle | OBJ_ALLOCATED_TAG; else
Re: [PATCH v1 09/19] zsmalloc: keep max_object in size_class
On 2016/3/11 15:30, Minchan Kim wrote: Every zspage in a size_class has same number of max objects so we could move it to a size_class. Signed-off-by: Minchan Kim--- mm/zsmalloc.c | 29 ++--- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index b4fb11831acb..ca663c82c1fc 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -32,8 +32,6 @@ *page->freelist: points to the first free object in zspage. *Free objects are linked together using in-place *metadata. - * page->objects: maximum number of objects we can store in this - * zspage (class->zspage_order * PAGE_SIZE / class->size) *page->lru: links together first pages of various zspages. *Basically forming list of zspages in a fullness group. *page->mapping: class index and fullness group of the zspage @@ -211,6 +209,7 @@ struct size_class { * of ZS_ALIGN. */ int size; + int objs_per_zspage; unsigned int index; struct zs_size_stat stats; @@ -622,21 +621,22 @@ static inline void zs_pool_stat_destroy(struct zs_pool *pool) * the pool (not yet implemented). This function returns fullness * status of the given page. */ -static enum fullness_group get_fullness_group(struct page *first_page) +static enum fullness_group get_fullness_group(struct size_class *class, + struct page *first_page) { - int inuse, max_objects; + int inuse, objs_per_zspage; enum fullness_group fg; VM_BUG_ON_PAGE(!is_first_page(first_page), first_page); inuse = first_page->inuse; - max_objects = first_page->objects; + objs_per_zspage = class->objs_per_zspage; if (inuse == 0) fg = ZS_EMPTY; - else if (inuse == max_objects) + else if (inuse == objs_per_zspage) fg = ZS_FULL; - else if (inuse <= 3 * max_objects / fullness_threshold_frac) + else if (inuse <= 3 * objs_per_zspage / fullness_threshold_frac) fg = ZS_ALMOST_EMPTY; else fg = ZS_ALMOST_FULL; @@ -723,7 +723,7 @@ static enum fullness_group fix_fullness_group(struct size_class *class, enum fullness_group currfg, newfg; get_zspage_mapping(first_page, _idx, ); - newfg = get_fullness_group(first_page); + newfg = get_fullness_group(class, first_page); if (newfg == currfg) goto out; @@ -1003,9 +1003,6 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) init_zspage(class, first_page); first_page->freelist = location_to_obj(first_page, 0); - /* Maximum number of objects we can store in this zspage */ - first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size; - error = 0; /* Success */ cleanup: @@ -1235,11 +1232,11 @@ static bool can_merge(struct size_class *prev, int size, int pages_per_zspage) return true; } -static bool zspage_full(struct page *first_page) +static bool zspage_full(struct size_class *class, struct page *first_page) { VM_BUG_ON_PAGE(!is_first_page(first_page), first_page); - return first_page->inuse == first_page->objects; + return first_page->inuse == class->objs_per_zspage; } unsigned long zs_get_total_pages(struct zs_pool *pool) @@ -1625,7 +1622,7 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class, } /* Stop if there is no more space */ - if (zspage_full(d_page)) { + if (zspage_full(class, d_page)) { unpin_tag(handle); ret = -ENOMEM; break; @@ -1684,7 +1681,7 @@ static enum fullness_group putback_zspage(struct zs_pool *pool, { enum fullness_group fullness; - fullness = get_fullness_group(first_page); + fullness = get_fullness_group(class, first_page); insert_zspage(class, fullness, first_page); set_zspage_mapping(first_page, class->index, fullness); @@ -1933,6 +1930,8 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t flags) class->size = size; class->index = i; class->pages_per_zspage = pages_per_zspage; + class->objs_per_zspage = class->pages_per_zspage * + PAGE_SIZE / class->size; if (pages_per_zspage == 1 && get_maxobj_per_zspage(size, pages_per_zspage) == 1) class->huge = true; computes the "objs_per_zspage" twice here. class->objs_per_zspage = get_maxobj_per_zspage(size, pages_per_zspage); if (pages_per_zspage == 1 && class->objs_per_zspage ==1)
Re: [PATCH v1 09/19] zsmalloc: keep max_object in size_class
On 2016/3/11 15:30, Minchan Kim wrote: Every zspage in a size_class has same number of max objects so we could move it to a size_class. Signed-off-by: Minchan Kim --- mm/zsmalloc.c | 29 ++--- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index b4fb11831acb..ca663c82c1fc 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -32,8 +32,6 @@ *page->freelist: points to the first free object in zspage. *Free objects are linked together using in-place *metadata. - * page->objects: maximum number of objects we can store in this - * zspage (class->zspage_order * PAGE_SIZE / class->size) *page->lru: links together first pages of various zspages. *Basically forming list of zspages in a fullness group. *page->mapping: class index and fullness group of the zspage @@ -211,6 +209,7 @@ struct size_class { * of ZS_ALIGN. */ int size; + int objs_per_zspage; unsigned int index; struct zs_size_stat stats; @@ -622,21 +621,22 @@ static inline void zs_pool_stat_destroy(struct zs_pool *pool) * the pool (not yet implemented). This function returns fullness * status of the given page. */ -static enum fullness_group get_fullness_group(struct page *first_page) +static enum fullness_group get_fullness_group(struct size_class *class, + struct page *first_page) { - int inuse, max_objects; + int inuse, objs_per_zspage; enum fullness_group fg; VM_BUG_ON_PAGE(!is_first_page(first_page), first_page); inuse = first_page->inuse; - max_objects = first_page->objects; + objs_per_zspage = class->objs_per_zspage; if (inuse == 0) fg = ZS_EMPTY; - else if (inuse == max_objects) + else if (inuse == objs_per_zspage) fg = ZS_FULL; - else if (inuse <= 3 * max_objects / fullness_threshold_frac) + else if (inuse <= 3 * objs_per_zspage / fullness_threshold_frac) fg = ZS_ALMOST_EMPTY; else fg = ZS_ALMOST_FULL; @@ -723,7 +723,7 @@ static enum fullness_group fix_fullness_group(struct size_class *class, enum fullness_group currfg, newfg; get_zspage_mapping(first_page, _idx, ); - newfg = get_fullness_group(first_page); + newfg = get_fullness_group(class, first_page); if (newfg == currfg) goto out; @@ -1003,9 +1003,6 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) init_zspage(class, first_page); first_page->freelist = location_to_obj(first_page, 0); - /* Maximum number of objects we can store in this zspage */ - first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size; - error = 0; /* Success */ cleanup: @@ -1235,11 +1232,11 @@ static bool can_merge(struct size_class *prev, int size, int pages_per_zspage) return true; } -static bool zspage_full(struct page *first_page) +static bool zspage_full(struct size_class *class, struct page *first_page) { VM_BUG_ON_PAGE(!is_first_page(first_page), first_page); - return first_page->inuse == first_page->objects; + return first_page->inuse == class->objs_per_zspage; } unsigned long zs_get_total_pages(struct zs_pool *pool) @@ -1625,7 +1622,7 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class, } /* Stop if there is no more space */ - if (zspage_full(d_page)) { + if (zspage_full(class, d_page)) { unpin_tag(handle); ret = -ENOMEM; break; @@ -1684,7 +1681,7 @@ static enum fullness_group putback_zspage(struct zs_pool *pool, { enum fullness_group fullness; - fullness = get_fullness_group(first_page); + fullness = get_fullness_group(class, first_page); insert_zspage(class, fullness, first_page); set_zspage_mapping(first_page, class->index, fullness); @@ -1933,6 +1930,8 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t flags) class->size = size; class->index = i; class->pages_per_zspage = pages_per_zspage; + class->objs_per_zspage = class->pages_per_zspage * + PAGE_SIZE / class->size; if (pages_per_zspage == 1 && get_maxobj_per_zspage(size, pages_per_zspage) == 1) class->huge = true; computes the "objs_per_zspage" twice here. class->objs_per_zspage = get_maxobj_per_zspage(size, pages_per_zspage); if (pages_per_zspage == 1 && class->objs_per_zspage ==1)
Re: [PATCH] zsmalloc: drop unused member 'mapping_area->huge'
HI, Sergery On 2016/2/17 10:26, Sergey Senozhatsky wrote: Hello, On (02/17/16 09:56), YiPing Xu wrote: static int create_handle_cache(struct zs_pool *pool) @@ -1127,11 +1126,9 @@ static void __zs_unmap_object(struct mapping_area *area, goto out; buf = area->vm_buf; - if (!area->huge) { - buf = buf + ZS_HANDLE_SIZE; - size -= ZS_HANDLE_SIZE; - off += ZS_HANDLE_SIZE; - } + buf = buf + ZS_HANDLE_SIZE; + size -= ZS_HANDLE_SIZE; + off += ZS_HANDLE_SIZE; sizes[0] = PAGE_SIZE - off; sizes[1] = size - sizes[0]; hm, indeed. shouldn't it depend on class->huge? void *zs_map_object() { if (off + class->size <= PAGE_SIZE) { for huge object, the code will get into this branch, there is no more huge object process in __zs_map_object. /* this object is contained entirely within a page */ area->vm_addr = kmap_atomic(page); ret = area->vm_addr + off; goto out; } void *ret = __zs_map_object(area, pages, off, class->size); if (!class->huge) ret += ZS_HANDLE_SIZE; /* area->vm_buf + ZS_HANDLE_SIZE */ return ret; } void zs_unmap_object(struct zs_pool *pool, unsigned long handle) { .. area = this_cpu_ptr(_map_area); if (off + class->size <= PAGE_SIZE) for huge object, the code will get into this branch, so, in __zs_unmap_object there is no depend on class->huge. it is a little implicated here. kunmap_atomic(area->vm_addr); else { struct page *pages[2]; pages[0] = page; pages[1] = get_next_page(page); BUG_ON(!pages[1]); __zs_unmap_object(area, pages, off, class->size); } .. } static void __zs_unmap_object(struct mapping_area *area...) { char *buf = area->vm_buf; /* handle is in page->private for class->huge */ buf = buf + ZS_HANDLE_SIZE; size -= ZS_HANDLE_SIZE; off += ZS_HANDLE_SIZE; memcpy(..); } -ss .
Re: [PATCH] zsmalloc: drop unused member 'mapping_area->huge'
HI, Sergery On 2016/2/17 10:26, Sergey Senozhatsky wrote: Hello, On (02/17/16 09:56), YiPing Xu wrote: static int create_handle_cache(struct zs_pool *pool) @@ -1127,11 +1126,9 @@ static void __zs_unmap_object(struct mapping_area *area, goto out; buf = area->vm_buf; - if (!area->huge) { - buf = buf + ZS_HANDLE_SIZE; - size -= ZS_HANDLE_SIZE; - off += ZS_HANDLE_SIZE; - } + buf = buf + ZS_HANDLE_SIZE; + size -= ZS_HANDLE_SIZE; + off += ZS_HANDLE_SIZE; sizes[0] = PAGE_SIZE - off; sizes[1] = size - sizes[0]; hm, indeed. shouldn't it depend on class->huge? void *zs_map_object() { if (off + class->size <= PAGE_SIZE) { for huge object, the code will get into this branch, there is no more huge object process in __zs_map_object. /* this object is contained entirely within a page */ area->vm_addr = kmap_atomic(page); ret = area->vm_addr + off; goto out; } void *ret = __zs_map_object(area, pages, off, class->size); if (!class->huge) ret += ZS_HANDLE_SIZE; /* area->vm_buf + ZS_HANDLE_SIZE */ return ret; } void zs_unmap_object(struct zs_pool *pool, unsigned long handle) { .. area = this_cpu_ptr(_map_area); if (off + class->size <= PAGE_SIZE) for huge object, the code will get into this branch, so, in __zs_unmap_object there is no depend on class->huge. it is a little implicated here. kunmap_atomic(area->vm_addr); else { struct page *pages[2]; pages[0] = page; pages[1] = get_next_page(page); BUG_ON(!pages[1]); __zs_unmap_object(area, pages, off, class->size); } .. } static void __zs_unmap_object(struct mapping_area *area...) { char *buf = area->vm_buf; /* handle is in page->private for class->huge */ buf = buf + ZS_HANDLE_SIZE; size -= ZS_HANDLE_SIZE; off += ZS_HANDLE_SIZE; memcpy(..); } -ss .
Re: [PATCH 2/3] staging: android: ion: Add ion driver for Hi6220 SoC platform
On 2015/10/8 15:55, Chen Feng wrote: Signed-off-by: Chen Feng Signed-off-by: Yu Dongbin --- drivers/staging/android/ion/Kconfig| 7 + drivers/staging/android/ion/Makefile | 1 + drivers/staging/android/ion/hisilicon/Kconfig | 5 + drivers/staging/android/ion/hisilicon/Makefile | 1 + drivers/staging/android/ion/hisilicon/hi6220_ion.c | 201 + 5 files changed, 215 insertions(+) create mode 100644 drivers/staging/android/ion/hisilicon/Kconfig create mode 100644 drivers/staging/android/ion/hisilicon/Makefile create mode 100644 drivers/staging/android/ion/hisilicon/hi6220_ion.c diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig index 3452346..19c1572 100644 --- a/drivers/staging/android/ion/Kconfig +++ b/drivers/staging/android/ion/Kconfig @@ -33,3 +33,10 @@ config ION_TEGRA help Choose this option if you wish to use ion on an nVidia Tegra. +config ION_HISI + tristate "Ion for Hisilicon" + depends on ARCH_HISI && ION + help + Choose this option if you wish to use ion on Hisilicon Platform. + +source "drivers/staging/android/ion/hisilicon/Kconfig" diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index b56fd2b..18cc2aa 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -7,4 +7,5 @@ endif obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o obj-$(CONFIG_ION_TEGRA) += tegra/ +obj-$(CONFIG_ION_HISI) += hisilicon/ diff --git a/drivers/staging/android/ion/hisilicon/Kconfig b/drivers/staging/android/ion/hisilicon/Kconfig new file mode 100644 index 000..2b4bd07 --- /dev/null +++ b/drivers/staging/android/ion/hisilicon/Kconfig @@ -0,0 +1,5 @@ +config HI6220_ION +bool "Hi6220 ION Driver" +depends on ARCH_HISI && ION +help + Build the Hisilicon Hi6220 ion driver. diff --git a/drivers/staging/android/ion/hisilicon/Makefile b/drivers/staging/android/ion/hisilicon/Makefile new file mode 100644 index 000..2a89414 --- /dev/null +++ b/drivers/staging/android/ion/hisilicon/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_HI6220_ION) += hi6220_ion.o diff --git a/drivers/staging/android/ion/hisilicon/hi6220_ion.c b/drivers/staging/android/ion/hisilicon/hi6220_ion.c new file mode 100644 index 000..b7d39b8 --- /dev/null +++ b/drivers/staging/android/ion/hisilicon/hi6220_ion.c @@ -0,0 +1,201 @@ +#define pr_fmt(fmt) "Ion: " fmt + +#include +#include +#include +#include +#include +#include "../ion_priv.h" +#include "../ion.h" + +struct hi6220_ion_type_table { + const char *name; + enum ion_heap_type type; +}; + +static struct hi6220_ion_type_table ion_type_table[] = { + {"ion_system", ION_HEAP_TYPE_SYSTEM}, + {"ion_system_contig", ION_HEAP_TYPE_SYSTEM_CONTIG}, + {"ion_carveout", ION_HEAP_TYPE_CARVEOUT}, + {"ion_chunk", ION_HEAP_TYPE_CHUNK}, + {"ion_dma", ION_HEAP_TYPE_DMA}, + {"ion_custom", ION_HEAP_TYPE_CUSTOM}, +}; + +static struct ion_device *idev; +static int num_heaps; +static struct ion_heap **heaps; +static struct ion_platform_heap **heaps_data; + +static int get_type_by_name(const char *name, enum ion_heap_type *type) +{ + int i, n; + + n = ARRAY_SIZE(ion_type_table); + for (i = 0; i < n; i++) { + if (strncmp(name, ion_type_table[i].name, strlen(name))) + continue; + + *type = ion_type_table[i].type; + return 0; + } + + return -1; +} + +static int hi6220_set_platform_data(struct platform_device *pdev) +{ + unsigned int base; + unsigned int size; + unsigned int id; + const char *heap_name; + const char *type_name; + enum ion_heap_type type; + int ret; + struct device_node *np; + struct ion_platform_heap *p_data; + const struct device_node *dt_node = pdev->dev.of_node; + int index = 0; + + for_each_child_of_node(dt_node, np) + num_heaps++; indentation + heaps_data = devm_kzalloc(>dev, + sizeof(struct ion_platform_heap *) * num_heaps, + GFP_KERNEL); check the result of malloc + for_each_child_of_node(dt_node, np) { + p_data = devm_kzalloc(>dev, + sizeof(struct ion_platform_heap), + GFP_KERNEL); check the result of malloc + ret = of_property_read_string(np, "heap-name", _name); + if (ret < 0) { + pr_err("check the name of node %s\n", np->name); + continue; + } + + ret = of_property_read_u32(np, "heap-id", ); + if (ret < 0) { + pr_err("check the id %s\n",
Re: [PATCH 2/3] staging: android: ion: Add ion driver for Hi6220 SoC platform
On 2015/10/8 15:55, Chen Feng wrote: Signed-off-by: Chen FengSigned-off-by: Yu Dongbin --- drivers/staging/android/ion/Kconfig| 7 + drivers/staging/android/ion/Makefile | 1 + drivers/staging/android/ion/hisilicon/Kconfig | 5 + drivers/staging/android/ion/hisilicon/Makefile | 1 + drivers/staging/android/ion/hisilicon/hi6220_ion.c | 201 + 5 files changed, 215 insertions(+) create mode 100644 drivers/staging/android/ion/hisilicon/Kconfig create mode 100644 drivers/staging/android/ion/hisilicon/Makefile create mode 100644 drivers/staging/android/ion/hisilicon/hi6220_ion.c diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig index 3452346..19c1572 100644 --- a/drivers/staging/android/ion/Kconfig +++ b/drivers/staging/android/ion/Kconfig @@ -33,3 +33,10 @@ config ION_TEGRA help Choose this option if you wish to use ion on an nVidia Tegra. +config ION_HISI + tristate "Ion for Hisilicon" + depends on ARCH_HISI && ION + help + Choose this option if you wish to use ion on Hisilicon Platform. + +source "drivers/staging/android/ion/hisilicon/Kconfig" diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index b56fd2b..18cc2aa 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -7,4 +7,5 @@ endif obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o obj-$(CONFIG_ION_TEGRA) += tegra/ +obj-$(CONFIG_ION_HISI) += hisilicon/ diff --git a/drivers/staging/android/ion/hisilicon/Kconfig b/drivers/staging/android/ion/hisilicon/Kconfig new file mode 100644 index 000..2b4bd07 --- /dev/null +++ b/drivers/staging/android/ion/hisilicon/Kconfig @@ -0,0 +1,5 @@ +config HI6220_ION +bool "Hi6220 ION Driver" +depends on ARCH_HISI && ION +help + Build the Hisilicon Hi6220 ion driver. diff --git a/drivers/staging/android/ion/hisilicon/Makefile b/drivers/staging/android/ion/hisilicon/Makefile new file mode 100644 index 000..2a89414 --- /dev/null +++ b/drivers/staging/android/ion/hisilicon/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_HI6220_ION) += hi6220_ion.o diff --git a/drivers/staging/android/ion/hisilicon/hi6220_ion.c b/drivers/staging/android/ion/hisilicon/hi6220_ion.c new file mode 100644 index 000..b7d39b8 --- /dev/null +++ b/drivers/staging/android/ion/hisilicon/hi6220_ion.c @@ -0,0 +1,201 @@ +#define pr_fmt(fmt) "Ion: " fmt + +#include +#include +#include +#include +#include +#include "../ion_priv.h" +#include "../ion.h" + +struct hi6220_ion_type_table { + const char *name; + enum ion_heap_type type; +}; + +static struct hi6220_ion_type_table ion_type_table[] = { + {"ion_system", ION_HEAP_TYPE_SYSTEM}, + {"ion_system_contig", ION_HEAP_TYPE_SYSTEM_CONTIG}, + {"ion_carveout", ION_HEAP_TYPE_CARVEOUT}, + {"ion_chunk", ION_HEAP_TYPE_CHUNK}, + {"ion_dma", ION_HEAP_TYPE_DMA}, + {"ion_custom", ION_HEAP_TYPE_CUSTOM}, +}; + +static struct ion_device *idev; +static int num_heaps; +static struct ion_heap **heaps; +static struct ion_platform_heap **heaps_data; + +static int get_type_by_name(const char *name, enum ion_heap_type *type) +{ + int i, n; + + n = ARRAY_SIZE(ion_type_table); + for (i = 0; i < n; i++) { + if (strncmp(name, ion_type_table[i].name, strlen(name))) + continue; + + *type = ion_type_table[i].type; + return 0; + } + + return -1; +} + +static int hi6220_set_platform_data(struct platform_device *pdev) +{ + unsigned int base; + unsigned int size; + unsigned int id; + const char *heap_name; + const char *type_name; + enum ion_heap_type type; + int ret; + struct device_node *np; + struct ion_platform_heap *p_data; + const struct device_node *dt_node = pdev->dev.of_node; + int index = 0; + + for_each_child_of_node(dt_node, np) + num_heaps++; indentation + heaps_data = devm_kzalloc(>dev, + sizeof(struct ion_platform_heap *) * num_heaps, + GFP_KERNEL); check the result of malloc + for_each_child_of_node(dt_node, np) { + p_data = devm_kzalloc(>dev, + sizeof(struct ion_platform_heap), + GFP_KERNEL); check the result of malloc + ret = of_property_read_string(np, "heap-name", _name); + if (ret < 0) { + pr_err("check the name of node %s\n", np->name); + continue; + } + + ret = of_property_read_u32(np, "heap-id", ); + if (ret < 0) { +
Re: [PATCH V3 3/3] reset: hi6220: Reset driver for hisilicon hi6220 SoC
On 2015/9/15 11:58, Chen Feng wrote: Add reset driver for hi6220-hikey board,this driver supply deassert of IP. on hi6220 SoC. Signed-off-by: Chen Feng --- drivers/reset/Kconfig | 1 + drivers/reset/Makefile | 1 + drivers/reset/hisilicon/Kconfig| 5 ++ drivers/reset/hisilicon/Makefile | 1 + drivers/reset/hisilicon/hi6220_reset.c | 121 + 5 files changed, 129 insertions(+) create mode 100644 drivers/reset/hisilicon/Kconfig create mode 100644 drivers/reset/hisilicon/Makefile create mode 100644 drivers/reset/hisilicon/hi6220_reset.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 0615f50..df37212 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -13,3 +13,4 @@ menuconfig RESET_CONTROLLER If unsure, say no. source "drivers/reset/sti/Kconfig" +source "drivers/reset/hisilicon/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 157d421..331d7b2 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ +obj-$(CONFIG_ARCH_HISI) += hisilicon/ diff --git a/drivers/reset/hisilicon/Kconfig b/drivers/reset/hisilicon/Kconfig new file mode 100644 index 000..26bf95a --- /dev/null +++ b/drivers/reset/hisilicon/Kconfig @@ -0,0 +1,5 @@ +config COMMON_RESET_HI6220 + tristate "Hi6220 Reset Driver" + depends on (ARCH_HISI && RESET_CONTROLLER) + help + Build the Hisilicon Hi6220 reset driver. diff --git a/drivers/reset/hisilicon/Makefile b/drivers/reset/hisilicon/Makefile new file mode 100644 index 000..c932f86 --- /dev/null +++ b/drivers/reset/hisilicon/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_COMMON_RESET_HI6220) += hi6220_reset.o diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c new file mode 100644 index 000..3d3de94 --- /dev/null +++ b/drivers/reset/hisilicon/hi6220_reset.c @@ -0,0 +1,121 @@ +/* + * Hisilicon Hi6220 reset controller driver + * + * Copyright (c) 2015 Hisilicon Limited. + * + * Author: Feng Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ASSET_OFFSET0x300 +#define DEASSET_OFFSET 0x304 + +#define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev) + +struct hi6220_reset_data { + spinlock_t reset_lock; /*device spin-lock*/ it looks useless + void __iomem*asset_base; + void __iomem*deasset_base; + struct reset_controller_dev rc_dev; +}; + +static int hi6220_reset_assert(struct reset_controller_dev *rc_dev, + unsigned long idx) +{ + struct hi6220_reset_data *data = to_reset_data(rc_dev); + + unsigned long flags; + int bank = idx >> 8; + int offset = idx & 0xff; + + spin_lock_irqsave(>reset_lock, flags); + + writel(BIT(offset), data->asset_base + (bank * 0x10)); + + spin_unlock_irqrestore(>reset_lock, flags); + + return 0; +} + +static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev, +unsigned long idx) +{ + struct hi6220_reset_data *data = to_reset_data(rc_dev); + + unsigned long flags; + int bank = idx >> 8; + int offset = idx & 0xff; + + spin_lock_irqsave(>reset_lock, flags); + + writel(BIT(offset), data->deasset_base + (bank * 0x10)); + + spin_unlock_irqrestore(>reset_lock, flags); + + return 0; +} + +static struct reset_control_ops hi6220_reset_ops = { + .assert = hi6220_reset_assert, + .deassert = hi6220_reset_deassert, +}; + +static int hi6220_reset_probe(struct platform_device *pdev) +{ + struct hi6220_reset_data *data; + struct resource *res; + void __iomem *src_base; + + data = devm_kzalloc(>dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + src_base = devm_ioremap_resource(>dev, res); + if (IS_ERR(src_base)) + return PTR_ERR(src_base); + + spin_lock_init(>reset_lock); + + data->asset_base = src_base + ASSET_OFFSET; + data->deasset_base = src_base + DEASSET_OFFSET; + data->rc_dev.nr_resets = SZ_4K; use the max index of the reset bit + data->rc_dev.ops = _reset_ops; + data->rc_dev.of_node = pdev->dev.of_node; + + reset_controller_register(>rc_dev); + + return 0; +} + +static const struct
Re: [PATCH V3 3/3] reset: hi6220: Reset driver for hisilicon hi6220 SoC
On 2015/9/15 11:58, Chen Feng wrote: Add reset driver for hi6220-hikey board,this driver supply deassert of IP. on hi6220 SoC. Signed-off-by: Chen Feng--- drivers/reset/Kconfig | 1 + drivers/reset/Makefile | 1 + drivers/reset/hisilicon/Kconfig| 5 ++ drivers/reset/hisilicon/Makefile | 1 + drivers/reset/hisilicon/hi6220_reset.c | 121 + 5 files changed, 129 insertions(+) create mode 100644 drivers/reset/hisilicon/Kconfig create mode 100644 drivers/reset/hisilicon/Makefile create mode 100644 drivers/reset/hisilicon/hi6220_reset.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 0615f50..df37212 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -13,3 +13,4 @@ menuconfig RESET_CONTROLLER If unsure, say no. source "drivers/reset/sti/Kconfig" +source "drivers/reset/hisilicon/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 157d421..331d7b2 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ +obj-$(CONFIG_ARCH_HISI) += hisilicon/ diff --git a/drivers/reset/hisilicon/Kconfig b/drivers/reset/hisilicon/Kconfig new file mode 100644 index 000..26bf95a --- /dev/null +++ b/drivers/reset/hisilicon/Kconfig @@ -0,0 +1,5 @@ +config COMMON_RESET_HI6220 + tristate "Hi6220 Reset Driver" + depends on (ARCH_HISI && RESET_CONTROLLER) + help + Build the Hisilicon Hi6220 reset driver. diff --git a/drivers/reset/hisilicon/Makefile b/drivers/reset/hisilicon/Makefile new file mode 100644 index 000..c932f86 --- /dev/null +++ b/drivers/reset/hisilicon/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_COMMON_RESET_HI6220) += hi6220_reset.o diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c new file mode 100644 index 000..3d3de94 --- /dev/null +++ b/drivers/reset/hisilicon/hi6220_reset.c @@ -0,0 +1,121 @@ +/* + * Hisilicon Hi6220 reset controller driver + * + * Copyright (c) 2015 Hisilicon Limited. + * + * Author: Feng Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ASSET_OFFSET0x300 +#define DEASSET_OFFSET 0x304 + +#define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev) + +struct hi6220_reset_data { + spinlock_t reset_lock; /*device spin-lock*/ it looks useless + void __iomem*asset_base; + void __iomem*deasset_base; + struct reset_controller_dev rc_dev; +}; + +static int hi6220_reset_assert(struct reset_controller_dev *rc_dev, + unsigned long idx) +{ + struct hi6220_reset_data *data = to_reset_data(rc_dev); + + unsigned long flags; + int bank = idx >> 8; + int offset = idx & 0xff; + + spin_lock_irqsave(>reset_lock, flags); + + writel(BIT(offset), data->asset_base + (bank * 0x10)); + + spin_unlock_irqrestore(>reset_lock, flags); + + return 0; +} + +static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev, +unsigned long idx) +{ + struct hi6220_reset_data *data = to_reset_data(rc_dev); + + unsigned long flags; + int bank = idx >> 8; + int offset = idx & 0xff; + + spin_lock_irqsave(>reset_lock, flags); + + writel(BIT(offset), data->deasset_base + (bank * 0x10)); + + spin_unlock_irqrestore(>reset_lock, flags); + + return 0; +} + +static struct reset_control_ops hi6220_reset_ops = { + .assert = hi6220_reset_assert, + .deassert = hi6220_reset_deassert, +}; + +static int hi6220_reset_probe(struct platform_device *pdev) +{ + struct hi6220_reset_data *data; + struct resource *res; + void __iomem *src_base; + + data = devm_kzalloc(>dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + src_base = devm_ioremap_resource(>dev, res); + if (IS_ERR(src_base)) + return PTR_ERR(src_base); + + spin_lock_init(>reset_lock); + + data->asset_base = src_base + ASSET_OFFSET; + data->deasset_base = src_base + DEASSET_OFFSET; + data->rc_dev.nr_resets = SZ_4K; use the max index of the reset bit + data->rc_dev.ops = _reset_ops; + data->rc_dev.of_node = pdev->dev.of_node; + + reset_controller_register(>rc_dev); + +
Re: [PATCH V2 3/3] reset: hi6220: Reset driver for hisilicon hi6220 SoC
On 2015/9/11 16:18, Chen Feng wrote: Add reset driver for hi6220-hikey board,this driver supply deassert of IP. on hi6220 SoC. Signed-off-by: Chen Feng --- drivers/reset/Kconfig | 1 + drivers/reset/Makefile | 1 + drivers/reset/hisilicon/Kconfig| 5 ++ drivers/reset/hisilicon/Makefile | 1 + drivers/reset/hisilicon/hi6220_reset.c | 118 + 5 files changed, 126 insertions(+) create mode 100644 drivers/reset/hisilicon/Kconfig create mode 100644 drivers/reset/hisilicon/Makefile create mode 100644 drivers/reset/hisilicon/hi6220_reset.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 0615f50..df37212 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -13,3 +13,4 @@ menuconfig RESET_CONTROLLER If unsure, say no. source "drivers/reset/sti/Kconfig" +source "drivers/reset/hisilicon/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 157d421..331d7b2 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ +obj-$(CONFIG_ARCH_HISI) += hisilicon/ diff --git a/drivers/reset/hisilicon/Kconfig b/drivers/reset/hisilicon/Kconfig new file mode 100644 index 000..26bf95a --- /dev/null +++ b/drivers/reset/hisilicon/Kconfig @@ -0,0 +1,5 @@ +config COMMON_RESET_HI6220 + tristate "Hi6220 Reset Driver" + depends on (ARCH_HISI && RESET_CONTROLLER) + help + Build the Hisilicon Hi6220 reset driver. diff --git a/drivers/reset/hisilicon/Makefile b/drivers/reset/hisilicon/Makefile new file mode 100644 index 000..c932f86 --- /dev/null +++ b/drivers/reset/hisilicon/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_COMMON_RESET_HI6220) += hi6220_reset.o diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c new file mode 100644 index 000..097133d --- /dev/null +++ b/drivers/reset/hisilicon/hi6220_reset.c @@ -0,0 +1,118 @@ +/* + * Hisilicon Hi6220 reset controller driver + * + * Copyright (c) 2015 Hisilicon Limited. + * + * Author: Feng Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ASSET_OFFSET0x300 +#define DEASSET_OFFSET 0x304 + +struct hi6220_reset_data { + spinlock_t reset_lock; /*device spin-lock*/ + void __iomem*src_base; + void __iomem*asset_base; + void __iomem*deasset_base; + struct reset_controller_dev rc_dev; +}; + +static int hi6220_reset_assert(struct reset_controller_dev *rc_dev, + unsigned long idx) +{ + struct hi6220_reset_data *data = container_of(rc_dev, + struct hi6220_reset_data, + rc_dev); + + unsigned long flags; + int bank = idx >> 8; + int offset = idx & 0xff; + + spin_lock_irqsave(>reset_lock, flags); the spin_lock looks useless. it is not a "read and write" register. + writel(BIT(offset), data->asset_base + (bank * 0x10)); + + spin_unlock_irqrestore(>reset_lock, flags); + + return 0; +} + +static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev, +unsigned long idx) +{ + struct hi6220_reset_data *data = container_of(rc_dev, + struct hi6220_reset_data, + rc_dev); + + unsigned long flags; + int bank = idx >> 8; + int offset = idx & 0xff; no need to check the idx scope ? + spin_lock_irqsave(>reset_lock, flags); + + writel(BIT(offset), data->deasset_base + (bank * 0x10)); + + spin_unlock_irqrestore(>reset_lock, flags); + + return 0; +} + +static struct reset_control_ops hi6220_reset_ops = { + .assert = hi6220_reset_assert, + .deassert = hi6220_reset_deassert, +}; + +static int __init hi6220_reset_init(void) +{ + int ret; + struct device_node *np; + struct hi6220_reset_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + np = of_find_compatible_node(NULL, NULL, "hisilicon,hi6220_reset_ctl"); + if (!np) { + ret = -ENXIO; + goto err_alloc; + } + spin_lock_init(>reset_lock); + data->src_base = of_iomap(np, 0); + if (!data->src_base) { + ret = -ENOMEM; + goto err_alloc; + } + + data->asset_base =
Re: [PATCH V2 3/3] reset: hi6220: Reset driver for hisilicon hi6220 SoC
On 2015/9/11 16:18, Chen Feng wrote: Add reset driver for hi6220-hikey board,this driver supply deassert of IP. on hi6220 SoC. Signed-off-by: Chen Feng--- drivers/reset/Kconfig | 1 + drivers/reset/Makefile | 1 + drivers/reset/hisilicon/Kconfig| 5 ++ drivers/reset/hisilicon/Makefile | 1 + drivers/reset/hisilicon/hi6220_reset.c | 118 + 5 files changed, 126 insertions(+) create mode 100644 drivers/reset/hisilicon/Kconfig create mode 100644 drivers/reset/hisilicon/Makefile create mode 100644 drivers/reset/hisilicon/hi6220_reset.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 0615f50..df37212 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -13,3 +13,4 @@ menuconfig RESET_CONTROLLER If unsure, say no. source "drivers/reset/sti/Kconfig" +source "drivers/reset/hisilicon/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 157d421..331d7b2 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ +obj-$(CONFIG_ARCH_HISI) += hisilicon/ diff --git a/drivers/reset/hisilicon/Kconfig b/drivers/reset/hisilicon/Kconfig new file mode 100644 index 000..26bf95a --- /dev/null +++ b/drivers/reset/hisilicon/Kconfig @@ -0,0 +1,5 @@ +config COMMON_RESET_HI6220 + tristate "Hi6220 Reset Driver" + depends on (ARCH_HISI && RESET_CONTROLLER) + help + Build the Hisilicon Hi6220 reset driver. diff --git a/drivers/reset/hisilicon/Makefile b/drivers/reset/hisilicon/Makefile new file mode 100644 index 000..c932f86 --- /dev/null +++ b/drivers/reset/hisilicon/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_COMMON_RESET_HI6220) += hi6220_reset.o diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c new file mode 100644 index 000..097133d --- /dev/null +++ b/drivers/reset/hisilicon/hi6220_reset.c @@ -0,0 +1,118 @@ +/* + * Hisilicon Hi6220 reset controller driver + * + * Copyright (c) 2015 Hisilicon Limited. + * + * Author: Feng Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ASSET_OFFSET0x300 +#define DEASSET_OFFSET 0x304 + +struct hi6220_reset_data { + spinlock_t reset_lock; /*device spin-lock*/ + void __iomem*src_base; + void __iomem*asset_base; + void __iomem*deasset_base; + struct reset_controller_dev rc_dev; +}; + +static int hi6220_reset_assert(struct reset_controller_dev *rc_dev, + unsigned long idx) +{ + struct hi6220_reset_data *data = container_of(rc_dev, + struct hi6220_reset_data, + rc_dev); + + unsigned long flags; + int bank = idx >> 8; + int offset = idx & 0xff; + + spin_lock_irqsave(>reset_lock, flags); the spin_lock looks useless. it is not a "read and write" register. + writel(BIT(offset), data->asset_base + (bank * 0x10)); + + spin_unlock_irqrestore(>reset_lock, flags); + + return 0; +} + +static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev, +unsigned long idx) +{ + struct hi6220_reset_data *data = container_of(rc_dev, + struct hi6220_reset_data, + rc_dev); + + unsigned long flags; + int bank = idx >> 8; + int offset = idx & 0xff; no need to check the idx scope ? + spin_lock_irqsave(>reset_lock, flags); + + writel(BIT(offset), data->deasset_base + (bank * 0x10)); + + spin_unlock_irqrestore(>reset_lock, flags); + + return 0; +} + +static struct reset_control_ops hi6220_reset_ops = { + .assert = hi6220_reset_assert, + .deassert = hi6220_reset_deassert, +}; + +static int __init hi6220_reset_init(void) +{ + int ret; + struct device_node *np; + struct hi6220_reset_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + np = of_find_compatible_node(NULL, NULL, "hisilicon,hi6220_reset_ctl"); + if (!np) { + ret = -ENXIO; + goto err_alloc; + } + spin_lock_init(>reset_lock); + data->src_base = of_iomap(np, 0); + if (!data->src_base) { + ret = -ENOMEM; + goto