* Re: Device Tree Binding for DSA on P1023RDB
From: Pannirselvam Kanagaratnam @ 2014-06-13 10:34 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <1402608088.6603.549.camel@snotra.buserror.net>
On Fri, Jun 13, 2014, at 05:21 AM, Scott Wood wrote:
> On Thu, 2014-06-12 at 23:36 +0800, Pannirselvam Kanagaratnam wrote:
> > The QORIQ P1023RDB has an option to populate the Marvell 88E6165
> > Ethernet switch. We populated this device and was able to initialize
> > it as a basic switch in U-Boot. However, the switch driver was not
> > loaded upon kernel bootup. DSA kernel config was enabled for the
> > 88E6165. The following patch was applied:
> >
> >
> > http://patchwork.ozlabs.org/patch/230257/
> >
> >
> > The switch is attached to phy address 0x3 via dtsec2. My dts file is
> > as below. Would appreciate any feedback on whether the DSA is
> > correctly structured in the dts.
>
> If you have a dtsec driver you're not working with an upstream kernel
> (or you've ported a lot of SDK code to it)... What tree are you working
> with? Are there prerequisites to the above patch that you might be
> missing?
>
I am using QorIQ-SDK-V1.5-20131219-yocto (3.8-r11.1). Not sure if I am
missing
any prerequisites.
> The above patch is a platform driver and you put the node in the
> toplevel device tree node. Have you added marvell,dsa to the list of
> compatible strings that get probed (of_device_ids in corenet_generic.c
> or an equivalent list in your SDK kernel)?
> >
I was missing this. I added it in arch/powerpc/platforms/85xx/common.c
After adding the above, the driver is now attempting to probe. However,
I got the following message:
Distributed Switch Architecture driver version 0.1
dsa: probe of dsa.16 failed with error -22
I dumped the mdio, mdio_bus and ethernet parameters:
1) For mdio = of_parse_phandle(np, "dsa,mii-bus", 0); I get the
following:
np-name: dsa
mdio-name: mdio
mdio-type: <NULL>
mdio-full-name: /soc@ff600000/fman@100000/mdio@e1120
2) mdio_bus = of_mdio_find_bus(mdio);
mdio_bus_name: Freescale PowerQUICC MII Bus
mdio_bus_id: mdio@ff7e1120
3) ethernet = of_parse_phandle(np, "dsa,ethernet", 0);
ethernet-name: ethernet
ethernet-type: <NULL>
ethernet-full-name: /soc@ff600000/fman@100000/ethernet@e2000
Anything amiss here?
> > dsa@0 {
> > compatible = "marvell,dsa";
> > #address-cells = <2>;
> > #size-cells = <0>;
> >
> > interrupts = <3>;
>
> This interrupts property needs to be four cells rather than one, if MPIC
> is the parent -- assuming you have #interrupt-cells = <4> and not some
> old device tree with #interrupt-cells = <2>, but in any case you need
> more than one cell.
>
The interrupt is an optional entry and not supported by the driver. I
have omitted it for now.
Pannir
^ permalink raw reply
* [PATCH] selftests/powerpc: Use the test harness for the TM DSCR test
From: Michael Ellerman @ 2014-06-13 11:16 UTC (permalink / raw)
To: linuxppc-dev; +Cc: sam.bobroff
This gives us standardised success/failure output and also handles
killing the test if it runs forever (2 minutes).
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
tools/testing/selftests/powerpc/tm/Makefile | 2 +-
tools/testing/selftests/powerpc/tm/tm-resched-dscr.c | 14 +++++++++++---
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile
index 51267f4..2cede23 100644
--- a/tools/testing/selftests/powerpc/tm/Makefile
+++ b/tools/testing/selftests/powerpc/tm/Makefile
@@ -2,7 +2,7 @@ PROGS := tm-resched-dscr
all: $(PROGS)
-$(PROGS):
+$(PROGS): ../harness.c
run_tests: all
@-for PROG in $(PROGS); do \
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
index ee98e38..42d4c8c 100644
--- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
+++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
@@ -28,6 +28,8 @@
#include <assert.h>
#include <asm/tm.h>
+#include "utils.h"
+
#define TBEGIN ".long 0x7C00051D ;"
#define TEND ".long 0x7C00055D ;"
#define TCHECK ".long 0x7C00059C ;"
@@ -36,7 +38,8 @@
#define SPRN_TEXASR 0x82
#define SPRN_DSCR 0x03
-int main(void) {
+int test_body(void)
+{
uint64_t rv, dscr1 = 1, dscr2, texasr;
printf("Check DSCR TM context switch: ");
@@ -81,10 +84,15 @@ int main(void) {
}
if (dscr2 != dscr1) {
printf(" FAIL\n");
- exit(EXIT_FAILURE);
+ return 1;
} else {
printf(" OK\n");
- exit(EXIT_SUCCESS);
+ return 0;
}
}
}
+
+int main(void)
+{
+ return test_harness(test_body, "tm_resched_dscr");
+}
--
1.9.1
^ permalink raw reply related
* [PATCH] fsl-rio: add support for mapping inbound windows
From: Martijn de Gouw @ 2014-06-13 11:09 UTC (permalink / raw)
To: linuxppc-dev, scottwood
Cc: Alexandre.Bounine, Martijn de Gouw, Barry.Wood, stef.van.os
From: Martijn de Gouw <martijn.de.gouw@prodrive.nl>
Add support for mapping and unmapping of inbound rapidio windows.
Signed-off-by: Martijn de Gouw <martijn.de.gouw@prodrive.nl>
---
arch/powerpc/sysdev/fsl_rio.c | 84 +++++++++++++++++++++++++++++++++++++++++
arch/powerpc/sysdev/fsl_rio.h | 12 ++++++
2 files changed, 96 insertions(+)
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index cf2b084..23d6f49 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -58,6 +58,19 @@
#define RIO_ISR_AACR 0x10120
#define RIO_ISR_AACR_AA 0x1 /* Accept All ID */
+#define RIWTAR_TRAD_VAL_SHIFT 12
+#define RIWTAR_TRAD_MASK 0x00FFFFFF
+#define RIWBAR_BADD_VAL_SHIFT 12
+#define RIWBAR_BADD_MASK 0x003FFFFF
+#define RIWAR_ENABLE 0x80000000
+#define RIWAR_TGINT_LOCAL 0x00F00000
+#define RIWAR_RDTYP_NO_SNOOP 0x00040000
+#define RIWAR_RDTYP_SNOOP 0x00050000
+#define RIWAR_WRTYP_NO_SNOOP 0x00004000
+#define RIWAR_WRTYP_SNOOP 0x00005000
+#define RIWAR_WRTYP_ALLOC 0x00006000
+#define RIWAR_SIZE_MASK 0x0000003F
+
#define __fsl_read_rio_config(x, addr, err, op) \
__asm__ __volatile__( \
"1: "op" %1,0(%2)\n" \
@@ -266,6 +279,72 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
return 0;
}
+static void fsl_rio_inbound_mem_init(struct rio_priv *priv)
+{
+ int i;
+
+ /* close inbound windows */
+ for (i = 0; i < RIO_INB_ATMU_COUNT; i++)
+ out_be32(&priv->inb_atmu_regs[i].riwar, 0);
+}
+
+int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
+ u64 rstart, u32 size, u32 flags)
+{
+ struct rio_priv *priv = mport->priv;
+ u32 base_size;
+ unsigned int base_size_log;
+ u64 win_start, win_end;
+ u32 riwar;
+ int i;
+
+ base_size_log = __ilog2(size) + ((size & (size - 1)) != 0);
+ base_size = 1 << base_size_log;
+
+ for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {
+ riwar = in_be32(&priv->inb_atmu_regs[i].riwar);
+ if ((riwar & RIWAR_ENABLE) == 0)
+ break;
+ /* check conflicting ranges */
+ win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK))
+ << RIWBAR_BADD_VAL_SHIFT;
+ win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1);
+ if (rstart < win_end && (rstart + size) > win_start)
+ return -EINVAL;
+ }
+ if (i >= RIO_INB_ATMU_COUNT)
+ return -ENOMEM;
+
+ out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT);
+ out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT);
+ out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL |
+ RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1));
+ return 0;
+}
+
+void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart)
+{
+ u32 win_start_shift, base_start_shift;
+ struct rio_priv *priv = mport->priv;
+ u32 riwar, riwtar;
+ int i;
+
+ /* skip default window */
+ base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT;
+ for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {
+ riwar = in_be32(&priv->inb_atmu_regs[i].riwar);
+ if ((riwar & RIWAR_ENABLE) == 0)
+ continue;
+
+ riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar);
+ win_start_shift = riwtar & RIWTAR_TRAD_MASK;
+ if (win_start_shift == base_start_shift) {
+ out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE);
+ return;
+ }
+ }
+}
+
void fsl_rio_port_error_handler(int offset)
{
/*XXX: Error recovery is not implemented, we just clear errors */
@@ -389,6 +468,8 @@ int fsl_rio_setup(struct platform_device *dev)
ops->add_outb_message = fsl_add_outb_message;
ops->add_inb_buffer = fsl_add_inb_buffer;
ops->get_inb_message = fsl_get_inb_message;
+ ops->map_inb = fsl_map_inb_mem;
+ ops->unmap_inb = fsl_unmap_inb_mem;
rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0);
if (!rmu_node)
@@ -598,6 +679,8 @@ int fsl_rio_setup(struct platform_device *dev)
RIO_ATMU_REGS_PORT2_OFFSET));
priv->maint_atmu_regs = priv->atmu_regs + 1;
+ priv->inb_atmu_regs = (struct rio_inb_atmu_regs *)
+ (priv->regs_win + RIO_INB_ATMU_REGS_OFFSET);
/* Set to receive any dist ID for serial RapidIO controller. */
if (port->phy_type == RIO_PHY_SERIAL)
@@ -616,6 +699,7 @@ int fsl_rio_setup(struct platform_device *dev)
rio_law_start = range_start;
fsl_rio_setup_rmu(port, rmu_np[i]);
+ fsl_rio_inbound_mem_init(priv);
dbell->mport[i] = port;
diff --git a/arch/powerpc/sysdev/fsl_rio.h b/arch/powerpc/sysdev/fsl_rio.h
index ae8e274..dad17f9 100644
--- a/arch/powerpc/sysdev/fsl_rio.h
+++ b/arch/powerpc/sysdev/fsl_rio.h
@@ -50,9 +50,11 @@
#define RIO_S_DBELL_REGS_OFFSET 0x13400
#define RIO_S_PW_REGS_OFFSET 0x134e0
#define RIO_ATMU_REGS_DBELL_OFFSET 0x10C40
+#define RIO_INB_ATMU_REGS_OFFSET 0x10d60
#define MAX_MSG_UNIT_NUM 2
#define MAX_PORT_NUM 4
+#define RIO_INB_ATMU_COUNT 4
struct rio_atmu_regs {
u32 rowtar;
@@ -63,6 +65,15 @@ struct rio_atmu_regs {
u32 pad2[3];
};
+struct rio_inb_atmu_regs {
+ u32 riwtar;
+ u32 pad1;
+ u32 riwbar;
+ u32 pad2;
+ u32 riwar;
+ u32 pad3[3];
+};
+
struct rio_dbell_ring {
void *virt;
dma_addr_t phys;
@@ -99,6 +110,7 @@ struct rio_priv {
void __iomem *regs_win;
struct rio_atmu_regs __iomem *atmu_regs;
struct rio_atmu_regs __iomem *maint_atmu_regs;
+ struct rio_inb_atmu_regs __iomem *inb_atmu_regs;
void __iomem *maint_win;
void *rmm_handle; /* RapidIO message manager(unit) Handle */
};
--
1.7.10.4
^ permalink raw reply related
* Re: power and percpu: Could we move the paca into the percpu area?
From: Gabriel Paubert @ 2014-06-13 11:55 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: Tejun Heo, linuxppc-dev, Christoph Lameter
In-Reply-To: <20140612122639.GA17838@gate.crashing.org>
On Thu, Jun 12, 2014 at 07:26:39AM -0500, Segher Boessenkool wrote:
> > Actually, from gcc/config/rs6000.h:
> >
> > /* 1 for registers that have pervasive standard uses
> > and are not available for the register allocator.
>
> [snip]
>
> > So cr5, which is number 73, is never used by gcc.
>
> Not available for RA is not the same thing at all as not used by GCC.
> For example, GPR1 and XER[CA] are also fixed regs.
Indeed, I should have been more clear, it is never explicitly reserved
by any ABI like GPR1 for the stack pointer nor used implicitly by any pattern
like the carry (which is also never allocated, but used or clobbered
by many patterns). However no machine description pattern uses cr5.
The line "cr5 is not supposed to be used" has always been a mystery
to me, but gcc has always obeyed this rule. If memory serves it has
been in rs6000.h since I got my first PPC board in 1997.
>
> But, indeed, it does look like GCC doesn't use it. It seems to me that
> some ABI forbade userland (or non-libraries or whatever) from using it.
> I'll see what I can find out.
>
Take what I say with a grain of salt, but I always had the impression that
it was a remnant from the first port of GCC to Power, which could well have
been AIX. This first port might have been done by Richard Kenner.
Actually, a long time ago (1999-2000?) I toyed with he idea of using cr5 for
soft masking of interrupts on PPC32. But I got distracted by other things
and never came around to it.
Gabriel
^ permalink raw reply
* Re: [PATCH] IBM Akebono: Remove obsolete config select
From: Paul Bolle @ 2014-06-13 11:56 UTC (permalink / raw)
To: Alistair Popple; +Cc: linuxppc-dev, linux-kernel, devicetree
In-Reply-To: <1399018005-23136-1-git-send-email-alistair@popple.id.au>
On Fri, 2014-05-02 at 18:06 +1000, Alistair Popple wrote:
> The original implementation of MMC support for Akebono introduced a
> new configuration symbol (MMC_SDHCI_OF_476GTR). This symbol has been
> dropped in favour of using the generic platform driver however the
> select for this symbol was mistakenly left in the platform
> configuration.
>
> This patch removes the obsolete symbol selection.
>
> Signed-off-by: Alistair Popple <alistair@popple.id.au>
This patch hasn't yet entered linux-next nor Linus' tree. Is it queued
somewhere? If not, would a
Acked-by: Paul Bolle <pebolle@tiscali.nl>
help to get this trivial patch queued for either of those trees?
Paul Bolle
> ---
> arch/powerpc/platforms/44x/Kconfig | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
> index 8beec7d..908bf11 100644
> --- a/arch/powerpc/platforms/44x/Kconfig
> +++ b/arch/powerpc/platforms/44x/Kconfig
> @@ -220,7 +220,6 @@ config AKEBONO
> select USB_EHCI_HCD_PLATFORM
> select MMC_SDHCI
> select MMC_SDHCI_PLTFM
> - select MMC_SDHCI_OF_476GTR
> select ATA
> select SATA_AHCI_PLATFORM
> help
^ permalink raw reply
* Re: power and percpu: Could we move the paca into the percpu area?
From: Segher Boessenkool @ 2014-06-13 14:16 UTC (permalink / raw)
To: Gabriel Paubert; +Cc: Tejun Heo, linuxppc-dev, Christoph Lameter
In-Reply-To: <20140613115553.GA31054@visitor2.iram.es>
> > > So cr5, which is number 73, is never used by gcc.
> >
> > Not available for RA is not the same thing at all as not used by GCC.
> > For example, GPR1 and XER[CA] are also fixed regs.
>
> Indeed, I should have been more clear, it is never explicitly reserved
> by any ABI like GPR1 for the stack pointer nor used implicitly by any pattern
> like the carry (which is also never allocated, but used or clobbered
> by many patterns). However no machine description pattern uses cr5.
>
> The line "cr5 is not supposed to be used" has always been a mystery
> to me, but gcc has always obeyed this rule. If memory serves it has
> been in rs6000.h since I got my first PPC board in 1997.
It's been there (in the public repo) since 1992. The copyrights for
some of the rest of the port go back to 1990, so the code has most
likely existed at least that far back.
> > But, indeed, it does look like GCC doesn't use it. It seems to me that
> > some ABI forbade userland (or non-libraries or whatever) from using it.
> > I'll see what I can find out.
>
> Take what I say with a grain of salt, but I always had the impression that
> it was a remnant from the first port of GCC to Power, which could well have
> been AIX. This first port might have been done by Richard Kenner.
That is all correct as far as I can see.
Presumably the AIX ABI at that time (AIX2? AIX3?) had cr5 reserved.
Still digging...
Segher
^ permalink raw reply
* Re: [PATCH] KVM: PPC: BOOK3S: HV: Use base page size when comparing against slb value
From: Aneesh Kumar K.V @ 2014-06-13 14:28 UTC (permalink / raw)
To: Alexander Graf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc
In-Reply-To: <539ACC62.1040004@suse.de>
Alexander Graf <agraf@suse.de> writes:
> On 13.06.14 09:23, Aneesh Kumar K.V wrote:
>> With guest supporting Multiple page size per segment (MPSS),
>> hpte_page_size returns actual page size used. Add a new function to
>> return base page size and use that to compare against the the page size
>> calculated from SLB
>
> Why? What does this fix? Is this a bug fix, an enhancement? Don't
> describe only what you do, but also why you do it.
>
>
This could result in page fault failures (unhandled page fault) because
even though we have a valid hpte entry mapping a 16MB page, since we
were comparing actual page size against page size calculated from SLB
bits kvmppc_hv_find_lock_hpte will fail and return -1. I did not observe
a failure in real and the bug was found during code audit. That could be
because with THP we have guest ram backed by hugetlbfs and we always
find the page in the host linux page table. The will result in do_h_enter always
inserting HPTE_V_VALID entry and hence we might not really end up calling
kvmppc_hv_find_lock_hpte.
-aneesh
^ permalink raw reply
* RE: [PATCH] KVM: PPC: e500mc: Relax tlb invalidation condition on vcpu schedule
From: mihai.caraman @ 2014-06-13 14:43 UTC (permalink / raw)
To: Alexander Graf, Scott Wood
Cc: linuxppc-dev@lists.ozlabs.org, kvm@vger.kernel.org,
kvm-ppc@vger.kernel.org
In-Reply-To: <5399DDA8.5060404@suse.de>
> -----Original Message-----
> From: Alexander Graf [mailto:agraf@suse.de]
> Sent: Thursday, June 12, 2014 8:05 PM
> To: Caraman Mihai Claudiu-B02008
> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; linuxppc-
> dev@lists.ozlabs.org; Wood Scott-B07421
> Subject: Re: [PATCH] KVM: PPC: e500mc: Relax tlb invalidation condition
> on vcpu schedule
>=20
> On 06/12/2014 04:00 PM, Mihai Caraman wrote:
> > On vcpu schedule, the condition checked for tlb pollution is too tight.
> > The tlb entries of one vcpu are polluted when a different vcpu from the
> > same partition runs in-between. Relax the current tlb invalidation
> > condition taking into account the lpid.
> >
> > Signed-off-by: Mihai Caraman <mihai.caraman <at> freescale.com>
>=20
> Your mailer is broken? :)
> This really should be an @.
>=20
> I think this should work. Scott, please ack.
Alex, you were right. I screwed up the patch description by inverting relax
and tight terms :) It should have been more like this:
KVM: PPC: e500mc: Enhance tlb invalidation condition on vcpu schedule
On vcpu schedule, the condition checked for tlb pollution is too loose.
The tlb entries of a vcpu are polluted (vs stale) only when a different vcp=
u
within the same logical partition runs in-between. Optimize the tlb invalid=
ation
condition taking into account the lpid.
-Mike
^ permalink raw reply
* Re: [PATCH] KVM: PPC: BOOK3S: HV: Use base page size when comparing against slb value
From: Alexander Graf @ 2014-06-13 14:44 UTC (permalink / raw)
To: Aneesh Kumar K.V, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc
In-Reply-To: <87vbs4dgt6.fsf@linux.vnet.ibm.com>
On 13.06.14 16:28, Aneesh Kumar K.V wrote:
> Alexander Graf <agraf@suse.de> writes:
>
>> On 13.06.14 09:23, Aneesh Kumar K.V wrote:
>>> With guest supporting Multiple page size per segment (MPSS),
>>> hpte_page_size returns actual page size used. Add a new function to
>>> return base page size and use that to compare against the the page size
>>> calculated from SLB
>> Why? What does this fix? Is this a bug fix, an enhancement? Don't
>> describe only what you do, but also why you do it.
>>
>>
> This could result in page fault failures (unhandled page fault) because
> even though we have a valid hpte entry mapping a 16MB page, since we
> were comparing actual page size against page size calculated from SLB
> bits kvmppc_hv_find_lock_hpte will fail and return -1. I did not observe
> a failure in real and the bug was found during code audit. That could be
> because with THP we have guest ram backed by hugetlbfs and we always
> find the page in the host linux page table. The will result in do_h_enter always
> inserting HPTE_V_VALID entry and hence we might not really end up calling
> kvmppc_hv_find_lock_hpte.
So why do we need to override to base page size for the VRMA region?
Also I think you want to change the comment above the line in
find_lock_hpte you're changing.
Alex
^ permalink raw reply
* Re: [PATCH] KVM: PPC: e500mc: Relax tlb invalidation condition on vcpu schedule
From: Alexander Graf @ 2014-06-13 14:55 UTC (permalink / raw)
To: mihai.caraman@freescale.com, Scott Wood
Cc: linuxppc-dev@lists.ozlabs.org, kvm@vger.kernel.org,
kvm-ppc@vger.kernel.org
In-Reply-To: <306b1e4daa2f4441aaef7c7383b484fc@BY2PR03MB508.namprd03.prod.outlook.com>
On 13.06.14 16:43, mihai.caraman@freescale.com wrote:
>> -----Original Message-----
>> From: Alexander Graf [mailto:agraf@suse.de]
>> Sent: Thursday, June 12, 2014 8:05 PM
>> To: Caraman Mihai Claudiu-B02008
>> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; linuxppc-
>> dev@lists.ozlabs.org; Wood Scott-B07421
>> Subject: Re: [PATCH] KVM: PPC: e500mc: Relax tlb invalidation condition
>> on vcpu schedule
>>
>> On 06/12/2014 04:00 PM, Mihai Caraman wrote:
>>> On vcpu schedule, the condition checked for tlb pollution is too tight.
>>> The tlb entries of one vcpu are polluted when a different vcpu from the
>>> same partition runs in-between. Relax the current tlb invalidation
>>> condition taking into account the lpid.
>>>
>>> Signed-off-by: Mihai Caraman <mihai.caraman <at> freescale.com>
>> Your mailer is broken? :)
>> This really should be an @.
>>
>> I think this should work. Scott, please ack.
> Alex, you were right. I screwed up the patch description by inverting relax
> and tight terms :) It should have been more like this:
>
> KVM: PPC: e500mc: Enhance tlb invalidation condition on vcpu schedule
>
> On vcpu schedule, the condition checked for tlb pollution is too loose.
> The tlb entries of a vcpu are polluted (vs stale) only when a different vcpu
> within the same logical partition runs in-between. Optimize the tlb invalidation
> condition taking into account the lpid.
Can't we give every vcpu its own lpid? Or don't we trap on global
invalidates?
Alex
^ permalink raw reply
* [PATCH] powerpc: Fix build warning
From: Guenter Roeck @ 2014-06-13 16:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev, Paul Mackerras, linux-kernel, Guenter Roeck,
Vincent Guittot
If compiled with W=1, the following warning is seen in powerpc builds.
arch/powerpc/kernel/smp.c:750:18: warning:
type qualifiers ignored on function return type
static const int powerpc_smt_flags(void)
^
This is caused by a function returning 'const int', which doesn't
make sense to gcc. Drop 'const' to fix the problem.
Reported-by: Vincent Guittot <vincent.guittot@linaro.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
arch/powerpc/kernel/smp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 10ffffe..49d5d4e 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -768,7 +768,7 @@ int setup_profiling_timer(unsigned int multiplier)
#ifdef CONFIG_SCHED_SMT
/* cpumask of CPUs with asymetric SMT dependancy */
-static const int powerpc_smt_flags(void)
+static int powerpc_smt_flags(void)
{
int flags = SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES;
--
1.9.1
^ permalink raw reply related
* Re: [PATCH] KVM: PPC: BOOK3S: HV: Use base page size when comparing against slb value
From: Aneesh Kumar K.V @ 2014-06-13 16:43 UTC (permalink / raw)
To: Alexander Graf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc
In-Reply-To: <539B0E38.6050100@suse.de>
Alexander Graf <agraf@suse.de> writes:
> On 13.06.14 16:28, Aneesh Kumar K.V wrote:
>> Alexander Graf <agraf@suse.de> writes:
>>
>>> On 13.06.14 09:23, Aneesh Kumar K.V wrote:
>>>> With guest supporting Multiple page size per segment (MPSS),
>>>> hpte_page_size returns actual page size used. Add a new function to
>>>> return base page size and use that to compare against the the page size
>>>> calculated from SLB
>>> Why? What does this fix? Is this a bug fix, an enhancement? Don't
>>> describe only what you do, but also why you do it.
>>>
>>>
>> This could result in page fault failures (unhandled page fault) because
>> even though we have a valid hpte entry mapping a 16MB page, since we
>> were comparing actual page size against page size calculated from SLB
>> bits kvmppc_hv_find_lock_hpte will fail and return -1. I did not observe
>> a failure in real and the bug was found during code audit. That could be
>> because with THP we have guest ram backed by hugetlbfs and we always
>> find the page in the host linux page table. The will result in do_h_enter always
>> inserting HPTE_V_VALID entry and hence we might not really end up calling
>> kvmppc_hv_find_lock_hpte.
>
> So why do we need to override to base page size for the VRMA region?
slb encoding should be derived based on base page size.
> Also I think you want to change the comment above the line in
> find_lock_hpte you're changing.
>
Will do that.
-aneesh
^ permalink raw reply
* Re: [PATCH] KVM: PPC: e500mc: Relax tlb invalidation condition on vcpu schedule
From: Scott Wood @ 2014-06-13 19:42 UTC (permalink / raw)
To: Alexander Graf
Cc: mihai.caraman@freescale.com, linuxppc-dev@lists.ozlabs.org,
kvm@vger.kernel.org, kvm-ppc@vger.kernel.org
In-Reply-To: <539B10DF.6070509@suse.de>
On Fri, 2014-06-13 at 16:55 +0200, Alexander Graf wrote:
> On 13.06.14 16:43, mihai.caraman@freescale.com wrote:
> >> -----Original Message-----
> >> From: Alexander Graf [mailto:agraf@suse.de]
> >> Sent: Thursday, June 12, 2014 8:05 PM
> >> To: Caraman Mihai Claudiu-B02008
> >> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; linuxppc-
> >> dev@lists.ozlabs.org; Wood Scott-B07421
> >> Subject: Re: [PATCH] KVM: PPC: e500mc: Relax tlb invalidation condition
> >> on vcpu schedule
> >>
> >> On 06/12/2014 04:00 PM, Mihai Caraman wrote:
> >>> On vcpu schedule, the condition checked for tlb pollution is too tight.
> >>> The tlb entries of one vcpu are polluted when a different vcpu from the
> >>> same partition runs in-between. Relax the current tlb invalidation
> >>> condition taking into account the lpid.
Can you quantify the performance improvement from this? We've had bugs
in this area before, so let's make sure it's worth it before making this
more complicated.
> >>> Signed-off-by: Mihai Caraman <mihai.caraman <at> freescale.com>
> >> Your mailer is broken? :)
> >> This really should be an @.
> >>
> >> I think this should work. Scott, please ack.
> > Alex, you were right. I screwed up the patch description by inverting relax
> > and tight terms :) It should have been more like this:
> >
> > KVM: PPC: e500mc: Enhance tlb invalidation condition on vcpu schedule
> >
> > On vcpu schedule, the condition checked for tlb pollution is too loose.
> > The tlb entries of a vcpu are polluted (vs stale) only when a different vcpu
> > within the same logical partition runs in-between. Optimize the tlb invalidation
> > condition taking into account the lpid.
>
> Can't we give every vcpu its own lpid? Or don't we trap on global
> invalidates?
That would significantly increase the odds of exhausting LPIDs,
especially on large chips like t4240 with similarly large VMs. If we
were to do that, the LPIDs would need to be dynamically assigned (like
PIDs), and should probably be a separate numberspace per physical core.
-Scott
^ permalink raw reply
* Re: kmemleak: Unable to handle kernel paging request
From: Benjamin Herrenschmidt @ 2014-06-13 21:44 UTC (permalink / raw)
To: Catalin Marinas
Cc: Denis Kirjanov, linux-kernel@vger.kernel.org, linux-mm@kvack.org,
Paul Mackerras, Naoya Horiguchi, linuxppc-dev
In-Reply-To: <20140613085640.GA21018@arm.com>
On Fri, 2014-06-13 at 09:56 +0100, Catalin Marinas wrote:
> OK, so that's the DART table allocated via alloc_dart_table(). Is
> dart_tablebase removed from the kernel linear mapping after allocation?
Yes.
> If that's the case, we need to tell kmemleak to ignore this block (see
> patch below, untested). But I still can't explain how commit
> d4c54919ed863020 causes this issue.
>
> (also cc'ing the powerpc list and maintainers)
We remove the DART from the linear mapping because it has to be mapped
non-cachable and having it in the linear mapping would cause cache
paradoxes. We also can't just change the caching attributes in the
linear mapping because we use 16M pages for it and 970 CPUs don't
support cache-inhibited 16M pages :-( And due to the MMU segmentation
model, we also can't mix & match page sizes in that area.
So we just unmap it, and ioremap it elsewhere.
Cheers,
Ben.
> ---------------8<--------------------------
>
> >From 09a7f1c97166c7bdca7ca4e8a4ff2774f3706ea3 Mon Sep 17 00:00:00 2001
> From: Catalin Marinas <catalin.marinas@arm.com>
> Date: Fri, 13 Jun 2014 09:44:21 +0100
> Subject: [PATCH] powerpc/kmemleak: Do not scan the DART table
>
> The DART table allocation is registered to kmemleak via the
> memblock_alloc_base() call. However, the DART table is later unmapped
> and dart_tablebase VA no longer accessible. This patch tells kmemleak
> not to scan this block and avoid an unhandled paging request.
>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> ---
> arch/powerpc/sysdev/dart_iommu.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
> index 62c47bb76517..9e5353ff6d1b 100644
> --- a/arch/powerpc/sysdev/dart_iommu.c
> +++ b/arch/powerpc/sysdev/dart_iommu.c
> @@ -476,6 +476,11 @@ void __init alloc_dart_table(void)
> */
> dart_tablebase = (unsigned long)
> __va(memblock_alloc_base(1UL<<24, 1UL<<24, 0x80000000L));
> + /*
> + * The DART space is later unmapped from the kernel linear mapping and
> + * accessing dart_tablebase during kmemleak scanning will fault.
> + */
> + kmemleak_no_scan((void *)dart_tablebase);
>
> printk(KERN_INFO "DART table allocated at: %lx\n", dart_tablebase);
> }
^ permalink raw reply
* Re: [PATCH 4/4 v3] KVM: PPC: Bookehv: Get vcpu's last instruction for emulation
From: Scott Wood @ 2014-06-13 21:56 UTC (permalink / raw)
To: Alexander Graf; +Cc: Mihai Caraman, linuxppc-dev, kvm, kvm-ppc
In-Reply-To: <5399CF74.9040502@suse.de>
On Thu, 2014-06-12 at 18:04 +0200, Alexander Graf wrote:
> On 06/02/2014 05:50 PM, Mihai Caraman wrote:
> > On book3e, KVM uses load external pid (lwepx) dedicated instruction to read
> > guest last instruction on the exit path. lwepx exceptions (DTLB_MISS, DSI
> > and LRAT), generated by loading a guest address, needs to be handled by KVM.
> > These exceptions are generated in a substituted guest translation context
> > (EPLC[EGS] = 1) from host context (MSR[GS] = 0).
> >
> > Currently, KVM hooks only interrupts generated from guest context (MSR[GS] = 1),
> > doing minimal checks on the fast path to avoid host performance degradation.
> > lwepx exceptions originate from host state (MSR[GS] = 0) which implies
> > additional checks in DO_KVM macro (beside the current MSR[GS] = 1) by looking
> > at the Exception Syndrome Register (ESR[EPID]) and the External PID Load Context
> > Register (EPLC[EGS]). Doing this on each Data TLB miss exception is obvious
> > too intrusive for the host.
> >
> > Read guest last instruction from kvmppc_load_last_inst() by searching for the
> > physical address and kmap it. This address the TODO for TLB eviction and
> > execute-but-not-read entries, and allow us to get rid of lwepx until we are
> > able to handle failures.
> >
> > A simple stress benchmark shows a 1% sys performance degradation compared with
> > previous approach (lwepx without failure handling):
> >
> > time for i in `seq 1 10000`; do /bin/echo > /dev/null; done
> >
> > real 0m 8.85s
> > user 0m 4.34s
> > sys 0m 4.48s
> >
> > vs
> >
> > real 0m 8.84s
> > user 0m 4.36s
> > sys 0m 4.44s
> >
> > An alternative solution, to handle lwepx exceptions in KVM, is to temporary
> > highjack the interrupt vector from host. Some cores share host IVOR registers
> > between hardware threads, which is the case of FSL e6500, which impose additional
> > synchronization logic for this solution to work. This optimized solution can
> > be developed later on top of this patch.
> >
> > Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
> > ---
> > v3:
> > - reworked patch description
> > - use unaltered kmap addr for kunmap
> > - get last instruction before beeing preempted
> >
> > v2:
> > - reworked patch description
> > - used pr_* functions
> > - addressed cosmetic feedback
> >
> > arch/powerpc/kvm/booke.c | 32 ++++++++++++
> > arch/powerpc/kvm/bookehv_interrupts.S | 37 ++++----------
> > arch/powerpc/kvm/e500_mmu_host.c | 93 +++++++++++++++++++++++++++++++++++
> > 3 files changed, 134 insertions(+), 28 deletions(-)
> >
> > diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
> > index 34a42b9..4ef52a8 100644
> > --- a/arch/powerpc/kvm/booke.c
> > +++ b/arch/powerpc/kvm/booke.c
> > @@ -880,6 +880,8 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
> > int r = RESUME_HOST;
> > int s;
> > int idx;
> > + u32 last_inst = KVM_INST_FETCH_FAILED;
> > + enum emulation_result emulated = EMULATE_DONE;
> >
> > /* update before a new last_exit_type is rewritten */
> > kvmppc_update_timing_stats(vcpu);
> > @@ -887,6 +889,15 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
> > /* restart interrupts if they were meant for the host */
> > kvmppc_restart_interrupt(vcpu, exit_nr);
> >
> > + /*
> > + * get last instruction before beeing preempted
> > + * TODO: for e6500 check also BOOKE_INTERRUPT_LRAT_ERROR & ESR_DATA
> > + */
> > + if (exit_nr == BOOKE_INTERRUPT_DATA_STORAGE ||
> > + exit_nr == BOOKE_INTERRUPT_DTLB_MISS ||
> > + exit_nr == BOOKE_INTERRUPT_HV_PRIV)
>
> Please make this a switch() - that's easier to read.
>
> > + emulated = kvmppc_get_last_inst(vcpu, false, &last_inst);
> > +
> > local_irq_enable();
> >
> > trace_kvm_exit(exit_nr, vcpu);
> > @@ -895,6 +906,26 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
> > run->exit_reason = KVM_EXIT_UNKNOWN;
> > run->ready_for_interrupt_injection = 1;
> >
> > + switch (emulated) {
> > + case EMULATE_AGAIN:
> > + r = RESUME_GUEST;
> > + goto out;
> > +
> > + case EMULATE_FAIL:
> > + pr_debug("%s: emulation at %lx failed (%08x)\n",
> > + __func__, vcpu->arch.pc, last_inst);
> > + /* For debugging, encode the failing instruction and
> > + * report it to userspace. */
> > + run->hw.hardware_exit_reason = ~0ULL << 32;
> > + run->hw.hardware_exit_reason |= last_inst;
> > + kvmppc_core_queue_program(vcpu, ESR_PIL);
> > + r = RESUME_HOST;
> > + goto out;
> > +
> > + default:
> > + break;
> > + }
>
> I think you can just put this into a function.
>
> Scott, I think the patch overall looks quite good. Can you please check
> as well and if you agree give it your reviewed-by? Mike, when Scott
> gives you a reviewed-by, please include it for the next version.
>
>
> Alex
>
> > +
> > switch (exit_nr) {
> > case BOOKE_INTERRUPT_MACHINE_CHECK:
> > printk("MACHINE CHECK: %lx\n", mfspr(SPRN_MCSR));
> > @@ -1184,6 +1215,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
> > BUG();
> > }
> >
> > +out:
> > /*
> > * To avoid clobbering exit_reason, only check for signals if we
> > * aren't already exiting to userspace for some other reason.
> > diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
> > index 6ff4480..e000b39 100644
> > --- a/arch/powerpc/kvm/bookehv_interrupts.S
> > +++ b/arch/powerpc/kvm/bookehv_interrupts.S
> > @@ -121,38 +121,14 @@
> > 1:
> >
> > .if \flags & NEED_EMU
> > - /*
> > - * This assumes you have external PID support.
> > - * To support a bookehv CPU without external PID, you'll
> > - * need to look up the TLB entry and create a temporary mapping.
> > - *
> > - * FIXME: we don't currently handle if the lwepx faults. PR-mode
> > - * booke doesn't handle it either. Since Linux doesn't use
> > - * broadcast tlbivax anymore, the only way this should happen is
> > - * if the guest maps its memory execute-but-not-read, or if we
> > - * somehow take a TLB miss in the middle of this entry code and
> > - * evict the relevant entry. On e500mc, all kernel lowmem is
> > - * bolted into TLB1 large page mappings, and we don't use
> > - * broadcast invalidates, so we should not take a TLB miss here.
> > - *
> > - * Later we'll need to deal with faults here. Disallowing guest
> > - * mappings that are execute-but-not-read could be an option on
> > - * e500mc, but not on chips with an LRAT if it is used.
> > - */
> > -
> > - mfspr r3, SPRN_EPLC /* will already have correct ELPID and EGS */
> > PPC_STL r15, VCPU_GPR(R15)(r4)
> > PPC_STL r16, VCPU_GPR(R16)(r4)
> > PPC_STL r17, VCPU_GPR(R17)(r4)
> > PPC_STL r18, VCPU_GPR(R18)(r4)
> > PPC_STL r19, VCPU_GPR(R19)(r4)
> > - mr r8, r3
> > PPC_STL r20, VCPU_GPR(R20)(r4)
> > - rlwimi r8, r6, EPC_EAS_SHIFT - MSR_IR_LG, EPC_EAS
> > PPC_STL r21, VCPU_GPR(R21)(r4)
> > - rlwimi r8, r6, EPC_EPR_SHIFT - MSR_PR_LG, EPC_EPR
> > PPC_STL r22, VCPU_GPR(R22)(r4)
> > - rlwimi r8, r10, EPC_EPID_SHIFT, EPC_EPID
> > PPC_STL r23, VCPU_GPR(R23)(r4)
> > PPC_STL r24, VCPU_GPR(R24)(r4)
> > PPC_STL r25, VCPU_GPR(R25)(r4)
> > @@ -162,10 +138,15 @@
> > PPC_STL r29, VCPU_GPR(R29)(r4)
> > PPC_STL r30, VCPU_GPR(R30)(r4)
> > PPC_STL r31, VCPU_GPR(R31)(r4)
> > - mtspr SPRN_EPLC, r8
> > - isync
> > - lwepx r9, 0, r5
> > - mtspr SPRN_EPLC, r3
> > +
> > + /*
> > + * We don't use external PID support. lwepx faults would need to be
> > + * handled by KVM and this implies aditional code in DO_KVM (for
> > + * DTB_MISS, DSI and LRAT) to check ESR[EPID] and EPLC[EGS] which
> > + * is too intrusive for the host. Get last instuction in
> > + * kvmppc_get_last_inst().
> > + */
> > + li r9, KVM_INST_FETCH_FAILED
> > stw r9, VCPU_LAST_INST(r4)
> > .endif
> >
> > diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
> > index f692c12..0528fe5 100644
> > --- a/arch/powerpc/kvm/e500_mmu_host.c
> > +++ b/arch/powerpc/kvm/e500_mmu_host.c
> > @@ -606,10 +606,103 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
> > }
> > }
> >
> > +#ifdef CONFIG_KVM_BOOKE_HV
> > int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, bool prev, u32 *instr)
> > {
> > + gva_t geaddr;
> > + hpa_t addr;
> > + hfn_t pfn;
> > + hva_t eaddr;
> > + u32 mas0, mas1, mas2, mas3;
> > + u64 mas7_mas3;
> > + struct page *page;
> > + unsigned int addr_space, psize_shift;
> > + bool pr;
> > + unsigned long flags;
> > +
> > + WARN_ON_ONCE(prev);
What are the semantics of "prev"?
> > + /* Search TLB for guest pc to get the real address */
> > + geaddr = kvmppc_get_pc(vcpu);
> > +
> > + addr_space = (vcpu->arch.shared->msr & MSR_IS) >> MSR_IR_LG;
> > +
> > + local_irq_save(flags);
> > + mtspr(SPRN_MAS6, (vcpu->arch.pid << MAS6_SPID_SHIFT) | addr_space);
> > + mtspr(SPRN_MAS5, MAS5_SGS | vcpu->kvm->arch.lpid);
> > + asm volatile("tlbsx 0, %[geaddr]\n" : :
> > + [geaddr] "r" (geaddr));
> > + mtspr(SPRN_MAS5, 0);
> > + mtspr(SPRN_MAS8, 0);
> > + mas0 = mfspr(SPRN_MAS0);
> > + mas1 = mfspr(SPRN_MAS1);
> > + mas2 = mfspr(SPRN_MAS2);
> > + mas3 = mfspr(SPRN_MAS3);
> > + mas7_mas3 = (((u64) mfspr(SPRN_MAS7)) << 32) | mas3;
> > + local_irq_restore(flags);
Where is mas0 used?
On 64-bit you could read directly from SPRN_MAS7_MAS3.
> > + /*
> > + * If the TLB entry for guest pc was evicted, return to the guest.
> > + * There are high chances to find a valid TLB entry next time.
> > + */
> > + if (!(mas1 & MAS1_VALID))
> > + return EMULATE_AGAIN;
> > +
> > + /*
> > + * Another thread may rewrite the TLB entry in parallel, don't
> > + * execute from the address if the execute permission is not set
> > + */
> > + pr = vcpu->arch.shared->msr & MSR_PR;
> > + if ((pr && !(mas3 & MAS3_UX)) || (!pr && !(mas3 & MAS3_SX))) {
> > + pr_debug("Instuction emulation from a guest page\n"
> > + "withot execute permission\n");
Don't split user-visible strings.
s/withot/without/
Give more context in the message, such as __func__ and the address.
> > + return EMULATE_FAIL;
> > + }
> > +
> > + /*
> > + * We will map the real address through a cacheable page, so we will
> > + * not support cache-inhibited guest pages. Fortunately emulated
> > + * instructions should not live there.
> > + */
> > + if (mas2 & MAS2_I) {
> > + pr_debug("Instuction emulation from cache-inhibited\n"
> > + "guest pages is not supported\n");
> > + return EMULATE_FAIL;
> > + }
Mismatches in M or W are bad as well, but shouldn't the page_is_ram()
protect us? Except when LRAT is used, but there we can't prevent
mismatches anyway.
> > + /* Get page size */
> > + psize_shift = MAS1_GET_TSIZE(mas1) + 10;
> > +
> > + /* Map a page and get guest's instruction */
> > + addr = (mas7_mas3 & (~0ULL << psize_shift)) |
> > + (geaddr & ((1ULL << psize_shift) - 1ULL));
> > + pfn = addr >> PAGE_SHIFT;
> > +
> > + /* Guard us against emulation from devices area */
> > + if (unlikely(!page_is_ram(pfn))) {
> > + pr_debug("Instruction emulation from non-RAM host\n"
> > + "pages is not supported\n");
> > + return EMULATE_FAIL;
> > + }
> > +
> > + if (unlikely(!pfn_valid(pfn))) {
> > + pr_debug("Invalid frame number\n");
> > + return EMULATE_FAIL;
> > + }
Can we ever have page_is_ram(pfn) && !pfn_valid(pfn)?
-Scott
^ permalink raw reply
* Re: [PATCH] crypto/nx: disable NX on little endian builds
From: Marek Vasut @ 2014-06-14 3:48 UTC (permalink / raw)
To: Anton Blanchard
Cc: herbert, linuxppc-dev, paulus, linux-crypto, nfont, mhcerri,
davem
In-Reply-To: <20140607113334.474343b8@kryten>
On Saturday, June 07, 2014 at 03:33:34 AM, Anton Blanchard wrote:
> The NX driver has endian issues so disable it for now.
>
> Signed-off-by: Anton Blanchard <anton@samba.org>
What kind of issues ? Are they hard to fix ?
Best regards,
Marek Vasut
^ permalink raw reply
* Re: [PATCH v2 08/10] mm, cma: clean-up cma allocation error path
From: Aneesh Kumar K.V @ 2014-06-14 7:18 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-9-git-send-email-iamjoonsoo.kim@lge.com>
Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
> 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>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.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
* Re: [PATCH v2 09/10] mm, cma: move output param to the end of param list
From: Aneesh Kumar K.V @ 2014-06-14 7:20 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-10-git-send-email-iamjoonsoo.kim@lge.com>
Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
> 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>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.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
* Re: [PATCH v2 00/10] CMA: generalize CMA reserved area management code
From: Aneesh Kumar K.V @ 2014-06-14 7:25 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-1-git-send-email-iamjoonsoo.kim@lge.com>
Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
> 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.
I wanted to test the ppc changes and found that the patch series doesn't apply
against v3.15 . Do you have a kernel tree which I can clone to test this
series ?
^ permalink raw reply
* Re: [PATCH v2 07/10] PPC, KVM, CMA: use general CMA reserved area management framework
From: Aneesh Kumar K.V @ 2014-06-14 8:53 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-8-git-send-email-iamjoonsoo.kim@lge.com>
Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
> 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>
Need this. We may want to keep the VM_BUG_ON by moving
KVM_CMA_CHUNK_ORDER around.
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 8056107..1932e0e 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -37,8 +37,6 @@
#include <asm/ppc-opcode.h>
#include <asm/cputable.h>
-#include "book3s_hv_cma.h"
-
/* POWER7 has 10-bit LPIDs, PPC970 has 6-bit LPIDs */
#define MAX_LPID_970 63
@@ -64,7 +62,6 @@ long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp)
}
kvm->arch.hpt_cma_alloc = 0;
- VM_BUG_ON(order < KVM_CMA_CHUNK_ORDER);
page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT));
if (page) {
hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
-aneesh
^ permalink raw reply related
* Re: [PATCH v2 07/10] PPC, KVM, CMA: use general CMA reserved area management framework
From: Aneesh Kumar K.V @ 2014-06-14 10:05 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-8-git-send-email-iamjoonsoo.kim@lge.com>
Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
> 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);
The above memset is missing in the generic code. May be
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 6f13ee6..8740b4c 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -75,6 +75,7 @@ long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp)
page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT));
if (page) {
hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
+ memset((void *)hpt, 0, (1 << order));
kvm->arch.hpt_cma_alloc = 1;
} else
--order;
With that
Tested-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
-aneesh
^ permalink raw reply related
* Re: [PATCH v2 06/10] CMA: generalize CMA reserved area management functionality
From: Aneesh Kumar K.V @ 2014-06-14 10:08 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-7-git-send-email-iamjoonsoo.kim@lge.com>
Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
> 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>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.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
* Re: [PATCH v2 06/10] CMA: generalize CMA reserved area management functionality
From: Aneesh Kumar K.V @ 2014-06-14 10:06 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-7-git-send-email-iamjoonsoo.kim@lge.com>
Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
> 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>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.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
* Re: [PATCH v2 05/10] DMA, CMA: support arbitrary bitmap granularity
From: Aneesh Kumar K.V @ 2014-06-14 10:09 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-6-git-send-email-iamjoonsoo.kim@lge.com>
Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
> 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>
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 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
* Re: [PATCH v2 06/10] CMA: generalize CMA reserved area management functionality
From: Aneesh Kumar K.V @ 2014-06-14 10:16 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-7-git-send-email-iamjoonsoo.kim@lge.com>
Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
> 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>
>
.....
> +
> + 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;
> + }
> +
For setting bit map we do
bitmap_set(cma->bitmap, bitmapno, nr_bits);
alloc_contig()..
if (error)
clear_cma_bitmap(cma, pfn, count);
Why ?
why not bitmap_clear() ?
-aneesh
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox