* Re: [PATCH 0/9] dma_debug: add debug_dma_mapping_error support to architectures that support DMA_DEB
From: Marek Szyprowski @ 2012-12-03 8:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121202140644.GP30633@8bytes.org>
On 12/2/2012 3:06 PM, Joerg Roedel wrote:
> Hi Marek,
>
> On Mon, Nov 26, 2012 at 11:57:19AM +0100, Marek Szyprowski wrote:
>
> > I've took all the patches to the next-dma-debug branch in my tree, I sorry
> > that You have to wait so long for it. My branch is based on Joerg's
> > dma-debug branch and I've included it for testing in linux-next branch.
>
> The patches are now two times in next. One version from my tree and one
> from yours. Please remove the version from your tree, the patches should
> go upstream via my dma-debug branch.
Ok, I've removed them from my dma-mapping-next tree. Please add/cherry-pick
the missing patch for ARM architecture, which I've accidentally already
pushed to mainline some time ago and then reverted. See commit
871ae57adc5ed092 (and 697575896670ba).
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
^ permalink raw reply
* RE: [PATCH 3.7] dma: sh: Don't use ENODEV for failing slave lookup
From: Koul, Vinod @ 2012-12-03 17:48 UTC (permalink / raw)
To: Guennadi Liakhovetski, linux-kernel@vger.kernel.org
Cc: linux-sh@vger.kernel.org, Kuninori Morimoto
In-Reply-To: <Pine.LNX.4.64.1211280740190.32652@axis700.grange>
>
> If dmaengine driver's .device_alloc_chan_resources() method returns -ENODEV,
> dma_request_channel() will decide, that the driver has been removed and will remove
> the device from its list. To prevent this use ENXIO if a slave lookup fails.
>
> Reported-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Applied thanks, CCed stable as well
--
~Vinod
^ permalink raw reply
* Re: [PATCH] mmc: sh_mobile_sdhi: fix clock frequency printing
From: Chris Ball @ 2012-12-03 19:21 UTC (permalink / raw)
To: Simon Horman; +Cc: Guennadi Liakhovetski, linux-mmc, linux-sh
In-Reply-To: <20121130090238.GH4501@verge.net.au>
Hi,
On Fri, Nov 30 2012, Simon Horman wrote:
> On Wed, Nov 28, 2012 at 10:24:13AM +0100, Guennadi Liakhovetski wrote:
>> During its probing the SDHI driver prints out the clock frequency, but
>> does it wrongly, always reporting 0Hz. Use the MMC host frequency value
>> to fix this issue.
>>
>> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
>
> Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
Thanks, pushed to mmc-next for 3.8.
- Chris.
--
Chris Ball <cjb@laptop.org> <http://printf.net/>
One Laptop Per Child
^ permalink raw reply
* Re: [PATCH] mmc: sh_mobile_sdhi: remove unneeded clock connection ID
From: Chris Ball @ 2012-12-03 19:23 UTC (permalink / raw)
To: Simon Horman; +Cc: Guennadi Liakhovetski, linux-mmc, linux-sh
In-Reply-To: <20121130085903.GF4501@verge.net.au>
Hi,
On Fri, Nov 30 2012, Simon Horman wrote:
> On Wed, Nov 28, 2012 at 10:24:21AM +0100, Guennadi Liakhovetski wrote:
>> SDHI only uses one clock, all ARM and SuperH platform register SDHI clock
>> lookup entries with no connection ID, hence it can be dropped in the
>> driver too.
>>
>> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
>
> Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
Thanks, pushed to mmc-next for 3.8.
- Chris.
--
Chris Ball <cjb@laptop.org> <http://printf.net/>
One Laptop Per Child
^ permalink raw reply
* Re: [PATCH] mmc: sh_mmcif: remove unneeded clock connection ID
From: Chris Ball @ 2012-12-03 19:24 UTC (permalink / raw)
To: Simon Horman; +Cc: Guennadi Liakhovetski, linux-mmc, linux-sh
In-Reply-To: <20121130090224.GG4501@verge.net.au>
Hi,
On Fri, Nov 30 2012, Simon Horman wrote:
> On Wed, Nov 28, 2012 at 10:24:27AM +0100, Guennadi Liakhovetski wrote:
>> MMCIF only uses one clock, all ARM and SuperH platforms register MMCIF
>> clock lookup entries with no connection ID, hence it can be dropped in
>> the driver too.
>>
>> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
>
> Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
Thanks, pushed to mmc-next for 3.8.
- Chris.
--
Chris Ball <cjb@laptop.org> <http://printf.net/>
One Laptop Per Child
^ permalink raw reply
* Re: [PATCH shmobile/DT 1/2] ARM: shmobile: Remove some of_sh_intc_* functions
From: Simon Horman @ 2012-12-04 5:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1353572619-29098-1-git-send-email-nobuhiro.iwamatsu.yj@renesas.com>
On Thu, Nov 22, 2012 at 05:23:38PM +0900, Nobuhiro Iwamatsu wrote:
> This removes of_sh_intc_get_meminfo, of_sh_intc_get_pint and of_sh_intc_get_intc functions.
> These are not already used.
Hi Iwamatsu-san,
these patches are for Paul, right?
>
> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
> ---
> drivers/sh/intc/of_intc.c | 76 ---------------------------------------------
> include/linux/sh_intc.h | 28 -----------------
> 2 files changed, 104 deletions(-)
>
> diff --git a/drivers/sh/intc/of_intc.c b/drivers/sh/intc/of_intc.c
> index 30b1090..e833e48 100644
> --- a/drivers/sh/intc/of_intc.c
> +++ b/drivers/sh/intc/of_intc.c
> @@ -529,49 +529,6 @@ void __init of_sh_intc_get_skip_syscore_suspend(struct device_node *np,
> d->skip_syscore_suspend = false;
> }
>
> -int __init of_sh_intc_get_meminfo(struct device_node *np,
> - struct resource *res, int res_no)
> -{
> - int ret = 0, i;
> -
> - for (i = 0 ; i < res_no ; i++) {
> - ret = of_address_to_resource(np, i, &res[i]);
> - if (ret) {
> - pr_err("could not determine device base address\n");
> - return ret;
> - }
> -
> - pr_debug("%s: Address 0x%x, size %d\n",
> - __func__, res[i].start, resource_size(&res[i]));
> - }
> -
> - return ret;
> -}
> -
> -int __init of_sh_intc_get_pint(struct device_node *np, struct intc_desc *d)
> -{
> - /* pint uses vector, mask and sence. */
> - int ret = of_sh_intc_get_vector(np, &d->hw.vectors,
> - &d->hw.nr_vectors);
> - if (ret)
> - return ret;
> -
> - ret = of_sh_intc_get_mask(np, &d->hw.mask_regs,
> - &d->hw.nr_mask_regs);
> - if (ret)
> - return ret;
> -
> - ret = of_sh_intc_get_sense(np, &d->hw.sense_regs,
> - &d->hw.nr_sense_regs);
> - /* INTC may not need Sence register. */
> - if (ret && ret != -ENOENT)
> - return ret;
> -
> - d->of_node = np;
> -
> - return 0;
> -}
> -
> int __init of_sh_intc_get_intc(struct device_node *np, struct intc_desc *d)
> {
> int ret = of_sh_intc_get_vector(np, &d->hw.vectors,
> @@ -611,36 +568,3 @@ int __init of_sh_intc_get_intc(struct device_node *np, struct intc_desc *d)
>
> return 0;
> }
> -
> -int __init of_sh_intc_get_intc_pins(struct device_node *np,
> - struct intc_desc *d)
> -{
> - int ret = of_sh_intc_get_vector(np, &d->hw.vectors,
> - &d->hw.nr_vectors);
> - if (ret)
> - return ret;
> -
> - ret = of_sh_intc_get_mask(np, &d->hw.mask_regs,
> - &d->hw.nr_mask_regs);
> - if (ret)
> - return ret;
> -
> - ret = of_sh_intc_get_prio(np, &d->hw.prio_regs,
> - &d->hw.nr_prio_regs);
> - if (ret)
> - return ret;
> -
> - ret = of_sh_intc_get_sense(np, &d->hw.sense_regs,
> - &d->hw.nr_sense_regs);
> - if (ret)
> - return ret;
> -
> - ret = of_sh_intc_get_ack(np, &d->hw.ack_regs,
> - &d->hw.nr_ack_regs);
> - if (ret)
> - return ret;
> -
> - d->of_node = np;
> -
> - return 0;
> -}
> diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
> index 6603da6..c7954ee 100644
> --- a/include/linux/sh_intc.h
> +++ b/include/linux/sh_intc.h
> @@ -161,26 +161,6 @@ static inline int register_intc_userimask(unsigned long addr)
> int of_sh_intc_get_intc(struct device_node *np, struct intc_desc *d);
>
> /*
> - * of_sh_initc_get_intc_pins() - Get INTC Pins table.
> - * @np: device node to get INTC from
> - * @d: a pointer of intc pins table
> - *
> - * Return: one of the errno value on the error condition
> - */
> -int of_sh_intc_get_intc_pins(struct device_node *np, struct intc_desc *d);
> -
> -/*
> - * of_sh_intc_get_meminfo() - Get and set INTC register of memory.
> - * @np: device node to get INTC from
> - * @res_mem: a pointer of resource
> - * @res_no: resource number
> - *
> - * Return: one of the errno value on the error condition
> - */
> -int of_sh_intc_get_meminfo(struct device_node *np,
> - struct resource *res_mem, int resno);
> -
> -/*
> * of_sh_intc_get_force_enable - Get and set force_enable vector in
> * struct intc_desc.
> * @np: device node to get INTC from
> @@ -221,13 +201,5 @@ void of_sh_intc_get_skip_syscore_suspend(struct device_node *np,
> * Return: one of the errno value on the error condition
> */
> int of_sh_intc_get_intevtsa_vect(struct device_node *np, unsigned short *vect);
> -/*
> - * of_sh_initc_get_intc_pint() - Get INTC Pint table.
> - * @np: device node to get INTC from
> - * @d: a pointer of intc pint table
> - *
> - * Return: one of the errno value on the error condition
> - */
> -int of_sh_intc_get_pint(struct device_node *np, struct intc_desc *d);
>
> #endif /* __SH_INTC_H */
> --
> 1.7.10.4
>
^ permalink raw reply
* Re: [PATCH shmobile/DT 1/2] ARM: shmobile: Remove some of_sh_intc_* functions
From: Nobuhiro Iwamatsu @ 2012-12-04 7:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121204055029.GC15969@verge.net.au>
Hi,
No, These patches are to devel/dt of your repository.
Best regards,
Nobuhiro
On Tue, Dec 4, 2012 at 2:50 PM, Simon Horman <horms@verge.net.au> wrote:
> On Thu, Nov 22, 2012 at 05:23:38PM +0900, Nobuhiro Iwamatsu wrote:
>> This removes of_sh_intc_get_meminfo, of_sh_intc_get_pint and of_sh_intc_get_intc functions.
>> These are not already used.
>
> Hi Iwamatsu-san,
>
> these patches are for Paul, right?
>
>>
>> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
>> ---
>> drivers/sh/intc/of_intc.c | 76 ---------------------------------------------
>> include/linux/sh_intc.h | 28 -----------------
>> 2 files changed, 104 deletions(-)
>>
>> diff --git a/drivers/sh/intc/of_intc.c b/drivers/sh/intc/of_intc.c
>> index 30b1090..e833e48 100644
>> --- a/drivers/sh/intc/of_intc.c
>> +++ b/drivers/sh/intc/of_intc.c
>> @@ -529,49 +529,6 @@ void __init of_sh_intc_get_skip_syscore_suspend(struct device_node *np,
>> d->skip_syscore_suspend = false;
>> }
>>
>> -int __init of_sh_intc_get_meminfo(struct device_node *np,
>> - struct resource *res, int res_no)
>> -{
>> - int ret = 0, i;
>> -
>> - for (i = 0 ; i < res_no ; i++) {
>> - ret = of_address_to_resource(np, i, &res[i]);
>> - if (ret) {
>> - pr_err("could not determine device base address\n");
>> - return ret;
>> - }
>> -
>> - pr_debug("%s: Address 0x%x, size %d\n",
>> - __func__, res[i].start, resource_size(&res[i]));
>> - }
>> -
>> - return ret;
>> -}
>> -
>> -int __init of_sh_intc_get_pint(struct device_node *np, struct intc_desc *d)
>> -{
>> - /* pint uses vector, mask and sence. */
>> - int ret = of_sh_intc_get_vector(np, &d->hw.vectors,
>> - &d->hw.nr_vectors);
>> - if (ret)
>> - return ret;
>> -
>> - ret = of_sh_intc_get_mask(np, &d->hw.mask_regs,
>> - &d->hw.nr_mask_regs);
>> - if (ret)
>> - return ret;
>> -
>> - ret = of_sh_intc_get_sense(np, &d->hw.sense_regs,
>> - &d->hw.nr_sense_regs);
>> - /* INTC may not need Sence register. */
>> - if (ret && ret != -ENOENT)
>> - return ret;
>> -
>> - d->of_node = np;
>> -
>> - return 0;
>> -}
>> -
>> int __init of_sh_intc_get_intc(struct device_node *np, struct intc_desc *d)
>> {
>> int ret = of_sh_intc_get_vector(np, &d->hw.vectors,
>> @@ -611,36 +568,3 @@ int __init of_sh_intc_get_intc(struct device_node *np, struct intc_desc *d)
>>
>> return 0;
>> }
>> -
>> -int __init of_sh_intc_get_intc_pins(struct device_node *np,
>> - struct intc_desc *d)
>> -{
>> - int ret = of_sh_intc_get_vector(np, &d->hw.vectors,
>> - &d->hw.nr_vectors);
>> - if (ret)
>> - return ret;
>> -
>> - ret = of_sh_intc_get_mask(np, &d->hw.mask_regs,
>> - &d->hw.nr_mask_regs);
>> - if (ret)
>> - return ret;
>> -
>> - ret = of_sh_intc_get_prio(np, &d->hw.prio_regs,
>> - &d->hw.nr_prio_regs);
>> - if (ret)
>> - return ret;
>> -
>> - ret = of_sh_intc_get_sense(np, &d->hw.sense_regs,
>> - &d->hw.nr_sense_regs);
>> - if (ret)
>> - return ret;
>> -
>> - ret = of_sh_intc_get_ack(np, &d->hw.ack_regs,
>> - &d->hw.nr_ack_regs);
>> - if (ret)
>> - return ret;
>> -
>> - d->of_node = np;
>> -
>> - return 0;
>> -}
>> diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
>> index 6603da6..c7954ee 100644
>> --- a/include/linux/sh_intc.h
>> +++ b/include/linux/sh_intc.h
>> @@ -161,26 +161,6 @@ static inline int register_intc_userimask(unsigned long addr)
>> int of_sh_intc_get_intc(struct device_node *np, struct intc_desc *d);
>>
>> /*
>> - * of_sh_initc_get_intc_pins() - Get INTC Pins table.
>> - * @np: device node to get INTC from
>> - * @d: a pointer of intc pins table
>> - *
>> - * Return: one of the errno value on the error condition
>> - */
>> -int of_sh_intc_get_intc_pins(struct device_node *np, struct intc_desc *d);
>> -
>> -/*
>> - * of_sh_intc_get_meminfo() - Get and set INTC register of memory.
>> - * @np: device node to get INTC from
>> - * @res_mem: a pointer of resource
>> - * @res_no: resource number
>> - *
>> - * Return: one of the errno value on the error condition
>> - */
>> -int of_sh_intc_get_meminfo(struct device_node *np,
>> - struct resource *res_mem, int resno);
>> -
>> -/*
>> * of_sh_intc_get_force_enable - Get and set force_enable vector in
>> * struct intc_desc.
>> * @np: device node to get INTC from
>> @@ -221,13 +201,5 @@ void of_sh_intc_get_skip_syscore_suspend(struct device_node *np,
>> * Return: one of the errno value on the error condition
>> */
>> int of_sh_intc_get_intevtsa_vect(struct device_node *np, unsigned short *vect);
>> -/*
>> - * of_sh_initc_get_intc_pint() - Get INTC Pint table.
>> - * @np: device node to get INTC from
>> - * @d: a pointer of intc pint table
>> - *
>> - * Return: one of the errno value on the error condition
>> - */
>> -int of_sh_intc_get_pint(struct device_node *np, struct intc_desc *d);
>>
>> #endif /* __SH_INTC_H */
>> --
>> 1.7.10.4
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Nobuhiro Iwamatsu
^ permalink raw reply
* Re: [Patch v4 08/12] memory-hotplug: remove memmap of sparse-vmemmap
From: Tang Chen @ 2012-12-04 9:13 UTC (permalink / raw)
To: Jianguo Wu
Cc: Wen Congyang, x86, linux-mm, linux-kernel, linuxppc-dev,
linux-acpi, linux-s390, linux-sh, linux-ia64, cmetcalf,
sparclinux, David Rientjes, Jiang Liu, Len Brown, benh, paulus,
Christoph Lameter, Minchan Kim, Andrew Morton, KOSAKI Motohiro,
Yasuaki Ishimatsu
In-Reply-To: <50BC0D2D.8040008@huawei.com>
Hi Wu,
Sorry to make noise here. Please see below. :)
On 12/03/2012 10:23 AM, Jianguo Wu wrote:
> Signed-off-by: Jianguo Wu<wujianguo@huawei.com>
> Signed-off-by: Jiang Liu<jiang.liu@huawei.com>
> ---
> include/linux/mm.h | 1 +
> mm/sparse-vmemmap.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++
> mm/sparse.c | 3 +-
> 3 files changed, 234 insertions(+), 1 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 5657670..1f26af5 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1642,6 +1642,7 @@ int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
> void vmemmap_populate_print_last(void);
> void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
> unsigned long size);
> +void vmemmap_free(struct page *memmap, unsigned long nr_pages);
>
> enum mf_flags {
> MF_COUNT_INCREASED = 1<< 0,
> diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
> index 1b7e22a..748732d 100644
> --- a/mm/sparse-vmemmap.c
> +++ b/mm/sparse-vmemmap.c
> @@ -29,6 +29,10 @@
> #include<asm/pgalloc.h>
> #include<asm/pgtable.h>
>
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +#include<asm/tlbflush.h>
> +#endif
> +
> /*
> * Allocate a block of memory to be used to back the virtual memory map
> * or to back the page tables that are used to create the mapping.
> @@ -224,3 +228,230 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
> vmemmap_buf_end = NULL;
> }
> }
> +
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +
> +#define PAGE_INUSE 0xFD
> +
> +static void vmemmap_free_pages(struct page *page, int order)
> +{
> + struct zone *zone;
> + unsigned long magic;
> +
> + magic = (unsigned long) page->lru.next;
> + if (magic = SECTION_INFO || magic = MIX_SECTION_INFO) {
> + put_page_bootmem(page);
> +
> + zone = page_zone(page);
> + zone_span_writelock(zone);
> + zone->present_pages++;
> + zone_span_writeunlock(zone);
> + totalram_pages++;
Seems that we have different ways to handle pages allocated by bootmem
or by regular allocator. Is the checking way in [PATCH 09/12] available
here ?
+ /* bootmem page has reserved flag */
+ if (PageReserved(page)) {
......
+ }
If so, I think we can just merge these two functions.
> + } else
> + free_pages((unsigned long)page_address(page), order);
> +}
> +
> +static void free_pte_table(pmd_t *pmd)
> +{
> + pte_t *pte, *pte_start;
> + int i;
> +
> + pte_start = (pte_t *)pmd_page_vaddr(*pmd);
> + for (i = 0; i< PTRS_PER_PTE; i++) {
> + pte = pte_start + i;
> + if (pte_val(*pte))
> + return;
> + }
> +
> + /* free a pte talbe */
> + vmemmap_free_pages(pmd_page(*pmd), 0);
> + spin_lock(&init_mm.page_table_lock);
> + pmd_clear(pmd);
> + spin_unlock(&init_mm.page_table_lock);
> +}
> +
> +static void free_pmd_table(pud_t *pud)
> +{
> + pmd_t *pmd, *pmd_start;
> + int i;
> +
> + pmd_start = (pmd_t *)pud_page_vaddr(*pud);
> + for (i = 0; i< PTRS_PER_PMD; i++) {
> + pmd = pmd_start + i;
> + if (pmd_val(*pmd))
> + return;
> + }
> +
> + /* free a pmd talbe */
> + vmemmap_free_pages(pud_page(*pud), 0);
> + spin_lock(&init_mm.page_table_lock);
> + pud_clear(pud);
> + spin_unlock(&init_mm.page_table_lock);
> +}
> +
> +static void free_pud_table(pgd_t *pgd)
> +{
> + pud_t *pud, *pud_start;
> + int i;
> +
> + pud_start = (pud_t *)pgd_page_vaddr(*pgd);
> + for (i = 0; i< PTRS_PER_PUD; i++) {
> + pud = pud_start + i;
> + if (pud_val(*pud))
> + return;
> + }
> +
> + /* free a pud table */
> + vmemmap_free_pages(pgd_page(*pgd), 0);
> + spin_lock(&init_mm.page_table_lock);
> + pgd_clear(pgd);
> + spin_unlock(&init_mm.page_table_lock);
> +}
All the free_xxx_table() are very similar to the functions in
[PATCH 09/12]. Could we reuse them anyway ?
> +
> +static int split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase)
> +{
> + struct page *page = pmd_page(*(pmd_t *)kpte);
> + int i = 0;
> + unsigned long magic;
> + unsigned long section_nr;
> +
> + __split_large_page(kpte, address, pbase);
Is this patch going to replace [PATCH 08/12] ?
If so, __split_large_page() was added and exported in [PATCH 09/12],
then we should move it here, right ?
If not, free_map_bootmem() and __kfree_section_memmap() were changed in
[PATCH 08/12], and we need to handle this.
> + __flush_tlb_all();
> +
> + magic = (unsigned long) page->lru.next;
> + if (magic = SECTION_INFO) {
> + section_nr = pfn_to_section_nr(page_to_pfn(page));
> + while (i< PTRS_PER_PMD) {
> + page++;
> + i++;
> + get_page_bootmem(section_nr, page, SECTION_INFO);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static void vmemmap_pte_remove(pmd_t *pmd, unsigned long addr, unsigned long end)
> +{
> + pte_t *pte;
> + unsigned long next;
> + void *page_addr;
> +
> + pte = pte_offset_kernel(pmd, addr);
> + for (; addr< end; pte++, addr += PAGE_SIZE) {
> + next = (addr + PAGE_SIZE)& PAGE_MASK;
> + if (next> end)
> + next = end;
> +
> + if (pte_none(*pte))
> + continue;
> + if (IS_ALIGNED(addr, PAGE_SIZE)&&
> + IS_ALIGNED(next, PAGE_SIZE)) {
> + vmemmap_free_pages(pte_page(*pte), 0);
> + spin_lock(&init_mm.page_table_lock);
> + pte_clear(&init_mm, addr, pte);
> + spin_unlock(&init_mm.page_table_lock);
> + } else {
> + /*
> + * Removed page structs are filled with 0xFD.
> + */
> + memset((void *)addr, PAGE_INUSE, next - addr);
> + page_addr = page_address(pte_page(*pte));
> +
> + if (!memchr_inv(page_addr, PAGE_INUSE, PAGE_SIZE)) {
> + spin_lock(&init_mm.page_table_lock);
> + pte_clear(&init_mm, addr, pte);
> + spin_unlock(&init_mm.page_table_lock);
> + }
> + }
> + }
> +
> + free_pte_table(pmd);
> + __flush_tlb_all();
> +}
> +
> +static void vmemmap_pmd_remove(pud_t *pud, unsigned long addr, unsigned long end)
> +{
> + unsigned long next;
> + pmd_t *pmd;
> +
> + pmd = pmd_offset(pud, addr);
> + for (; addr< end; addr = next, pmd++) {
> + next = pmd_addr_end(addr, end);
> + if (pmd_none(*pmd))
> + continue;
> +
> + if (cpu_has_pse) {
> + unsigned long pte_base;
> +
> + if (IS_ALIGNED(addr, PMD_SIZE)&&
> + IS_ALIGNED(next, PMD_SIZE)) {
> + vmemmap_free_pages(pmd_page(*pmd),
> + get_order(PMD_SIZE));
> + spin_lock(&init_mm.page_table_lock);
> + pmd_clear(pmd);
> + spin_unlock(&init_mm.page_table_lock);
> + continue;
> + }
> +
> + /*
> + * We use 2M page, but we need to remove part of them,
> + * so split 2M page to 4K page.
> + */
> + pte_base = get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK);
> + if (!pte_base) {
> + WARN_ON(1);
> + continue;
> + }
> +
> + split_large_page((pte_t *)pmd, addr, (pte_t *)pte_base);
> + __flush_tlb_all();
> +
> + spin_lock(&init_mm.page_table_lock);
> + pmd_populate_kernel(&init_mm, pmd, (pte_t *)pte_base);
> + spin_unlock(&init_mm.page_table_lock);
> + }
> +
> + vmemmap_pte_remove(pmd, addr, next);
> + }
> +
> + free_pmd_table(pud);
> + __flush_tlb_all();
> +}
> +
> +static void vmemmap_pud_remove(pgd_t *pgd, unsigned long addr, unsigned long end)
> +{
> + unsigned long next;
> + pud_t *pud;
> +
> + pud = pud_offset(pgd, addr);
> + for (; addr< end; addr = next, pud++) {
> + next = pud_addr_end(addr, end);
> + if (pud_none(*pud))
> + continue;
> +
> + vmemmap_pmd_remove(pud, addr, next);
> + }
> +
> + free_pud_table(pgd);
> + __flush_tlb_all();
> +}
> +
> +void vmemmap_free(struct page *memmap, unsigned long nr_pages)
> +{
> + unsigned long addr = (unsigned long)memmap;
> + unsigned long end = (unsigned long)(memmap + nr_pages);
> + unsigned long next;
> +
> + for (; addr< end; addr = next) {
> + pgd_t *pgd = pgd_offset_k(addr);
> +
> + next = pgd_addr_end(addr, end);
> + if (!pgd_present(*pgd))
> + continue;
> +
> + vmemmap_pud_remove(pgd, addr, next);
> + sync_global_pgds(addr, next - 1);
> + }
> +}
> +#endif
> diff --git a/mm/sparse.c b/mm/sparse.c
> index fac95f2..4060229 100644
> --- a/mm/sparse.c
> +++ b/mm/sparse.c
> @@ -615,10 +615,11 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
> }
> static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
> {
> - return; /* XXX: Not implemented yet */
> + vmemmap_free(memmap, nr_pages);
> }
> static void free_map_bootmem(struct page *page, unsigned long nr_pages)
In the latest kernel, this line was:
static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
> {
> + vmemmap_free(page, nr_pages);
> }
> #else
> static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
^ permalink raw reply
* Re: [Patch v4 01/12] memory-hotplug: try to offline the memory twice to avoid dependence
From: Tang Chen @ 2012-12-04 9:17 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <1354010422-19648-2-git-send-email-wency@cn.fujitsu.com>
On 11/27/2012 06:00 PM, Wen Congyang wrote:
> memory can't be offlined when CONFIG_MEMCG is selected.
> For example: there is a memory device on node 1. The address range
> is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
> and memory11 under the directory /sys/devices/system/memory/.
>
> If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
> when we online pages. When we online memory8, the memory stored page cgroup
> is not provided by this memory device. But when we online memory9, the memory
> stored page cgroup may be provided by memory8. So we can't offline memory8
> now. We should offline the memory in the reversed order.
>
> When the memory device is hotremoved, we will auto offline memory provided
> by this memory device. But we don't know which memory is onlined first, so
> offlining memory may fail. In such case, iterate twice to offline the memory.
> 1st iterate: offline every non primary memory block.
> 2nd iterate: offline primary (i.e. first added) memory block.
>
> This idea is suggested by KOSAKI Motohiro.
>
> CC: David Rientjes<rientjes@google.com>
> CC: Jiang Liu<liuj97@gmail.com>
> CC: Len Brown<len.brown@intel.com>
> CC: Christoph Lameter<cl@linux.com>
> Cc: Minchan Kim<minchan.kim@gmail.com>
> CC: Andrew Morton<akpm@linux-foundation.org>
> CC: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
> CC: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
> Signed-off-by: Wen Congyang<wency@cn.fujitsu.com>
Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
> ---
> mm/memory_hotplug.c | 16 ++++++++++++++--
> 1 file changed, 14 insertions(+), 2 deletions(-)
>
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index e4eeaca..b825dbc 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -1012,10 +1012,13 @@ int remove_memory(u64 start, u64 size)
> unsigned long start_pfn, end_pfn;
> unsigned long pfn, section_nr;
> int ret;
> + int return_on_error = 0;
> + int retry = 0;
>
> start_pfn = PFN_DOWN(start);
> end_pfn = start_pfn + PFN_DOWN(size);
>
> +repeat:
> for (pfn = start_pfn; pfn< end_pfn; pfn += PAGES_PER_SECTION) {
> section_nr = pfn_to_section_nr(pfn);
> if (!present_section_nr(section_nr))
> @@ -1034,14 +1037,23 @@ int remove_memory(u64 start, u64 size)
>
> ret = offline_memory_block(mem);
> if (ret) {
> - kobject_put(&mem->dev.kobj);
> - return ret;
> + if (return_on_error) {
> + kobject_put(&mem->dev.kobj);
> + return ret;
> + } else {
> + retry = 1;
> + }
> }
> }
>
> if (mem)
> kobject_put(&mem->dev.kobj);
>
> + if (retry) {
> + return_on_error = 1;
> + goto repeat;
> + }
> +
> return 0;
> }
> #else
^ permalink raw reply
* Re: [Patch v4 02/12] memory-hotplug: check whether all memory blocks are offlined or not when removi
From: Tang Chen @ 2012-12-04 9:22 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <1354010422-19648-3-git-send-email-wency@cn.fujitsu.com>
On 11/27/2012 06:00 PM, Wen Congyang wrote:
> From: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
>
> We remove the memory like this:
> 1. lock memory hotplug
> 2. offline a memory block
> 3. unlock memory hotplug
> 4. repeat 1-3 to offline all memory blocks
> 5. lock memory hotplug
> 6. remove memory(TODO)
> 7. unlock memory hotplug
>
> All memory blocks must be offlined before removing memory. But we don't hold
> the lock in the whole operation. So we should check whether all memory blocks
> are offlined before step6. Otherwise, kernel maybe panicked.
>
> CC: David Rientjes<rientjes@google.com>
> CC: Jiang Liu<liuj97@gmail.com>
> CC: Len Brown<len.brown@intel.com>
> CC: Christoph Lameter<cl@linux.com>
> Cc: Minchan Kim<minchan.kim@gmail.com>
> CC: Andrew Morton<akpm@linux-foundation.org>
> CC: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
> Signed-off-by: Wen Congyang<wency@cn.fujitsu.com>
> Signed-off-by: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
> ---
> drivers/base/memory.c | 6 ++++++
> include/linux/memory_hotplug.h | 1 +
> mm/memory_hotplug.c | 47 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 54 insertions(+)
>
> diff --git a/drivers/base/memory.c b/drivers/base/memory.c
> index 86c8821..badb025 100644
> --- a/drivers/base/memory.c
> +++ b/drivers/base/memory.c
> @@ -675,6 +675,12 @@ int offline_memory_block(struct memory_block *mem)
> return ret;
> }
>
> +/* return true if the memory block is offlined, otherwise, return false */
> +bool is_memblock_offlined(struct memory_block *mem)
> +{
> + return mem->state = MEM_OFFLINE;
> +}
> +
> /*
> * Initialize the sysfs support for memory devices...
> */
> diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
> index 95573ec..38675e9 100644
> --- a/include/linux/memory_hotplug.h
> +++ b/include/linux/memory_hotplug.h
> @@ -236,6 +236,7 @@ extern int add_memory(int nid, u64 start, u64 size);
> extern int arch_add_memory(int nid, u64 start, u64 size);
> extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
> extern int offline_memory_block(struct memory_block *mem);
> +extern bool is_memblock_offlined(struct memory_block *mem);
> extern int remove_memory(u64 start, u64 size);
> extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
> int nr_pages);
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index b825dbc..b6d1101 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -1054,6 +1054,53 @@ repeat:
> goto repeat;
> }
>
> + lock_memory_hotplug();
> +
> + /*
> + * we have offlined all memory blocks like this:
> + * 1. lock memory hotplug
> + * 2. offline a memory block
> + * 3. unlock memory hotplug
> + *
> + * repeat step1-3 to offline the memory block. All memory blocks
> + * must be offlined before removing memory. But we don't hold the
> + * lock in the whole operation. So we should check whether all
> + * memory blocks are offlined.
> + */
> +
> + for (pfn = start_pfn; pfn< end_pfn; pfn += PAGES_PER_SECTION) {
> + section_nr = pfn_to_section_nr(pfn);
> + if (!present_section_nr(section_nr))
> + continue;
> +
> + section = __nr_to_section(section_nr);
> + /* same memblock? */
> + if (mem)
> + if ((section_nr>= mem->start_section_nr)&&
> + (section_nr<= mem->end_section_nr))
> + continue;
> +
> + mem = find_memory_block_hinted(section, mem);
> + if (!mem)
> + continue;
> +
> + ret = is_memblock_offlined(mem);
> + if (!ret) {
> + pr_warn("removing memory fails, because memory "
> + "[%#010llx-%#010llx] is onlined\n",
> + PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)),
> + PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1)) - 1);
> +
> + kobject_put(&mem->dev.kobj);
> + unlock_memory_hotplug();
> + return ret;
> + }
> + }
> +
> + if (mem)
> + kobject_put(&mem->dev.kobj);
> + unlock_memory_hotplug();
> +
> return 0;
> }
> #else
^ permalink raw reply
* Re: [Patch v4 03/12] memory-hotplug: remove redundant codes
From: Tang Chen @ 2012-12-04 9:22 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <1354010422-19648-4-git-send-email-wency@cn.fujitsu.com>
On 11/27/2012 06:00 PM, Wen Congyang wrote:
> offlining memory blocks and checking whether memory blocks are offlined
> are very similar. This patch introduces a new function to remove
> redundant codes.
>
> CC: David Rientjes<rientjes@google.com>
> CC: Jiang Liu<liuj97@gmail.com>
> CC: Len Brown<len.brown@intel.com>
> CC: Christoph Lameter<cl@linux.com>
> Cc: Minchan Kim<minchan.kim@gmail.com>
> CC: Andrew Morton<akpm@linux-foundation.org>
> CC: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
> CC: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
> Signed-off-by: Wen Congyang<wency@cn.fujitsu.com>
Can we merge this patch with [PATCH 03/12] ?
Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
> ---
> mm/memory_hotplug.c | 101 ++++++++++++++++++++++++++++------------------------
> 1 file changed, 55 insertions(+), 46 deletions(-)
>
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index b6d1101..6d06488 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -1005,20 +1005,14 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
> return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ);
> }
>
> -int remove_memory(u64 start, u64 size)
> +static int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
> + void *arg, int (*func)(struct memory_block *, void *))
> {
> struct memory_block *mem = NULL;
> struct mem_section *section;
> - unsigned long start_pfn, end_pfn;
> unsigned long pfn, section_nr;
> int ret;
> - int return_on_error = 0;
> - int retry = 0;
> -
> - start_pfn = PFN_DOWN(start);
> - end_pfn = start_pfn + PFN_DOWN(size);
>
> -repeat:
> for (pfn = start_pfn; pfn< end_pfn; pfn += PAGES_PER_SECTION) {
> section_nr = pfn_to_section_nr(pfn);
> if (!present_section_nr(section_nr))
> @@ -1035,22 +1029,61 @@ repeat:
> if (!mem)
> continue;
>
> - ret = offline_memory_block(mem);
> + ret = func(mem, arg);
> if (ret) {
> - if (return_on_error) {
> - kobject_put(&mem->dev.kobj);
> - return ret;
> - } else {
> - retry = 1;
> - }
> + kobject_put(&mem->dev.kobj);
> + return ret;
> }
> }
>
> if (mem)
> kobject_put(&mem->dev.kobj);
>
> - if (retry) {
> - return_on_error = 1;
> + return 0;
> +}
> +
> +static int offline_memory_block_cb(struct memory_block *mem, void *arg)
> +{
> + int *ret = arg;
> + int error = offline_memory_block(mem);
> +
> + if (error != 0&& *ret = 0)
> + *ret = error;
> +
> + return 0;
> +}
> +
> +static int is_memblock_offlined_cb(struct memory_block *mem, void *arg)
> +{
> + int ret = !is_memblock_offlined(mem);
> +
> + if (unlikely(ret))
> + pr_warn("removing memory fails, because memory "
> + "[%#010llx-%#010llx] is onlined\n",
> + PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)),
> + PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1))-1);
> +
> + return ret;
> +}
> +
> +int remove_memory(u64 start, u64 size)
> +{
> + unsigned long start_pfn, end_pfn;
> + int ret = 0;
> + int retry = 1;
> +
> + start_pfn = PFN_DOWN(start);
> + end_pfn = start_pfn + PFN_DOWN(size);
> +
> +repeat:
> + walk_memory_range(start_pfn, end_pfn,&ret,
> + offline_memory_block_cb);
> + if (ret) {
> + if (!retry)
> + return ret;
> +
> + retry = 0;
> + ret = 0;
> goto repeat;
> }
>
> @@ -1068,37 +1101,13 @@ repeat:
> * memory blocks are offlined.
> */
>
> - for (pfn = start_pfn; pfn< end_pfn; pfn += PAGES_PER_SECTION) {
> - section_nr = pfn_to_section_nr(pfn);
> - if (!present_section_nr(section_nr))
> - continue;
> -
> - section = __nr_to_section(section_nr);
> - /* same memblock? */
> - if (mem)
> - if ((section_nr>= mem->start_section_nr)&&
> - (section_nr<= mem->end_section_nr))
> - continue;
> -
> - mem = find_memory_block_hinted(section, mem);
> - if (!mem)
> - continue;
> -
> - ret = is_memblock_offlined(mem);
> - if (!ret) {
> - pr_warn("removing memory fails, because memory "
> - "[%#010llx-%#010llx] is onlined\n",
> - PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)),
> - PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1)) - 1);
> -
> - kobject_put(&mem->dev.kobj);
> - unlock_memory_hotplug();
> - return ret;
> - }
> + ret = walk_memory_range(start_pfn, end_pfn, NULL,
> + is_memblock_offlined_cb);
> + if (ret) {
> + unlock_memory_hotplug();
> + return ret;
> }
>
> - if (mem)
> - kobject_put(&mem->dev.kobj);
> unlock_memory_hotplug();
>
> return 0;
^ permalink raw reply
* Re: [Patch v4 05/12] memory-hotplug: introduce new function arch_remove_memory() for removing page t
From: Tang Chen @ 2012-12-04 9:30 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <1354010422-19648-6-git-send-email-wency@cn.fujitsu.com>
On 11/27/2012 06:00 PM, Wen Congyang wrote:
> For removing memory, we need to remove page table. But it depends
> on architecture. So the patch introduce arch_remove_memory() for
> removing page table. Now it only calls __remove_pages().
>
> Note: __remove_pages() for some archtecuture is not implemented
> (I don't know how to implement it for s390).
>
> CC: David Rientjes<rientjes@google.com>
> CC: Jiang Liu<liuj97@gmail.com>
> CC: Len Brown<len.brown@intel.com>
> CC: Benjamin Herrenschmidt<benh@kernel.crashing.org>
> CC: Paul Mackerras<paulus@samba.org>
> CC: Christoph Lameter<cl@linux.com>
> Cc: Minchan Kim<minchan.kim@gmail.com>
> CC: Andrew Morton<akpm@linux-foundation.org>
> CC: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
> CC: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
> Signed-off-by: Wen Congyang<wency@cn.fujitsu.com>
> ---
> arch/ia64/mm/init.c | 18 ++++++++++++++++++
> arch/powerpc/mm/mem.c | 12 ++++++++++++
> arch/s390/mm/init.c | 12 ++++++++++++
> arch/sh/mm/init.c | 17 +++++++++++++++++
> arch/tile/mm/init.c | 8 ++++++++
> arch/x86/mm/init_32.c | 12 ++++++++++++
> arch/x86/mm/init_64.c | 15 +++++++++++++++
> include/linux/memory_hotplug.h | 1 +
> mm/memory_hotplug.c | 2 ++
> 9 files changed, 97 insertions(+)
>
> diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
> index 082e383..e333822 100644
> --- a/arch/ia64/mm/init.c
> +++ b/arch/ia64/mm/init.c
> @@ -689,6 +689,24 @@ int arch_add_memory(int nid, u64 start, u64 size)
>
> return ret;
> }
> +
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +int arch_remove_memory(u64 start, u64 size)
> +{
> + unsigned long start_pfn = start>> PAGE_SHIFT;
> + unsigned long nr_pages = size>> PAGE_SHIFT;
> + struct zone *zone;
> + int ret;
> +
> + zone = page_zone(pfn_to_page(start_pfn));
> + ret = __remove_pages(zone, start_pfn, nr_pages);
> + if (ret)
> + pr_warn("%s: Problem encountered in __remove_pages() as"
> + " ret=%d\n", __func__, ret);
> +
> + return ret;
Just a little question, why do we have different handlers for ret on
different platforms ? Sometimes we print a msg, sometimes we just
return, and sometimes we give a WARN_ON(). But no big deal. :)
Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
> +}
> +#endif
> #endif
>
> /*
> diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
> index 0dba506..09c6451 100644
> --- a/arch/powerpc/mm/mem.c
> +++ b/arch/powerpc/mm/mem.c
> @@ -133,6 +133,18 @@ int arch_add_memory(int nid, u64 start, u64 size)
>
> return __add_pages(nid, zone, start_pfn, nr_pages);
> }
> +
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +int arch_remove_memory(u64 start, u64 size)
> +{
> + unsigned long start_pfn = start>> PAGE_SHIFT;
> + unsigned long nr_pages = size>> PAGE_SHIFT;
> + struct zone *zone;
> +
> + zone = page_zone(pfn_to_page(start_pfn));
> + return __remove_pages(zone, start_pfn, nr_pages);
> +}
> +#endif
> #endif /* CONFIG_MEMORY_HOTPLUG */
>
> /*
> diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
> index 81e596c..b565190 100644
> --- a/arch/s390/mm/init.c
> +++ b/arch/s390/mm/init.c
> @@ -257,4 +257,16 @@ int arch_add_memory(int nid, u64 start, u64 size)
> vmem_remove_mapping(start, size);
> return rc;
> }
> +
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +int arch_remove_memory(u64 start, u64 size)
> +{
> + /*
> + * There is no hardware or firmware interface which could trigger a
> + * hot memory remove on s390. So there is nothing that needs to be
> + * implemented.
> + */
> + return -EBUSY;
> +}
> +#endif
> #endif /* CONFIG_MEMORY_HOTPLUG */
> diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
> index 82cc576..1057940 100644
> --- a/arch/sh/mm/init.c
> +++ b/arch/sh/mm/init.c
> @@ -558,4 +558,21 @@ int memory_add_physaddr_to_nid(u64 addr)
> EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
> #endif
>
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +int arch_remove_memory(u64 start, u64 size)
> +{
> + unsigned long start_pfn = start>> PAGE_SHIFT;
> + unsigned long nr_pages = size>> PAGE_SHIFT;
> + struct zone *zone;
> + int ret;
> +
> + zone = page_zone(pfn_to_page(start_pfn));
> + ret = __remove_pages(zone, start_pfn, nr_pages);
> + if (unlikely(ret))
> + pr_warn("%s: Failed, __remove_pages() = %d\n", __func__,
> + ret);
> +
> + return ret;
> +}
> +#endif
> #endif /* CONFIG_MEMORY_HOTPLUG */
> diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
> index ef29d6c..2749515 100644
> --- a/arch/tile/mm/init.c
> +++ b/arch/tile/mm/init.c
> @@ -935,6 +935,14 @@ int remove_memory(u64 start, u64 size)
> {
> return -EINVAL;
> }
> +
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +int arch_remove_memory(u64 start, u64 size)
> +{
> + /* TODO */
> + return -EBUSY;
> +}
> +#endif
> #endif
>
> struct kmem_cache *pgd_cache;
> diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
> index 11a5800..b19eba4 100644
> --- a/arch/x86/mm/init_32.c
> +++ b/arch/x86/mm/init_32.c
> @@ -839,6 +839,18 @@ int arch_add_memory(int nid, u64 start, u64 size)
>
> return __add_pages(nid, zone, start_pfn, nr_pages);
> }
> +
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +int arch_remove_memory(u64 start, u64 size)
> +{
> + unsigned long start_pfn = start>> PAGE_SHIFT;
> + unsigned long nr_pages = size>> PAGE_SHIFT;
> + struct zone *zone;
> +
> + zone = page_zone(pfn_to_page(start_pfn));
> + return __remove_pages(zone, start_pfn, nr_pages);
> +}
> +#endif
> #endif
>
> /*
> diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
> index 3baff25..5675335 100644
> --- a/arch/x86/mm/init_64.c
> +++ b/arch/x86/mm/init_64.c
> @@ -680,6 +680,21 @@ int arch_add_memory(int nid, u64 start, u64 size)
> }
> EXPORT_SYMBOL_GPL(arch_add_memory);
>
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +int __ref arch_remove_memory(u64 start, u64 size)
> +{
> + unsigned long start_pfn = start>> PAGE_SHIFT;
> + unsigned long nr_pages = size>> PAGE_SHIFT;
> + struct zone *zone;
> + int ret;
> +
> + zone = page_zone(pfn_to_page(start_pfn));
> + ret = __remove_pages(zone, start_pfn, nr_pages);
> + WARN_ON_ONCE(ret);
> +
> + return ret;
> +}
> +#endif
> #endif /* CONFIG_MEMORY_HOTPLUG */
>
> static struct kcore_list kcore_vsyscall;
> diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
> index 38675e9..191b2d9 100644
> --- a/include/linux/memory_hotplug.h
> +++ b/include/linux/memory_hotplug.h
> @@ -85,6 +85,7 @@ extern void __online_page_free(struct page *page);
>
> #ifdef CONFIG_MEMORY_HOTREMOVE
> extern bool is_pageblock_removable_nolock(struct page *page);
> +extern int arch_remove_memory(u64 start, u64 size);
> #endif /* CONFIG_MEMORY_HOTREMOVE */
>
> /* reasonably generic interface to expand the physical pages in a zone */
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index 63d5388..e741732 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -1111,6 +1111,8 @@ repeat:
> /* remove memmap entry */
> firmware_map_remove(start, start + size, "System RAM");
>
> + arch_remove_memory(start, size);
> +
> unlock_memory_hotplug();
>
> return 0;
^ permalink raw reply
* Re: [Patch v4 06/12] memory-hotplug: unregister memory section on SPARSEMEM_VMEMMAP
From: Tang Chen @ 2012-12-04 9:34 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <1354010422-19648-7-git-send-email-wency@cn.fujitsu.com>
On 11/27/2012 06:00 PM, Wen Congyang wrote:
> From: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
>
> Currently __remove_section for SPARSEMEM_VMEMMAP does nothing. But even if
> we use SPARSEMEM_VMEMMAP, we can unregister the memory_section.
>
> So the patch add unregister_memory_section() into __remove_section().
>
> CC: David Rientjes<rientjes@google.com>
> CC: Jiang Liu<liuj97@gmail.com>
> CC: Len Brown<len.brown@intel.com>
> CC: Christoph Lameter<cl@linux.com>
> Cc: Minchan Kim<minchan.kim@gmail.com>
> CC: Andrew Morton<akpm@linux-foundation.org>
> CC: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
> Signed-off-by: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
> Signed-off-by: Wen Congyang<wency@cn.fujitsu.com>
__remove_section() of CONFIG_SPARSEMEM_VMEMMAP will be integrated
into one in [PATCH 08/12], so I think we can merge this patch into
[PATCH 08/12].
Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
> ---
> mm/memory_hotplug.c | 13 ++++++++-----
> 1 file changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index e741732..171610d 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -279,11 +279,14 @@ static int __meminit __add_section(int nid, struct zone *zone,
> #ifdef CONFIG_SPARSEMEM_VMEMMAP
> static int __remove_section(struct zone *zone, struct mem_section *ms)
> {
> - /*
> - * XXX: Freeing memmap with vmemmap is not implement yet.
> - * This should be removed later.
> - */
> - return -EBUSY;
> + int ret = -EINVAL;
> +
> + if (!valid_section(ms))
> + return ret;
> +
> + ret = unregister_memory_section(ms);
> +
> + return ret;
> }
> #else
> static int __remove_section(struct zone *zone, struct mem_section *ms)
^ permalink raw reply
* Re: [Patch v4 08/12] memory-hotplug: remove memmap of sparse-vmemmap
From: Tang Chen @ 2012-12-04 9:47 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <1354010422-19648-9-git-send-email-wency@cn.fujitsu.com>
On 11/27/2012 06:00 PM, Wen Congyang wrote:
> static int __remove_section(struct zone *zone, struct mem_section *ms)
> {
> unsigned long flags;
> @@ -330,9 +317,9 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)
> pgdat_resize_lock(pgdat,&flags);
> sparse_remove_one_section(zone, ms);
> pgdat_resize_unlock(pgdat,&flags);
> - return 0;
> +
> + return ret;
I think we don't need to change this line. :)
Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
^ permalink raw reply
* Re: [Patch v4 10/12] memory-hotplug: memory_hotplug: clear zone when removing the memory
From: Tang Chen @ 2012-12-04 10:09 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <1354010422-19648-11-git-send-email-wency@cn.fujitsu.com>
On 11/27/2012 06:00 PM, Wen Congyang wrote:
> From: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
>
> When a memory is added, we update zone's and pgdat's start_pfn and
> spanned_pages in the function __add_zone(). So we should revert them
> when the memory is removed.
>
> The patch adds a new function __remove_zone() to do this.
>
> CC: David Rientjes<rientjes@google.com>
> CC: Jiang Liu<liuj97@gmail.com>
> CC: Len Brown<len.brown@intel.com>
> CC: Christoph Lameter<cl@linux.com>
> Cc: Minchan Kim<minchan.kim@gmail.com>
> CC: Andrew Morton<akpm@linux-foundation.org>
> CC: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
> Signed-off-by: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
> Signed-off-by: Wen Congyang<wency@cn.fujitsu.com>
Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
> ---
> mm/memory_hotplug.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 207 insertions(+)
>
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index 7797e91..aa97d56 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -301,10 +301,213 @@ static int __meminit __add_section(int nid, struct zone *zone,
> return register_new_memory(nid, __pfn_to_section(phys_start_pfn));
> }
>
> +/* find the smallest valid pfn in the range [start_pfn, end_pfn) */
> +static int find_smallest_section_pfn(int nid, struct zone *zone,
> + unsigned long start_pfn,
> + unsigned long end_pfn)
> +{
> + struct mem_section *ms;
> +
> + for (; start_pfn< end_pfn; start_pfn += PAGES_PER_SECTION) {
> + ms = __pfn_to_section(start_pfn);
> +
> + if (unlikely(!valid_section(ms)))
> + continue;
> +
> + if (unlikely(pfn_to_nid(start_pfn) != nid))
> + continue;
> +
> + if (zone&& zone != page_zone(pfn_to_page(start_pfn)))
> + continue;
> +
> + return start_pfn;
> + }
> +
> + return 0;
> +}
> +
> +/* find the biggest valid pfn in the range [start_pfn, end_pfn). */
> +static int find_biggest_section_pfn(int nid, struct zone *zone,
> + unsigned long start_pfn,
> + unsigned long end_pfn)
> +{
> + struct mem_section *ms;
> + unsigned long pfn;
> +
> + /* pfn is the end pfn of a memory section. */
> + pfn = end_pfn - 1;
> + for (; pfn>= start_pfn; pfn -= PAGES_PER_SECTION) {
> + ms = __pfn_to_section(pfn);
> +
> + if (unlikely(!valid_section(ms)))
> + continue;
> +
> + if (unlikely(pfn_to_nid(pfn) != nid))
> + continue;
> +
> + if (zone&& zone != page_zone(pfn_to_page(pfn)))
> + continue;
> +
> + return pfn;
> + }
> +
> + return 0;
> +}
> +
> +static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
> + unsigned long end_pfn)
> +{
> + unsigned long zone_start_pfn = zone->zone_start_pfn;
> + unsigned long zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages;
> + unsigned long pfn;
> + struct mem_section *ms;
> + int nid = zone_to_nid(zone);
> +
> + zone_span_writelock(zone);
> + if (zone_start_pfn = start_pfn) {
> + /*
> + * If the section is smallest section in the zone, it need
> + * shrink zone->zone_start_pfn and zone->zone_spanned_pages.
> + * In this case, we find second smallest valid mem_section
> + * for shrinking zone.
> + */
> + pfn = find_smallest_section_pfn(nid, zone, end_pfn,
> + zone_end_pfn);
> + if (pfn) {
> + zone->zone_start_pfn = pfn;
> + zone->spanned_pages = zone_end_pfn - pfn;
> + }
> + } else if (zone_end_pfn = end_pfn) {
> + /*
> + * If the section is biggest section in the zone, it need
> + * shrink zone->spanned_pages.
> + * In this case, we find second biggest valid mem_section for
> + * shrinking zone.
> + */
> + pfn = find_biggest_section_pfn(nid, zone, zone_start_pfn,
> + start_pfn);
> + if (pfn)
> + zone->spanned_pages = pfn - zone_start_pfn + 1;
> + }
> +
> + /*
> + * The section is not biggest or smallest mem_section in the zone, it
> + * only creates a hole in the zone. So in this case, we need not
> + * change the zone. But perhaps, the zone has only hole data. Thus
> + * it check the zone has only hole or not.
> + */
> + pfn = zone_start_pfn;
> + for (; pfn< zone_end_pfn; pfn += PAGES_PER_SECTION) {
> + ms = __pfn_to_section(pfn);
> +
> + if (unlikely(!valid_section(ms)))
> + continue;
> +
> + if (page_zone(pfn_to_page(pfn)) != zone)
> + continue;
> +
> + /* If the section is current section, it continues the loop */
> + if (start_pfn = pfn)
> + continue;
> +
> + /* If we find valid section, we have nothing to do */
> + zone_span_writeunlock(zone);
> + return;
> + }
> +
> + /* The zone has no valid section */
> + zone->zone_start_pfn = 0;
> + zone->spanned_pages = 0;
> + zone_span_writeunlock(zone);
> +}
> +
> +static void shrink_pgdat_span(struct pglist_data *pgdat,
> + unsigned long start_pfn, unsigned long end_pfn)
> +{
> + unsigned long pgdat_start_pfn = pgdat->node_start_pfn;
> + unsigned long pgdat_end_pfn > + pgdat->node_start_pfn + pgdat->node_spanned_pages;
> + unsigned long pfn;
> + struct mem_section *ms;
> + int nid = pgdat->node_id;
> +
> + if (pgdat_start_pfn = start_pfn) {
> + /*
> + * If the section is smallest section in the pgdat, it need
> + * shrink pgdat->node_start_pfn and pgdat->node_spanned_pages.
> + * In this case, we find second smallest valid mem_section
> + * for shrinking zone.
> + */
> + pfn = find_smallest_section_pfn(nid, NULL, end_pfn,
> + pgdat_end_pfn);
> + if (pfn) {
> + pgdat->node_start_pfn = pfn;
> + pgdat->node_spanned_pages = pgdat_end_pfn - pfn;
> + }
> + } else if (pgdat_end_pfn = end_pfn) {
> + /*
> + * If the section is biggest section in the pgdat, it need
> + * shrink pgdat->node_spanned_pages.
> + * In this case, we find second biggest valid mem_section for
> + * shrinking zone.
> + */
> + pfn = find_biggest_section_pfn(nid, NULL, pgdat_start_pfn,
> + start_pfn);
> + if (pfn)
> + pgdat->node_spanned_pages = pfn - pgdat_start_pfn + 1;
> + }
> +
> + /*
> + * If the section is not biggest or smallest mem_section in the pgdat,
> + * it only creates a hole in the pgdat. So in this case, we need not
> + * change the pgdat.
> + * But perhaps, the pgdat has only hole data. Thus it check the pgdat
> + * has only hole or not.
> + */
> + pfn = pgdat_start_pfn;
> + for (; pfn< pgdat_end_pfn; pfn += PAGES_PER_SECTION) {
> + ms = __pfn_to_section(pfn);
> +
> + if (unlikely(!valid_section(ms)))
> + continue;
> +
> + if (pfn_to_nid(pfn) != nid)
> + continue;
> +
> + /* If the section is current section, it continues the loop */
> + if (start_pfn = pfn)
> + continue;
> +
> + /* If we find valid section, we have nothing to do */
> + return;
> + }
> +
> + /* The pgdat has no valid section */
> + pgdat->node_start_pfn = 0;
> + pgdat->node_spanned_pages = 0;
> +}
> +
> +static void __remove_zone(struct zone *zone, unsigned long start_pfn)
> +{
> + struct pglist_data *pgdat = zone->zone_pgdat;
> + int nr_pages = PAGES_PER_SECTION;
> + int zone_type;
> + unsigned long flags;
> +
> + zone_type = zone - pgdat->node_zones;
> +
> + pgdat_resize_lock(zone->zone_pgdat,&flags);
> + shrink_zone_span(zone, start_pfn, start_pfn + nr_pages);
> + shrink_pgdat_span(pgdat, start_pfn, start_pfn + nr_pages);
> + pgdat_resize_unlock(zone->zone_pgdat,&flags);
> +}
> +
> static int __remove_section(struct zone *zone, struct mem_section *ms)
> {
> unsigned long flags;
> struct pglist_data *pgdat = zone->zone_pgdat;
> + unsigned long start_pfn;
> + int scn_nr;
> int ret = -EINVAL;
>
> if (!valid_section(ms))
> @@ -314,6 +517,10 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)
> if (ret)
> return ret;
>
> + scn_nr = __section_nr(ms);
> + start_pfn = section_nr_to_pfn(scn_nr);
> + __remove_zone(zone, start_pfn);
> +
> pgdat_resize_lock(pgdat,&flags);
> sparse_remove_one_section(zone, ms);
> pgdat_resize_unlock(pgdat,&flags);
^ permalink raw reply
* Re: [Patch v4 11/12] memory-hotplug: remove sysfs file of node
From: Tang Chen @ 2012-12-04 10:10 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <1354010422-19648-12-git-send-email-wency@cn.fujitsu.com>
On 11/27/2012 06:00 PM, Wen Congyang wrote:
> This patch introduces a new function try_offline_node() to
> remove sysfs file of node when all memory sections of this
> node are removed. If some memory sections of this node are
> not removed, this function does nothing.
>
> CC: David Rientjes<rientjes@google.com>
> CC: Jiang Liu<liuj97@gmail.com>
> CC: Len Brown<len.brown@intel.com>
> CC: Christoph Lameter<cl@linux.com>
> Cc: Minchan Kim<minchan.kim@gmail.com>
> CC: Andrew Morton<akpm@linux-foundation.org>
> CC: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
> CC: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
> Signed-off-by: Wen Congyang<wency@cn.fujitsu.com>
Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
> ---
> drivers/acpi/acpi_memhotplug.c | 8 +++++-
> include/linux/memory_hotplug.h | 2 +-
> mm/memory_hotplug.c | 58 ++++++++++++++++++++++++++++++++++++++++--
> 3 files changed, 64 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
> index 24c807f..0780f99 100644
> --- a/drivers/acpi/acpi_memhotplug.c
> +++ b/drivers/acpi/acpi_memhotplug.c
> @@ -310,7 +310,9 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
> {
> int result;
> struct acpi_memory_info *info, *n;
> + int node;
>
> + node = acpi_get_node(mem_device->device->handle);
>
> /*
> * Ask the VM to offline this memory range.
> @@ -318,7 +320,11 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
> */
> list_for_each_entry_safe(info, n,&mem_device->res_list, list) {
> if (info->enabled) {
> - result = remove_memory(info->start_addr, info->length);
> + if (node< 0)
> + node = memory_add_physaddr_to_nid(
> + info->start_addr);
> + result = remove_memory(node, info->start_addr,
> + info->length);
> if (result)
> return result;
> }
> diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
> index d4c4402..7b4cfe6 100644
> --- a/include/linux/memory_hotplug.h
> +++ b/include/linux/memory_hotplug.h
> @@ -231,7 +231,7 @@ extern int arch_add_memory(int nid, u64 start, u64 size);
> extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
> extern int offline_memory_block(struct memory_block *mem);
> extern bool is_memblock_offlined(struct memory_block *mem);
> -extern int remove_memory(u64 start, u64 size);
> +extern int remove_memory(int node, u64 start, u64 size);
> extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
> int nr_pages);
> extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms);
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index aa97d56..449663e 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -29,6 +29,7 @@
> #include<linux/suspend.h>
> #include<linux/mm_inline.h>
> #include<linux/firmware-map.h>
> +#include<linux/stop_machine.h>
>
> #include<asm/tlbflush.h>
>
> @@ -1288,7 +1289,58 @@ static int is_memblock_offlined_cb(struct memory_block *mem, void *arg)
> return ret;
> }
>
> -int __ref remove_memory(u64 start, u64 size)
> +static int check_cpu_on_node(void *data)
> +{
> + struct pglist_data *pgdat = data;
> + int cpu;
> +
> + for_each_present_cpu(cpu) {
> + if (cpu_to_node(cpu) = pgdat->node_id)
> + /*
> + * the cpu on this node isn't removed, and we can't
> + * offline this node.
> + */
> + return -EBUSY;
> + }
> +
> + return 0;
> +}
> +
> +/* offline the node if all memory sections of this node are removed */
> +static void try_offline_node(int nid)
> +{
> + unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
> + unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
> + unsigned long pfn;
> +
> + for (pfn = start_pfn; pfn< end_pfn; pfn += PAGES_PER_SECTION) {
> + unsigned long section_nr = pfn_to_section_nr(pfn);
> +
> + if (!present_section_nr(section_nr))
> + continue;
> +
> + if (pfn_to_nid(pfn) != nid)
> + continue;
> +
> + /*
> + * some memory sections of this node are not removed, and we
> + * can't offline node now.
> + */
> + return;
> + }
> +
> + if (stop_machine(check_cpu_on_node, NODE_DATA(nid), NULL))
> + return;
> +
> + /*
> + * all memory/cpu of this node are removed, we can offline this
> + * node now.
> + */
> + node_set_offline(nid);
> + unregister_one_node(nid);
> +}
> +
> +int __ref remove_memory(int nid, u64 start, u64 size)
> {
> unsigned long start_pfn, end_pfn;
> int ret = 0;
> @@ -1335,6 +1387,8 @@ repeat:
>
> arch_remove_memory(start, size);
>
> + try_offline_node(nid);
> +
> unlock_memory_hotplug();
>
> return 0;
> @@ -1344,7 +1398,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
> {
> return -EINVAL;
> }
> -int remove_memory(u64 start, u64 size)
> +int remove_memory(int nid, u64 start, u64 size)
> {
> return -EINVAL;
> }
^ permalink raw reply
* Re: [Patch v4 12/12] memory-hotplug: free node_data when a node is offlined
From: Tang Chen @ 2012-12-04 10:10 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <1354010422-19648-13-git-send-email-wency@cn.fujitsu.com>
On 11/27/2012 06:00 PM, Wen Congyang wrote:
> We call hotadd_new_pgdat() to allocate memory to store node_data. So we
> should free it when removing a node.
>
> CC: David Rientjes<rientjes@google.com>
> CC: Jiang Liu<liuj97@gmail.com>
> CC: Len Brown<len.brown@intel.com>
> CC: Benjamin Herrenschmidt<benh@kernel.crashing.org>
> CC: Paul Mackerras<paulus@samba.org>
> CC: Christoph Lameter<cl@linux.com>
> Cc: Minchan Kim<minchan.kim@gmail.com>
> CC: Andrew Morton<akpm@linux-foundation.org>
> CC: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
> CC: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
> Signed-off-by: Wen Congyang<wency@cn.fujitsu.com>
Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
> ---
> mm/memory_hotplug.c | 20 +++++++++++++++++++-
> 1 file changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index 449663e..d1451ab 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -1309,9 +1309,12 @@ static int check_cpu_on_node(void *data)
> /* offline the node if all memory sections of this node are removed */
> static void try_offline_node(int nid)
> {
> + pg_data_t *pgdat = NODE_DATA(nid);
> unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
> - unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
> + unsigned long end_pfn = start_pfn + pgdat->node_spanned_pages;
> unsigned long pfn;
> + struct page *pgdat_page = virt_to_page(pgdat);
> + int i;
>
> for (pfn = start_pfn; pfn< end_pfn; pfn += PAGES_PER_SECTION) {
> unsigned long section_nr = pfn_to_section_nr(pfn);
> @@ -1338,6 +1341,21 @@ static void try_offline_node(int nid)
> */
> node_set_offline(nid);
> unregister_one_node(nid);
> +
> + if (!PageSlab(pgdat_page)&& !PageCompound(pgdat_page))
> + /* node data is allocated from boot memory */
> + return;
> +
> + /* free waittable in each zone */
> + for (i = 0; i< MAX_NR_ZONES; i++) {
> + struct zone *zone = pgdat->node_zones + i;
> +
> + if (zone->wait_table)
> + vfree(zone->wait_table);
> + }
> +
> + arch_refresh_nodedata(nid, NULL);
> + arch_free_nodedata(pgdat);
> }
>
> int __ref remove_memory(int nid, u64 start, u64 size)
^ permalink raw reply
* Re: [Patch v4 03/12] memory-hotplug: remove redundant codes
From: Tang Chen @ 2012-12-04 10:31 UTC (permalink / raw)
To: Wen Congyang
Cc: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
linux-sh, linux-ia64, cmetcalf, sparclinux, David Rientjes,
Jiang Liu, Len Brown, benh, paulus, Christoph Lameter,
Minchan Kim, Andrew Morton, KOSAKI Motohiro, Yasuaki Ishimatsu,
Jianguo Wu
In-Reply-To: <50BDC0DE.4010103@cn.fujitsu.com>
On 12/04/2012 05:22 PM, Tang Chen wrote:
> On 11/27/2012 06:00 PM, Wen Congyang wrote:
>> offlining memory blocks and checking whether memory blocks are offlined
>> are very similar. This patch introduces a new function to remove
>> redundant codes.
>>
>> CC: David Rientjes<rientjes@google.com>
>> CC: Jiang Liu<liuj97@gmail.com>
>> CC: Len Brown<len.brown@intel.com>
>> CC: Christoph Lameter<cl@linux.com>
>> Cc: Minchan Kim<minchan.kim@gmail.com>
>> CC: Andrew Morton<akpm@linux-foundation.org>
>> CC: KOSAKI Motohiro<kosaki.motohiro@jp.fujitsu.com>
>> CC: Yasuaki Ishimatsu<isimatu.yasuaki@jp.fujitsu.com>
>> Signed-off-by: Wen Congyang<wency@cn.fujitsu.com>
>
> Can we merge this patch with [PATCH 03/12] ?
Sorry, I think we can merge this patch into [PATCH 02/12].
Thanks. :)
>
> Reviewed-by: Tang Chen <tangchen@cn.fujitsu.com>
>
^ permalink raw reply
* [PATCH v3] media: V4L2: add temporary clock helpers
From: Guennadi Liakhovetski @ 2012-12-04 10:42 UTC (permalink / raw)
To: Linux Media Mailing List
Cc: Laurent Pinchart, Sakari Ailus, Sylwester Nawrocki, Hans Verkuil,
Sylwester Nawrocki, Magnus Damm, linux-sh
Typical video devices like camera sensors require an external clock source.
Many such devices cannot even access their hardware registers without a
running clock. These clock sources should be controlled by their consumers.
This should be performed, using the generic clock framework. Unfortunately
so far only very few systems have been ported to that framework. This patch
adds a set of temporary helpers, mimicking the generic clock API, to V4L2.
Platforms, adopting the clock API, should switch to using it. Eventually
this temporary API should be removed.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
v3: (thanks for all the comments)
1. add and use a mutex to protect the enable counter instead of an atomic
variable
2. add a use-count
3. add "const" to dev_id
4. move allocations outside the mutex
5. allow rate reading and setting on disabled clock
6. rename the clock list head:-)
drivers/media/v4l2-core/Makefile | 2 +-
drivers/media/v4l2-core/v4l2-clk.c | 176 ++++++++++++++++++++++++++++++++++++
include/media/v4l2-clk.h | 54 +++++++++++
3 files changed, 231 insertions(+), 1 deletions(-)
create mode 100644 drivers/media/v4l2-core/v4l2-clk.c
create mode 100644 include/media/v4l2-clk.h
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index c2d61d4..d065c01 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -5,7 +5,7 @@
tuner-objs := tuner-core.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
- v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
+ v4l2-event.o v4l2-ctrls.o v4l2-subdev.o v4l2-clk.o
ifeq ($(CONFIG_COMPAT),y)
videodev-objs += v4l2-compat-ioctl32.o
endif
diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c
new file mode 100644
index 0000000..2225081
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-clk.c
@@ -0,0 +1,176 @@
+/*
+ * V4L2 clock service
+ *
+ * Copyright (C) 2012, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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 <linux/atomic.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+
+#include <media/v4l2-clk.h>
+#include <media/v4l2-subdev.h>
+
+static DEFINE_MUTEX(clk_lock);
+static LIST_HEAD(clk_list);
+
+static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id)
+{
+ struct v4l2_clk *clk;
+
+ list_for_each_entry(clk, &clk_list, list) {
+ if (strcmp(dev_id, clk->dev_id))
+ continue;
+
+ if (!id || !clk->id || !strcmp(clk->id, id))
+ return clk;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+struct v4l2_clk *v4l2_clk_get(struct v4l2_subdev *sd, const char *id)
+{
+ struct v4l2_clk *clk;
+
+ mutex_lock(&clk_lock);
+ clk = v4l2_clk_find(sd->name, id);
+
+ if (!IS_ERR(clk) && !try_module_get(clk->ops->owner))
+ clk = ERR_PTR(-ENODEV);
+ mutex_unlock(&clk_lock);
+
+ if (!IS_ERR(clk))
+ atomic_inc(&clk->use_count);
+
+ return clk;
+}
+EXPORT_SYMBOL(v4l2_clk_get);
+
+void v4l2_clk_put(struct v4l2_clk *clk)
+{
+ if (!IS_ERR(clk)) {
+ atomic_dec(&clk->use_count);
+ module_put(clk->ops->owner);
+ }
+}
+EXPORT_SYMBOL(v4l2_clk_put);
+
+int v4l2_clk_enable(struct v4l2_clk *clk)
+{
+ int ret;
+ mutex_lock(&clk->lock);
+ if (++clk->enable = 1 && clk->ops->enable) {
+ ret = clk->ops->enable(clk);
+ if (ret < 0)
+ clk->enable--;
+ } else {
+ ret = 0;
+ }
+ mutex_unlock(&clk->lock);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_clk_enable);
+
+void v4l2_clk_disable(struct v4l2_clk *clk)
+{
+ int enable;
+
+ mutex_lock(&clk->lock);
+ enable = --clk->enable;
+ if (WARN(enable < 0, "Unbalanced %s() on %s:%s!\n", __func__,
+ clk->dev_id, clk->id))
+ clk->enable++;
+ else if (!enable && clk->ops->disable)
+ clk->ops->disable(clk);
+ mutex_unlock(&clk->lock);
+}
+EXPORT_SYMBOL(v4l2_clk_disable);
+
+unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk)
+{
+ if (!clk->ops->get_rate)
+ return -ENOSYS;
+
+ return clk->ops->get_rate(clk);
+}
+EXPORT_SYMBOL(v4l2_clk_get_rate);
+
+int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate)
+{
+ if (!clk->ops->set_rate)
+ return -ENOSYS;
+
+ return clk->ops->set_rate(clk, rate);
+}
+EXPORT_SYMBOL(v4l2_clk_set_rate);
+
+struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,
+ const char *dev_id,
+ const char *id, void *priv)
+{
+ struct v4l2_clk *clk;
+ int ret;
+
+ if (!ops || !dev_id)
+ return ERR_PTR(-EINVAL);
+
+ clk = kzalloc(sizeof(struct v4l2_clk), GFP_KERNEL);
+ if (!clk)
+ return ERR_PTR(-ENOMEM);
+
+ clk->id = kstrdup(id, GFP_KERNEL);
+ clk->dev_id = kstrdup(dev_id, GFP_KERNEL);
+ if ((id && !clk->id) || !clk->dev_id) {
+ ret = -ENOMEM;
+ goto ealloc;
+ }
+ clk->ops = ops;
+ clk->priv = priv;
+ atomic_set(&clk->use_count, 0);
+ mutex_init(&clk->lock);
+
+ mutex_lock(&clk_lock);
+ if (!IS_ERR(v4l2_clk_find(dev_id, id))) {
+ mutex_unlock(&clk_lock);
+ ret = -EEXIST;
+ goto eexist;
+ }
+ list_add_tail(&clk->list, &clk_list);
+ mutex_unlock(&clk_lock);
+
+ return clk;
+
+eexist:
+ealloc:
+ kfree(clk->id);
+ kfree(clk->dev_id);
+ kfree(clk);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(v4l2_clk_register);
+
+void v4l2_clk_unregister(struct v4l2_clk *clk)
+{
+ if (unlikely(atomic_read(&clk->use_count))) {
+ pr_err("%s(): Unregistering ref-counted %s:%s clock!\n",
+ __func__, clk->dev_id, clk->id);
+ BUG();
+ }
+
+ mutex_lock(&clk_lock);
+ list_del(&clk->list);
+ mutex_unlock(&clk_lock);
+
+ kfree(clk->id);
+ kfree(clk->dev_id);
+ kfree(clk);
+}
+EXPORT_SYMBOL(v4l2_clk_unregister);
diff --git a/include/media/v4l2-clk.h b/include/media/v4l2-clk.h
new file mode 100644
index 0000000..9b67472
--- /dev/null
+++ b/include/media/v4l2-clk.h
@@ -0,0 +1,54 @@
+/*
+ * V4L2 clock service
+ *
+ * Copyright (C) 2012, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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.
+ *
+ * ATTENTION: This is a temporary API and it shall be replaced by the generic
+ * clock API, when the latter becomes widely available.
+ */
+
+#ifndef MEDIA_V4L2_CLK_H
+#define MEDIA_V4L2_CLK_H
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+struct module;
+struct v4l2_subdev;
+
+struct v4l2_clk {
+ struct list_head list;
+ const struct v4l2_clk_ops *ops;
+ const char *dev_id;
+ const char *id;
+ int enable;
+ struct mutex lock; /* Protect the enable count */
+ atomic_t use_count;
+ void *priv;
+};
+
+struct v4l2_clk_ops {
+ struct module *owner;
+ int (*enable)(struct v4l2_clk *clk);
+ void (*disable)(struct v4l2_clk *clk);
+ unsigned long (*get_rate)(struct v4l2_clk *clk);
+ int (*set_rate)(struct v4l2_clk *clk, unsigned long);
+};
+
+struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,
+ const char *dev_name,
+ const char *name, void *priv);
+void v4l2_clk_unregister(struct v4l2_clk *clk);
+struct v4l2_clk *v4l2_clk_get(struct v4l2_subdev *sd, const char *id);
+void v4l2_clk_put(struct v4l2_clk *clk);
+int v4l2_clk_enable(struct v4l2_clk *clk);
+void v4l2_clk_disable(struct v4l2_clk *clk);
+unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk);
+int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate);
+
+#endif
--
1.7.2.5
^ permalink raw reply related
* Re: [Patch v4 08/12] memory-hotplug: remove memmap of sparse-vmemmap
From: Jianguo Wu @ 2012-12-04 12:20 UTC (permalink / raw)
To: Tang Chen
Cc: Wen Congyang, x86, linux-mm, linux-kernel, linuxppc-dev,
linux-acpi, linux-s390, linux-sh, linux-ia64, cmetcalf,
sparclinux, David Rientjes, Jiang Liu, Len Brown, benh, paulus,
Christoph Lameter, Minchan Kim, Andrew Morton, KOSAKI Motohiro,
Yasuaki Ishimatsu
In-Reply-To: <50BDBEB7.3070807@cn.fujitsu.com>
Hi Tang,
Thanks for your review and comments, Please see below for my reply.
On 2012/12/4 17:13, Tang Chen wrote:
> Hi Wu,
>
> Sorry to make noise here. Please see below. :)
>
> On 12/03/2012 10:23 AM, Jianguo Wu wrote:
>> Signed-off-by: Jianguo Wu<wujianguo@huawei.com>
>> Signed-off-by: Jiang Liu<jiang.liu@huawei.com>
>> ---
>> include/linux/mm.h | 1 +
>> mm/sparse-vmemmap.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++
>> mm/sparse.c | 3 +-
>> 3 files changed, 234 insertions(+), 1 deletions(-)
>>
>> diff --git a/include/linux/mm.h b/include/linux/mm.h
>> index 5657670..1f26af5 100644
>> --- a/include/linux/mm.h
>> +++ b/include/linux/mm.h
>> @@ -1642,6 +1642,7 @@ int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
>> void vmemmap_populate_print_last(void);
>> void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
>> unsigned long size);
>> +void vmemmap_free(struct page *memmap, unsigned long nr_pages);
>>
>> enum mf_flags {
>> MF_COUNT_INCREASED = 1<< 0,
>> diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
>> index 1b7e22a..748732d 100644
>> --- a/mm/sparse-vmemmap.c
>> +++ b/mm/sparse-vmemmap.c
>> @@ -29,6 +29,10 @@
>> #include<asm/pgalloc.h>
>> #include<asm/pgtable.h>
>>
>> +#ifdef CONFIG_MEMORY_HOTREMOVE
>> +#include<asm/tlbflush.h>
>> +#endif
>> +
>> /*
>> * Allocate a block of memory to be used to back the virtual memory map
>> * or to back the page tables that are used to create the mapping.
>> @@ -224,3 +228,230 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
>> vmemmap_buf_end = NULL;
>> }
>> }
>> +
>> +#ifdef CONFIG_MEMORY_HOTREMOVE
>> +
>> +#define PAGE_INUSE 0xFD
>> +
>> +static void vmemmap_free_pages(struct page *page, int order)
>> +{
>> + struct zone *zone;
>> + unsigned long magic;
>> +
>> + magic = (unsigned long) page->lru.next;
>> + if (magic = SECTION_INFO || magic = MIX_SECTION_INFO) {
>> + put_page_bootmem(page);
>> +
>> + zone = page_zone(page);
>> + zone_span_writelock(zone);
>> + zone->present_pages++;
>> + zone_span_writeunlock(zone);
>> + totalram_pages++;
>
> Seems that we have different ways to handle pages allocated by bootmem
> or by regular allocator. Is the checking way in [PATCH 09/12] available
> here ?
>
> + /* bootmem page has reserved flag */
> + if (PageReserved(page)) {
> ......
> + }
>
> If so, I think we can just merge these two functions.
Hmm, direct mapping table isn't allocated by bootmem allocator such as memblock, can't be free by put_page_bootmem().
But I will try to merge these two functions.
>
>> + } else
>> + free_pages((unsigned long)page_address(page), order);
>> +}
>> +
>> +static void free_pte_table(pmd_t *pmd)
>> +{
>> + pte_t *pte, *pte_start;
>> + int i;
>> +
>> + pte_start = (pte_t *)pmd_page_vaddr(*pmd);
>> + for (i = 0; i< PTRS_PER_PTE; i++) {
>> + pte = pte_start + i;
>> + if (pte_val(*pte))
>> + return;
>> + }
>> +
>> + /* free a pte talbe */
>> + vmemmap_free_pages(pmd_page(*pmd), 0);
>> + spin_lock(&init_mm.page_table_lock);
>> + pmd_clear(pmd);
>> + spin_unlock(&init_mm.page_table_lock);
>> +}
>> +
>> +static void free_pmd_table(pud_t *pud)
>> +{
>> + pmd_t *pmd, *pmd_start;
>> + int i;
>> +
>> + pmd_start = (pmd_t *)pud_page_vaddr(*pud);
>> + for (i = 0; i< PTRS_PER_PMD; i++) {
>> + pmd = pmd_start + i;
>> + if (pmd_val(*pmd))
>> + return;
>> + }
>> +
>> + /* free a pmd talbe */
>> + vmemmap_free_pages(pud_page(*pud), 0);
>> + spin_lock(&init_mm.page_table_lock);
>> + pud_clear(pud);
>> + spin_unlock(&init_mm.page_table_lock);
>> +}
>> +
>> +static void free_pud_table(pgd_t *pgd)
>> +{
>> + pud_t *pud, *pud_start;
>> + int i;
>> +
>> + pud_start = (pud_t *)pgd_page_vaddr(*pgd);
>> + for (i = 0; i< PTRS_PER_PUD; i++) {
>> + pud = pud_start + i;
>> + if (pud_val(*pud))
>> + return;
>> + }
>> +
>> + /* free a pud table */
>> + vmemmap_free_pages(pgd_page(*pgd), 0);
>> + spin_lock(&init_mm.page_table_lock);
>> + pgd_clear(pgd);
>> + spin_unlock(&init_mm.page_table_lock);
>> +}
>
> All the free_xxx_table() are very similar to the functions in
> [PATCH 09/12]. Could we reuse them anyway ?
yes, we can reuse them.
>
>> +
>> +static int split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase)
>> +{
>> + struct page *page = pmd_page(*(pmd_t *)kpte);
>> + int i = 0;
>> + unsigned long magic;
>> + unsigned long section_nr;
>> +
>> + __split_large_page(kpte, address, pbase);
>
> Is this patch going to replace [PATCH 08/12] ?
>
I wish to replace [PATCH 08/12], but need Congyang and Yasuaki to confirm first:)
> If so, __split_large_page() was added and exported in [PATCH 09/12],
> then we should move it here, right ?
yes.
and what do you think about moving vmemmap_pud[pmd/pte]_remove() to arch/x86/mm/init_64.c,
to be consistent with vmemmap_populate() ?
I will rework [PATCH 08/12] and [PATCH 09/12] soon.
Thanks,
Jianguo Wu.
>
> If not, free_map_bootmem() and __kfree_section_memmap() were changed in
> [PATCH 08/12], and we need to handle this.
>
>> + __flush_tlb_all();
>> +
>> + magic = (unsigned long) page->lru.next;
>> + if (magic = SECTION_INFO) {
>> + section_nr = pfn_to_section_nr(page_to_pfn(page));
>> + while (i< PTRS_PER_PMD) {
>> + page++;
>> + i++;
>> + get_page_bootmem(section_nr, page, SECTION_INFO);
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void vmemmap_pte_remove(pmd_t *pmd, unsigned long addr, unsigned long end)
>> +{
>> + pte_t *pte;
>> + unsigned long next;
>> + void *page_addr;
>> +
>> + pte = pte_offset_kernel(pmd, addr);
>> + for (; addr< end; pte++, addr += PAGE_SIZE) {
>> + next = (addr + PAGE_SIZE)& PAGE_MASK;
>> + if (next> end)
>> + next = end;
>> +
>> + if (pte_none(*pte))
>> + continue;
>> + if (IS_ALIGNED(addr, PAGE_SIZE)&&
>> + IS_ALIGNED(next, PAGE_SIZE)) {
>> + vmemmap_free_pages(pte_page(*pte), 0);
>> + spin_lock(&init_mm.page_table_lock);
>> + pte_clear(&init_mm, addr, pte);
>> + spin_unlock(&init_mm.page_table_lock);
>> + } else {
>> + /*
>> + * Removed page structs are filled with 0xFD.
>> + */
>> + memset((void *)addr, PAGE_INUSE, next - addr);
>> + page_addr = page_address(pte_page(*pte));
>> +
>> + if (!memchr_inv(page_addr, PAGE_INUSE, PAGE_SIZE)) {
>> + spin_lock(&init_mm.page_table_lock);
>> + pte_clear(&init_mm, addr, pte);
>> + spin_unlock(&init_mm.page_table_lock);
>> + }
>> + }
>> + }
>> +
>> + free_pte_table(pmd);
>> + __flush_tlb_all();
>> +}
>> +
>> +static void vmemmap_pmd_remove(pud_t *pud, unsigned long addr, unsigned long end)
>> +{
>> + unsigned long next;
>> + pmd_t *pmd;
>> +
>> + pmd = pmd_offset(pud, addr);
>> + for (; addr< end; addr = next, pmd++) {
>> + next = pmd_addr_end(addr, end);
>> + if (pmd_none(*pmd))
>> + continue;
>> +
>> + if (cpu_has_pse) {
>> + unsigned long pte_base;
>> +
>> + if (IS_ALIGNED(addr, PMD_SIZE)&&
>> + IS_ALIGNED(next, PMD_SIZE)) {
>> + vmemmap_free_pages(pmd_page(*pmd),
>> + get_order(PMD_SIZE));
>> + spin_lock(&init_mm.page_table_lock);
>> + pmd_clear(pmd);
>> + spin_unlock(&init_mm.page_table_lock);
>> + continue;
>> + }
>> +
>> + /*
>> + * We use 2M page, but we need to remove part of them,
>> + * so split 2M page to 4K page.
>> + */
>> + pte_base = get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK);
>> + if (!pte_base) {
>> + WARN_ON(1);
>> + continue;
>> + }
>> +
>> + split_large_page((pte_t *)pmd, addr, (pte_t *)pte_base);
>> + __flush_tlb_all();
>> +
>> + spin_lock(&init_mm.page_table_lock);
>> + pmd_populate_kernel(&init_mm, pmd, (pte_t *)pte_base);
>> + spin_unlock(&init_mm.page_table_lock);
>> + }
>> +
>> + vmemmap_pte_remove(pmd, addr, next);
>> + }
>> +
>> + free_pmd_table(pud);
>> + __flush_tlb_all();
>> +}
>> +
>> +static void vmemmap_pud_remove(pgd_t *pgd, unsigned long addr, unsigned long end)
>> +{
>> + unsigned long next;
>> + pud_t *pud;
>> +
>> + pud = pud_offset(pgd, addr);
>> + for (; addr< end; addr = next, pud++) {
>> + next = pud_addr_end(addr, end);
>> + if (pud_none(*pud))
>> + continue;
>> +
>> + vmemmap_pmd_remove(pud, addr, next);
>> + }
>> +
>> + free_pud_table(pgd);
>> + __flush_tlb_all();
>> +}
>> +
>> +void vmemmap_free(struct page *memmap, unsigned long nr_pages)
>> +{
>> + unsigned long addr = (unsigned long)memmap;
>> + unsigned long end = (unsigned long)(memmap + nr_pages);
>> + unsigned long next;
>> +
>> + for (; addr< end; addr = next) {
>> + pgd_t *pgd = pgd_offset_k(addr);
>> +
>> + next = pgd_addr_end(addr, end);
>> + if (!pgd_present(*pgd))
>> + continue;
>> +
>> + vmemmap_pud_remove(pgd, addr, next);
>> + sync_global_pgds(addr, next - 1);
>> + }
>> +}
>> +#endif
>> diff --git a/mm/sparse.c b/mm/sparse.c
>> index fac95f2..4060229 100644
>> --- a/mm/sparse.c
>> +++ b/mm/sparse.c
>> @@ -615,10 +615,11 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
>> }
>> static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
>> {
>> - return; /* XXX: Not implemented yet */
>> + vmemmap_free(memmap, nr_pages);
>> }
>> static void free_map_bootmem(struct page *page, unsigned long nr_pages)
>
> In the latest kernel, this line was:
> static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
>
>> {
>> + vmemmap_free(page, nr_pages);
>> }
>> #else
>> static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
>
>
> .
>
^ permalink raw reply
* [PATCH 0/1] ARM: shmobile: sh73a0: fixup div4 bitmask
From: Kuninori Morimoto @ 2012-12-05 1:42 UTC (permalink / raw)
To: linux-sh
Hi Simon, Magnus
I guess currect div4_clks bitmap on sh73a0 was wrong.
This patch fixes it. it is based on v2.0 datasheet.
>> Magnus
Could you please check this patch ?
and give it your Acked-by if you can agree.
BTW, v2.0 datasheet shows FRQCRA : ZGFC 1010 is 1/5,
but I guess it is 1001 ?
I'm not sure...
current code is still keeping 1010 but...
^ permalink raw reply
* [PATCH] ARM: shmobile: sh73a0: fixup div4_clks bitmap
From: Kuninori Morimoto @ 2012-12-05 1:43 UTC (permalink / raw)
To: linux-sh
div4_clks's bitmap of sh73a0 was wrong.
This patch is based on v2.0 datasheet.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
arch/arm/mach-shmobile/clock-sh73a0.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 516ff7f..5f57701 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -264,17 +264,17 @@ enum { DIV4_I, DIV4_ZG, DIV4_M3, DIV4_B, DIV4_M1, DIV4_M2,
SH_CLK_DIV4(&pll1_clk, _reg, _bit, _mask, _flags)
static struct clk div4_clks[DIV4_NR] = {
- [DIV4_I] = DIV4(FRQCRA, 20, 0xfff, CLK_ENABLE_ON_INIT),
- [DIV4_ZG] = DIV4(FRQCRA, 16, 0xbff, CLK_ENABLE_ON_INIT),
- [DIV4_M3] = DIV4(FRQCRA, 12, 0xfff, CLK_ENABLE_ON_INIT),
- [DIV4_B] = DIV4(FRQCRA, 8, 0xfff, CLK_ENABLE_ON_INIT),
- [DIV4_M1] = DIV4(FRQCRA, 4, 0xfff, 0),
- [DIV4_M2] = DIV4(FRQCRA, 0, 0xfff, 0),
- [DIV4_Z] = DIV4(FRQCRB, 24, 0xbff, 0),
- [DIV4_ZTR] = DIV4(FRQCRB, 20, 0xfff, 0),
- [DIV4_ZT] = DIV4(FRQCRB, 16, 0xfff, 0),
- [DIV4_ZX] = DIV4(FRQCRB, 12, 0xfff, 0),
- [DIV4_HP] = DIV4(FRQCRB, 4, 0xfff, 0),
+ [DIV4_I] = DIV4(FRQCRA, 20, 0xdff, CLK_ENABLE_ON_INIT),
+ [DIV4_ZG] = DIV4(FRQCRA, 16, 0xd7f, CLK_ENABLE_ON_INIT),
+ [DIV4_M3] = DIV4(FRQCRA, 12, 0x1dff, CLK_ENABLE_ON_INIT),
+ [DIV4_B] = DIV4(FRQCRA, 8, 0xdff, CLK_ENABLE_ON_INIT),
+ [DIV4_M1] = DIV4(FRQCRA, 4, 0x1dff, 0),
+ [DIV4_M2] = DIV4(FRQCRA, 0, 0x1dff, 0),
+ [DIV4_Z] = DIV4(FRQCRB, 24, 0x97f, 0),
+ [DIV4_ZTR] = DIV4(FRQCRB, 20, 0xdff, 0),
+ [DIV4_ZT] = DIV4(FRQCRB, 16, 0xdff, 0),
+ [DIV4_ZX] = DIV4(FRQCRB, 12, 0xdff, 0),
+ [DIV4_HP] = DIV4(FRQCRB, 4, 0xdff, 0),
};
enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_ZB1,
--
1.7.9.5
^ permalink raw reply related
* Re: [Patch v4 08/12] memory-hotplug: remove memmap of sparse-vmemmap
From: Tang Chen @ 2012-12-05 2:07 UTC (permalink / raw)
To: Jianguo Wu
Cc: Wen Congyang, x86, linux-mm, linux-kernel, linuxppc-dev,
linux-acpi, linux-s390, linux-sh, linux-ia64, cmetcalf,
sparclinux, David Rientjes, Jiang Liu, Len Brown, benh, paulus,
Christoph Lameter, Minchan Kim, Andrew Morton, KOSAKI Motohiro,
Yasuaki Ishimatsu
In-Reply-To: <50BDEA82.4050809@huawei.com>
Hi Wu,
On 12/04/2012 08:20 PM, Jianguo Wu wrote:
(snip)
>>
>> Seems that we have different ways to handle pages allocated by bootmem
>> or by regular allocator. Is the checking way in [PATCH 09/12] available
>> here ?
>>
>> + /* bootmem page has reserved flag */
>> + if (PageReserved(page)) {
>> ......
>> + }
>>
>> If so, I think we can just merge these two functions.
>
> Hmm, direct mapping table isn't allocated by bootmem allocator such as memblock, can't be free by put_page_bootmem().
> But I will try to merge these two functions.
>
Oh, I didn't notice this, thanks. :)
(snip)
>>> +
>>> + __split_large_page(kpte, address, pbase);
>>
>> Is this patch going to replace [PATCH 08/12] ?
>>
>
> I wish to replace [PATCH 08/12], but need Congyang and Yasuaki to confirm first:)
>
>> If so, __split_large_page() was added and exported in [PATCH 09/12],
>> then we should move it here, right ?
>
> yes.
>
> and what do you think about moving vmemmap_pud[pmd/pte]_remove() to arch/x86/mm/init_64.c,
> to be consistent with vmemmap_populate() ?
It is a good idea since pud/pmd/pte related code could be platform
dependent. And I'm also trying to move vmemmap_free() to
arch/x86/mm/init_64.c too. I want to have a common interface just
like vmemmap_populate(). :)
>
> I will rework [PATCH 08/12] and [PATCH 09/12] soon.
I am rebasing the whole patch set now. And I think I chould finish part
of your work too. A new patch-set is coming soon, and your rework is
also welcome. :)
Thanks. :)
^ permalink raw reply
* Re: [Patch v4 08/12] memory-hotplug: remove memmap of sparse-vmemmap
From: Jianguo Wu @ 2012-12-05 3:23 UTC (permalink / raw)
To: Tang Chen
Cc: Wen Congyang, x86, linux-mm, linux-kernel, linuxppc-dev,
linux-acpi, linux-s390, linux-sh, linux-ia64, cmetcalf,
sparclinux, David Rientjes, Jiang Liu, Len Brown, benh, paulus,
Christoph Lameter, Minchan Kim, Andrew Morton, KOSAKI Motohiro,
Yasuaki Ishimatsu
In-Reply-To: <50BEAC66.8020500@cn.fujitsu.com>
Hi Tang,
On 2012/12/5 10:07, Tang Chen wrote:
> Hi Wu,
>
> On 12/04/2012 08:20 PM, Jianguo Wu wrote:
> (snip)
>>>
>>> Seems that we have different ways to handle pages allocated by bootmem
>>> or by regular allocator. Is the checking way in [PATCH 09/12] available
>>> here ?
>>>
>>> + /* bootmem page has reserved flag */
>>> + if (PageReserved(page)) {
>>> ......
>>> + }
>>>
>>> If so, I think we can just merge these two functions.
>>
>> Hmm, direct mapping table isn't allocated by bootmem allocator such as memblock, can't be free by put_page_bootmem().
>> But I will try to merge these two functions.
>>
>
> Oh, I didn't notice this, thanks. :)
>
> (snip)
>
>>>> +
>>>> + __split_large_page(kpte, address, pbase);
>>>
>>> Is this patch going to replace [PATCH 08/12] ?
>>>
>>
>> I wish to replace [PATCH 08/12], but need Congyang and Yasuaki to confirm first:)
>>
>>> If so, __split_large_page() was added and exported in [PATCH 09/12],
>>> then we should move it here, right ?
>>
>> yes.
>>
>> and what do you think about moving vmemmap_pud[pmd/pte]_remove() to arch/x86/mm/init_64.c,
>> to be consistent with vmemmap_populate() ?
>
> It is a good idea since pud/pmd/pte related code could be platform
> dependent. And I'm also trying to move vmemmap_free() to
> arch/x86/mm/init_64.c too. I want to have a common interface just
> like vmemmap_populate(). :)
>
Great.
>>
>> I will rework [PATCH 08/12] and [PATCH 09/12] soon.
>
> I am rebasing the whole patch set now. And I think I chould finish part
> of your work too. A new patch-set is coming soon, and your rework is
> also welcome. :)
>
Since you are rebasing now, I will wait for your new patche-set :).
Thanks.
Jianguo Wu
> Thanks. :)
>
>
>
> .
>
^ permalink raw reply
* [PATCH 1/2] ARM: shmobile: sh73a0: Add CPU sleep suspend
From: Bastian Hecht @ 2012-12-05 12:13 UTC (permalink / raw)
To: linux-arm-kernel
From: Bastian Hecht <hechtb@gmail.com>
Add the lighest possible sleep mode on Cortex-A9 cores: CPU sleep. It is
entered by a simple dsb and wfi instruction via cpu_do_idle(). As just
clocks are stopped there is no need to save or restore any state of the
system.
Signed-off-by: Bastian Hecht <hechtb+renesas@gmail.com>
---
arch/arm/mach-shmobile/Makefile | 1 +
arch/arm/mach-shmobile/board-kzm9g.c | 2 ++
arch/arm/mach-shmobile/include/mach/common.h | 1 +
arch/arm/mach-shmobile/pm-sh73a0.c | 32 ++++++++++++++++++++++++++
4 files changed, 36 insertions(+)
create mode 100644 arch/arm/mach-shmobile/pm-sh73a0.c
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index fe2c97c..d0d06f2 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_ARCH_SHMOBILE) += pm-rmobile.o
obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o
obj-$(CONFIG_ARCH_R8A7740) += pm-r8a7740.o
obj-$(CONFIG_ARCH_R8A7779) += pm-r8a7779.o
+obj-$(CONFIG_ARCH_SH73A0) += pm-sh73a0.o
# Board objects
obj-$(CONFIG_MACH_G3EVM) += board-g3evm.o
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index 0a43f31..dc8c0f8 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -760,6 +760,8 @@ static void __init kzm_init(void)
sh73a0_add_standard_devices();
platform_add_devices(kzm_devices, ARRAY_SIZE(kzm_devices));
+
+ sh73a0_pm_init();
}
static void kzm9g_restart(char mode, const char *cmd)
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index d47e215..318551b3 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -54,6 +54,7 @@ extern void sh73a0_add_early_devices(void);
extern void sh73a0_add_standard_devices(void);
extern void sh73a0_clock_init(void);
extern void sh73a0_pinmux_init(void);
+extern void sh73a0_pm_init(void);
extern struct clk sh73a0_extal1_clk;
extern struct clk sh73a0_extal2_clk;
extern struct clk sh73a0_extcki_clk;
diff --git a/arch/arm/mach-shmobile/pm-sh73a0.c b/arch/arm/mach-shmobile/pm-sh73a0.c
new file mode 100644
index 0000000..9cf67bb
--- /dev/null
+++ b/arch/arm/mach-shmobile/pm-sh73a0.c
@@ -0,0 +1,32 @@
+/*
+ * sh73a0 Power management support
+ *
+ * Copyright (C) 2012 Bastian Hecht <hechtb+renesas@gmail.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/suspend.h>
+#include <mach/common.h>
+
+#ifdef CONFIG_SUSPEND
+static int sh73a0_enter_suspend(suspend_state_t suspend_state)
+{
+ cpu_do_idle();
+ return 0;
+}
+
+static void sh73a0_suspend_init(void)
+{
+ shmobile_suspend_ops.enter = sh73a0_enter_suspend;
+}
+#else
+static void sh73a0_suspend_init(void) {}
+#endif
+
+void __init sh73a0_pm_init(void)
+{
+ sh73a0_suspend_init();
+}
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox