LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: Kernel build fail with "Circular xxxx <- xxxx dependency dropped"
From: Mike Qiu @ 2014-06-11 12:36 UTC (permalink / raw)
  To: Michal Marek; +Cc: Sam Ravnborg, linuxppc, linux-kbuild
In-Reply-To: <539849F6.8010501@suse.cz>

Hi Michal,

after ally you patch, it also has some issue, see below:

WARNING: 1 bad relocations
c000000001455040 R_PPC64_ADDR64    uprobes_fetch_type_table
arch/powerpc/boot/Makefile:336: target 
`arch/powerpc/boot/zImage.pseries' given more than once in the same rule.
gcc -m32 -Wp,-MD,arch/powerpc/boot/.zImage.lds.d  -nostdinc -isystem 
/usr/lib/gcc/ppc64-redhat-linux/4.7.2/include -I./arch/powerpc/include 
-Iarch/powerpc/include/generated -Iinclude -I./arch/powe
rpc/include/uapi -Iarch/powerpc/include/generated/uapi -I./include/uapi 
-Iinclude/generated/uapi -include ./include/linux/kconfig.h -D__KERNEL__ 
-Iarch/powerpc      -E -Wp,-MD,arch/powerpc/boot/.zI
mage.lds.d -P -Upowerpc \
         -D__ASSEMBLY__ -DLINKER_SCRIPT -o arch/powerpc/boot/zImage.lds 
arch/powerpc/boot/zImage.lds.S
   WRAP    arch/powerpc/boot/zImage.pseries
   WRAP    arch/powerpc/boot/zImage.epapr
   MODPOST 1853 modules
INFO: Uncompressed kernel (size 0x14d0db8) overlaps the address of the 
wrapper(0x400000)
INFO: Fixing the link_address of wrapper to (0x1500000)
ld: cannot find arch/powerpc/boot/vmlinux.o: No such file or directory
make[1]: *** [arch/powerpc/boot/zImage.pseries] Error 1
make[1]: *** Waiting for unfinished jobs....
INFO: Uncompressed kernel (size 0x14d0db8) overlaps the address of the 
wrapper(0x400000)
INFO: Fixing the link_address of wrapper to (0x1500000)
ld: cannot find arch/powerpc/boot/vmlinux.o: No such file or directory
make[1]: *** [arch/powerpc/boot/zImage.epapr] Error 1
make: *** [zImage] Error 2
make: *** Waiting for unfinished jobs....

Thanks
Mike

On 06/11/2014 08:22 PM, Michal Marek wrote:
> Dne 11.6.2014 14:21, Michal Marek napsal(a):
>> On Wed, Jun 11, 2014 at 10:24:24AM +0200, Michal Marek wrote:
>>> Dne 11.6.2014 08:02, Mike Qiu napsal(a):
>>>> make[1]: Circular arch/powerpc/boot/zImage.lds.S <-
>>>> arch/powerpc/boot/zImage.lds dependency dropped.
>>>> make[1]: Circular arch/powerpc/boot/zImage.coff.lds.S <-
>>>> arch/powerpc/boot/zImage.lds dependency dropped.
>>>> make[1]: Circular arch/powerpc/boot/zImage.coff.lds.S <-
>>>> arch/powerpc/boot/zImage.coff.lds dependency dropped.
>>>> make[1]: Circular arch/powerpc/boot/zImage.ps3.lds.S <-
>>>> arch/powerpc/boot/zImage.lds dependency dropped.
>>>> make[1]: Circular arch/powerpc/boot/zImage.ps3.lds.S <-
>>>> arch/powerpc/boot/zImage.coff.lds dependency dropped.
>>>> make[1]: Circular arch/powerpc/boot/zImage.ps3.lds.S <-
>>>> arch/powerpc/boot/zImage.ps3.lds dependency dropped.
>>>>    WRAP    arch/powerpc/boot/zImage.ps3.lds.S
>>>> INFO: Uncompressed kernel (size 0x14d0db8) overlaps the address of the
>>>> wrapper(0x400000)
>>>> INFO: Fixing the link_address of wrapper to (0x1500000)
>>>> ld: cannot open linker script file arch/powerpc/boot/zImage.lds: No such
>>>> file or directory
>>>> make[1]: *** [arch/powerpc/boot/zImage.ps3.lds.S] Error 1
>>>> make: *** [zImage] Error 2
>>>> make: *** Waiting for unfinished jobs....
>>>>    MODPOST 1853 modules
>>>>
>>>> I use git bisect to find out the possible commits to lead this problem:
>>>> 7e1c04779efd51154baf652e653ceb24ce68939b kbuild: Use relative path for
>>>> $(objtree)
>>>> 890676c65d699db3ad82e7dddd0cf8fb449031af kbuild: Use relative path when
>>>> building in the source tree
>>>> 9da0763bdd82572be243fcf5161734f11568960f kbuild: Use relative path when
>>>> building in a subdir of the source tree
>>> Thanks for the report, I'll have a look. If I do not come up with a
>>> solution soon, I'll revert the series.
>> I have yet to test this, but can you try the patch below?
>>
>> Thanks!
>> Michal
>>
>>
>>  From 7f8336f4c7f2131efbe82543580dda3ec1988609 Mon Sep 17 00:00:00 2001
>> From: Michal Marek <mmarek@suse.cz>
>> Date: Wed, 11 Jun 2014 13:53:48 +0200
>> Subject: [PATCH] powerpc: Avoid circular dependency with zImage.%
>>
>> The rule to create the final images uses a zImage.% pattern.
>> Unfortunately, this also matches the names of the zImage.*.lds linker
>> scripts, which appear as a dependency of the final images. This somehow
>> worked when $(srctree) used to be an absolute path, but now the pattern
>> matches too much. List only the images from $(image-y) as the target of
>> the rule, to avoid the circular dependency.
>>
> If merged, this should of course have a Reported-by: Mike Qiu
> <qiudayu@linux.vnet.ibm.com>
>
> Michal
>
>

^ permalink raw reply

* [PATCH][RESEND] powerpc/85xx: drop hypervisor specific board compatibles
From: Laurentiu Tudor @ 2014-06-11 15:13 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Laurentiu Tudor

They're almost a duplicate of the boards array
and we can build them at run-time.

Signed-off-by: Laurentiu Tudor <Laurentiu.Tudor@freescale.com>
---
 arch/powerpc/platforms/85xx/corenet_generic.c | 49 +++++++++++----------------
 1 file changed, 20 insertions(+), 29 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
index 5db1e11..7850988 100644
--- a/arch/powerpc/platforms/85xx/corenet_generic.c
+++ b/arch/powerpc/platforms/85xx/corenet_generic.c
@@ -129,28 +129,14 @@ static const char * const boards[] __initconst = {
 	NULL
 };
 
-static const char * const hv_boards[] __initconst = {
-	"fsl,P2041RDB-hv",
-	"fsl,P3041DS-hv",
-	"fsl,OCA4080-hv",
-	"fsl,P4080DS-hv",
-	"fsl,P5020DS-hv",
-	"fsl,P5040DS-hv",
-	"fsl,T4240QDS-hv",
-	"fsl,B4860QDS-hv",
-	"fsl,B4420QDS-hv",
-	"fsl,B4220QDS-hv",
-	"fsl,T1040QDS-hv",
-	"fsl,T1042QDS-hv",
-	NULL
-};
-
 /*
  * Called very early, device-tree isn't unflattened
  */
 static int __init corenet_generic_probe(void)
 {
 	unsigned long root = of_get_flat_dt_root();
+	char hv_compat[24];
+	int i;
 #ifdef CONFIG_SMP
 	extern struct smp_ops_t smp_85xx_ops;
 #endif
@@ -159,21 +145,26 @@ static int __init corenet_generic_probe(void)
 		return 1;
 
 	/* Check if we're running under the Freescale hypervisor */
-	if (of_flat_dt_match(root, hv_boards)) {
-		ppc_md.init_IRQ = ehv_pic_init;
-		ppc_md.get_irq = ehv_pic_get_irq;
-		ppc_md.restart = fsl_hv_restart;
-		ppc_md.power_off = fsl_hv_halt;
-		ppc_md.halt = fsl_hv_halt;
+	for (i = 0; boards[i]; i++) {
+		snprintf(hv_compat, sizeof(hv_compat), "%s-hv", boards[i]);
+		if (of_flat_dt_is_compatible(root, hv_compat)) {
+			ppc_md.init_IRQ = ehv_pic_init;
+
+			ppc_md.get_irq = ehv_pic_get_irq;
+			ppc_md.restart = fsl_hv_restart;
+			ppc_md.power_off = fsl_hv_halt;
+			ppc_md.halt = fsl_hv_halt;
 #ifdef CONFIG_SMP
-		/*
-		 * Disable the timebase sync operations because we can't write
-		 * to the timebase registers under the hypervisor.
-		  */
-		smp_85xx_ops.give_timebase = NULL;
-		smp_85xx_ops.take_timebase = NULL;
+			/*
+			 * Disable the timebase sync operations because we
+			 * can't write to the timebase registers under the
+			 * hypervisor.
+			 */
+			smp_85xx_ops.give_timebase = NULL;
+			smp_85xx_ops.take_timebase = NULL;
 #endif
-		return 1;
+			return 1;
+		}
 	}
 
 	return 0;
-- 
1.9.2

^ permalink raw reply related

* [PATCH v2] powerpc: Avoid circular dependency with zImage.%
From: Michal Marek @ 2014-06-11 15:40 UTC (permalink / raw)
  To: Mike Qiu; +Cc: Sam Ravnborg, linuxppc-dev, linux-kernel, linux-kbuild
In-Reply-To: <53984D4F.6040808@linux.vnet.ibm.com>

The rule to create the final images uses a zImage.% pattern.
Unfortunately, this also matches the names of the zImage.*.lds linker
scripts, which appear as a dependency of the final images. This somehow
worked when $(srctree) used to be an absolute path, but now the pattern
matches too much. List only the images from $(image-y) as the target of
the rule, to avoid the circular dependency.

Signed-off-by: Michal Marek <mmarek@suse.cz>
---
v2:
  - Filter out duplicates in the target list
  - fix the platform argument to cmd_wrap

 arch/powerpc/boot/Makefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 426dce7..ccc25ed 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -333,8 +333,8 @@ $(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
 $(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
 	$(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
 
-$(obj)/zImage.%: vmlinux $(wrapperbits)
-	$(call if_changed,wrap,$*)
+$(addprefix $(obj)/, $(sort $(filter zImage.%, $(image-y)))): vmlinux $(wrapperbits)
+	$(call if_changed,wrap,$(subst $(obj)/zImage.,,$@))
 
 # dtbImage% - a dtbImage is a zImage with an embedded device tree blob
 $(obj)/dtbImage.initrd.%: vmlinux $(wrapperbits) $(obj)/%.dtb
-- 
1.9.2

^ permalink raw reply related

* Kernel build issues after yesterdays merge by Linus
From: Christoph Lameter @ 2014-06-11 15:44 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anton Blanchard

[-- Attachment #1: Type: TEXT/PLAIN, Size: 4110 bytes --]

This is under Ubuntu Utopic Unicorn on a Power 8 system while simply
trying to build with the Ubuntu standard kernel config. It could be that
these issues come about because we do not have an rc1 yet but I wanted to
give some early notice. Also this is a new arch to me so I may not be
aware of how things work.


1. Bad relocation while building:

root@rd-power8:/rdhome/clameter/linux# make
  CHK     include/config/kernel.release
  CHK     include/generated/uapi/linux/version.h
  CHK     include/generated/utsrelease.h
  CALL    scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  SKIPPED include/generated/compile.h
  CALL    arch/powerpc/kernel/systbl_chk.sh
  CALL    arch/powerpc/kernel/prom_init_check.sh
  CHK     kernel/config_data.h
  CALL    arch/powerpc/relocs_check.pl
WARNING: 1 bad relocations
c000000000cc7df0 R_PPC64_ADDR64    __crc_TOC.



2. "make install" fails

root@rd-power8:/rdhome/clameter/linux# make install
sh -x /rdhome/clameter/linux/arch/powerpc/boot/install.sh "3.15.0+"
vmlinux System.map "/boot" arch/powerpc/boot/zImage.pseries
arch/powerpc/boot/zImage.epapr
+ set -e
+ [ -x /home/clameter/bin/installkernel ]
+ [ -x /sbin/installkernel ]
+ exec /sbin/installkernel 3.15.0+ vmlinux System.map /boot
arch/powerpc/boot/zImage.pseries arch/powerpc/boot/zImage.epapr
Usage: installkernel <version> <image> <System.map> <directory>
/rdhome/clameter/linux/arch/powerpc/boot/Makefile:393: recipe for target
'install' failed
make[1]: *** [install] Error 1
/rdhome/clameter/linux/arch/powerpc/Makefile:294: recipe for target
'install' failed
make: *** [install] Error 2



3. Ubuntu "make-kpkg" fails

clameter@rd-power8:~/linux$ fakeroot make-kpkg --initrd --revision 1
kernel_image
exec make kpkg_version=13.013 -f
/usr/share/kernel-package/ruleset/minimal.mk debian DEBIAN_REVISION=1
INITRD=YES
====== making target debian/stamp/conf/minimal_debian [new prereqs:
]======
This is kernel package version 13.013.
test -d debian             || mkdir debian
test ! -e stamp-building || rm -f stamp-building
install -p -m 755 /usr/share/kernel-package/rules debian/rules
for file in ChangeLog  Control  Control.bin86 config templates.in rules;
do                                      \
            cp -f  /usr/share/kernel-package/$file ./debian/;
\
        done
cp: cannot stat ‘/usr/share/kernel-package/ChangeLog’: No such file or
directory
for dir  in Config docs examples ruleset scripts pkg po;  do
\
          cp -af /usr/share/kernel-package/$dir  ./debian/;
\
        done
test -f debian/control || sed         -e 's/=V/../g'  \
                -e 's/=D/1/g'         -e 's/=A/ppc64el/g'  \
	-e 's/=SA//g'  \
	-e 's/=I//g'				    \
	-e 's/=CV/./g'			    \
	-e 's/=M/Unknown Kernel Package Maintainer
<unknown@unconfigured.in.etc.kernel-pkg.conf>/g'
\
	-e 's/=ST/linux/g'      -e 's/=B/ppc64el/g'    \
                -e 's/=R//g'    /usr/share/kernel-package/Control >
debian/control
test -f debian/changelog ||  sed -e 's/=V/../g'       \
            -e 's/=D/1/g'        -e 's/=A/ppc64el/g'       \
            -e 's/=ST/linux/g'     -e 's/=B/ppc64el/g'         \
            -e 's/=M/Unknown Kernel Package Maintainer
<unknown@unconfigured.in.etc.kernel-pkg.conf>/g'
\
             /usr/share/kernel-package/changelog > debian/changelog
chmod 0644 debian/control debian/changelog
test -d ./debian/stamp || mkdir debian/stamp
make -f debian/rules debian/stamp/conf/kernel-conf
make[1]: Entering directory '/rdhome/clameter/linux'
debian/ruleset/misc/checks.mk:36: *** Error. I do not know where the
kernel image goes to [kimagedest undefined] The usual case for this is
that I could not determine which arch or subarch this machine belongs to.
Please specify a subarch, and try again..  Stop.
make[1]: Leaving directory '/rdhome/clameter/linux'
/usr/share/kernel-package/ruleset/minimal.mk:93: recipe for target
'debian/stamp/conf/minimal_debian' failed
make: *** [debian/stamp/conf/minimal_debian] Error 2
Failed to create a ./debian directory:  at /usr/bin/make-kpkg line 966.




4. Errors during build:

Lots of integer to differnt pointer size conversions?

^ permalink raw reply

* power and percpu: Could we move the paca into the percpu area?
From: Christoph Lameter @ 2014-06-11 19:37 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Tejun Heo


Looking at arch/powerpc/include/asm/percpu.h I see that the per cpu offset
comes from a local_paca field and local_paca is in r13. That means that
for all percpu operations we first have to determine the address through a
memory access.

Would it be possible to put the paca at the beginning of the percpu data
area and then have r31 point to the percpu area?

power has these nice instructions that fetch from an offset relative to a
base register which could be used throughout for percpu operations in the
kernel (similar to x86 segment registers).

With that we may also be able to use the atomic ops for fast percpu access
so that we can avoid the irq enable/disable sequence that is now required
for percpu atomics. Would result in fast and reliable percpu
counters for powerpc.

I.e. powerpc atomic inc
static __inline__ void atomic_inc(atomic_t *v)
{
        int t;

        __asm__ __volatile__(
"1:     lwarx   %0,0,%2         # atomic_inc\n\
        addic   %0,%0,1\n"
        PPC405_ERR77(0,%2)
"       stwcx.  %0,0,%2 \n\
        bne-    1b"
        : "=&r" (t), "+m" (v->counter)
        : "r" (&v->counter)
        : "cc", "xer");
}

Could be used as a template to get:

static __inline__ void raw_cpu_inc_4(__percpu void *v)
{
        int t;

        __asm__ __volatile__(
"1:     lwarx   %0,r31,%2         # percpu_inc\n\
        addic   %0,%0,1\n"
        PPC405_ERR77(0,%2)
"       stwcx.  %0,r31,%2 \n\
        bne-    1b"
        : "=&r" (t), "+m" (v)
        : "r" (&v->counter)
        : "cc", "xer");
}

^ permalink raw reply

* Re: power and percpu: Could we move the paca into the percpu area?
From: Benjamin Herrenschmidt @ 2014-06-11 20:22 UTC (permalink / raw)
  To: Christoph Lameter; +Cc: Tejun Heo, linuxppc-dev
In-Reply-To: <alpine.DEB.2.10.1406111426480.10600@gentwo.org>

On Wed, 2014-06-11 at 14:37 -0500, Christoph Lameter wrote:
> Looking at arch/powerpc/include/asm/percpu.h I see that the per cpu offset
> comes from a local_paca field and local_paca is in r13. That means that
> for all percpu operations we first have to determine the address through a
> memory access.
> 
> Would it be possible to put the paca at the beginning of the percpu data
> area and then have r31 point to the percpu area?
> 
> power has these nice instructions that fetch from an offset relative to a
> base register which could be used throughout for percpu operations in the
> kernel (similar to x86 segment registers).
> 
> With that we may also be able to use the atomic ops for fast percpu access
> so that we can avoid the irq enable/disable sequence that is now required
> for percpu atomics. Would result in fast and reliable percpu
> counters for powerpc.

So.... this is complicated :) And it's something I did want to tackle
for a while but haven't had a chance.

The issues off the top of my head are:

 - The PACA must be accessible in real mode, which means that when
running under a hypervisor, it must be allocated in the "RMA" which is
the low part of memory up to a limit that depends on the hypervisor, but
can be as low as 128M on some older machines.

 - However, we use percpu more than paca in normal kernel C code, the
PACA is mostly used during exception entry/exit, KVM, and for interrupt
soft-enable/disable. So it might make sense to change things so that r13
contains the per-cpu offset instead. However, doing that change and
updating the asm to cope isn't a trivial undertaking.

 - Direct offset from r13 in asm ... works as long as the offset is
within the signed 32k range. Otherwise we need at least one more addis
instruction. Anton mentioned the linker may have some smarts however for
removing that addis if the high part of the offset happens to be 0.

 - For atomics, the jury is still out as to whether it would be faster
or not. The atomic ops (lwarx/stwcx.) are expensive. They flush the
value out of the L1 (to L2) among others. On the other hand we have
interrupts soft-disable so masking interrupts isn't very expensive.
Unmasking, while cheap, is currently out of line however. I have been
wondering if we could move some of the soft-irq state instead to a CR
field and mark that -ffixed with gcc so we can make irq
soft-disable/enable even faster and more in-line.

Cheers,
Ben.

^ permalink raw reply

* Re: Kernel build issues after yesterdays merge by Linus
From: Benjamin Herrenschmidt @ 2014-06-11 20:26 UTC (permalink / raw)
  To: Christoph Lameter; +Cc: linuxppc-dev, Anton Blanchard
In-Reply-To: <alpine.DEB.2.10.1406111013580.8422@gentwo.org>

On Wed, 2014-06-11 at 10:44 -0500, Christoph Lameter wrote:
> This is under Ubuntu Utopic Unicorn on a Power 8 system while simply
> trying to build with the Ubuntu standard kernel config. It could be that
> these issues come about because we do not have an rc1 yet but I wanted to
> give some early notice. Also this is a new arch to me so I may not be
> aware of how things work.

Can you try my current -next ? It has an additional fix or two by Anton
for building with ABIv2 that I'll send to Linus tomorrow.

Cheers,
Ben.

> 1. Bad relocation while building:
> 
> root@rd-power8:/rdhome/clameter/linux# make
>   CHK     include/config/kernel.release
>   CHK     include/generated/uapi/linux/version.h
>   CHK     include/generated/utsrelease.h
>   CALL    scripts/checksyscalls.sh
>   CHK     include/generated/compile.h
>   SKIPPED include/generated/compile.h
>   CALL    arch/powerpc/kernel/systbl_chk.sh
>   CALL    arch/powerpc/kernel/prom_init_check.sh
>   CHK     kernel/config_data.h
>   CALL    arch/powerpc/relocs_check.pl
> WARNING: 1 bad relocations
> c000000000cc7df0 R_PPC64_ADDR64    __crc_TOC.
> 
> 
> 
> 2. "make install" fails
> 
> root@rd-power8:/rdhome/clameter/linux# make install
> sh -x /rdhome/clameter/linux/arch/powerpc/boot/install.sh "3.15.0+"
> vmlinux System.map "/boot" arch/powerpc/boot/zImage.pseries
> arch/powerpc/boot/zImage.epapr
> + set -e
> + [ -x /home/clameter/bin/installkernel ]
> + [ -x /sbin/installkernel ]
> + exec /sbin/installkernel 3.15.0+ vmlinux System.map /boot
> arch/powerpc/boot/zImage.pseries arch/powerpc/boot/zImage.epapr
> Usage: installkernel <version> <image> <System.map> <directory>
> /rdhome/clameter/linux/arch/powerpc/boot/Makefile:393: recipe for target
> 'install' failed
> make[1]: *** [install] Error 1
> /rdhome/clameter/linux/arch/powerpc/Makefile:294: recipe for target
> 'install' failed
> make: *** [install] Error 2
> 
> 
> 
> 3. Ubuntu "make-kpkg" fails
> 
> clameter@rd-power8:~/linux$ fakeroot make-kpkg --initrd --revision 1
> kernel_image
> exec make kpkg_version=13.013 -f
> /usr/share/kernel-package/ruleset/minimal.mk debian DEBIAN_REVISION=1
> INITRD=YES
> ====== making target debian/stamp/conf/minimal_debian [new prereqs:
> ]======
> This is kernel package version 13.013.
> test -d debian             || mkdir debian
> test ! -e stamp-building || rm -f stamp-building
> install -p -m 755 /usr/share/kernel-package/rules debian/rules
> for file in ChangeLog  Control  Control.bin86 config templates.in rules;
> do                                      \
>             cp -f  /usr/share/kernel-package/$file ./debian/;
> \
>         done
> cp: cannot stat ‘/usr/share/kernel-package/ChangeLog’: No such file or
> directory
> for dir  in Config docs examples ruleset scripts pkg po;  do
> \
>           cp -af /usr/share/kernel-package/$dir  ./debian/;
> \
>         done
> test -f debian/control || sed         -e 's/=V/../g'  \
>                 -e 's/=D/1/g'         -e 's/=A/ppc64el/g'  \
> 	-e 's/=SA//g'  \
> 	-e 's/=I//g'				    \
> 	-e 's/=CV/./g'			    \
> 	-e 's/=M/Unknown Kernel Package Maintainer
> <unknown@unconfigured.in.etc.kernel-pkg.conf>/g'
> \
> 	-e 's/=ST/linux/g'      -e 's/=B/ppc64el/g'    \
>                 -e 's/=R//g'    /usr/share/kernel-package/Control >
> debian/control
> test -f debian/changelog ||  sed -e 's/=V/../g'       \
>             -e 's/=D/1/g'        -e 's/=A/ppc64el/g'       \
>             -e 's/=ST/linux/g'     -e 's/=B/ppc64el/g'         \
>             -e 's/=M/Unknown Kernel Package Maintainer
> <unknown@unconfigured.in.etc.kernel-pkg.conf>/g'
> \
>              /usr/share/kernel-package/changelog > debian/changelog
> chmod 0644 debian/control debian/changelog
> test -d ./debian/stamp || mkdir debian/stamp
> make -f debian/rules debian/stamp/conf/kernel-conf
> make[1]: Entering directory '/rdhome/clameter/linux'
> debian/ruleset/misc/checks.mk:36: *** Error. I do not know where the
> kernel image goes to [kimagedest undefined] The usual case for this is
> that I could not determine which arch or subarch this machine belongs to.
> Please specify a subarch, and try again..  Stop.
> make[1]: Leaving directory '/rdhome/clameter/linux'
> /usr/share/kernel-package/ruleset/minimal.mk:93: recipe for target
> 'debian/stamp/conf/minimal_debian' failed
> make: *** [debian/stamp/conf/minimal_debian] Error 2
> Failed to create a ./debian directory:  at /usr/bin/make-kpkg line 966.
> 
> 
> 
> 
> 4. Errors during build:
> 
> Lots of integer to differnt pointer size conversions?

^ permalink raw reply

* Re: [PATCH v10 3/3] drivers/vfio: EEH support for VFIO PCI device
From: Alex Williamson @ 2014-06-11 20:59 UTC (permalink / raw)
  To: Gavin Shan; +Cc: aik, agraf, kvm-ppc, qiudayu, linuxppc-dev
In-Reply-To: <1402364517-28561-4-git-send-email-gwshan@linux.vnet.ibm.com>

On Tue, 2014-06-10 at 11:41 +1000, Gavin Shan wrote:
> The patch adds new IOCTL commands for sPAPR VFIO container device
> to support EEH functionality for PCI devices, which have been passed
> through from host to somebody else via VFIO.
> 
> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
> Acked-by: Alexander Graf <agraf@suse.de>

Acked-by: Alex Williamson <alex.williamson@redhat.com>

> ---
>  Documentation/vfio.txt              | 87 +++++++++++++++++++++++++++++++++++--
>  drivers/vfio/Makefile               |  1 +
>  drivers/vfio/pci/vfio_pci.c         | 18 ++++++--
>  drivers/vfio/vfio_iommu_spapr_tce.c | 17 +++++++-
>  drivers/vfio/vfio_spapr_eeh.c       | 87 +++++++++++++++++++++++++++++++++++++
>  include/linux/vfio.h                | 23 ++++++++++
>  include/uapi/linux/vfio.h           | 34 +++++++++++++++
>  7 files changed, 259 insertions(+), 8 deletions(-)
>  create mode 100644 drivers/vfio/vfio_spapr_eeh.c
> 
> diff --git a/Documentation/vfio.txt b/Documentation/vfio.txt
> index b9ca023..96978ec 100644
> --- a/Documentation/vfio.txt
> +++ b/Documentation/vfio.txt
> @@ -305,7 +305,15 @@ faster, the map/unmap handling has been implemented in real mode which provides
>  an excellent performance which has limitations such as inability to do
>  locked pages accounting in real time.
>  
> -So 3 additional ioctls have been added:
> +4) According to sPAPR specification, A Partitionable Endpoint (PE) is an I/O
> +subtree that can be treated as a unit for the purposes of partitioning and
> +error recovery. A PE may be a single or multi-function IOA (IO Adapter), a
> +function of a multi-function IOA, or multiple IOAs (possibly including switch
> +and bridge structures above the multiple IOAs). PPC64 guests detect PCI errors
> +and recover from them via EEH RTAS services, which works on the basis of
> +additional ioctl commands.
> +
> +So 4 additional ioctls have been added:
>  
>  	VFIO_IOMMU_SPAPR_TCE_GET_INFO - returns the size and the start
>  		of the DMA window on the PCI bus.
> @@ -316,9 +324,12 @@ So 3 additional ioctls have been added:
>  
>  	VFIO_IOMMU_DISABLE - disables the container.
>  
> +	VFIO_EEH_PE_OP - provides an API for EEH setup, error detection and recovery.
>  
>  The code flow from the example above should be slightly changed:
>  
> +	struct vfio_eeh_pe_op pe_op = { .argsz = sizeof(pe_op), .flags = 0 };
> +
>  	.....
>  	/* Add the group to the container */
>  	ioctl(group, VFIO_GROUP_SET_CONTAINER, &container);
> @@ -342,9 +353,79 @@ The code flow from the example above should be slightly changed:
>  	dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
>  
>  	/* Check here is .iova/.size are within DMA window from spapr_iommu_info */
> -
>  	ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map);
> -	.....
> +
> +	/* Get a file descriptor for the device */
> +	device = ioctl(group, VFIO_GROUP_GET_DEVICE_FD, "0000:06:0d.0");
> +
> +	....
> +
> +	/* Gratuitous device reset and go... */
> +	ioctl(device, VFIO_DEVICE_RESET);
> +
> +	/* Make sure EEH is supported */
> +	ioctl(container, VFIO_CHECK_EXTENSION, VFIO_EEH);
> +
> +	/* Enable the EEH functionality on the device */
> +	pe_op.op = VFIO_EEH_PE_ENABLE;
> +	ioctl(container, VFIO_EEH_PE_OP, &pe_op);
> +
> +	/* You're suggested to create additional data struct to represent
> +	 * PE, and put child devices belonging to same IOMMU group to the
> +	 * PE instance for later reference.
> +	 */
> +
> +	/* Check the PE's state and make sure it's in functional state */
> +	pe_op.op = VFIO_EEH_PE_GET_STATE;
> +	ioctl(container, VFIO_EEH_PE_OP, &pe_op);
> +
> +	/* Save device state using pci_save_state().
> +	 * EEH should be enabled on the specified device.
> +	 */
> +
> +	....
> +
> +	/* When 0xFF's returned from reading PCI config space or IO BARs
> +	 * of the PCI device. Check the PE's state to see if that has been
> +	 * frozen.
> +	 */
> +	ioctl(container, VFIO_EEH_PE_OP, &pe_op);
> +
> +	/* Waiting for pending PCI transactions to be completed and don't
> +	 * produce any more PCI traffic from/to the affected PE until
> +	 * recovery is finished.
> +	 */
> +
> +	/* Enable IO for the affected PE and collect logs. Usually, the
> +	 * standard part of PCI config space, AER registers are dumped
> +	 * as logs for further analysis.
> +	 */
> +	pe_op.op = VFIO_EEH_PE_UNFREEZE_IO;
> +	ioctl(container, VFIO_EEH_PE_OP, &pe_op);
> +
> +	/*
> +	 * Issue PE reset: hot or fundamental reset. Usually, hot reset
> +	 * is enough. However, the firmware of some PCI adapters would
> +	 * require fundamental reset.
> +	 */
> +	pe_op.op = VFIO_EEH_PE_RESET_HOT;
> +	ioctl(container, VFIO_EEH_PE_OP, &pe_op);
> +	pe_op.op = VFIO_EEH_PE_RESET_DEACTIVATE;
> +	ioctl(container, VFIO_EEH_PE_OP, &pe_op);
> +
> +	/* Configure the PCI bridges for the affected PE */
> +	pe_op.op = VFIO_EEH_PE_CONFIGURE;
> +	ioctl(container, VFIO_EEH_PE_OP, &pe_op);
> +
> +	/* Restored state we saved at initialization time. pci_restore_state()
> +	 * is good enough as an example.
> +	 */
> +
> +	/* Hopefully, error is recovered successfully. Now, you can resume to
> +	 * start PCI traffic to/from the affected PE.
> +	 */
> +
> +	....
>  
>  -------------------------------------------------------------------------------
>  
> diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
> index 72bfabc..50e30bc 100644
> --- a/drivers/vfio/Makefile
> +++ b/drivers/vfio/Makefile
> @@ -1,4 +1,5 @@
>  obj-$(CONFIG_VFIO) += vfio.o
>  obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
>  obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
> +obj-$(CONFIG_EEH) += vfio_spapr_eeh.o
>  obj-$(CONFIG_VFIO_PCI) += pci/
> diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
> index 7ba0424..0122665 100644
> --- a/drivers/vfio/pci/vfio_pci.c
> +++ b/drivers/vfio/pci/vfio_pci.c
> @@ -156,8 +156,10 @@ static void vfio_pci_release(void *device_data)
>  {
>  	struct vfio_pci_device *vdev = device_data;
>  
> -	if (atomic_dec_and_test(&vdev->refcnt))
> +	if (atomic_dec_and_test(&vdev->refcnt)) {
> +		vfio_spapr_pci_eeh_release(vdev->pdev);
>  		vfio_pci_disable(vdev);
> +	}
>  
>  	module_put(THIS_MODULE);
>  }
> @@ -165,19 +167,27 @@ static void vfio_pci_release(void *device_data)
>  static int vfio_pci_open(void *device_data)
>  {
>  	struct vfio_pci_device *vdev = device_data;
> +	int ret;
>  
>  	if (!try_module_get(THIS_MODULE))
>  		return -ENODEV;
>  
>  	if (atomic_inc_return(&vdev->refcnt) == 1) {
> -		int ret = vfio_pci_enable(vdev);
> +		ret = vfio_pci_enable(vdev);
> +		if (ret)
> +			goto error;
> +
> +		ret = vfio_spapr_pci_eeh_open(vdev->pdev);
>  		if (ret) {
> -			module_put(THIS_MODULE);
> -			return ret;
> +			vfio_pci_disable(vdev);
> +			goto error;
>  		}
>  	}
>  
>  	return 0;
> +error:
> +	module_put(THIS_MODULE);
> +	return ret;
>  }
>  
>  static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
> diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
> index a84788b..730b4ef 100644
> --- a/drivers/vfio/vfio_iommu_spapr_tce.c
> +++ b/drivers/vfio/vfio_iommu_spapr_tce.c
> @@ -156,7 +156,16 @@ static long tce_iommu_ioctl(void *iommu_data,
>  
>  	switch (cmd) {
>  	case VFIO_CHECK_EXTENSION:
> -		return (arg == VFIO_SPAPR_TCE_IOMMU) ? 1 : 0;
> +		switch (arg) {
> +		case VFIO_SPAPR_TCE_IOMMU:
> +			ret = 1;
> +			break;
> +		default:
> +			ret = vfio_spapr_iommu_eeh_ioctl(NULL, cmd, arg);
> +			break;
> +		}
> +
> +		return (ret < 0) ? 0 : ret;
>  
>  	case VFIO_IOMMU_SPAPR_TCE_GET_INFO: {
>  		struct vfio_iommu_spapr_tce_info info;
> @@ -283,6 +292,12 @@ static long tce_iommu_ioctl(void *iommu_data,
>  		tce_iommu_disable(container);
>  		mutex_unlock(&container->lock);
>  		return 0;
> +	case VFIO_EEH_PE_OP:
> +		if (!container->tbl || !container->tbl->it_group)
> +			return -ENODEV;
> +
> +		return vfio_spapr_iommu_eeh_ioctl(container->tbl->it_group,
> +						  cmd, arg);
>  	}
>  
>  	return -ENOTTY;
> diff --git a/drivers/vfio/vfio_spapr_eeh.c b/drivers/vfio/vfio_spapr_eeh.c
> new file mode 100644
> index 0000000..f834b4c
> --- /dev/null
> +++ b/drivers/vfio/vfio_spapr_eeh.c
> @@ -0,0 +1,87 @@
> +/*
> + * EEH functionality support for VFIO devices. The feature is only
> + * available on sPAPR compatible platforms.
> + *
> + * Copyright Gavin Shan, IBM Corporation 2014.
> + *
> + * 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/uaccess.h>
> +#include <linux/vfio.h>
> +#include <asm/eeh.h>
> +
> +/* We might build address mapping here for "fast" path later */
> +int vfio_spapr_pci_eeh_open(struct pci_dev *pdev)
> +{
> +	return eeh_dev_open(pdev);
> +}
> +
> +void vfio_spapr_pci_eeh_release(struct pci_dev *pdev)
> +{
> +	eeh_dev_release(pdev);
> +}
> +
> +long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group,
> +				unsigned int cmd, unsigned long arg)
> +{
> +	struct eeh_pe *pe;
> +	struct vfio_eeh_pe_op op;
> +	unsigned long minsz;
> +	long ret = -EINVAL;
> +
> +	switch (cmd) {
> +	case VFIO_CHECK_EXTENSION:
> +		if (arg == VFIO_EEH)
> +			ret = eeh_enabled() ? 1 : 0;
> +		else
> +			ret = 0;
> +		break;
> +	case VFIO_EEH_PE_OP:
> +		pe = eeh_iommu_group_to_pe(group);
> +		if (!pe)
> +			return -ENODEV;
> +
> +		minsz = offsetofend(struct vfio_eeh_pe_op, op);
> +		if (copy_from_user(&op, (void __user *)arg, minsz))
> +			return -EFAULT;
> +		if (op.argsz < minsz || op.flags)
> +			return -EINVAL;
> +
> +		switch (op.op) {
> +		case VFIO_EEH_PE_DISABLE:
> +			ret = eeh_pe_set_option(pe, EEH_OPT_DISABLE);
> +			break;
> +		case VFIO_EEH_PE_ENABLE:
> +			ret = eeh_pe_set_option(pe, EEH_OPT_ENABLE);
> +			break;
> +		case VFIO_EEH_PE_UNFREEZE_IO:
> +			ret = eeh_pe_set_option(pe, EEH_OPT_THAW_MMIO);
> +			break;
> +		case VFIO_EEH_PE_UNFREEZE_DMA:
> +			ret = eeh_pe_set_option(pe, EEH_OPT_THAW_DMA);
> +			break;
> +		case VFIO_EEH_PE_GET_STATE:
> +			ret = eeh_pe_get_state(pe);
> +			break;
> +		case VFIO_EEH_PE_RESET_DEACTIVATE:
> +			ret = eeh_pe_reset(pe, EEH_RESET_DEACTIVATE);
> +			break;
> +		case VFIO_EEH_PE_RESET_HOT:
> +			ret = eeh_pe_reset(pe, EEH_RESET_HOT);
> +			break;
> +		case VFIO_EEH_PE_RESET_FUNDAMENTAL:
> +			ret = eeh_pe_reset(pe, EEH_RESET_FUNDAMENTAL);
> +			break;
> +		case VFIO_EEH_PE_CONFIGURE:
> +			ret = eeh_pe_configure(pe);
> +			break;
> +		default:
> +			ret = -EINVAL;
> +		}
> +	}
> +
> +	return ret;
> +}
> diff --git a/include/linux/vfio.h b/include/linux/vfio.h
> index 81022a52..0d3bb8f 100644
> --- a/include/linux/vfio.h
> +++ b/include/linux/vfio.h
> @@ -99,4 +99,27 @@ extern int vfio_external_user_iommu_id(struct vfio_group *group);
>  extern long vfio_external_check_extension(struct vfio_group *group,
>  					  unsigned long arg);
>  
> +#ifdef CONFIG_EEH
> +extern int vfio_spapr_pci_eeh_open(struct pci_dev *pdev);
> +extern void vfio_spapr_pci_eeh_release(struct pci_dev *pdev);
> +extern long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group,
> +				       unsigned int cmd,
> +				       unsigned long arg);
> +#else
> +static inline int vfio_spapr_pci_eeh_open(struct pci_dev *pdev)
> +{
> +	return 0;
> +}
> +
> +static inline void vfio_spapr_pci_eeh_release(struct pci_dev *pdev)
> +{
> +}
> +
> +static inline long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group,
> +					      unsigned int cmd,
> +					      unsigned long arg)
> +{
> +	return -ENOTTY;
> +}
> +#endif /* CONFIG_EEH */
>  #endif /* VFIO_H */
> diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
> index cb9023d..6612974 100644
> --- a/include/uapi/linux/vfio.h
> +++ b/include/uapi/linux/vfio.h
> @@ -30,6 +30,9 @@
>   */
>  #define VFIO_DMA_CC_IOMMU		4
>  
> +/* Check if EEH is supported */
> +#define VFIO_EEH			5
> +
>  /*
>   * The IOCTL interface is designed for extensibility by embedding the
>   * structure length (argsz) and flags into structures passed between
> @@ -455,6 +458,37 @@ struct vfio_iommu_spapr_tce_info {
>  
>  #define VFIO_IOMMU_SPAPR_TCE_GET_INFO	_IO(VFIO_TYPE, VFIO_BASE + 12)
>  
> +/*
> + * EEH PE operation struct provides ways to:
> + * - enable/disable EEH functionality;
> + * - unfreeze IO/DMA for frozen PE;
> + * - read PE state;
> + * - reset PE;
> + * - configure PE.
> + */
> +struct vfio_eeh_pe_op {
> +	__u32 argsz;
> +	__u32 flags;
> +	__u32 op;
> +};
> +
> +#define VFIO_EEH_PE_DISABLE		0	/* Disable EEH functionality */
> +#define VFIO_EEH_PE_ENABLE		1	/* Enable EEH functionality  */
> +#define VFIO_EEH_PE_UNFREEZE_IO		2	/* Enable IO for frozen PE   */
> +#define VFIO_EEH_PE_UNFREEZE_DMA	3	/* Enable DMA for frozen PE  */
> +#define VFIO_EEH_PE_GET_STATE		4	/* PE state retrieval        */
> +#define  VFIO_EEH_PE_STATE_NORMAL	0	/* PE in functional state    */
> +#define  VFIO_EEH_PE_STATE_RESET	1	/* PE reset in progress      */
> +#define  VFIO_EEH_PE_STATE_STOPPED	2	/* Stopped DMA and IO        */
> +#define  VFIO_EEH_PE_STATE_STOPPED_DMA	4	/* Stopped DMA only          */
> +#define  VFIO_EEH_PE_STATE_UNAVAIL	5	/* State unavailable         */
> +#define VFIO_EEH_PE_RESET_DEACTIVATE	5	/* Deassert PE reset         */
> +#define VFIO_EEH_PE_RESET_HOT		6	/* Assert hot reset          */
> +#define VFIO_EEH_PE_RESET_FUNDAMENTAL	7	/* Assert fundamental reset  */
> +#define VFIO_EEH_PE_CONFIGURE		8	/* PE configuration          */
> +
> +#define VFIO_EEH_PE_OP			_IO(VFIO_TYPE, VFIO_BASE + 21)
> +
>  /* ***************************************************************** */
>  
>  #endif /* _UAPIVFIO_H */

^ permalink raw reply

* Re: power and percpu: Could we move the paca into the percpu area?
From: Gabriel Paubert @ 2014-06-11 21:03 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Tejun Heo, linuxppc-dev, Christoph Lameter
In-Reply-To: <1402518131.14780.60.camel@pasglop>

On Thu, Jun 12, 2014 at 06:22:11AM +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2014-06-11 at 14:37 -0500, Christoph Lameter wrote:
> > Looking at arch/powerpc/include/asm/percpu.h I see that the per cpu offset
> > comes from a local_paca field and local_paca is in r13. That means that
> > for all percpu operations we first have to determine the address through a
> > memory access.
> > 
> > Would it be possible to put the paca at the beginning of the percpu data
> > area and then have r31 point to the percpu area?
> > 
> > power has these nice instructions that fetch from an offset relative to a
> > base register which could be used throughout for percpu operations in the
> > kernel (similar to x86 segment registers).
> > 
> > With that we may also be able to use the atomic ops for fast percpu access
> > so that we can avoid the irq enable/disable sequence that is now required
> > for percpu atomics. Would result in fast and reliable percpu
> > counters for powerpc.
> 
> So.... this is complicated :) And it's something I did want to tackle
> for a while but haven't had a chance.
> 
> The issues off the top of my head are:
> 
>  - The PACA must be accessible in real mode, which means that when
> running under a hypervisor, it must be allocated in the "RMA" which is
> the low part of memory up to a limit that depends on the hypervisor, but
> can be as low as 128M on some older machines.
> 
>  - However, we use percpu more than paca in normal kernel C code, the
> PACA is mostly used during exception entry/exit, KVM, and for interrupt
> soft-enable/disable. So it might make sense to change things so that r13
> contains the per-cpu offset instead. However, doing that change and
> updating the asm to cope isn't a trivial undertaking.
> 
>  - Direct offset from r13 in asm ... works as long as the offset is
> within the signed 32k range. Otherwise we need at least one more addis
> instruction. Anton mentioned the linker may have some smarts however for
> removing that addis if the high part of the offset happens to be 0.
> 
>  - For atomics, the jury is still out as to whether it would be faster
> or not. The atomic ops (lwarx/stwcx.) are expensive. They flush the
> value out of the L1 (to L2) among others. On the other hand we have
> interrupts soft-disable so masking interrupts isn't very expensive.
> Unmasking, while cheap, is currently out of line however. I have been
> wondering if we could move some of the soft-irq state instead to a CR
> field and mark that -ffixed with gcc so we can make irq
> soft-disable/enable even faster and more in-line.

Actually, from gcc/config/rs6000.h:

/* 1 for registers that have pervasive standard uses
   and are not available for the register allocator.

   On RS/6000, r1 is used for the stack.  On Darwin, r2 is available
   as a local register; for all other OS's r2 is the TOC pointer.

   cr5 is not supposed to be used.

   On System V implementations, r13 is fixed and not available for use.  */

#define FIXED_REGISTERS  \
  {0, 1, FIXED_R2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FIXED_R13, 0, 0, \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
   0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1,          \
   /* AltiVec registers.  */                       \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
   1, 1                                            \
   , 1, 1, 1, 1, 1, 1                              \
}

So cr5, which is number 73, is never used by gcc. 
Disassembling a few kernels seems to confirm this.
This gives you 4 booleans to play with...

	Gabriel

^ permalink raw reply

* [PATCH] powerpc/book3s: Fix some ABIv2 issues in machine check code
From: Anton Blanchard @ 2014-06-11 23:08 UTC (permalink / raw)
  To: benh, paulus, mahesh; +Cc: linuxppc-dev

Commit 2749a2f26a7c (powerpc/book3s: Fix machine check handling for
unhandled errors) introduced a few ABIv2 issues.

We can maintain ABIv1 and ABIv2 compatibility by branching to the
function rather than the dot symbol.

Fixes: 2749a2f26a7c ("powerpc/book3s: Fix machine check handling for unhandled errors")
Signed-off-by: Anton Blanchard <anton@samba.org>
---

Index: b/arch/powerpc/kernel/exceptions-64s.S
===================================================================
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -1502,13 +1502,13 @@ machine_check_handle_early:
 unrecover_mce:
 	/* Invoke machine_check_exception to print MCE event and panic. */
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	.machine_check_exception
+	bl	machine_check_exception
 	/*
 	 * We will not reach here. Even if we did, there is no way out. Call
 	 * unrecoverable_exception and die.
 	 */
 1:	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	.unrecoverable_exception
+	bl	unrecoverable_exception
 	b	1b
 /*
  * r13 points to the PACA, r9 contains the saved CR,

^ permalink raw reply

* Re: [PATCH] ASoC: fsl: Fix build problem
From: Mark Brown @ 2014-06-11 23:34 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: alsa-devel, Liam Girdwood, Takashi Iwai, Timur Tabi,
	Jaroslav Kysela, Markus Pargmann, linuxppc-dev
In-Reply-To: <1402470832-24889-1-git-send-email-linux@roeck-us.net>

[-- Attachment #1: Type: text/plain, Size: 278 bytes --]

On Wed, Jun 11, 2014 at 12:13:52AM -0700, Guenter Roeck wrote:
> Commit 432481220 (ASoC: fsl-ssi: Use regmap) removed struct ccsr_ssi.
> Unfortunately, the structure is still used. This causes
> mpc85xx_smp_defconfig and mpc85xx_defconfig builds to fail with

Applied, thanks,.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply

* Re: [PATCH v2] powerpc: Avoid circular dependency with zImage.%
From: Mike Qiu @ 2014-06-12  2:07 UTC (permalink / raw)
  To: Michal Marek; +Cc: Sam Ravnborg, linuxppc-dev, linux-kernel, linux-kbuild
In-Reply-To: <1402501243-28213-1-git-send-email-mmarek@suse.cz>

This v2 patch is good,

Tested-by: Mike Qiu <qiudayu@linux.vnet.ibm.com>

On 06/11/2014 11:40 PM, Michal Marek wrote:
> The rule to create the final images uses a zImage.% pattern.
> Unfortunately, this also matches the names of the zImage.*.lds linker
> scripts, which appear as a dependency of the final images. This somehow
> worked when $(srctree) used to be an absolute path, but now the pattern
> matches too much. List only the images from $(image-y) as the target of
> the rule, to avoid the circular dependency.
>
> Signed-off-by: Michal Marek <mmarek@suse.cz>
> ---
> v2:
>    - Filter out duplicates in the target list
>    - fix the platform argument to cmd_wrap
>
>   arch/powerpc/boot/Makefile | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
> index 426dce7..ccc25ed 100644
> --- a/arch/powerpc/boot/Makefile
> +++ b/arch/powerpc/boot/Makefile
> @@ -333,8 +333,8 @@ $(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
>   $(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
>   	$(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
>
> -$(obj)/zImage.%: vmlinux $(wrapperbits)
> -	$(call if_changed,wrap,$*)
> +$(addprefix $(obj)/, $(sort $(filter zImage.%, $(image-y)))): vmlinux $(wrapperbits)
> +	$(call if_changed,wrap,$(subst $(obj)/zImage.,,$@))
>
>   # dtbImage% - a dtbImage is a zImage with an embedded device tree blob
>   $(obj)/dtbImage.initrd.%: vmlinux $(wrapperbits) $(obj)/%.dtb

^ permalink raw reply

* [PATCH v2 08/10] mm, cma: clean-up cma allocation error path
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

We can remove one call sites for clear_cma_bitmap() if we first
call it before checking error number.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/cma.c b/mm/cma.c
index 1e1b017..01a0713 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -282,11 +282,12 @@ struct page *cma_alloc(struct cma *cma, int count, unsigned int align)
 		if (ret == 0) {
 			page = pfn_to_page(pfn);
 			break;
-		} else if (ret != -EBUSY) {
-			clear_cma_bitmap(cma, pfn, count);
-			break;
 		}
+
 		clear_cma_bitmap(cma, pfn, count);
+		if (ret != -EBUSY)
+			break;
+
 		pr_debug("%s(): memory range at %p is busy, retrying\n",
 			 __func__, pfn_to_page(pfn));
 		/* try again with a bit different memory target */
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 04/10] DMA, CMA: support alignment constraint on cma region
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

ppc kvm's cma area management needs alignment constraint on
cma region. So support it to prepare generalization of cma area
management functionality.

Additionally, add some comments which tell us why alignment
constraint is needed on cma region.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 8a44c82..bc4c171 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -32,6 +32,7 @@
 #include <linux/swap.h>
 #include <linux/mm_types.h>
 #include <linux/dma-contiguous.h>
+#include <linux/log2.h>
 
 struct cma {
 	unsigned long	base_pfn;
@@ -219,6 +220,7 @@ core_initcall(cma_init_reserved_areas);
  * @size: Size of the reserved area (in bytes),
  * @base: Base address of the reserved area optional, use 0 for any
  * @limit: End address of the reserved memory (optional, 0 for any).
+ * @alignment: Alignment for the contiguous memory area, should be power of 2
  * @res_cma: Pointer to store the created cma region.
  * @fixed: hint about where to place the reserved area
  *
@@ -233,15 +235,15 @@ core_initcall(cma_init_reserved_areas);
  */
 static int __init __dma_contiguous_reserve_area(phys_addr_t size,
 				phys_addr_t base, phys_addr_t limit,
+				phys_addr_t alignment,
 				struct cma **res_cma, bool fixed)
 {
 	struct cma *cma = &cma_areas[cma_area_count];
-	phys_addr_t alignment;
 	int ret = 0;
 
-	pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
-		 (unsigned long)size, (unsigned long)base,
-		 (unsigned long)limit);
+	pr_debug("%s(size %lx, base %08lx, limit %08lx align_order %08lx)\n",
+		__func__, (unsigned long)size, (unsigned long)base,
+		(unsigned long)limit, (unsigned long)alignment);
 
 	/* Sanity checks */
 	if (cma_area_count == ARRAY_SIZE(cma_areas)) {
@@ -253,8 +255,17 @@ static int __init __dma_contiguous_reserve_area(phys_addr_t size,
 	if (!size)
 		return -EINVAL;
 
-	/* Sanitise input arguments */
-	alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
+	if (alignment && !is_power_of_2(alignment))
+		return -EINVAL;
+
+	/*
+	 * Sanitise input arguments.
+	 * CMA area should be at least MAX_ORDER - 1 aligned. Otherwise,
+	 * CMA area could be merged into other MIGRATE_TYPE by buddy mechanism
+	 * and CMA property will be broken.
+	 */
+	alignment = max(alignment,
+		(phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order));
 	base = ALIGN(base, alignment);
 	size = ALIGN(size, alignment);
 	limit &= ~(alignment - 1);
@@ -302,7 +313,8 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 {
 	int ret;
 
-	ret = __dma_contiguous_reserve_area(size, base, limit, res_cma, fixed);
+	ret = __dma_contiguous_reserve_area(size, base, limit, 0,
+						res_cma, fixed);
 	if (ret)
 		return ret;
 
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 10/10] mm, cma: use spinlock instead of mutex
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

Currently, we should take the mutex for manipulating bitmap.
This job may be really simple and short so we don't need to sleep
if contended. So I change it to spinlock.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/mm/cma.c b/mm/cma.c
index 22a5b23..3085e8c 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -27,6 +27,7 @@
 #include <linux/memblock.h>
 #include <linux/err.h>
 #include <linux/mm.h>
+#include <linux/spinlock.h>
 #include <linux/mutex.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
@@ -36,7 +37,7 @@ struct cma {
 	unsigned long	count;
 	unsigned long	*bitmap;
 	int order_per_bit; /* Order of pages represented by one bit */
-	struct mutex	lock;
+	spinlock_t	lock;
 };
 
 /*
@@ -72,9 +73,9 @@ static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
 	bitmapno = (pfn - cma->base_pfn) >> cma->order_per_bit;
 	nr_bits = cma_bitmap_pages_to_bits(cma, count);
 
-	mutex_lock(&cma->lock);
+	spin_lock(&cma->lock);
 	bitmap_clear(cma->bitmap, bitmapno, nr_bits);
-	mutex_unlock(&cma->lock);
+	spin_unlock(&cma->lock);
 }
 
 static int __init cma_activate_area(struct cma *cma)
@@ -112,7 +113,7 @@ static int __init cma_activate_area(struct cma *cma)
 		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
 	} while (--i);
 
-	mutex_init(&cma->lock);
+	spin_lock_init(&cma->lock);
 	return 0;
 
 err:
@@ -261,11 +262,11 @@ struct page *cma_alloc(struct cma *cma, int count, unsigned int align)
 	nr_bits = cma_bitmap_pages_to_bits(cma, count);
 
 	for (;;) {
-		mutex_lock(&cma->lock);
+		spin_lock(&cma->lock);
 		bitmapno = bitmap_find_next_zero_area(cma->bitmap,
 					bitmap_maxno, start, nr_bits, mask);
 		if (bitmapno >= bitmap_maxno) {
-			mutex_unlock(&cma->lock);
+			spin_unlock(&cma->lock);
 			break;
 		}
 		bitmap_set(cma->bitmap, bitmapno, nr_bits);
@@ -274,7 +275,7 @@ struct page *cma_alloc(struct cma *cma, int count, unsigned int align)
 		 * our exclusive use. If the migration fails we will take the
 		 * lock again and unmark it.
 		 */
-		mutex_unlock(&cma->lock);
+		spin_unlock(&cma->lock);
 
 		pfn = cma->base_pfn + (bitmapno << cma->order_per_bit);
 		mutex_lock(&cma_mutex);
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 02/10] DMA, CMA: fix possible memory leak
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

We should free memory for bitmap when we find zone mis-match,
otherwise this memory will leak.

Additionally, I copy code comment from ppc kvm's cma code to notify
why we need to check zone mis-match.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index bd0bb81..fb0cdce 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -177,14 +177,24 @@ static int __init cma_activate_area(struct cma *cma)
 		base_pfn = pfn;
 		for (j = pageblock_nr_pages; j; --j, pfn++) {
 			WARN_ON_ONCE(!pfn_valid(pfn));
+			/*
+			 * alloc_contig_range requires the pfn range
+			 * specified to be in the same zone. Make this
+			 * simple by forcing the entire CMA resv range
+			 * to be in the same zone.
+			 */
 			if (page_zone(pfn_to_page(pfn)) != zone)
-				return -EINVAL;
+				goto err;
 		}
 		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
 	} while (--i);
 
 	mutex_init(&cma->lock);
 	return 0;
+
+err:
+	kfree(cma->bitmap);
+	return -EINVAL;
 }
 
 static struct cma cma_areas[MAX_CMA_AREAS];
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 01/10] DMA, CMA: clean-up log message
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

We don't need explicit 'CMA:' prefix, since we already define prefix
'cma:' in pr_fmt. So remove it.

And, some logs print function name and others doesn't. This looks
bad to me, so I unify log format to print function name consistently.

Lastly, I add one more debug log on cma_activate_area().

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 83969f8..bd0bb81 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -144,7 +144,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
 	}
 
 	if (selected_size && !dma_contiguous_default_area) {
-		pr_debug("%s: reserving %ld MiB for global area\n", __func__,
+		pr_debug("%s(): reserving %ld MiB for global area\n", __func__,
 			 (unsigned long)selected_size / SZ_1M);
 
 		dma_contiguous_reserve_area(selected_size, selected_base,
@@ -163,8 +163,9 @@ static int __init cma_activate_area(struct cma *cma)
 	unsigned i = cma->count >> pageblock_order;
 	struct zone *zone;
 
-	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	pr_debug("%s()\n", __func__);
 
+	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
 	if (!cma->bitmap)
 		return -ENOMEM;
 
@@ -234,7 +235,8 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 
 	/* Sanity checks */
 	if (cma_area_count == ARRAY_SIZE(cma_areas)) {
-		pr_err("Not enough slots for CMA reserved regions!\n");
+		pr_err("%s(): Not enough slots for CMA reserved regions!\n",
+			__func__);
 		return -ENOSPC;
 	}
 
@@ -274,14 +276,15 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 	*res_cma = cma;
 	cma_area_count++;
 
-	pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
-		(unsigned long)base);
+	pr_info("%s(): reserved %ld MiB at %08lx\n",
+		__func__, (unsigned long)size / SZ_1M, (unsigned long)base);
 
 	/* Architecture specific contiguous memory fixup. */
 	dma_contiguous_early_fixup(base, size);
 	return 0;
 err:
-	pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
+	pr_err("%s(): failed to reserve %ld MiB\n",
+		__func__, (unsigned long)size / SZ_1M);
 	return ret;
 }
 
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 09/10] mm, cma: move output param to the end of param list
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

Conventionally, we put output param to the end of param list.
cma_declare_contiguous() doesn't look like that, so change it.

Additionally, move down cma_areas reference code to the position
where it is really needed.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index 28ec226..97613ea 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -184,7 +184,7 @@ void __init kvm_cma_reserve(void)
 
 		align_size = max(kvm_rma_pages << PAGE_SHIFT, align_size);
 		cma_declare_contiguous(selected_size, 0, 0, align_size,
-			KVM_CMA_CHUNK_ORDER - PAGE_SHIFT, &kvm_cma, false);
+			KVM_CMA_CHUNK_ORDER - PAGE_SHIFT, false, &kvm_cma);
 	}
 }
 
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index f177f73..bfd4553 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -149,7 +149,7 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 {
 	int ret;
 
-	ret = cma_declare_contiguous(size, base, limit, 0, 0, res_cma, fixed);
+	ret = cma_declare_contiguous(size, base, limit, 0, 0, fixed, res_cma);
 	if (ret)
 		return ret;
 
diff --git a/include/linux/cma.h b/include/linux/cma.h
index e38efe9..e53eead 100644
--- a/include/linux/cma.h
+++ b/include/linux/cma.h
@@ -6,7 +6,7 @@ struct cma;
 extern int __init cma_declare_contiguous(phys_addr_t size,
 				phys_addr_t base, phys_addr_t limit,
 				phys_addr_t alignment, int order_per_bit,
-				struct cma **res_cma, bool fixed);
+				bool fixed, struct cma **res_cma);
 extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align);
 extern bool cma_release(struct cma *cma, struct page *pages, int count);
 #endif
diff --git a/mm/cma.c b/mm/cma.c
index 01a0713..22a5b23 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -142,8 +142,8 @@ core_initcall(cma_init_reserved_areas);
  * @limit: End address of the reserved memory (optional, 0 for any).
  * @alignment: Alignment for the contiguous memory area, should be power of 2
  * @order_per_bit: Order of pages represented by one bit on bitmap.
- * @res_cma: Pointer to store the created cma region.
  * @fixed: hint about where to place the reserved area
+ * @res_cma: Pointer to store the created cma region.
  *
  * This function reserves memory from early allocator. It should be
  * called by arch specific code once the early allocator (memblock or bootmem)
@@ -156,9 +156,9 @@ core_initcall(cma_init_reserved_areas);
 int __init cma_declare_contiguous(phys_addr_t size,
 				phys_addr_t base, phys_addr_t limit,
 				phys_addr_t alignment, int order_per_bit,
-				struct cma **res_cma, bool fixed)
+				bool fixed, struct cma **res_cma)
 {
-	struct cma *cma = &cma_areas[cma_area_count];
+	struct cma *cma;
 	int ret = 0;
 
 	pr_debug("%s(size %lx, base %08lx, limit %08lx alignment %08lx)\n",
@@ -214,6 +214,7 @@ int __init cma_declare_contiguous(phys_addr_t size,
 	 * Each reserved area must be initialised later, when more kernel
 	 * subsystems (like slab allocator) are available.
 	 */
+	cma = &cma_areas[cma_area_count];
 	cma->base_pfn = PFN_DOWN(base);
 	cma->count = size >> PAGE_SHIFT;
 	cma->order_per_bit = order_per_bit;
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 05/10] DMA, CMA: support arbitrary bitmap granularity
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

ppc kvm's cma region management requires arbitrary bitmap granularity,
since they want to reserve very large memory and manage this region
with bitmap that one bit for several pages to reduce management overheads.
So support arbitrary bitmap granularity for following generalization.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index bc4c171..9bc9340 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -38,6 +38,7 @@ struct cma {
 	unsigned long	base_pfn;
 	unsigned long	count;
 	unsigned long	*bitmap;
+	int order_per_bit; /* Order of pages represented by one bit */
 	struct mutex	lock;
 };
 
@@ -157,9 +158,38 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
 
 static DEFINE_MUTEX(cma_mutex);
 
+static unsigned long cma_bitmap_aligned_mask(struct cma *cma, int align_order)
+{
+	return (1 << (align_order >> cma->order_per_bit)) - 1;
+}
+
+static unsigned long cma_bitmap_maxno(struct cma *cma)
+{
+	return cma->count >> cma->order_per_bit;
+}
+
+static unsigned long cma_bitmap_pages_to_bits(struct cma *cma,
+						unsigned long pages)
+{
+	return ALIGN(pages, 1 << cma->order_per_bit) >> cma->order_per_bit;
+}
+
+static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
+{
+	unsigned long bitmapno, nr_bits;
+
+	bitmapno = (pfn - cma->base_pfn) >> cma->order_per_bit;
+	nr_bits = cma_bitmap_pages_to_bits(cma, count);
+
+	mutex_lock(&cma->lock);
+	bitmap_clear(cma->bitmap, bitmapno, nr_bits);
+	mutex_unlock(&cma->lock);
+}
+
 static int __init cma_activate_area(struct cma *cma)
 {
-	int bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long);
+	int bitmap_maxno = cma_bitmap_maxno(cma);
+	int bitmap_size = BITS_TO_LONGS(bitmap_maxno) * sizeof(long);
 	unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
 	unsigned i = cma->count >> pageblock_order;
 	struct zone *zone;
@@ -221,6 +251,7 @@ core_initcall(cma_init_reserved_areas);
  * @base: Base address of the reserved area optional, use 0 for any
  * @limit: End address of the reserved memory (optional, 0 for any).
  * @alignment: Alignment for the contiguous memory area, should be power of 2
+ * @order_per_bit: Order of pages represented by one bit on bitmap.
  * @res_cma: Pointer to store the created cma region.
  * @fixed: hint about where to place the reserved area
  *
@@ -235,7 +266,7 @@ core_initcall(cma_init_reserved_areas);
  */
 static int __init __dma_contiguous_reserve_area(phys_addr_t size,
 				phys_addr_t base, phys_addr_t limit,
-				phys_addr_t alignment,
+				phys_addr_t alignment, int order_per_bit,
 				struct cma **res_cma, bool fixed)
 {
 	struct cma *cma = &cma_areas[cma_area_count];
@@ -269,6 +300,8 @@ static int __init __dma_contiguous_reserve_area(phys_addr_t size,
 	base = ALIGN(base, alignment);
 	size = ALIGN(size, alignment);
 	limit &= ~(alignment - 1);
+	/* size should be aligned with order_per_bit */
+	BUG_ON(!IS_ALIGNED(size >> PAGE_SHIFT, 1 << order_per_bit));
 
 	/* Reserve memory */
 	if (base && fixed) {
@@ -294,6 +327,7 @@ static int __init __dma_contiguous_reserve_area(phys_addr_t size,
 	 */
 	cma->base_pfn = PFN_DOWN(base);
 	cma->count = size >> PAGE_SHIFT;
+	cma->order_per_bit = order_per_bit;
 	*res_cma = cma;
 	cma_area_count++;
 
@@ -313,7 +347,7 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 {
 	int ret;
 
-	ret = __dma_contiguous_reserve_area(size, base, limit, 0,
+	ret = __dma_contiguous_reserve_area(size, base, limit, 0, 0,
 						res_cma, fixed);
 	if (ret)
 		return ret;
@@ -324,13 +358,6 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 	return 0;
 }
 
-static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
-{
-	mutex_lock(&cma->lock);
-	bitmap_clear(cma->bitmap, pfn - cma->base_pfn, count);
-	mutex_unlock(&cma->lock);
-}
-
 /**
  * dma_alloc_from_contiguous() - allocate pages from contiguous area
  * @dev:   Pointer to device for which the allocation is performed.
@@ -345,7 +372,8 @@ static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
 static struct page *__dma_alloc_from_contiguous(struct cma *cma, int count,
 				       unsigned int align)
 {
-	unsigned long mask, pfn, pageno, start = 0;
+	unsigned long mask, pfn, start = 0;
+	unsigned long bitmap_maxno, bitmapno, nr_bits;
 	struct page *page = NULL;
 	int ret;
 
@@ -358,18 +386,19 @@ static struct page *__dma_alloc_from_contiguous(struct cma *cma, int count,
 	if (!count)
 		return NULL;
 
-	mask = (1 << align) - 1;
-
+	mask = cma_bitmap_aligned_mask(cma, align);
+	bitmap_maxno = cma_bitmap_maxno(cma);
+	nr_bits = cma_bitmap_pages_to_bits(cma, count);
 
 	for (;;) {
 		mutex_lock(&cma->lock);
-		pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count,
-						    start, count, mask);
-		if (pageno >= cma->count) {
+		bitmapno = bitmap_find_next_zero_area(cma->bitmap,
+					bitmap_maxno, start, nr_bits, mask);
+		if (bitmapno >= bitmap_maxno) {
 			mutex_unlock(&cma->lock);
 			break;
 		}
-		bitmap_set(cma->bitmap, pageno, count);
+		bitmap_set(cma->bitmap, bitmapno, nr_bits);
 		/*
 		 * It's safe to drop the lock here. We've marked this region for
 		 * our exclusive use. If the migration fails we will take the
@@ -377,7 +406,7 @@ static struct page *__dma_alloc_from_contiguous(struct cma *cma, int count,
 		 */
 		mutex_unlock(&cma->lock);
 
-		pfn = cma->base_pfn + pageno;
+		pfn = cma->base_pfn + (bitmapno << cma->order_per_bit);
 		mutex_lock(&cma_mutex);
 		ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
 		mutex_unlock(&cma_mutex);
@@ -392,7 +421,7 @@ static struct page *__dma_alloc_from_contiguous(struct cma *cma, int count,
 		pr_debug("%s(): memory range at %p is busy, retrying\n",
 			 __func__, pfn_to_page(pfn));
 		/* try again with a bit different memory target */
-		start = pageno + mask + 1;
+		start = bitmapno + mask + 1;
 	}
 
 	pr_debug("%s(): returned %p\n", __func__, page);
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 00/10] CMA: generalize CMA reserved area management code
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel

Currently, there are two users on CMA functionality, one is the DMA
subsystem and the other is the kvm on powerpc. They have their own code
to manage CMA reserved area even if they looks really similar.
>From my guess, it is caused by some needs on bitmap management. Kvm side
wants to maintain bitmap not for 1 page, but for more size. Eventually it
use bitmap where one bit represents 64 pages.

When I implement CMA related patches, I should change those two places
to apply my change and it seem to be painful to me. I want to change
this situation and reduce future code management overhead through
this patch.

This change could also help developer who want to use CMA in their
new feature development, since they can use CMA easily without
copying & pasting this reserved area management code.

v2:
  Although this patchset looks very different with v1, the end result,
  that is, mm/cma.c is same with v1's one. So I carry Ack to patch 6-7.

Patch 1-5 prepare some features to cover ppc kvm's requirements.
Patch 6-7 generalize CMA reserved area management code and change users
to use it.
Patch 8-10 clean-up minor things.

Joonsoo Kim (10):
  DMA, CMA: clean-up log message
  DMA, CMA: fix possible memory leak
  DMA, CMA: separate core cma management codes from DMA APIs
  DMA, CMA: support alignment constraint on cma region
  DMA, CMA: support arbitrary bitmap granularity
  CMA: generalize CMA reserved area management functionality
  PPC, KVM, CMA: use general CMA reserved area management framework
  mm, cma: clean-up cma allocation error path
  mm, cma: move output param to the end of param list
  mm, cma: use spinlock instead of mutex

 arch/powerpc/kvm/book3s_hv_builtin.c |   17 +-
 arch/powerpc/kvm/book3s_hv_cma.c     |  240 ------------------------
 arch/powerpc/kvm/book3s_hv_cma.h     |   27 ---
 drivers/base/Kconfig                 |   10 -
 drivers/base/dma-contiguous.c        |  248 ++-----------------------
 include/linux/cma.h                  |   12 ++
 include/linux/dma-contiguous.h       |    3 +-
 mm/Kconfig                           |   11 ++
 mm/Makefile                          |    1 +
 mm/cma.c                             |  333 ++++++++++++++++++++++++++++++++++
 10 files changed, 382 insertions(+), 520 deletions(-)
 delete mode 100644 arch/powerpc/kvm/book3s_hv_cma.c
 delete mode 100644 arch/powerpc/kvm/book3s_hv_cma.h
 create mode 100644 include/linux/cma.h
 create mode 100644 mm/cma.c

-- 
1.7.9.5

^ permalink raw reply

* [PATCH v2 03/10] DMA, CMA: separate core cma management codes from DMA APIs
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

To prepare future generalization work on cma area management code,
we need to separate core cma management codes from DMA APIs.
We will extend these core functions to cover requirements of
ppc kvm's cma area management functionality in following patches.
This separation helps us not to touch DMA APIs while extending
core functions.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index fb0cdce..8a44c82 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -231,9 +231,9 @@ core_initcall(cma_init_reserved_areas);
  * If @fixed is true, reserve contiguous area at exactly @base.  If false,
  * reserve in range from @base to @limit.
  */
-int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
-				       phys_addr_t limit, struct cma **res_cma,
-				       bool fixed)
+static int __init __dma_contiguous_reserve_area(phys_addr_t size,
+				phys_addr_t base, phys_addr_t limit,
+				struct cma **res_cma, bool fixed)
 {
 	struct cma *cma = &cma_areas[cma_area_count];
 	phys_addr_t alignment;
@@ -288,16 +288,30 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 
 	pr_info("%s(): reserved %ld MiB at %08lx\n",
 		__func__, (unsigned long)size / SZ_1M, (unsigned long)base);
-
-	/* Architecture specific contiguous memory fixup. */
-	dma_contiguous_early_fixup(base, size);
 	return 0;
+
 err:
 	pr_err("%s(): failed to reserve %ld MiB\n",
 		__func__, (unsigned long)size / SZ_1M);
 	return ret;
 }
 
+int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
+				       phys_addr_t limit, struct cma **res_cma,
+				       bool fixed)
+{
+	int ret;
+
+	ret = __dma_contiguous_reserve_area(size, base, limit, res_cma, fixed);
+	if (ret)
+		return ret;
+
+	/* Architecture specific contiguous memory fixup. */
+	dma_contiguous_early_fixup(base, size);
+
+	return 0;
+}
+
 static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
 {
 	mutex_lock(&cma->lock);
@@ -316,20 +330,16 @@ static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
  * global one. Requires architecture specific dev_get_cma_area() helper
  * function.
  */
-struct page *dma_alloc_from_contiguous(struct device *dev, int count,
+static struct page *__dma_alloc_from_contiguous(struct cma *cma, int count,
 				       unsigned int align)
 {
 	unsigned long mask, pfn, pageno, start = 0;
-	struct cma *cma = dev_get_cma_area(dev);
 	struct page *page = NULL;
 	int ret;
 
 	if (!cma || !cma->count)
 		return NULL;
 
-	if (align > CONFIG_CMA_ALIGNMENT)
-		align = CONFIG_CMA_ALIGNMENT;
-
 	pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma,
 		 count, align);
 
@@ -377,6 +387,17 @@ struct page *dma_alloc_from_contiguous(struct device *dev, int count,
 	return page;
 }
 
+struct page *dma_alloc_from_contiguous(struct device *dev, int count,
+				       unsigned int align)
+{
+	struct cma *cma = dev_get_cma_area(dev);
+
+	if (align > CONFIG_CMA_ALIGNMENT)
+		align = CONFIG_CMA_ALIGNMENT;
+
+	return __dma_alloc_from_contiguous(cma, count, align);
+}
+
 /**
  * dma_release_from_contiguous() - release allocated pages
  * @dev:   Pointer to device for which the pages were allocated.
@@ -387,10 +408,9 @@ struct page *dma_alloc_from_contiguous(struct device *dev, int count,
  * It returns false when provided pages do not belong to contiguous area and
  * true otherwise.
  */
-bool dma_release_from_contiguous(struct device *dev, struct page *pages,
+static bool __dma_release_from_contiguous(struct cma *cma, struct page *pages,
 				 int count)
 {
-	struct cma *cma = dev_get_cma_area(dev);
 	unsigned long pfn;
 
 	if (!cma || !pages)
@@ -410,3 +430,11 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
 
 	return true;
 }
+
+bool dma_release_from_contiguous(struct device *dev, struct page *pages,
+				 int count)
+{
+	struct cma *cma = dev_get_cma_area(dev);
+
+	return __dma_release_from_contiguous(cma, pages, count);
+}
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 07/10] PPC, KVM, CMA: use general CMA reserved area management framework
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

Now, we have general CMA reserved area management framework,
so use it for future maintainabilty. There is no functional change.

Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index 7cde8a6..28ec226 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -16,12 +16,14 @@
 #include <linux/init.h>
 #include <linux/memblock.h>
 #include <linux/sizes.h>
+#include <linux/cma.h>
 
 #include <asm/cputable.h>
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
 
-#include "book3s_hv_cma.h"
+#define KVM_CMA_CHUNK_ORDER	18
+
 /*
  * Hash page table alignment on newer cpus(CPU_FTR_ARCH_206)
  * should be power of 2.
@@ -43,6 +45,8 @@ static unsigned long kvm_cma_resv_ratio = 5;
 unsigned long kvm_rma_pages = (1 << 27) >> PAGE_SHIFT;	/* 128MB */
 EXPORT_SYMBOL_GPL(kvm_rma_pages);
 
+static struct cma *kvm_cma;
+
 /* Work out RMLS (real mode limit selector) field value for a given RMA size.
    Assumes POWER7 or PPC970. */
 static inline int lpcr_rmls(unsigned long rma_size)
@@ -97,7 +101,7 @@ struct kvm_rma_info *kvm_alloc_rma()
 	ri = kmalloc(sizeof(struct kvm_rma_info), GFP_KERNEL);
 	if (!ri)
 		return NULL;
-	page = kvm_alloc_cma(kvm_rma_pages, kvm_rma_pages);
+	page = cma_alloc(kvm_cma, kvm_rma_pages, get_order(kvm_rma_pages));
 	if (!page)
 		goto err_out;
 	atomic_set(&ri->use_count, 1);
@@ -112,7 +116,7 @@ EXPORT_SYMBOL_GPL(kvm_alloc_rma);
 void kvm_release_rma(struct kvm_rma_info *ri)
 {
 	if (atomic_dec_and_test(&ri->use_count)) {
-		kvm_release_cma(pfn_to_page(ri->base_pfn), kvm_rma_pages);
+		cma_release(kvm_cma, pfn_to_page(ri->base_pfn), kvm_rma_pages);
 		kfree(ri);
 	}
 }
@@ -134,13 +138,13 @@ struct page *kvm_alloc_hpt(unsigned long nr_pages)
 	/* Old CPUs require HPT aligned on a multiple of its size */
 	if (!cpu_has_feature(CPU_FTR_ARCH_206))
 		align_pages = nr_pages;
-	return kvm_alloc_cma(nr_pages, align_pages);
+	return cma_alloc(kvm_cma, nr_pages, get_order(align_pages));
 }
 EXPORT_SYMBOL_GPL(kvm_alloc_hpt);
 
 void kvm_release_hpt(struct page *page, unsigned long nr_pages)
 {
-	kvm_release_cma(page, nr_pages);
+	cma_release(kvm_cma, page, nr_pages);
 }
 EXPORT_SYMBOL_GPL(kvm_release_hpt);
 
@@ -179,7 +183,8 @@ void __init kvm_cma_reserve(void)
 			align_size = HPT_ALIGN_PAGES << PAGE_SHIFT;
 
 		align_size = max(kvm_rma_pages << PAGE_SHIFT, align_size);
-		kvm_cma_declare_contiguous(selected_size, align_size);
+		cma_declare_contiguous(selected_size, 0, 0, align_size,
+			KVM_CMA_CHUNK_ORDER - PAGE_SHIFT, &kvm_cma, false);
 	}
 }
 
diff --git a/arch/powerpc/kvm/book3s_hv_cma.c b/arch/powerpc/kvm/book3s_hv_cma.c
deleted file mode 100644
index d9d3d85..0000000
--- a/arch/powerpc/kvm/book3s_hv_cma.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Contiguous Memory Allocator for ppc KVM hash pagetable  based on CMA
- * for DMA mapping framework
- *
- * Copyright IBM Corporation, 2013
- * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License or (at your optional) any later version of the license.
- *
- */
-#define pr_fmt(fmt) "kvm_cma: " fmt
-
-#ifdef CONFIG_CMA_DEBUG
-#ifndef DEBUG
-#  define DEBUG
-#endif
-#endif
-
-#include <linux/memblock.h>
-#include <linux/mutex.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
-
-#include "book3s_hv_cma.h"
-
-struct kvm_cma {
-	unsigned long	base_pfn;
-	unsigned long	count;
-	unsigned long	*bitmap;
-};
-
-static DEFINE_MUTEX(kvm_cma_mutex);
-static struct kvm_cma kvm_cma_area;
-
-/**
- * kvm_cma_declare_contiguous() - reserve area for contiguous memory handling
- *			          for kvm hash pagetable
- * @size:  Size of the reserved memory.
- * @alignment:  Alignment for the contiguous memory area
- *
- * This function reserves memory for kvm cma area. It should be
- * called by arch code when early allocator (memblock or bootmem)
- * is still activate.
- */
-long __init kvm_cma_declare_contiguous(phys_addr_t size, phys_addr_t alignment)
-{
-	long base_pfn;
-	phys_addr_t addr;
-	struct kvm_cma *cma = &kvm_cma_area;
-
-	pr_debug("%s(size %lx)\n", __func__, (unsigned long)size);
-
-	if (!size)
-		return -EINVAL;
-	/*
-	 * Sanitise input arguments.
-	 * We should be pageblock aligned for CMA.
-	 */
-	alignment = max(alignment, (phys_addr_t)(PAGE_SIZE << pageblock_order));
-	size = ALIGN(size, alignment);
-	/*
-	 * Reserve memory
-	 * Use __memblock_alloc_base() since
-	 * memblock_alloc_base() panic()s.
-	 */
-	addr = __memblock_alloc_base(size, alignment, 0);
-	if (!addr) {
-		base_pfn = -ENOMEM;
-		goto err;
-	} else
-		base_pfn = PFN_DOWN(addr);
-
-	/*
-	 * Each reserved area must be initialised later, when more kernel
-	 * subsystems (like slab allocator) are available.
-	 */
-	cma->base_pfn = base_pfn;
-	cma->count    = size >> PAGE_SHIFT;
-	pr_info("CMA: reserved %ld MiB\n", (unsigned long)size / SZ_1M);
-	return 0;
-err:
-	pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
-	return base_pfn;
-}
-
-/**
- * kvm_alloc_cma() - allocate pages from contiguous area
- * @nr_pages: Requested number of pages.
- * @align_pages: Requested alignment in number of pages
- *
- * This function allocates memory buffer for hash pagetable.
- */
-struct page *kvm_alloc_cma(unsigned long nr_pages, unsigned long align_pages)
-{
-	int ret;
-	struct page *page = NULL;
-	struct kvm_cma *cma = &kvm_cma_area;
-	unsigned long chunk_count, nr_chunk;
-	unsigned long mask, pfn, pageno, start = 0;
-
-
-	if (!cma || !cma->count)
-		return NULL;
-
-	pr_debug("%s(cma %p, count %lu, align pages %lu)\n", __func__,
-		 (void *)cma, nr_pages, align_pages);
-
-	if (!nr_pages)
-		return NULL;
-	/*
-	 * align mask with chunk size. The bit tracks pages in chunk size
-	 */
-	VM_BUG_ON(!is_power_of_2(align_pages));
-	mask = (align_pages >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT)) - 1;
-	BUILD_BUG_ON(PAGE_SHIFT > KVM_CMA_CHUNK_ORDER);
-
-	chunk_count = cma->count >>  (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
-	nr_chunk = nr_pages >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
-
-	mutex_lock(&kvm_cma_mutex);
-	for (;;) {
-		pageno = bitmap_find_next_zero_area(cma->bitmap, chunk_count,
-						    start, nr_chunk, mask);
-		if (pageno >= chunk_count)
-			break;
-
-		pfn = cma->base_pfn + (pageno << (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT));
-		ret = alloc_contig_range(pfn, pfn + nr_pages, MIGRATE_CMA);
-		if (ret == 0) {
-			bitmap_set(cma->bitmap, pageno, nr_chunk);
-			page = pfn_to_page(pfn);
-			memset(pfn_to_kaddr(pfn), 0, nr_pages << PAGE_SHIFT);
-			break;
-		} else if (ret != -EBUSY) {
-			break;
-		}
-		pr_debug("%s(): memory range at %p is busy, retrying\n",
-			 __func__, pfn_to_page(pfn));
-		/* try again with a bit different memory target */
-		start = pageno + mask + 1;
-	}
-	mutex_unlock(&kvm_cma_mutex);
-	pr_debug("%s(): returned %p\n", __func__, page);
-	return page;
-}
-
-/**
- * kvm_release_cma() - release allocated pages for hash pagetable
- * @pages: Allocated pages.
- * @nr_pages: Number of allocated pages.
- *
- * This function releases memory allocated by kvm_alloc_cma().
- * It returns false when provided pages do not belong to contiguous area and
- * true otherwise.
- */
-bool kvm_release_cma(struct page *pages, unsigned long nr_pages)
-{
-	unsigned long pfn;
-	unsigned long nr_chunk;
-	struct kvm_cma *cma = &kvm_cma_area;
-
-	if (!cma || !pages)
-		return false;
-
-	pr_debug("%s(page %p count %lu)\n", __func__, (void *)pages, nr_pages);
-
-	pfn = page_to_pfn(pages);
-
-	if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
-		return false;
-
-	VM_BUG_ON(pfn + nr_pages > cma->base_pfn + cma->count);
-	nr_chunk = nr_pages >>  (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
-
-	mutex_lock(&kvm_cma_mutex);
-	bitmap_clear(cma->bitmap,
-		     (pfn - cma->base_pfn) >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT),
-		     nr_chunk);
-	free_contig_range(pfn, nr_pages);
-	mutex_unlock(&kvm_cma_mutex);
-
-	return true;
-}
-
-static int __init kvm_cma_activate_area(unsigned long base_pfn,
-					unsigned long count)
-{
-	unsigned long pfn = base_pfn;
-	unsigned i = count >> pageblock_order;
-	struct zone *zone;
-
-	WARN_ON_ONCE(!pfn_valid(pfn));
-	zone = page_zone(pfn_to_page(pfn));
-	do {
-		unsigned j;
-		base_pfn = pfn;
-		for (j = pageblock_nr_pages; j; --j, pfn++) {
-			WARN_ON_ONCE(!pfn_valid(pfn));
-			/*
-			 * alloc_contig_range requires the pfn range
-			 * specified to be in the same zone. Make this
-			 * simple by forcing the entire CMA resv range
-			 * to be in the same zone.
-			 */
-			if (page_zone(pfn_to_page(pfn)) != zone)
-				return -EINVAL;
-		}
-		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
-	} while (--i);
-	return 0;
-}
-
-static int __init kvm_cma_init_reserved_areas(void)
-{
-	int bitmap_size, ret;
-	unsigned long chunk_count;
-	struct kvm_cma *cma = &kvm_cma_area;
-
-	pr_debug("%s()\n", __func__);
-	if (!cma->count)
-		return 0;
-	chunk_count = cma->count >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
-	bitmap_size = BITS_TO_LONGS(chunk_count) * sizeof(long);
-	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
-	if (!cma->bitmap)
-		return -ENOMEM;
-
-	ret = kvm_cma_activate_area(cma->base_pfn, cma->count);
-	if (ret)
-		goto error;
-	return 0;
-
-error:
-	kfree(cma->bitmap);
-	return ret;
-}
-core_initcall(kvm_cma_init_reserved_areas);
diff --git a/arch/powerpc/kvm/book3s_hv_cma.h b/arch/powerpc/kvm/book3s_hv_cma.h
deleted file mode 100644
index 655144f..0000000
--- a/arch/powerpc/kvm/book3s_hv_cma.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Contiguous Memory Allocator for ppc KVM hash pagetable  based on CMA
- * for DMA mapping framework
- *
- * Copyright IBM Corporation, 2013
- * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License or (at your optional) any later version of the license.
- *
- */
-
-#ifndef __POWERPC_KVM_CMA_ALLOC_H__
-#define __POWERPC_KVM_CMA_ALLOC_H__
-/*
- * Both RMA and Hash page allocation will be multiple of 256K.
- */
-#define KVM_CMA_CHUNK_ORDER	18
-
-extern struct page *kvm_alloc_cma(unsigned long nr_pages,
-				  unsigned long align_pages);
-extern bool kvm_release_cma(struct page *pages, unsigned long nr_pages);
-extern long kvm_cma_declare_contiguous(phys_addr_t size,
-				       phys_addr_t alignment) __init;
-#endif
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 06/10] CMA: generalize CMA reserved area management functionality
From: Joonsoo Kim @ 2014-06-12  3:21 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-1-git-send-email-iamjoonsoo.kim@lge.com>

Currently, there are two users on CMA functionality, one is the DMA
subsystem and the other is the kvm on powerpc. They have their own code
to manage CMA reserved area even if they looks really similar.
>From my guess, it is caused by some needs on bitmap management. Kvm side
wants to maintain bitmap not for 1 page, but for more size. Eventually it
use bitmap where one bit represents 64 pages.

When I implement CMA related patches, I should change those two places
to apply my change and it seem to be painful to me. I want to change
this situation and reduce future code management overhead through
this patch.

This change could also help developer who want to use CMA in their
new feature development, since they can use CMA easily without
copying & pasting this reserved area management code.

In previous patches, we have prepared some features to generalize
CMA reserved area management and now it's time to do it. This patch
moves core functions to mm/cma.c and change DMA APIs to use
these functions.

There is no functional change in DMA APIs.

v2: There is no big change from v1 in mm/cma.c. Mostly renaming.

Acked-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 00e13ce..4eac559 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -283,16 +283,6 @@ config CMA_ALIGNMENT
 
 	  If unsure, leave the default value "8".
 
-config CMA_AREAS
-	int "Maximum count of the CMA device-private areas"
-	default 7
-	help
-	  CMA allows to create CMA areas for particular devices. This parameter
-	  sets the maximum number of such device private CMA areas in the
-	  system.
-
-	  If unsure, leave the default value "7".
-
 endif
 
 endmenu
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 9bc9340..f177f73 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -24,25 +24,10 @@
 
 #include <linux/memblock.h>
 #include <linux/err.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <linux/page-isolation.h>
 #include <linux/sizes.h>
-#include <linux/slab.h>
-#include <linux/swap.h>
-#include <linux/mm_types.h>
 #include <linux/dma-contiguous.h>
 #include <linux/log2.h>
-
-struct cma {
-	unsigned long	base_pfn;
-	unsigned long	count;
-	unsigned long	*bitmap;
-	int order_per_bit; /* Order of pages represented by one bit */
-	struct mutex	lock;
-};
-
-struct cma *dma_contiguous_default_area;
+#include <linux/cma.h>
 
 #ifdef CONFIG_CMA_SIZE_MBYTES
 #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
@@ -50,6 +35,8 @@ struct cma *dma_contiguous_default_area;
 #define CMA_SIZE_MBYTES 0
 #endif
 
+struct cma *dma_contiguous_default_area;
+
 /*
  * Default global CMA area size can be defined in kernel's .config.
  * This is useful mainly for distro maintainers to create a kernel
@@ -156,199 +143,13 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
 	}
 }
 
-static DEFINE_MUTEX(cma_mutex);
-
-static unsigned long cma_bitmap_aligned_mask(struct cma *cma, int align_order)
-{
-	return (1 << (align_order >> cma->order_per_bit)) - 1;
-}
-
-static unsigned long cma_bitmap_maxno(struct cma *cma)
-{
-	return cma->count >> cma->order_per_bit;
-}
-
-static unsigned long cma_bitmap_pages_to_bits(struct cma *cma,
-						unsigned long pages)
-{
-	return ALIGN(pages, 1 << cma->order_per_bit) >> cma->order_per_bit;
-}
-
-static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
-{
-	unsigned long bitmapno, nr_bits;
-
-	bitmapno = (pfn - cma->base_pfn) >> cma->order_per_bit;
-	nr_bits = cma_bitmap_pages_to_bits(cma, count);
-
-	mutex_lock(&cma->lock);
-	bitmap_clear(cma->bitmap, bitmapno, nr_bits);
-	mutex_unlock(&cma->lock);
-}
-
-static int __init cma_activate_area(struct cma *cma)
-{
-	int bitmap_maxno = cma_bitmap_maxno(cma);
-	int bitmap_size = BITS_TO_LONGS(bitmap_maxno) * sizeof(long);
-	unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
-	unsigned i = cma->count >> pageblock_order;
-	struct zone *zone;
-
-	pr_debug("%s()\n", __func__);
-
-	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
-	if (!cma->bitmap)
-		return -ENOMEM;
-
-	WARN_ON_ONCE(!pfn_valid(pfn));
-	zone = page_zone(pfn_to_page(pfn));
-
-	do {
-		unsigned j;
-		base_pfn = pfn;
-		for (j = pageblock_nr_pages; j; --j, pfn++) {
-			WARN_ON_ONCE(!pfn_valid(pfn));
-			/*
-			 * alloc_contig_range requires the pfn range
-			 * specified to be in the same zone. Make this
-			 * simple by forcing the entire CMA resv range
-			 * to be in the same zone.
-			 */
-			if (page_zone(pfn_to_page(pfn)) != zone)
-				goto err;
-		}
-		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
-	} while (--i);
-
-	mutex_init(&cma->lock);
-	return 0;
-
-err:
-	kfree(cma->bitmap);
-	return -EINVAL;
-}
-
-static struct cma cma_areas[MAX_CMA_AREAS];
-static unsigned cma_area_count;
-
-static int __init cma_init_reserved_areas(void)
-{
-	int i;
-
-	for (i = 0; i < cma_area_count; i++) {
-		int ret = cma_activate_area(&cma_areas[i]);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-core_initcall(cma_init_reserved_areas);
-
-/**
- * dma_contiguous_reserve_area() - reserve custom contiguous area
- * @size: Size of the reserved area (in bytes),
- * @base: Base address of the reserved area optional, use 0 for any
- * @limit: End address of the reserved memory (optional, 0 for any).
- * @alignment: Alignment for the contiguous memory area, should be power of 2
- * @order_per_bit: Order of pages represented by one bit on bitmap.
- * @res_cma: Pointer to store the created cma region.
- * @fixed: hint about where to place the reserved area
- *
- * This function reserves memory from early allocator. It should be
- * called by arch specific code once the early allocator (memblock or bootmem)
- * has been activated and all other subsystems have already allocated/reserved
- * memory. This function allows to create custom reserved areas for specific
- * devices.
- *
- * If @fixed is true, reserve contiguous area at exactly @base.  If false,
- * reserve in range from @base to @limit.
- */
-static int __init __dma_contiguous_reserve_area(phys_addr_t size,
-				phys_addr_t base, phys_addr_t limit,
-				phys_addr_t alignment, int order_per_bit,
-				struct cma **res_cma, bool fixed)
-{
-	struct cma *cma = &cma_areas[cma_area_count];
-	int ret = 0;
-
-	pr_debug("%s(size %lx, base %08lx, limit %08lx align_order %08lx)\n",
-		__func__, (unsigned long)size, (unsigned long)base,
-		(unsigned long)limit, (unsigned long)alignment);
-
-	/* Sanity checks */
-	if (cma_area_count == ARRAY_SIZE(cma_areas)) {
-		pr_err("%s(): Not enough slots for CMA reserved regions!\n",
-			__func__);
-		return -ENOSPC;
-	}
-
-	if (!size)
-		return -EINVAL;
-
-	if (alignment && !is_power_of_2(alignment))
-		return -EINVAL;
-
-	/*
-	 * Sanitise input arguments.
-	 * CMA area should be at least MAX_ORDER - 1 aligned. Otherwise,
-	 * CMA area could be merged into other MIGRATE_TYPE by buddy mechanism
-	 * and CMA property will be broken.
-	 */
-	alignment = max(alignment,
-		(phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order));
-	base = ALIGN(base, alignment);
-	size = ALIGN(size, alignment);
-	limit &= ~(alignment - 1);
-	/* size should be aligned with order_per_bit */
-	BUG_ON(!IS_ALIGNED(size >> PAGE_SHIFT, 1 << order_per_bit));
-
-	/* Reserve memory */
-	if (base && fixed) {
-		if (memblock_is_region_reserved(base, size) ||
-		    memblock_reserve(base, size) < 0) {
-			ret = -EBUSY;
-			goto err;
-		}
-	} else {
-		phys_addr_t addr = memblock_alloc_range(size, alignment, base,
-							limit);
-		if (!addr) {
-			ret = -ENOMEM;
-			goto err;
-		} else {
-			base = addr;
-		}
-	}
-
-	/*
-	 * Each reserved area must be initialised later, when more kernel
-	 * subsystems (like slab allocator) are available.
-	 */
-	cma->base_pfn = PFN_DOWN(base);
-	cma->count = size >> PAGE_SHIFT;
-	cma->order_per_bit = order_per_bit;
-	*res_cma = cma;
-	cma_area_count++;
-
-	pr_info("%s(): reserved %ld MiB at %08lx\n",
-		__func__, (unsigned long)size / SZ_1M, (unsigned long)base);
-	return 0;
-
-err:
-	pr_err("%s(): failed to reserve %ld MiB\n",
-		__func__, (unsigned long)size / SZ_1M);
-	return ret;
-}
-
 int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 				       phys_addr_t limit, struct cma **res_cma,
 				       bool fixed)
 {
 	int ret;
 
-	ret = __dma_contiguous_reserve_area(size, base, limit, 0, 0,
-						res_cma, fixed);
+	ret = cma_declare_contiguous(size, base, limit, 0, 0, res_cma, fixed);
 	if (ret)
 		return ret;
 
@@ -358,124 +159,17 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 	return 0;
 }
 
-/**
- * dma_alloc_from_contiguous() - allocate pages from contiguous area
- * @dev:   Pointer to device for which the allocation is performed.
- * @count: Requested number of pages.
- * @align: Requested alignment of pages (in PAGE_SIZE order).
- *
- * This function allocates memory buffer for specified device. It uses
- * device specific contiguous memory area if available or the default
- * global one. Requires architecture specific dev_get_cma_area() helper
- * function.
- */
-static struct page *__dma_alloc_from_contiguous(struct cma *cma, int count,
-				       unsigned int align)
-{
-	unsigned long mask, pfn, start = 0;
-	unsigned long bitmap_maxno, bitmapno, nr_bits;
-	struct page *page = NULL;
-	int ret;
-
-	if (!cma || !cma->count)
-		return NULL;
-
-	pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma,
-		 count, align);
-
-	if (!count)
-		return NULL;
-
-	mask = cma_bitmap_aligned_mask(cma, align);
-	bitmap_maxno = cma_bitmap_maxno(cma);
-	nr_bits = cma_bitmap_pages_to_bits(cma, count);
-
-	for (;;) {
-		mutex_lock(&cma->lock);
-		bitmapno = bitmap_find_next_zero_area(cma->bitmap,
-					bitmap_maxno, start, nr_bits, mask);
-		if (bitmapno >= bitmap_maxno) {
-			mutex_unlock(&cma->lock);
-			break;
-		}
-		bitmap_set(cma->bitmap, bitmapno, nr_bits);
-		/*
-		 * It's safe to drop the lock here. We've marked this region for
-		 * our exclusive use. If the migration fails we will take the
-		 * lock again and unmark it.
-		 */
-		mutex_unlock(&cma->lock);
-
-		pfn = cma->base_pfn + (bitmapno << cma->order_per_bit);
-		mutex_lock(&cma_mutex);
-		ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
-		mutex_unlock(&cma_mutex);
-		if (ret == 0) {
-			page = pfn_to_page(pfn);
-			break;
-		} else if (ret != -EBUSY) {
-			clear_cma_bitmap(cma, pfn, count);
-			break;
-		}
-		clear_cma_bitmap(cma, pfn, count);
-		pr_debug("%s(): memory range at %p is busy, retrying\n",
-			 __func__, pfn_to_page(pfn));
-		/* try again with a bit different memory target */
-		start = bitmapno + mask + 1;
-	}
-
-	pr_debug("%s(): returned %p\n", __func__, page);
-	return page;
-}
-
 struct page *dma_alloc_from_contiguous(struct device *dev, int count,
 				       unsigned int align)
 {
-	struct cma *cma = dev_get_cma_area(dev);
-
 	if (align > CONFIG_CMA_ALIGNMENT)
 		align = CONFIG_CMA_ALIGNMENT;
 
-	return __dma_alloc_from_contiguous(cma, count, align);
-}
-
-/**
- * dma_release_from_contiguous() - release allocated pages
- * @dev:   Pointer to device for which the pages were allocated.
- * @pages: Allocated pages.
- * @count: Number of allocated pages.
- *
- * This function releases memory allocated by dma_alloc_from_contiguous().
- * It returns false when provided pages do not belong to contiguous area and
- * true otherwise.
- */
-static bool __dma_release_from_contiguous(struct cma *cma, struct page *pages,
-				 int count)
-{
-	unsigned long pfn;
-
-	if (!cma || !pages)
-		return false;
-
-	pr_debug("%s(page %p)\n", __func__, (void *)pages);
-
-	pfn = page_to_pfn(pages);
-
-	if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
-		return false;
-
-	VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
-
-	free_contig_range(pfn, count);
-	clear_cma_bitmap(cma, pfn, count);
-
-	return true;
+	return cma_alloc(dev_get_cma_area(dev), count, align);
 }
 
 bool dma_release_from_contiguous(struct device *dev, struct page *pages,
 				 int count)
 {
-	struct cma *cma = dev_get_cma_area(dev);
-
-	return __dma_release_from_contiguous(cma, pages, count);
+	return cma_release(dev_get_cma_area(dev), pages, count);
 }
diff --git a/include/linux/cma.h b/include/linux/cma.h
new file mode 100644
index 0000000..e38efe9
--- /dev/null
+++ b/include/linux/cma.h
@@ -0,0 +1,12 @@
+#ifndef __CMA_H__
+#define __CMA_H__
+
+struct cma;
+
+extern int __init cma_declare_contiguous(phys_addr_t size,
+				phys_addr_t base, phys_addr_t limit,
+				phys_addr_t alignment, int order_per_bit,
+				struct cma **res_cma, bool fixed);
+extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align);
+extern bool cma_release(struct cma *cma, struct page *pages, int count);
+#endif
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 772eab5..a40c1f3 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -53,9 +53,10 @@
 
 #ifdef __KERNEL__
 
+#include <linux/device.h>
+
 struct cma;
 struct page;
-struct device;
 
 #ifdef CONFIG_DMA_CMA
 
diff --git a/mm/Kconfig b/mm/Kconfig
index 3e9977a..f4899ec 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -508,6 +508,17 @@ config CMA_DEBUG
 	  processing calls such as dma_alloc_from_contiguous().
 	  This option does not affect warning and error messages.
 
+config CMA_AREAS
+	int "Maximum count of the CMA areas"
+	depends on CMA
+	default 7
+	help
+	  CMA allows to create CMA areas for particular purpose, mainly,
+	  used as device private area. This parameter sets the maximum
+	  number of CMA area in the system.
+
+	  If unsure, leave the default value "7".
+
 config ZBUD
 	tristate
 	default n
diff --git a/mm/Makefile b/mm/Makefile
index 1eaa70b..bc0422b 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -62,3 +62,4 @@ obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
 obj-$(CONFIG_ZBUD)	+= zbud.o
 obj-$(CONFIG_ZSMALLOC)	+= zsmalloc.o
 obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o
+obj-$(CONFIG_CMA)	+= cma.o
diff --git a/mm/cma.c b/mm/cma.c
new file mode 100644
index 0000000..1e1b017
--- /dev/null
+++ b/mm/cma.c
@@ -0,0 +1,330 @@
+/*
+ * Contiguous Memory Allocator
+ *
+ * Copyright (c) 2010-2011 by Samsung Electronics.
+ * Copyright IBM Corporation, 2013
+ * Copyright LG Electronics Inc., 2014
+ * Written by:
+ *	Marek Szyprowski <m.szyprowski@samsung.com>
+ *	Michal Nazarewicz <mina86@mina86.com>
+ *	Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *	Joonsoo Kim <iamjoonsoo.kim@lge.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License or (at your optional) any later version of the license.
+ */
+
+#define pr_fmt(fmt) "cma: " fmt
+
+#ifdef CONFIG_CMA_DEBUG
+#ifndef DEBUG
+#  define DEBUG
+#endif
+#endif
+
+#include <linux/memblock.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+struct cma {
+	unsigned long	base_pfn;
+	unsigned long	count;
+	unsigned long	*bitmap;
+	int order_per_bit; /* Order of pages represented by one bit */
+	struct mutex	lock;
+};
+
+/*
+ * There is always at least global CMA area and a few optional
+ * areas configured in kernel .config.
+ */
+#define MAX_CMA_AREAS	(1 + CONFIG_CMA_AREAS)
+
+static struct cma cma_areas[MAX_CMA_AREAS];
+static unsigned cma_area_count;
+static DEFINE_MUTEX(cma_mutex);
+
+static unsigned long cma_bitmap_aligned_mask(struct cma *cma, int align_order)
+{
+	return (1 << (align_order >> cma->order_per_bit)) - 1;
+}
+
+static unsigned long cma_bitmap_maxno(struct cma *cma)
+{
+	return cma->count >> cma->order_per_bit;
+}
+
+static unsigned long cma_bitmap_pages_to_bits(struct cma *cma,
+						unsigned long pages)
+{
+	return ALIGN(pages, 1 << cma->order_per_bit) >> cma->order_per_bit;
+}
+
+static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
+{
+	unsigned long bitmapno, nr_bits;
+
+	bitmapno = (pfn - cma->base_pfn) >> cma->order_per_bit;
+	nr_bits = cma_bitmap_pages_to_bits(cma, count);
+
+	mutex_lock(&cma->lock);
+	bitmap_clear(cma->bitmap, bitmapno, nr_bits);
+	mutex_unlock(&cma->lock);
+}
+
+static int __init cma_activate_area(struct cma *cma)
+{
+	int bitmap_maxno = cma_bitmap_maxno(cma);
+	int bitmap_size = BITS_TO_LONGS(bitmap_maxno) * sizeof(long);
+	unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
+	unsigned i = cma->count >> pageblock_order;
+	struct zone *zone;
+
+	pr_debug("%s()\n", __func__);
+
+	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!cma->bitmap)
+		return -ENOMEM;
+
+	WARN_ON_ONCE(!pfn_valid(pfn));
+	zone = page_zone(pfn_to_page(pfn));
+
+	do {
+		unsigned j;
+
+		base_pfn = pfn;
+		for (j = pageblock_nr_pages; j; --j, pfn++) {
+			WARN_ON_ONCE(!pfn_valid(pfn));
+			/*
+			 * alloc_contig_range requires the pfn range
+			 * specified to be in the same zone. Make this
+			 * simple by forcing the entire CMA resv range
+			 * to be in the same zone.
+			 */
+			if (page_zone(pfn_to_page(pfn)) != zone)
+				goto err;
+		}
+		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
+	} while (--i);
+
+	mutex_init(&cma->lock);
+	return 0;
+
+err:
+	kfree(cma->bitmap);
+	return -EINVAL;
+}
+
+static int __init cma_init_reserved_areas(void)
+{
+	int i;
+
+	for (i = 0; i < cma_area_count; i++) {
+		int ret = cma_activate_area(&cma_areas[i]);
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+core_initcall(cma_init_reserved_areas);
+
+/**
+ * cma_declare_contiguous() - reserve custom contiguous area
+ * @size: Size of the reserved area (in bytes),
+ * @base: Base address of the reserved area optional, use 0 for any
+ * @limit: End address of the reserved memory (optional, 0 for any).
+ * @alignment: Alignment for the contiguous memory area, should be power of 2
+ * @order_per_bit: Order of pages represented by one bit on bitmap.
+ * @res_cma: Pointer to store the created cma region.
+ * @fixed: hint about where to place the reserved area
+ *
+ * This function reserves memory from early allocator. It should be
+ * called by arch specific code once the early allocator (memblock or bootmem)
+ * has been activated and all other subsystems have already allocated/reserved
+ * memory. This function allows to create custom reserved areas.
+ *
+ * If @fixed is true, reserve contiguous area at exactly @base.  If false,
+ * reserve in range from @base to @limit.
+ */
+int __init cma_declare_contiguous(phys_addr_t size,
+				phys_addr_t base, phys_addr_t limit,
+				phys_addr_t alignment, int order_per_bit,
+				struct cma **res_cma, bool fixed)
+{
+	struct cma *cma = &cma_areas[cma_area_count];
+	int ret = 0;
+
+	pr_debug("%s(size %lx, base %08lx, limit %08lx alignment %08lx)\n",
+		__func__, (unsigned long)size, (unsigned long)base,
+		(unsigned long)limit, (unsigned long)alignment);
+
+	/* Sanity checks */
+	if (cma_area_count == ARRAY_SIZE(cma_areas)) {
+		pr_err("%s(): Not enough slots for CMA reserved regions!\n",
+			__func__);
+		return -ENOSPC;
+	}
+
+	if (!size)
+		return -EINVAL;
+
+	if (alignment && !is_power_of_2(alignment))
+		return -EINVAL;
+
+	/*
+	 * Sanitise input arguments.
+	 * CMA area should be at least MAX_ORDER - 1 aligned. Otherwise,
+	 * CMA area could be merged into other MIGRATE_TYPE by buddy mechanism
+	 * and CMA property will be broken.
+	 */
+	alignment = max(alignment,
+		(phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order));
+	base = ALIGN(base, alignment);
+	size = ALIGN(size, alignment);
+	limit &= ~(alignment - 1);
+	/* size should be aligned with order_per_bit */
+	BUG_ON(!IS_ALIGNED(size >> PAGE_SHIFT, 1 << order_per_bit));
+
+	/* Reserve memory */
+	if (base && fixed) {
+		if (memblock_is_region_reserved(base, size) ||
+		    memblock_reserve(base, size) < 0) {
+			ret = -EBUSY;
+			goto err;
+		}
+	} else {
+		phys_addr_t addr = memblock_alloc_range(size, alignment, base,
+							limit);
+		if (!addr) {
+			ret = -ENOMEM;
+			goto err;
+		} else {
+			base = addr;
+		}
+	}
+
+	/*
+	 * Each reserved area must be initialised later, when more kernel
+	 * subsystems (like slab allocator) are available.
+	 */
+	cma->base_pfn = PFN_DOWN(base);
+	cma->count = size >> PAGE_SHIFT;
+	cma->order_per_bit = order_per_bit;
+	*res_cma = cma;
+	cma_area_count++;
+
+	pr_info("%s(): reserved %ld MiB at %08lx\n",
+		__func__, (unsigned long)size / SZ_1M, (unsigned long)base);
+	return 0;
+
+err:
+	pr_err("%s(): failed to reserve %ld MiB\n",
+		__func__, (unsigned long)size / SZ_1M);
+	return ret;
+}
+
+/**
+ * cma_alloc() - allocate pages from contiguous area
+ * @cma:   Contiguous memory region for which the allocation is performed.
+ * @count: Requested number of pages.
+ * @align: Requested alignment of pages (in PAGE_SIZE order).
+ *
+ * This function allocates part of contiguous memory on specific
+ * contiguous memory area.
+ */
+struct page *cma_alloc(struct cma *cma, int count, unsigned int align)
+{
+	unsigned long mask, pfn, start = 0;
+	unsigned long bitmap_maxno, bitmapno, nr_bits;
+	struct page *page = NULL;
+	int ret;
+
+	if (!cma || !cma->count)
+		return NULL;
+
+	pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma,
+		 count, align);
+
+	if (!count)
+		return NULL;
+
+	mask = cma_bitmap_aligned_mask(cma, align);
+	bitmap_maxno = cma_bitmap_maxno(cma);
+	nr_bits = cma_bitmap_pages_to_bits(cma, count);
+
+	for (;;) {
+		mutex_lock(&cma->lock);
+		bitmapno = bitmap_find_next_zero_area(cma->bitmap,
+					bitmap_maxno, start, nr_bits, mask);
+		if (bitmapno >= bitmap_maxno) {
+			mutex_unlock(&cma->lock);
+			break;
+		}
+		bitmap_set(cma->bitmap, bitmapno, nr_bits);
+		/*
+		 * It's safe to drop the lock here. We've marked this region for
+		 * our exclusive use. If the migration fails we will take the
+		 * lock again and unmark it.
+		 */
+		mutex_unlock(&cma->lock);
+
+		pfn = cma->base_pfn + (bitmapno << cma->order_per_bit);
+		mutex_lock(&cma_mutex);
+		ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
+		mutex_unlock(&cma_mutex);
+		if (ret == 0) {
+			page = pfn_to_page(pfn);
+			break;
+		} else if (ret != -EBUSY) {
+			clear_cma_bitmap(cma, pfn, count);
+			break;
+		}
+		clear_cma_bitmap(cma, pfn, count);
+		pr_debug("%s(): memory range at %p is busy, retrying\n",
+			 __func__, pfn_to_page(pfn));
+		/* try again with a bit different memory target */
+		start = bitmapno + mask + 1;
+	}
+
+	pr_debug("%s(): returned %p\n", __func__, page);
+	return page;
+}
+
+/**
+ * cma_release() - release allocated pages
+ * @cma:   Contiguous memory region for which the allocation is performed.
+ * @pages: Allocated pages.
+ * @count: Number of allocated pages.
+ *
+ * This function releases memory allocated by alloc_cma().
+ * It returns false when provided pages do not belong to contiguous area and
+ * true otherwise.
+ */
+bool cma_release(struct cma *cma, struct page *pages, int count)
+{
+	unsigned long pfn;
+
+	if (!cma || !pages)
+		return false;
+
+	pr_debug("%s(page %p)\n", __func__, (void *)pages);
+
+	pfn = page_to_pfn(pages);
+
+	if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
+		return false;
+
+	VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
+
+	free_contig_range(pfn, count);
+	clear_cma_bitmap(cma, pfn, count);
+
+	return true;
+}
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH v2 01/10] DMA, CMA: clean-up log message
From: Aneesh Kumar K.V @ 2014-06-12  4:41 UTC (permalink / raw)
  To: Joonsoo Kim, Andrew Morton, Marek Szyprowski, Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-2-git-send-email-iamjoonsoo.kim@lge.com>

Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:

> We don't need explicit 'CMA:' prefix, since we already define prefix
> 'cma:' in pr_fmt. So remove it.
>
> And, some logs print function name and others doesn't. This looks
> bad to me, so I unify log format to print function name consistently.
>
> Lastly, I add one more debug log on cma_activate_area().
>
> Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
>
> diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
> index 83969f8..bd0bb81 100644
> --- a/drivers/base/dma-contiguous.c
> +++ b/drivers/base/dma-contiguous.c
> @@ -144,7 +144,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
>  	}
>
>  	if (selected_size && !dma_contiguous_default_area) {
> -		pr_debug("%s: reserving %ld MiB for global area\n", __func__,
> +		pr_debug("%s(): reserving %ld MiB for global area\n", __func__,
>  			 (unsigned long)selected_size / SZ_1M);

Do we need to do function(), or just function:. I have seen the later
usage in other parts of the kernel.

>
>  		dma_contiguous_reserve_area(selected_size, selected_base,
> @@ -163,8 +163,9 @@ static int __init cma_activate_area(struct cma *cma)
>  	unsigned i = cma->count >> pageblock_order;
>  	struct zone *zone;
>
> -	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
> +	pr_debug("%s()\n", __func__);

why ?

>
> +	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
>  	if (!cma->bitmap)
>  		return -ENOMEM;
>
> @@ -234,7 +235,8 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
>
>  	/* Sanity checks */
>  	if (cma_area_count == ARRAY_SIZE(cma_areas)) {
> -		pr_err("Not enough slots for CMA reserved regions!\n");
> +		pr_err("%s(): Not enough slots for CMA reserved regions!\n",
> +			__func__);
>  		return -ENOSPC;
>  	}
>
> @@ -274,14 +276,15 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
>  	*res_cma = cma;
>  	cma_area_count++;
>
> -	pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
> -		(unsigned long)base);
> +	pr_info("%s(): reserved %ld MiB at %08lx\n",
> +		__func__, (unsigned long)size / SZ_1M, (unsigned long)base);
>
>  	/* Architecture specific contiguous memory fixup. */
>  	dma_contiguous_early_fixup(base, size);
>  	return 0;
>  err:
> -	pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
> +	pr_err("%s(): failed to reserve %ld MiB\n",
> +		__func__, (unsigned long)size / SZ_1M);
>  	return ret;
>  }
>
> -- 
> 1.7.9.5

^ permalink raw reply

* Re: [PATCH v2 02/10] DMA, CMA: fix possible memory leak
From: Aneesh Kumar K.V @ 2014-06-12  4:43 UTC (permalink / raw)
  To: Joonsoo Kim, Andrew Morton, Marek Szyprowski, Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402543307-29800-3-git-send-email-iamjoonsoo.kim@lge.com>

Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:

> We should free memory for bitmap when we find zone mis-match,
> otherwise this memory will leak.
>
> Additionally, I copy code comment from ppc kvm's cma code to notify
> why we need to check zone mis-match.
>
> Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>

>
> diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
> index bd0bb81..fb0cdce 100644
> --- a/drivers/base/dma-contiguous.c
> +++ b/drivers/base/dma-contiguous.c
> @@ -177,14 +177,24 @@ static int __init cma_activate_area(struct cma *cma)
>  		base_pfn = pfn;
>  		for (j = pageblock_nr_pages; j; --j, pfn++) {
>  			WARN_ON_ONCE(!pfn_valid(pfn));
> +			/*
> +			 * alloc_contig_range requires the pfn range
> +			 * specified to be in the same zone. Make this
> +			 * simple by forcing the entire CMA resv range
> +			 * to be in the same zone.
> +			 */
>  			if (page_zone(pfn_to_page(pfn)) != zone)
> -				return -EINVAL;
> +				goto err;
>  		}
>  		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
>  	} while (--i);
>
>  	mutex_init(&cma->lock);
>  	return 0;
> +
> +err:
> +	kfree(cma->bitmap);
> +	return -EINVAL;
>  }
>
>  static struct cma cma_areas[MAX_CMA_AREAS];
> -- 
> 1.7.9.5

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox