From bab55417b10c95e6bff8cea315c315adfa009487 Mon Sep 17 00:00:00 2001 From: Cai Zhiyong Date: Wed, 11 Sep 2013 14:20:09 -0700 Subject: block: support embedded device command line partition Read block device partition table from command line. The partition used for fixed block device (eMMC) embedded device. It is no MBR, save storage space. Bootloader can be easily accessed by absolute address of data on the block device. Users can easily change the partition. This code reference MTD partition, source "drivers/mtd/cmdlinepart.c" About the partition verbose reference "Documentation/block/cmdline-partition.txt" [akpm@linux-foundation.org: fix printk text] [yongjun_wei@trendmicro.com.cn: fix error return code in parse_parts()] Signed-off-by: Cai Zhiyong Cc: Karel Zak Cc: "Wanglin (Albert)" Cc: Marius Groeger Cc: David Woodhouse Cc: Jens Axboe Cc: Brian Norris Cc: Artem Bityutskiy Signed-off-by: Wei Yongjun Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/block/cmdline-partition.txt | 39 +++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/block/cmdline-partition.txt (limited to 'Documentation') diff --git a/Documentation/block/cmdline-partition.txt b/Documentation/block/cmdline-partition.txt new file mode 100644 index 000000000000..2bbf4cc40c3f --- /dev/null +++ b/Documentation/block/cmdline-partition.txt @@ -0,0 +1,39 @@ +Embedded device command line partition +===================================================================== + +Read block device partition table from command line. +The partition used for fixed block device (eMMC) embedded device. +It is no MBR, save storage space. Bootloader can be easily accessed +by absolute address of data on the block device. +Users can easily change the partition. + +The format for the command line is just like mtdparts: + +blkdevparts=[;] + := :[,] + := [@](part-name) + + + block device disk name, embedded device used fixed block device, + it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0. + + + partition size, in bytes, such as: 512, 1m, 1G. + + + partition start address, in bytes. + +(part-name) + partition name, kernel send uevent with "PARTNAME". application can create + a link to block device partition with the name "PARTNAME". + user space application can access partition by partition name. + +Example: + eMMC disk name is "mmcblk0" and "mmcblk0boot0" + + bootargs: + 'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)' + + dmesg: + mmcblk0: p1(data0) p2(data1) p3() + mmcblk0boot0: p1(boot) p2(kernel) -- cgit v1.2.3-58-ga151 From 15610c86fa83ff778eb80d3cfaa71d6acceb628a Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 11 Sep 2013 14:21:48 -0700 Subject: hugepage: mention libhugetlbfs in doc Explicitly mention/recommend using the libhugetlbfs test cases when changing related kernel code. Developers that are unaware of the project can easily miss this and introduce potential regressions that may or may not be caught by community review. Also do some cleanups that make the document visually easier to view at a first glance. Signed-off-by: Davidlohr Bueso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/hugetlbpage.txt | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index 4ac359b7aa17..bdd4bb97fff7 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -165,6 +165,7 @@ which function as described above for the default huge page-sized case. Interaction of Task Memory Policy with Huge Page Allocation/Freeing +=================================================================== Whether huge pages are allocated and freed via the /proc interface or the /sysfs interface using the nr_hugepages_mempolicy attribute, the NUMA @@ -229,6 +230,7 @@ resulting effect on persistent huge page allocation is as follows: of huge pages over all on-lines nodes with memory. Per Node Hugepages Attributes +============================= A subset of the contents of the root huge page control directory in sysfs, described above, will be replicated under each the system device of each @@ -258,6 +260,7 @@ applied, from which node the huge page allocation will be attempted. Using Huge Pages +================ If the user applications are going to request huge pages using mmap system call, then it is required that system administrator mount a file system of @@ -296,20 +299,16 @@ calls, though the mount of filesystem will be required for using mmap calls without MAP_HUGETLB. For an example of how to use mmap with MAP_HUGETLB see map_hugetlb.c. -******************************************************************* +Examples +======== -/* - * map_hugetlb: see tools/testing/selftests/vm/map_hugetlb.c - */ +1) map_hugetlb: see tools/testing/selftests/vm/map_hugetlb.c -******************************************************************* +2) hugepage-shm: see tools/testing/selftests/vm/hugepage-shm.c -/* - * hugepage-shm: see tools/testing/selftests/vm/hugepage-shm.c - */ +3) hugepage-mmap: see tools/testing/selftests/vm/hugepage-mmap.c -******************************************************************* - -/* - * hugepage-mmap: see tools/testing/selftests/vm/hugepage-mmap.c - */ +4) The libhugetlbfs (http://libhugetlbfs.sourceforge.net) library provides a + wide range of userspace tools to help with huge page usability, environment + setup, and control. Furthermore it provides useful test cases that should be + used when modifying code to ensure no regressions are introduced. -- cgit v1.2.3-58-ga151 From 86cdb465cf3a9d81058b517af05074157fa9dcdd Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Wed, 11 Sep 2013 14:22:13 -0700 Subject: mm: prepare to remove /proc/sys/vm/hugepages_treat_as_movable Now hugepage migration is enabled, although restricted on pmd-based hugepages for now (due to lack of testing.) So we should allocate migratable hugepages from ZONE_MOVABLE if possible. This patch makes GFP flags in hugepage allocation dependent on migration support, not only the value of hugepages_treat_as_movable. It provides no change on the behavior for architectures which do not support hugepage migration, Signed-off-by: Naoya Horiguchi Acked-by: Andi Kleen Reviewed-by: Wanpeng Li Cc: Hillf Danton Cc: Mel Gorman Cc: Hugh Dickins Cc: KOSAKI Motohiro Cc: Michal Hocko Cc: Rik van Riel Cc: "Aneesh Kumar K.V" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/vm.txt | 30 +++++++++++++++++++----------- kernel/sysctl.c | 2 +- mm/hugetlb.c | 32 ++++++++++++++------------------ 3 files changed, 34 insertions(+), 30 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 36ecc26c7433..79a797eb3e87 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -200,17 +200,25 @@ fragmentation index is <= extfrag_threshold. The default value is 500. hugepages_treat_as_movable -This parameter is only useful when kernelcore= is specified at boot time to -create ZONE_MOVABLE for pages that may be reclaimed or migrated. Huge pages -are not movable so are not normally allocated from ZONE_MOVABLE. A non-zero -value written to hugepages_treat_as_movable allows huge pages to be allocated -from ZONE_MOVABLE. - -Once enabled, the ZONE_MOVABLE is treated as an area of memory the huge -pages pool can easily grow or shrink within. Assuming that applications are -not running that mlock() a lot of memory, it is likely the huge pages pool -can grow to the size of ZONE_MOVABLE by repeatedly entering the desired value -into nr_hugepages and triggering page reclaim. +This parameter controls whether we can allocate hugepages from ZONE_MOVABLE +or not. If set to non-zero, hugepages can be allocated from ZONE_MOVABLE. +ZONE_MOVABLE is created when kernel boot parameter kernelcore= is specified, +so this parameter has no effect if used without kernelcore=. + +Hugepage migration is now available in some situations which depend on the +architecture and/or the hugepage size. If a hugepage supports migration, +allocation from ZONE_MOVABLE is always enabled for the hugepage regardless +of the value of this parameter. +IOW, this parameter affects only non-migratable hugepages. + +Assuming that hugepages are not migratable in your system, one usecase of +this parameter is that users can make hugepage pool more extensible by +enabling the allocation from ZONE_MOVABLE. This is because on ZONE_MOVABLE +page reclaim/migration/compaction work more and you can get contiguous +memory more likely. Note that using ZONE_MOVABLE for non-migratable +hugepages can do harm to other features like memory hotremove (because +memory hotremove expects that memory blocks on ZONE_MOVABLE are always +removable,) so it's a trade-off responsible for the users. ============================================================== diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 07f6fc468e17..dc69093a8ec4 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1225,7 +1225,7 @@ static struct ctl_table vm_table[] = { .data = &hugepages_treat_as_movable, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = hugetlb_treat_movable_handler, + .proc_handler = proc_dointvec, }, { .procname = "nr_overcommit_hugepages", diff --git a/mm/hugetlb.c b/mm/hugetlb.c index fb4293b93fd0..b49579c7f2a5 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -34,7 +34,6 @@ #include "internal.h" const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL; -static gfp_t htlb_alloc_mask = GFP_HIGHUSER; unsigned long hugepages_treat_as_movable; int hugetlb_max_hstate __read_mostly; @@ -539,6 +538,15 @@ static struct page *dequeue_huge_page_node(struct hstate *h, int nid) return page; } +/* Movability of hugepages depends on migration support. */ +static inline gfp_t htlb_alloc_mask(struct hstate *h) +{ + if (hugepages_treat_as_movable || hugepage_migration_support(h)) + return GFP_HIGHUSER_MOVABLE; + else + return GFP_HIGHUSER; +} + static struct page *dequeue_huge_page_vma(struct hstate *h, struct vm_area_struct *vma, unsigned long address, int avoid_reserve, @@ -568,11 +576,11 @@ static struct page *dequeue_huge_page_vma(struct hstate *h, retry_cpuset: cpuset_mems_cookie = get_mems_allowed(); zonelist = huge_zonelist(vma, address, - htlb_alloc_mask, &mpol, &nodemask); + htlb_alloc_mask(h), &mpol, &nodemask); for_each_zone_zonelist_nodemask(zone, z, zonelist, MAX_NR_ZONES - 1, nodemask) { - if (cpuset_zone_allowed_softwall(zone, htlb_alloc_mask)) { + if (cpuset_zone_allowed_softwall(zone, htlb_alloc_mask(h))) { page = dequeue_huge_page_node(h, zone_to_nid(zone)); if (page) { if (avoid_reserve) @@ -738,7 +746,7 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid) return NULL; page = alloc_pages_exact_node(nid, - htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE| + htlb_alloc_mask(h)|__GFP_COMP|__GFP_THISNODE| __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h)); if (page) { @@ -965,12 +973,12 @@ static struct page *alloc_buddy_huge_page(struct hstate *h, int nid) spin_unlock(&hugetlb_lock); if (nid == NUMA_NO_NODE) - page = alloc_pages(htlb_alloc_mask|__GFP_COMP| + page = alloc_pages(htlb_alloc_mask(h)|__GFP_COMP| __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h)); else page = alloc_pages_exact_node(nid, - htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE| + htlb_alloc_mask(h)|__GFP_COMP|__GFP_THISNODE| __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h)); if (page && arch_prepare_hugepage(page)) { @@ -2117,18 +2125,6 @@ int hugetlb_mempolicy_sysctl_handler(struct ctl_table *table, int write, } #endif /* CONFIG_NUMA */ -int hugetlb_treat_movable_handler(struct ctl_table *table, int write, - void __user *buffer, - size_t *length, loff_t *ppos) -{ - proc_dointvec(table, write, buffer, length, ppos); - if (hugepages_treat_as_movable) - htlb_alloc_mask = GFP_HIGHUSER_MOVABLE; - else - htlb_alloc_mask = GFP_HIGHUSER; - return 0; -} - int hugetlb_overcommit_handler(struct ctl_table *table, int write, void __user *buffer, size_t *length, loff_t *ppos) -- cgit v1.2.3-58-ga151 From d9104d1ca9662498339c0de975b4666c30485f4e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 11 Sep 2013 14:22:24 -0700 Subject: mm: track vma changes with VM_SOFTDIRTY bit Pavel reported that in case if vma area get unmapped and then mapped (or expanded) in-place, the soft dirty tracker won't be able to recognize this situation since it works on pte level and ptes are get zapped on unmap, loosing soft dirty bit of course. So to resolve this situation we need to track actions on vma level, there VM_SOFTDIRTY flag comes in. When new vma area created (or old expanded) we set this bit, and keep it here until application calls for clearing soft dirty bit. Thus when user space application track memory changes now it can detect if vma area is renewed. Reported-by: Pavel Emelyanov Signed-off-by: Cyrill Gorcunov Cc: Andy Lutomirski Cc: Matt Mackall Cc: Xiao Guangrong Cc: Marcelo Tosatti Cc: KOSAKI Motohiro Cc: Stephen Rothwell Cc: Peter Zijlstra Cc: "Aneesh Kumar K.V" Cc: Rob Landley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/soft-dirty.txt | 7 +++++++ fs/exec.c | 2 +- fs/proc/task_mmu.c | 46 ++++++++++++++++++++++++++++++++--------- include/linux/mm.h | 6 ++++++ mm/mmap.c | 12 ++++++++++- 5 files changed, 61 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/soft-dirty.txt b/Documentation/vm/soft-dirty.txt index 9a12a5956bc0..55684d11a1e8 100644 --- a/Documentation/vm/soft-dirty.txt +++ b/Documentation/vm/soft-dirty.txt @@ -28,6 +28,13 @@ This is so, since the pages are still mapped to physical memory, and thus all the kernel does is finds this fact out and puts both writable and soft-dirty bits on the PTE. + While in most cases tracking memory changes by #PF-s is more than enough +there is still a scenario when we can lose soft dirty bits -- a task +unmaps a previously mapped memory region and then maps a new one at exactly +the same place. When unmap is called, the kernel internally clears PTE values +including soft dirty bits. To notify user space application about such +memory region renewal the kernel always marks new memory regions (and +expanded regions) as soft dirty. This feature is actively used by the checkpoint-restore project. You can find more details about it on http://criu.org diff --git a/fs/exec.c b/fs/exec.c index fd774c7cb483..2d1e52a58fe9 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -266,7 +266,7 @@ static int __bprm_mm_init(struct linux_binprm *bprm) BUILD_BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP); vma->vm_end = STACK_TOP_MAX; vma->vm_start = vma->vm_end - PAGE_SIZE; - vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; + vma->vm_flags = VM_SOFTDIRTY | VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); INIT_LIST_HEAD(&vma->anon_vma_chain); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 107d026f5d6e..09228639b83d 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -740,6 +740,9 @@ static inline void clear_soft_dirty(struct vm_area_struct *vma, ptent = pte_file_clear_soft_dirty(ptent); } + if (vma->vm_flags & VM_SOFTDIRTY) + vma->vm_flags &= ~VM_SOFTDIRTY; + set_pte_at(vma->vm_mm, addr, pte, ptent); #endif } @@ -949,13 +952,15 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, if (is_migration_entry(entry)) page = migration_entry_to_page(entry); } else { - *pme = make_pme(PM_NOT_PRESENT(pm->v2)); + if (vma->vm_flags & VM_SOFTDIRTY) + flags2 |= __PM_SOFT_DIRTY; + *pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, flags2)); return; } if (page && !PageAnon(page)) flags |= PM_FILE; - if (pte_soft_dirty(pte)) + if ((vma->vm_flags & VM_SOFTDIRTY) || pte_soft_dirty(pte)) flags2 |= __PM_SOFT_DIRTY; *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags); @@ -974,7 +979,7 @@ static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *p *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset) | PM_STATUS2(pm->v2, pmd_flags2) | PM_PRESENT); else - *pme = make_pme(PM_NOT_PRESENT(pm->v2)); + *pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, pmd_flags2)); } #else static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, @@ -997,7 +1002,11 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, if (vma && pmd_trans_huge_lock(pmd, vma) == 1) { int pmd_flags2; - pmd_flags2 = (pmd_soft_dirty(*pmd) ? __PM_SOFT_DIRTY : 0); + if ((vma->vm_flags & VM_SOFTDIRTY) || pmd_soft_dirty(*pmd)) + pmd_flags2 = __PM_SOFT_DIRTY; + else + pmd_flags2 = 0; + for (; addr != end; addr += PAGE_SIZE) { unsigned long offset; @@ -1015,12 +1024,17 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, if (pmd_trans_unstable(pmd)) return 0; for (; addr != end; addr += PAGE_SIZE) { + int flags2; /* check to see if we've left 'vma' behind * and need a new, higher one */ if (vma && (addr >= vma->vm_end)) { vma = find_vma(walk->mm, addr); - pme = make_pme(PM_NOT_PRESENT(pm->v2)); + if (vma && (vma->vm_flags & VM_SOFTDIRTY)) + flags2 = __PM_SOFT_DIRTY; + else + flags2 = 0; + pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, flags2)); } /* check that 'vma' actually covers this address, @@ -1044,13 +1058,15 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, #ifdef CONFIG_HUGETLB_PAGE static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, - pte_t pte, int offset) + pte_t pte, int offset, int flags2) { if (pte_present(pte)) - *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) - | PM_STATUS2(pm->v2, 0) | PM_PRESENT); + *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) | + PM_STATUS2(pm->v2, flags2) | + PM_PRESENT); else - *pme = make_pme(PM_NOT_PRESENT(pm->v2)); + *pme = make_pme(PM_NOT_PRESENT(pm->v2) | + PM_STATUS2(pm->v2, flags2)); } /* This function walks within one hugetlb entry in the single call */ @@ -1059,12 +1075,22 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, struct mm_walk *walk) { struct pagemapread *pm = walk->private; + struct vm_area_struct *vma; int err = 0; + int flags2; pagemap_entry_t pme; + vma = find_vma(walk->mm, addr); + WARN_ON_ONCE(!vma); + + if (vma && (vma->vm_flags & VM_SOFTDIRTY)) + flags2 = __PM_SOFT_DIRTY; + else + flags2 = 0; + for (; addr != end; addr += PAGE_SIZE) { int offset = (addr & ~hmask) >> PAGE_SHIFT; - huge_pte_to_pagemap_entry(&pme, pm, *pte, offset); + huge_pte_to_pagemap_entry(&pme, pm, *pte, offset, flags2); err = add_to_pagemap(addr, &pme, pm); if (err) return err; diff --git a/include/linux/mm.h b/include/linux/mm.h index d2d59b4149d0..dce24569f8fc 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -115,6 +115,12 @@ extern unsigned int kobjsize(const void *objp); #define VM_ARCH_1 0x01000000 /* Architecture-specific flag */ #define VM_DONTDUMP 0x04000000 /* Do not include in the core dump */ +#ifdef CONFIG_MEM_SOFT_DIRTY +# define VM_SOFTDIRTY 0x08000000 /* Not soft dirty clean area */ +#else +# define VM_SOFTDIRTY 0 +#endif + #define VM_MIXEDMAP 0x10000000 /* Can contain "struct page" and pure PFN pages */ #define VM_HUGEPAGE 0x20000000 /* MADV_HUGEPAGE marked this vma */ #define VM_NOHUGEPAGE 0x40000000 /* MADV_NOHUGEPAGE marked this vma */ diff --git a/mm/mmap.c b/mm/mmap.c index 13926a5a6901..51958d192a48 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1609,6 +1609,15 @@ out: if (file) uprobe_mmap(vma); + /* + * New (or expanded) vma always get soft dirty status. + * Otherwise user-space soft-dirty page tracker won't + * be able to distinguish situation when vma area unmapped, + * then new mapped in-place (which must be aimed as + * a completely new data area). + */ + vma->vm_flags |= VM_SOFTDIRTY; + return addr; unmap_and_free_vma: @@ -2652,6 +2661,7 @@ out: mm->total_vm += len >> PAGE_SHIFT; if (flags & VM_LOCKED) mm->locked_vm += (len >> PAGE_SHIFT); + vma->vm_flags |= VM_SOFTDIRTY; return addr; } @@ -2916,7 +2926,7 @@ int install_special_mapping(struct mm_struct *mm, vma->vm_start = addr; vma->vm_end = addr + len; - vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND; + vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND | VM_SOFTDIRTY; vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); vma->vm_ops = &special_mapping_vmops; -- cgit v1.2.3-58-ga151 From 453b4c6db59f7f6411a0b5eb58389a1fa129cc9a Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 11 Sep 2013 14:24:17 -0700 Subject: rtc: add MOXA ART RTC driver Add RTC driver for MOXA ART SoCs. Signed-off-by: Jonas Jensen Reviewed-by: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- .../devicetree/bindings/rtc/moxa,moxart-rtc.txt | 17 ++ drivers/rtc/Kconfig | 9 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-moxart.c | 330 +++++++++++++++++++++ 4 files changed, 357 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt create mode 100644 drivers/rtc/rtc-moxart.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt b/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt new file mode 100644 index 000000000000..c9d3ac1477fe --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt @@ -0,0 +1,17 @@ +MOXA ART real-time clock + +Required properties: + +- compatible : Should be "moxa,moxart-rtc" +- gpio-rtc-sclk : RTC sclk gpio, with zero flags +- gpio-rtc-data : RTC data gpio, with zero flags +- gpio-rtc-reset : RTC reset gpio, with zero flags + +Example: + + rtc: rtc { + compatible = "moxa,moxart-rtc"; + gpio-rtc-sclk = <&gpio 5 0>; + gpio-rtc-data = <&gpio 6 0>; + gpio-rtc-reset = <&gpio 7 0>; + }; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9e3498bf302b..9654aa3c05cb 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1249,6 +1249,15 @@ config RTC_DRV_SIRFSOC Say "yes" here to support the real time clock on SiRF SOC chips. This driver can also be built as a module called rtc-sirfsoc. +config RTC_DRV_MOXART + tristate "MOXA ART RTC" + help + If you say yes here you get support for the MOXA ART + RTC module. + + This driver can also be built as a module. If so, the module + will be called rtc-moxart + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d3b4488f48f2..2dff3d2009b5 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -130,3 +130,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o +obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c new file mode 100644 index 000000000000..c29dee0946e6 --- /dev/null +++ b/drivers/rtc/rtc-moxart.c @@ -0,0 +1,330 @@ +/* + * MOXA ART RTC driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen + * + * Based on code from + * Moxa Technology Co., Ltd. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_RTC_RESERVED 0x0C +#define GPIO_RTC_DATA_SET 0x10 +#define GPIO_RTC_DATA_CLEAR 0x14 +#define GPIO_RTC_PIN_PULL_ENABLE 0x18 +#define GPIO_RTC_PIN_PULL_TYPE 0x1C +#define GPIO_RTC_INT_ENABLE 0x20 +#define GPIO_RTC_INT_RAW_STATE 0x24 +#define GPIO_RTC_INT_MASKED_STATE 0x28 +#define GPIO_RTC_INT_MASK 0x2C +#define GPIO_RTC_INT_CLEAR 0x30 +#define GPIO_RTC_INT_TRIGGER 0x34 +#define GPIO_RTC_INT_BOTH 0x38 +#define GPIO_RTC_INT_RISE_NEG 0x3C +#define GPIO_RTC_BOUNCE_ENABLE 0x40 +#define GPIO_RTC_BOUNCE_PRE_SCALE 0x44 +#define GPIO_RTC_PROTECT_W 0x8E +#define GPIO_RTC_PROTECT_R 0x8F +#define GPIO_RTC_YEAR_W 0x8C +#define GPIO_RTC_YEAR_R 0x8D +#define GPIO_RTC_DAY_W 0x8A +#define GPIO_RTC_DAY_R 0x8B +#define GPIO_RTC_MONTH_W 0x88 +#define GPIO_RTC_MONTH_R 0x89 +#define GPIO_RTC_DATE_W 0x86 +#define GPIO_RTC_DATE_R 0x87 +#define GPIO_RTC_HOURS_W 0x84 +#define GPIO_RTC_HOURS_R 0x85 +#define GPIO_RTC_MINUTES_W 0x82 +#define GPIO_RTC_MINUTES_R 0x83 +#define GPIO_RTC_SECONDS_W 0x80 +#define GPIO_RTC_SECONDS_R 0x81 +#define GPIO_RTC_DELAY_TIME 8 + +struct moxart_rtc { + struct rtc_device *rtc; + spinlock_t rtc_lock; + int gpio_data, gpio_sclk, gpio_reset; +}; + +static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334 }; + +static void moxart_rtc_write_byte(struct device *dev, u8 data) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + int i; + + for (i = 0; i < 8; i++, data >>= 1) { + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1)); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(moxart_rtc->gpio_sclk, 1); + udelay(GPIO_RTC_DELAY_TIME); + } +} + +static u8 moxart_rtc_read_byte(struct device *dev) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + int i; + u8 data = 0; + + for (i = 0; i < 8; i++) { + gpio_set_value(moxart_rtc->gpio_sclk, 0); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(moxart_rtc->gpio_sclk, 1); + udelay(GPIO_RTC_DELAY_TIME); + if (gpio_get_value(moxart_rtc->gpio_data)) + data |= (1 << i); + udelay(GPIO_RTC_DELAY_TIME); + } + return data; +} + +static u8 moxart_rtc_read_register(struct device *dev, u8 cmd) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + u8 data; + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(moxart_rtc->gpio_data, 0); + gpio_set_value(moxart_rtc->gpio_reset, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(dev, cmd); + gpio_direction_input(moxart_rtc->gpio_data); + udelay(GPIO_RTC_DELAY_TIME); + data = moxart_rtc_read_byte(dev); + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_reset, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); + + return data; +} + +static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(moxart_rtc->gpio_data, 0); + gpio_set_value(moxart_rtc->gpio_reset, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(dev, cmd); + moxart_rtc_write_byte(dev, data); + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_reset, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); +} + +static int moxart_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + + spin_lock_irq(&moxart_rtc->rtc_lock); + + moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0); + moxart_rtc_write_register(dev, GPIO_RTC_YEAR_W, + (((tm->tm_year - 100) / 10) << 4) | + ((tm->tm_year - 100) % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_MONTH_W, + (((tm->tm_mon + 1) / 10) << 4) | + ((tm->tm_mon + 1) % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_DATE_W, + ((tm->tm_mday / 10) << 4) | + (tm->tm_mday % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_HOURS_W, + ((tm->tm_hour / 10) << 4) | + (tm->tm_hour % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_MINUTES_W, + ((tm->tm_min / 10) << 4) | + (tm->tm_min % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_SECONDS_W, + ((tm->tm_sec / 10) << 4) | + (tm->tm_sec % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0x80); + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + dev_dbg(dev, "%s: success tm_year=%d tm_mon=%d\n" + "tm_mday=%d tm_hour=%d tm_min=%d tm_sec=%d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static int moxart_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + unsigned char v; + + spin_lock_irq(&moxart_rtc->rtc_lock); + + v = moxart_rtc_read_register(dev, GPIO_RTC_SECONDS_R); + tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_MINUTES_R); + tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_HOURS_R); + if (v & 0x80) { /* 12-hour mode */ + tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + if (v & 0x20) { /* PM mode */ + tm->tm_hour += 12; + if (tm->tm_hour >= 24) + tm->tm_hour = 0; + } + } else { /* 24-hour mode */ + tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + } + + v = moxart_rtc_read_register(dev, GPIO_RTC_DATE_R); + tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_MONTH_R); + tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + tm->tm_mon--; + + v = moxart_rtc_read_register(dev, GPIO_RTC_YEAR_R); + tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); + tm->tm_year += 100; + if (tm->tm_year <= 69) + tm->tm_year += 100; + + v = moxart_rtc_read_register(dev, GPIO_RTC_DAY_R); + tm->tm_wday = (v & 0x0f) - 1; + tm->tm_yday = day_of_year[tm->tm_mon]; + tm->tm_yday += (tm->tm_mday - 1); + if (tm->tm_mon >= 2) { + if (!(tm->tm_year % 4) && (tm->tm_year % 100)) + tm->tm_yday++; + } + + tm->tm_isdst = 0; + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + return 0; +} + +static const struct rtc_class_ops moxart_rtc_ops = { + .read_time = moxart_rtc_read_time, + .set_time = moxart_rtc_set_time, +}; + +static int moxart_rtc_probe(struct platform_device *pdev) +{ + struct moxart_rtc *moxart_rtc; + int ret = 0; + + moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL); + if (!moxart_rtc) { + dev_err(&pdev->dev, "devm_kzalloc failed\n"); + return -ENOMEM; + } + + moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-data", 0); + if (!gpio_is_valid(moxart_rtc->gpio_data)) { + dev_err(&pdev->dev, "invalid gpio (data): %d\n", + moxart_rtc->gpio_data); + return moxart_rtc->gpio_data; + } + + moxart_rtc->gpio_sclk = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-sclk", 0); + if (!gpio_is_valid(moxart_rtc->gpio_sclk)) { + dev_err(&pdev->dev, "invalid gpio (sclk): %d\n", + moxart_rtc->gpio_sclk); + return moxart_rtc->gpio_sclk; + } + + moxart_rtc->gpio_reset = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-reset", 0); + if (!gpio_is_valid(moxart_rtc->gpio_reset)) { + dev_err(&pdev->dev, "invalid gpio (reset): %d\n", + moxart_rtc->gpio_reset); + return moxart_rtc->gpio_reset; + } + + spin_lock_init(&moxart_rtc->rtc_lock); + platform_set_drvdata(pdev, moxart_rtc); + + ret = devm_gpio_request(&pdev->dev, moxart_rtc->gpio_data, "rtc_data"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_data gpio\n"); + return ret; + } + + ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk, + GPIOF_DIR_OUT, "rtc_sclk"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_sclk gpio\n"); + return ret; + } + + ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset, + GPIOF_DIR_OUT, "rtc_reset"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_reset gpio\n"); + return ret; + } + + moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &moxart_rtc_ops, + THIS_MODULE); + if (IS_ERR(moxart_rtc->rtc)) { + dev_err(&pdev->dev, "devm_rtc_device_register failed\n"); + return PTR_ERR(moxart_rtc->rtc); + } + + return 0; +} + +static const struct of_device_id moxart_rtc_match[] = { + { .compatible = "moxa,moxart-rtc" }, + { }, +}; + +static struct platform_driver moxart_rtc_driver = { + .probe = moxart_rtc_probe, + .driver = { + .name = "moxart-rtc", + .owner = THIS_MODULE, + .of_match_table = moxart_rtc_match, + }, +}; +module_platform_driver(moxart_rtc_driver); + +MODULE_DESCRIPTION("MOXART RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Jensen "); -- cgit v1.2.3-58-ga151 From 8af750e3f5ca21eaa5595a96a4cf5eaa996deed4 Mon Sep 17 00:00:00 2001 From: Hebbar Gururaja Date: Wed, 11 Sep 2013 14:24:18 -0700 Subject: drivers/rtc/rtc-omap.c: add rtc wakeup support to alarm events On some platforms (like AM33xx), a special register (RTC_IRQWAKEEN) is available to enable Alarm Wakeup feature. This register needs to be properly handled for the rtcwake to work properly. Platforms using such IP should set "ti,am3352-rtc" in rtc device dt compatibility node. Signed-off-by: Hebbar Gururaja Acked-by: Kevin Hilman Acked-by: Sekhar Nori Cc: Grant Likely Cc: Rob Herring Cc: Rob Landley Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/devicetree/bindings/rtc/rtc-omap.txt | 6 ++- drivers/rtc/rtc-omap.c | 60 +++++++++++++++++++--- 2 files changed, 57 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/rtc-omap.txt b/Documentation/devicetree/bindings/rtc/rtc-omap.txt index b47aa415c820..5a0f02d34d95 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-omap.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-omap.txt @@ -1,7 +1,11 @@ TI Real Time Clock Required properties: -- compatible: "ti,da830-rtc" +- compatible: + - "ti,da830-rtc" - for RTC IP used similar to that on DA8xx SoC family. + - "ti,am3352-rtc" - for RTC IP used similar to that on AM335x SoC family. + This RTC IP has special WAKE-EN Register to enable + Wakeup generation for event Alarm. - reg: Address range of rtc register set - interrupts: rtc timer, alarm interrupts in order - interrupt-parent: phandle for the interrupt controller diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index c6ffbaec32a4..c7d97ee59327 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -70,6 +70,8 @@ #define OMAP_RTC_KICK0_REG 0x6c #define OMAP_RTC_KICK1_REG 0x70 +#define OMAP_RTC_IRQWAKEEN 0x7c + /* OMAP_RTC_CTRL_REG bit fields: */ #define OMAP_RTC_CTRL_SPLIT (1<<7) #define OMAP_RTC_CTRL_DISABLE (1<<6) @@ -94,12 +96,21 @@ #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) +/* OMAP_RTC_IRQWAKEEN bit fields: */ +#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN (1<<1) + /* OMAP_RTC_KICKER values */ #define KICK0_VALUE 0x83e70b13 #define KICK1_VALUE 0x95a4f1e0 #define OMAP_RTC_HAS_KICKER 0x1 +/* + * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup + * generation for event Alarm. + */ +#define OMAP_RTC_HAS_IRQWAKEEN 0x2 + static void __iomem *rtc_base; #define rtc_read(addr) readb(rtc_base + (addr)) @@ -299,12 +310,18 @@ static struct rtc_class_ops omap_rtc_ops = { static int omap_rtc_alarm; static int omap_rtc_timer; -#define OMAP_RTC_DATA_DA830_IDX 1 +#define OMAP_RTC_DATA_AM3352_IDX 1 +#define OMAP_RTC_DATA_DA830_IDX 2 static struct platform_device_id omap_rtc_devtype[] = { { .name = DRIVER_NAME, - }, { + }, + [OMAP_RTC_DATA_AM3352_IDX] = { + .name = "am3352-rtc", + .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN, + }, + [OMAP_RTC_DATA_DA830_IDX] = { .name = "da830-rtc", .driver_data = OMAP_RTC_HAS_KICKER, }, @@ -316,6 +333,9 @@ static const struct of_device_id omap_rtc_of_match[] = { { .compatible = "ti,da830-rtc", .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], }, + { .compatible = "ti,am3352-rtc", + .data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX], + }, {}, }; MODULE_DEVICE_TABLE(of, omap_rtc_of_match); @@ -464,16 +484,28 @@ static u8 irqstat; static int omap_rtc_suspend(struct device *dev) { + u8 irqwake_stat; + struct platform_device *pdev = to_platform_device(dev); + const struct platform_device_id *id_entry = + platform_get_device_id(pdev); + irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG); /* FIXME the RTC alarm is not currently acting as a wakeup event - * source, and in fact this enable() call is just saving a flag - * that's never used... + * source on some platforms, and in fact this enable() call is just + * saving a flag that's never used... */ - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev)) { enable_irq_wake(omap_rtc_alarm); - else + + if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { + irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); + irqwake_stat |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; + rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); + } + } else { rtc_write(0, OMAP_RTC_INTERRUPTS_REG); + } /* Disable the clock/module */ pm_runtime_put_sync(dev); @@ -483,13 +515,25 @@ static int omap_rtc_suspend(struct device *dev) static int omap_rtc_resume(struct device *dev) { + u8 irqwake_stat; + struct platform_device *pdev = to_platform_device(dev); + const struct platform_device_id *id_entry = + platform_get_device_id(pdev); + /* Enable the clock/module so that we can access the registers */ pm_runtime_get_sync(dev); - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev)) { disable_irq_wake(omap_rtc_alarm); - else + + if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { + irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); + irqwake_stat &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; + rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); + } + } else { rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG); + } return 0; } #endif -- cgit v1.2.3-58-ga151 From 666a584d3a765a914642f80deef7a33fb309df5d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 11 Sep 2013 14:24:19 -0700 Subject: drivers/rtc/rtc-palmas.c: support for backup battery charging Palmas series device like TPS65913, TPS80036 supports the backup battery for powering the RTC when no other energy source is available. The backup battery is optional, connected to the VBACKUP pin, and can be nonrechargeable or rechargeable. The rechargeable battery can be charged from the system supply using the backup battery charger. Add support for enabling charging of this backup battery. Also add the DT binding document and the new properties to have this support. Signed-off-by: Laxman Dewangan Reviewed-by: Felipe Balbi Acked-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- .../devicetree/bindings/rtc/rtc-palmas.txt | 33 ++++++++++++++++++++ drivers/rtc/rtc-palmas.c | 35 ++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/rtc-palmas.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/rtc/rtc-palmas.txt b/Documentation/devicetree/bindings/rtc/rtc-palmas.txt new file mode 100644 index 000000000000..adbccc0a51e1 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-palmas.txt @@ -0,0 +1,33 @@ +Palmas RTC controller bindings + +Required properties: +- compatible: + - "ti,palmas-rtc" for palma series of the RTC controller +- interrupt-parent: Parent interrupt device, must be handle of palmas node. +- interrupts: Interrupt number of RTC submodule on device. + +Optional properties: + +- ti,backup-battery-chargeable: The Palmas series device like TPS65913 or + TPS80036 supports the backup battery for powering the RTC when main + battery is removed or in very low power state. The backup battery + can be chargeable or non-chargeable. This flag will tells whether + battery is chargeable or not. If charging battery then driver can + enable the charging. +- ti,backup-battery-charge-high-current: Enable high current charging in + backup battery. Device supports the < 100mA and > 100mA charging. + The high current will be > 100mA. Absence of this property will + charge battery to lower current i.e. < 100mA. + +Example: + palmas: tps65913@58 { + ... + palmas_rtc: rtc { + compatible = "ti,palmas-rtc"; + interrupt-parent = <&palmas>; + interrupts = <8 0>; + ti,backup-battery-chargeable; + ti,backup-battery-charge-high-current; + }; + ... + }; diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index a1fecc8d97fc..fffb7d3449d7 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -238,6 +238,15 @@ static int palmas_rtc_probe(struct platform_device *pdev) struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_rtc *palmas_rtc = NULL; int ret; + bool enable_bb_charging = false; + bool high_bb_charging; + + if (pdev->dev.of_node) { + enable_bb_charging = of_property_read_bool(pdev->dev.of_node, + "ti,backup-battery-chargeable"); + high_bb_charging = of_property_read_bool(pdev->dev.of_node, + "ti,backup-battery-charge-high-current"); + } palmas_rtc = devm_kzalloc(&pdev->dev, sizeof(struct palmas_rtc), GFP_KERNEL); @@ -254,6 +263,32 @@ static int palmas_rtc_probe(struct platform_device *pdev) palmas_rtc->dev = &pdev->dev; platform_set_drvdata(pdev, palmas_rtc); + if (enable_bb_charging) { + unsigned reg = PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG; + + if (high_bb_charging) + reg = 0; + + ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, + PALMAS_BACKUP_BATTERY_CTRL, + PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG, reg); + if (ret < 0) { + dev_err(&pdev->dev, + "BACKUP_BATTERY_CTRL update failed, %d\n", ret); + return ret; + } + + ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, + PALMAS_BACKUP_BATTERY_CTRL, + PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN, + PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN); + if (ret < 0) { + dev_err(&pdev->dev, + "BACKUP_BATTERY_CTRL update failed, %d\n", ret); + return ret; + } + } + /* Start RTC */ ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG, PALMAS_RTC_CTRL_REG_STOP_RTC, -- cgit v1.2.3-58-ga151 From 65aafb1e7484b7434a0c1d4c593191ebe5776a2f Mon Sep 17 00:00:00 2001 From: Stéphane Graber Date: Wed, 11 Sep 2013 14:24:32 -0700 Subject: coredump: add new %P variable in core_pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new %P variable to be used in core_pattern. This variable contains the global PID (PID in the init namespace) as %p contains the PID in the current namespace which isn't always what we want. The main use for this is to make it easier to handle crashes that happened within a container. With that new variables it's possible to have the crashes dumped into the container or forwarded to the host with the right PID (from the host's point of view). Signed-off-by: Stéphane Graber Reported-by: Hans Feldt Cc: Alexander Viro Cc: Eric W. Biederman Cc: Andy Whitcroft Acked-by: Serge E. Hallyn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/kernel.txt | 1 + fs/coredump.c | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index ab7d16efa96b..9d4c1d18ad44 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -182,6 +182,7 @@ core_pattern is used to specify a core dumpfile pattern name. % '%' is dropped %% output one '%' %p pid + %P global pid (init PID namespace) %u uid %g gid %d dump mode, matches PR_SET_DUMPABLE and diff --git a/fs/coredump.c b/fs/coredump.c index 72f816d6cad9..9bdeca12ae0e 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -190,6 +190,11 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm) err = cn_printf(cn, "%d", task_tgid_vnr(current)); break; + /* global pid */ + case 'P': + err = cn_printf(cn, "%d", + task_tgid_nr(current)); + break; /* uid */ case 'u': err = cn_printf(cn, "%d", cred->uid); -- cgit v1.2.3-58-ga151 From 4649602265495a3bb776d777c91dba569f4afb5d Mon Sep 17 00:00:00 2001 From: Minto Joseph Date: Wed, 11 Sep 2013 14:24:35 -0700 Subject: Documentation/filesystems/proc.txt: fix mistake in the description of Committed_AS Fix mistake in the description of Committed_AS in kernel documentation. Signed-off-by: Minto Joseph Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/proc.txt | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index fcc22c982a25..823c95faebd2 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -854,16 +854,15 @@ Committed_AS: The amount of memory presently allocated on the system. The committed memory is a sum of all of the memory which has been allocated by processes, even if it has not been "used" by them as of yet. A process which malloc()'s 1G - of memory, but only touches 300M of it will only show up - as using 300M of memory even if it has the address space - allocated for the entire 1G. This 1G is memory which has - been "committed" to by the VM and can be used at any time - by the allocating application. With strict overcommit - enabled on the system (mode 2 in 'vm.overcommit_memory'), - allocations which would exceed the CommitLimit (detailed - above) will not be permitted. This is useful if one needs - to guarantee that processes will not fail due to lack of - memory once that memory has been successfully allocated. + of memory, but only touches 300M of it will show up as + using 1G. This 1G is memory which has been "committed" to + by the VM and can be used at any time by the allocating + application. With strict overcommit enabled on the system + (mode 2 in 'vm.overcommit_memory'),allocations which would + exceed the CommitLimit (detailed above) will not be permitted. + This is useful if one needs to guarantee that processes will + not fail due to lack of memory once that memory has been + successfully allocated. VmallocTotal: total size of vmalloc memory area VmallocUsed: amount of vmalloc area which is used VmallocChunk: largest contiguous block of vmalloc area which is free -- cgit v1.2.3-58-ga151 From 5173b414e42cb81e764f5e92a2f143e9a84fa3d1 Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 11 Sep 2013 14:25:47 -0700 Subject: aoe: remove do-nothing NAME="%k" term from example udev rules When the example udev rules in the documentation are used without modification, warnings like the one shown below appear in the system logs: /var/log/messages:Aug 22 11:09:11 kung udevd[445]: NAME="%k" \ is superfluous and breaks kernel supplied names, please remove \ it from /etc/udev/rules.d/60-aoe.rules:26 Removing the term does not cause any problems with the creation of the special character and block device nodes. Signed-off-by: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/aoe/udev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/aoe/udev.txt b/Documentation/aoe/udev.txt index 8686e789542e..1f06daf03f5b 100644 --- a/Documentation/aoe/udev.txt +++ b/Documentation/aoe/udev.txt @@ -23,4 +23,4 @@ SUBSYSTEM=="aoe", KERNEL=="revalidate", NAME="etherd/%k", GROUP="disk", MODE="02 SUBSYSTEM=="aoe", KERNEL=="flush", NAME="etherd/%k", GROUP="disk", MODE="0220" # aoe block devices -KERNEL=="etherd*", NAME="%k", GROUP="disk" +KERNEL=="etherd*", GROUP="disk" -- cgit v1.2.3-58-ga151 From 6e19eded3684dc184181093af3bff2ff440f5b53 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Wed, 11 Sep 2013 14:26:13 -0700 Subject: initmpfs: use initramfs if rootfstype= or root= specified Command line option rootfstype=ramfs to obtain old initramfs behavior, and use ramfs instead of tmpfs for stub when root= defined (for cosmetic reasons). [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Rob Landley Cc: Jeff Layton Cc: Jens Axboe Cc: Stephen Warren Cc: Rusty Russell Cc: Jim Cromie Cc: Sam Ravnborg Cc: Greg Kroah-Hartman Cc: "Eric W. Biederman" Cc: Alexander Viro Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/ramfs-rootfs-initramfs.txt | 4 ++++ init/do_mounts.c | 15 +++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/ramfs-rootfs-initramfs.txt b/Documentation/filesystems/ramfs-rootfs-initramfs.txt index 59b4a0962e0f..b176928e6963 100644 --- a/Documentation/filesystems/ramfs-rootfs-initramfs.txt +++ b/Documentation/filesystems/ramfs-rootfs-initramfs.txt @@ -79,6 +79,10 @@ to just make sure certain lists can't become empty. Most systems just mount another filesystem over rootfs and ignore it. The amount of space an empty instance of ramfs takes up is tiny. +If CONFIG_TMPFS is enabled, rootfs will use tmpfs instead of ramfs by +default. To force ramfs, add "rootfstype=ramfs" to the kernel command +line. + What is initramfs? ------------------ diff --git a/init/do_mounts.c b/init/do_mounts.c index e27908b949d4..a51cddc2ff8c 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -591,16 +591,20 @@ out: sys_chroot("."); } +static bool is_tmpfs; static struct dentry *rootfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { static unsigned long once; + void *fill = ramfs_fill_super; if (test_and_set_bit(0, &once)) return ERR_PTR(-ENODEV); - return mount_nodev(fs_type, flags, data, - IS_ENABLED(CONFIG_TMPFS) ? shmem_fill_super : ramfs_fill_super); + if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs) + fill = shmem_fill_super; + + return mount_nodev(fs_type, flags, data, fill); } static struct file_system_type rootfs_fs_type = { @@ -616,10 +620,13 @@ int __init init_rootfs(void) if (err) return err; - if (IS_ENABLED(CONFIG_TMPFS)) + if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] && + (!root_fs_names || strstr(root_fs_names, "tmpfs"))) { err = shmem_init(); - else + is_tmpfs = true; + } else { err = init_ramfs_fs(); + } if (err) unregister_filesystem(&rootfs_fs_type); -- cgit v1.2.3-58-ga151