get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/818137/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 818137,
    "url": "http://patchwork.ozlabs.org/api/patches/818137/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-imx/patch/1506330344-31556-2-git-send-email-vladimir.murzin@arm.com/",
    "project": {
        "id": 19,
        "url": "http://patchwork.ozlabs.org/api/projects/19/?format=api",
        "name": "Linux IMX development",
        "link_name": "linux-imx",
        "list_id": "linux-imx-kernel.lists.patchwork.ozlabs.org",
        "list_email": "linux-imx-kernel@lists.patchwork.ozlabs.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1506330344-31556-2-git-send-email-vladimir.murzin@arm.com>",
    "list_archive_url": null,
    "date": "2017-09-25T09:05:37",
    "name": "[v3,1/8] ARM: NOMMU: Move out MPU setup in separate module",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "4a249ecea25c8ab4f93164e6b0072b94827fd7e2",
    "submitter": {
        "id": 65248,
        "url": "http://patchwork.ozlabs.org/api/people/65248/?format=api",
        "name": "Vladimir Murzin",
        "email": "vladimir.murzin@arm.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-imx/patch/1506330344-31556-2-git-send-email-vladimir.murzin@arm.com/mbox/",
    "series": [
        {
            "id": 4911,
            "url": "http://patchwork.ozlabs.org/api/series/4911/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-imx/list/?series=4911",
            "date": "2017-09-25T09:05:36",
            "name": "ARM: NOMMU: MPU updates",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/4911/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/818137/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/818137/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org>",
        "X-Original-To": "incoming-imx@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming-imx@bilbo.ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.infradead.org\n\t(client-ip=65.50.211.133; helo=bombadil.infradead.org;\n\tenvelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org; dkim=pass (2048-bit key;\n\tunprotected) header.d=lists.infradead.org\n\theader.i=@lists.infradead.org\n\theader.b=\"c2bRgGaN\"; dkim-atps=neutral"
        ],
        "Received": [
            "from bombadil.infradead.org (bombadil.infradead.org\n\t[65.50.211.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y0ysf1Jzcz9tXD\n\tfor <incoming-imx@patchwork.ozlabs.org>;\n\tMon, 25 Sep 2017 19:07:50 +1000 (AEST)",
            "from localhost ([127.0.0.1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dwPMZ-0002UJ-8N; Mon, 25 Sep 2017 09:07:39 +0000",
            "from foss.arm.com ([217.140.101.70])\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dwPLP-0001Kj-2c for linux-arm-kernel@lists.infradead.org;\n\tMon, 25 Sep 2017 09:06:37 +0000",
            "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249])\n\tby usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id AE70015BE;\n\tMon, 25 Sep 2017 02:06:06 -0700 (PDT)",
            "from bc-c11-3-12.euhpc.arm.com. (bc-c11-3-12.euhpc.arm.com\n\t[10.6.2.250])\n\tby usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id\n\t357A83F3E1; Mon, 25 Sep 2017 02:06:05 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20170209; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post:\n\tList-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:\n\tMessage-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description:\n\tResent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:\n\tList-Owner; bh=pvaz6cF3k8kVoHjV74ZWAk7HLVL3hj0sQPeJlzfHt0E=;\n\tb=c2bRgGaNEDeXf5\n\tA15dloxlt135SvdXTQIhP+oIvVqtdtHU/4B+Ag1UY73H/NP1Ys8vju+P57UlF/SO5km4Ah3QULNLx\n\tCnvK9pdtyca6lwCiqhbZEg/qNHiwM0ItIpldAtEWxwL1RLlITncvcY/oadI+MB5pGekz61ISZNRtN\n\tgKdcMS/GM9MHEmZlo52OMNyK8mkyhvlLn4Lp7vRHNad+0qxeFHY6Kz6hf4mjUKbBtxwNXxpRQzMIX\n\tZvlu0J0AZ5J5MmLKBh0fi+S2Ns3oWgCA43TefIss+U3GXS5dPZxJMEi2ppuWktC9FFZknQ6LaAVSL\n\tlW5yHrMea1E/PMoWIXVw==;",
        "From": "Vladimir Murzin <vladimir.murzin@arm.com>",
        "To": "linux-arm-kernel@lists.infradead.org",
        "Subject": "[PATCH v3 1/8] ARM: NOMMU: Move out MPU setup in separate module",
        "Date": "Mon, 25 Sep 2017 10:05:37 +0100",
        "Message-Id": "<1506330344-31556-2-git-send-email-vladimir.murzin@arm.com>",
        "X-Mailer": "git-send-email 2.0.0",
        "In-Reply-To": "<1506330344-31556-1-git-send-email-vladimir.murzin@arm.com>",
        "References": "<1506330344-31556-1-git-send-email-vladimir.murzin@arm.com>",
        "MIME-Version": "1.0",
        "X-CRM114-Version": "20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ",
        "X-CRM114-CacheID": "sfid-20170925_020627_184588_7E3C09E8 ",
        "X-CRM114-Status": "GOOD (  22.37  )",
        "X-Spam-Score": "-6.9 (------)",
        "X-Spam-Report": "SpamAssassin version 3.4.1 on bombadil.infradead.org summary:\n\tContent analysis details:   (-6.9 points)\n\tpts rule name              description\n\t---- ----------------------\n\t--------------------------------------------------\n\t-5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/,\n\thigh trust [217.140.101.70 listed in list.dnswl.org]\n\t-0.0 SPF_PASS               SPF: sender matches SPF record\n\t-0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay\n\tdomain\n\t-1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%\n\t[score: 0.0000]",
        "X-BeenThere": "linux-arm-kernel@lists.infradead.org",
        "X-Mailman-Version": "2.1.21",
        "Precedence": "list",
        "List-Unsubscribe": "<http://lists.infradead.org/mailman/options/linux-arm-kernel>,\n\t<mailto:linux-arm-kernel-request@lists.infradead.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.infradead.org/pipermail/linux-arm-kernel/>",
        "List-Post": "<mailto:linux-arm-kernel@lists.infradead.org>",
        "List-Help": "<mailto:linux-arm-kernel-request@lists.infradead.org?subject=help>",
        "List-Subscribe": "<http://lists.infradead.org/mailman/listinfo/linux-arm-kernel>,\n\t<mailto:linux-arm-kernel-request@lists.infradead.org?subject=subscribe>",
        "Cc": "alexandre.torgue@st.com, manabian@gmail.com, linux@armlinux.org.uk,\n\tstefan@agner.ch, kbuild-all@01.org, u.kleine-koenig@pengutronix.de,\n\tsza@esh.hu",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Sender": "\"linux-arm-kernel\" <linux-arm-kernel-bounces@lists.infradead.org>",
        "Errors-To": "linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org",
        "List-Id": "linux-imx-kernel.lists.patchwork.ozlabs.org"
    },
    "content": "Having MPU handling code in dedicated module makes it easier to\nenhance/maintain it.\n\nTested-by: Szemző András <sza@esh.hu>\nTested-by: Alexandre TORGUE <alexandre.torgue@st.com>\nSigned-off-by: Vladimir Murzin <vladimir.murzin@arm.com>\n---\n arch/arm/include/asm/mpu.h |  16 ++-\n arch/arm/mm/Makefile       |   1 +\n arch/arm/mm/nommu.c        | 254 +------------------------------------------\n arch/arm/mm/pmsa-v7.c      | 262 +++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 276 insertions(+), 257 deletions(-)\n create mode 100644 arch/arm/mm/pmsa-v7.c",
    "diff": "diff --git a/arch/arm/include/asm/mpu.h b/arch/arm/include/asm/mpu.h\nindex c3247cc..edec5cf 100644\n--- a/arch/arm/include/asm/mpu.h\n+++ b/arch/arm/include/asm/mpu.h\n@@ -1,8 +1,6 @@\n #ifndef __ARM_MPU_H\n #define __ARM_MPU_H\n \n-#ifdef CONFIG_ARM_MPU\n-\n /* MPUIR layout */\n #define MPUIR_nU\t\t1\n #define MPUIR_DREGION\t\t8\n@@ -69,8 +67,18 @@ struct mpu_rgn_info {\n };\n extern struct mpu_rgn_info mpu_rgn_info;\n \n-#endif /* __ASSEMBLY__ */\n+#ifdef CONFIG_ARM_MPU\n+\n+extern void __init adjust_lowmem_bounds_mpu(void);\n+extern void __init mpu_setup(void);\n \n-#endif /* CONFIG_ARM_MPU */\n+#else\n+\n+static inline void adjust_lowmem_bounds_mpu(void) {}\n+static inline void mpu_setup(void) {}\n+\n+#endif /* !CONFIG_ARM_MPU */\n+\n+#endif /* __ASSEMBLY__ */\n \n #endif\ndiff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile\nindex 950d19b..bdb2ec1 100644\n--- a/arch/arm/mm/Makefile\n+++ b/arch/arm/mm/Makefile\n@@ -9,6 +9,7 @@ obj-$(CONFIG_MMU)\t\t+= fault-armv.o flush.o idmap.o ioremap.o \\\n \n ifneq ($(CONFIG_MMU),y)\n obj-y\t\t\t\t+= nommu.o\n+obj-$(CONFIG_ARM_MPU)\t\t+= pmsa-v7.o\n endif\n \n obj-$(CONFIG_ARM_PTDUMP)\t+= dump.o\ndiff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c\nindex 3b8e728..4c56b56 100644\n--- a/arch/arm/mm/nommu.c\n+++ b/arch/arm/mm/nommu.c\n@@ -27,259 +27,7 @@\n \n #ifdef CONFIG_ARM_MPU\n struct mpu_rgn_info mpu_rgn_info;\n-\n-/* Region number */\n-static void rgnr_write(u32 v)\n-{\n-\tasm(\"mcr        p15, 0, %0, c6, c2, 0\" : : \"r\" (v));\n-}\n-\n-/* Data-side / unified region attributes */\n-\n-/* Region access control register */\n-static void dracr_write(u32 v)\n-{\n-\tasm(\"mcr        p15, 0, %0, c6, c1, 4\" : : \"r\" (v));\n-}\n-\n-/* Region size register */\n-static void drsr_write(u32 v)\n-{\n-\tasm(\"mcr        p15, 0, %0, c6, c1, 2\" : : \"r\" (v));\n-}\n-\n-/* Region base address register */\n-static void drbar_write(u32 v)\n-{\n-\tasm(\"mcr        p15, 0, %0, c6, c1, 0\" : : \"r\" (v));\n-}\n-\n-static u32 drbar_read(void)\n-{\n-\tu32 v;\n-\tasm(\"mrc        p15, 0, %0, c6, c1, 0\" : \"=r\" (v));\n-\treturn v;\n-}\n-/* Optional instruction-side region attributes */\n-\n-/* I-side Region access control register */\n-static void iracr_write(u32 v)\n-{\n-\tasm(\"mcr        p15, 0, %0, c6, c1, 5\" : : \"r\" (v));\n-}\n-\n-/* I-side Region size register */\n-static void irsr_write(u32 v)\n-{\n-\tasm(\"mcr        p15, 0, %0, c6, c1, 3\" : : \"r\" (v));\n-}\n-\n-/* I-side Region base address register */\n-static void irbar_write(u32 v)\n-{\n-\tasm(\"mcr        p15, 0, %0, c6, c1, 1\" : : \"r\" (v));\n-}\n-\n-static unsigned long irbar_read(void)\n-{\n-\tunsigned long v;\n-\tasm(\"mrc        p15, 0, %0, c6, c1, 1\" : \"=r\" (v));\n-\treturn v;\n-}\n-\n-/* MPU initialisation functions */\n-void __init adjust_lowmem_bounds_mpu(void)\n-{\n-\tphys_addr_t phys_offset = PHYS_OFFSET;\n-\tphys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size;\n-\tstruct memblock_region *reg;\n-\tbool first = true;\n-\tphys_addr_t mem_start;\n-\tphys_addr_t mem_end;\n-\n-\tfor_each_memblock(memory, reg) {\n-\t\tif (first) {\n-\t\t\t/*\n-\t\t\t * Initially only use memory continuous from\n-\t\t\t * PHYS_OFFSET */\n-\t\t\tif (reg->base != phys_offset)\n-\t\t\t\tpanic(\"First memory bank must be contiguous from PHYS_OFFSET\");\n-\n-\t\t\tmem_start = reg->base;\n-\t\t\tmem_end = reg->base + reg->size;\n-\t\t\tspecified_mem_size = reg->size;\n-\t\t\tfirst = false;\n-\t\t} else {\n-\t\t\t/*\n-\t\t\t * memblock auto merges contiguous blocks, remove\n-\t\t\t * all blocks afterwards in one go (we can't remove\n-\t\t\t * blocks separately while iterating)\n-\t\t\t */\n-\t\t\tpr_notice(\"Ignoring RAM after %pa, memory at %pa ignored\\n\",\n-\t\t\t\t  &mem_end, &reg->base);\n-\t\t\tmemblock_remove(reg->base, 0 - reg->base);\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\t/*\n-\t * MPU has curious alignment requirements: Size must be power of 2, and\n-\t * region start must be aligned to the region size\n-\t */\n-\tif (phys_offset != 0)\n-\t\tpr_info(\"PHYS_OFFSET != 0 => MPU Region size constrained by alignment requirements\\n\");\n-\n-\t/*\n-\t * Maximum aligned region might overflow phys_addr_t if phys_offset is\n-\t * 0. Hence we keep everything below 4G until we take the smaller of\n-\t * the aligned_region_size and rounded_mem_size, one of which is\n-\t * guaranteed to be smaller than the maximum physical address.\n-\t */\n-\taligned_region_size = (phys_offset - 1) ^ (phys_offset);\n-\t/* Find the max power-of-two sized region that fits inside our bank */\n-\trounded_mem_size = (1 <<  __fls(specified_mem_size)) - 1;\n-\n-\t/* The actual region size is the smaller of the two */\n-\taligned_region_size = aligned_region_size < rounded_mem_size\n-\t\t\t\t? aligned_region_size + 1\n-\t\t\t\t: rounded_mem_size + 1;\n-\n-\tif (aligned_region_size != specified_mem_size) {\n-\t\tpr_warn(\"Truncating memory from %pa to %pa (MPU region constraints)\",\n-\t\t\t\t&specified_mem_size, &aligned_region_size);\n-\t\tmemblock_remove(mem_start + aligned_region_size,\n-\t\t\t\tspecified_mem_size - aligned_region_size);\n-\n-\t\tmem_end = mem_start + aligned_region_size;\n-\t}\n-\n-\tpr_debug(\"MPU Region from %pa size %pa (end %pa))\\n\",\n-\t\t&phys_offset, &aligned_region_size, &mem_end);\n-\n-}\n-\n-static int mpu_present(void)\n-{\n-\treturn ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);\n-}\n-\n-static int mpu_max_regions(void)\n-{\n-\t/*\n-\t * We don't support a different number of I/D side regions so if we\n-\t * have separate instruction and data memory maps then return\n-\t * whichever side has a smaller number of supported regions.\n-\t */\n-\tu32 dregions, iregions, mpuir;\n-\tmpuir = read_cpuid(CPUID_MPUIR);\n-\n-\tdregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;\n-\n-\t/* Check for separate d-side and i-side memory maps */\n-\tif (mpuir & MPUIR_nU)\n-\t\tiregions = (mpuir & MPUIR_IREGION_SZMASK) >> MPUIR_IREGION;\n-\n-\t/* Use the smallest of the two maxima */\n-\treturn min(dregions, iregions);\n-}\n-\n-static int mpu_iside_independent(void)\n-{\n-\t/* MPUIR.nU specifies whether there is *not* a unified memory map */\n-\treturn read_cpuid(CPUID_MPUIR) & MPUIR_nU;\n-}\n-\n-static int mpu_min_region_order(void)\n-{\n-\tu32 drbar_result, irbar_result;\n-\t/* We've kept a region free for this probing */\n-\trgnr_write(MPU_PROBE_REGION);\n-\tisb();\n-\t/*\n-\t * As per ARM ARM, write 0xFFFFFFFC to DRBAR to find the minimum\n-\t * region order\n-\t*/\n-\tdrbar_write(0xFFFFFFFC);\n-\tdrbar_result = irbar_result = drbar_read();\n-\tdrbar_write(0x0);\n-\t/* If the MPU is non-unified, we use the larger of the two minima*/\n-\tif (mpu_iside_independent()) {\n-\t\tirbar_write(0xFFFFFFFC);\n-\t\tirbar_result = irbar_read();\n-\t\tirbar_write(0x0);\n-\t}\n-\tisb(); /* Ensure that MPU region operations have completed */\n-\t/* Return whichever result is larger */\n-\treturn __ffs(max(drbar_result, irbar_result));\n-}\n-\n-static int mpu_setup_region(unsigned int number, phys_addr_t start,\n-\t\t\tunsigned int size_order, unsigned int properties)\n-{\n-\tu32 size_data;\n-\n-\t/* We kept a region free for probing resolution of MPU regions*/\n-\tif (number > mpu_max_regions() || number == MPU_PROBE_REGION)\n-\t\treturn -ENOENT;\n-\n-\tif (size_order > 32)\n-\t\treturn -ENOMEM;\n-\n-\tif (size_order < mpu_min_region_order())\n-\t\treturn -ENOMEM;\n-\n-\t/* Writing N to bits 5:1 (RSR_SZ)  specifies region size 2^N+1 */\n-\tsize_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN;\n-\n-\tdsb(); /* Ensure all previous data accesses occur with old mappings */\n-\trgnr_write(number);\n-\tisb();\n-\tdrbar_write(start);\n-\tdracr_write(properties);\n-\tisb(); /* Propagate properties before enabling region */\n-\tdrsr_write(size_data);\n-\n-\t/* Check for independent I-side registers */\n-\tif (mpu_iside_independent()) {\n-\t\tirbar_write(start);\n-\t\tiracr_write(properties);\n-\t\tisb();\n-\t\tirsr_write(size_data);\n-\t}\n-\tisb();\n-\n-\t/* Store region info (we treat i/d side the same, so only store d) */\n-\tmpu_rgn_info.rgns[number].dracr = properties;\n-\tmpu_rgn_info.rgns[number].drbar = start;\n-\tmpu_rgn_info.rgns[number].drsr = size_data;\n-\treturn 0;\n-}\n-\n-/*\n-* Set up default MPU regions, doing nothing if there is no MPU\n-*/\n-void __init mpu_setup(void)\n-{\n-\tint region_err;\n-\tif (!mpu_present())\n-\t\treturn;\n-\n-\tregion_err = mpu_setup_region(MPU_RAM_REGION, PHYS_OFFSET,\n-\t\t\t\t\tilog2(memblock.memory.regions[0].size),\n-\t\t\t\t\tMPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);\n-\tif (region_err) {\n-\t\tpanic(\"MPU region initialization failure! %d\", region_err);\n-\t} else {\n-\t\tpr_info(\"Using ARMv7 PMSA Compliant MPU. \"\n-\t\t\t \"Region independence: %s, Max regions: %d\\n\",\n-\t\t\tmpu_iside_independent() ? \"Yes\" : \"No\",\n-\t\t\tmpu_max_regions());\n-\t}\n-}\n-#else\n-static void adjust_lowmem_bounds_mpu(void) {}\n-static void __init mpu_setup(void) {}\n-#endif /* CONFIG_ARM_MPU */\n+#endif\n \n #ifdef CONFIG_CPU_CP15\n #ifdef CONFIG_CPU_HIGH_VECTOR\ndiff --git a/arch/arm/mm/pmsa-v7.c b/arch/arm/mm/pmsa-v7.c\nnew file mode 100644\nindex 0000000..ee3cf51\n--- /dev/null\n+++ b/arch/arm/mm/pmsa-v7.c\n@@ -0,0 +1,262 @@\n+/*\n+ *  linux/arch/arm/mm/nommu.c\n+ *\n+ * ARM uCLinux supporting functions.\n+ */\n+\n+#include <linux/memblock.h>\n+\n+#include <asm/cp15.h>\n+#include <asm/cputype.h>\n+#include <asm/mpu.h>\n+\n+#include \"mm.h\"\n+\n+/* Region number */\n+static void rgnr_write(u32 v)\n+{\n+\tasm(\"mcr        p15, 0, %0, c6, c2, 0\" : : \"r\" (v));\n+}\n+\n+/* Data-side / unified region attributes */\n+\n+/* Region access control register */\n+static void dracr_write(u32 v)\n+{\n+\tasm(\"mcr        p15, 0, %0, c6, c1, 4\" : : \"r\" (v));\n+}\n+\n+/* Region size register */\n+static void drsr_write(u32 v)\n+{\n+\tasm(\"mcr        p15, 0, %0, c6, c1, 2\" : : \"r\" (v));\n+}\n+\n+/* Region base address register */\n+static void drbar_write(u32 v)\n+{\n+\tasm(\"mcr        p15, 0, %0, c6, c1, 0\" : : \"r\" (v));\n+}\n+\n+static u32 drbar_read(void)\n+{\n+\tu32 v;\n+\tasm(\"mrc        p15, 0, %0, c6, c1, 0\" : \"=r\" (v));\n+\treturn v;\n+}\n+/* Optional instruction-side region attributes */\n+\n+/* I-side Region access control register */\n+static void iracr_write(u32 v)\n+{\n+\tasm(\"mcr        p15, 0, %0, c6, c1, 5\" : : \"r\" (v));\n+}\n+\n+/* I-side Region size register */\n+static void irsr_write(u32 v)\n+{\n+\tasm(\"mcr        p15, 0, %0, c6, c1, 3\" : : \"r\" (v));\n+}\n+\n+/* I-side Region base address register */\n+static void irbar_write(u32 v)\n+{\n+\tasm(\"mcr        p15, 0, %0, c6, c1, 1\" : : \"r\" (v));\n+}\n+\n+static unsigned long irbar_read(void)\n+{\n+\tunsigned long v;\n+\tasm(\"mrc        p15, 0, %0, c6, c1, 1\" : \"=r\" (v));\n+\treturn v;\n+}\n+\n+/* MPU initialisation functions */\n+void __init adjust_lowmem_bounds_mpu(void)\n+{\n+\tphys_addr_t phys_offset = PHYS_OFFSET;\n+\tphys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size;\n+\tstruct memblock_region *reg;\n+\tbool first = true;\n+\tphys_addr_t mem_start;\n+\tphys_addr_t mem_end;\n+\n+\tfor_each_memblock(memory, reg) {\n+\t\tif (first) {\n+\t\t\t/*\n+\t\t\t * Initially only use memory continuous from\n+\t\t\t * PHYS_OFFSET */\n+\t\t\tif (reg->base != phys_offset)\n+\t\t\t\tpanic(\"First memory bank must be contiguous from PHYS_OFFSET\");\n+\n+\t\t\tmem_start = reg->base;\n+\t\t\tmem_end = reg->base + reg->size;\n+\t\t\tspecified_mem_size = reg->size;\n+\t\t\tfirst = false;\n+\t\t} else {\n+\t\t\t/*\n+\t\t\t * memblock auto merges contiguous blocks, remove\n+\t\t\t * all blocks afterwards in one go (we can't remove\n+\t\t\t * blocks separately while iterating)\n+\t\t\t */\n+\t\t\tpr_notice(\"Ignoring RAM after %pa, memory at %pa ignored\\n\",\n+\t\t\t\t  &mem_end, &reg->base);\n+\t\t\tmemblock_remove(reg->base, 0 - reg->base);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * MPU has curious alignment requirements: Size must be power of 2, and\n+\t * region start must be aligned to the region size\n+\t */\n+\tif (phys_offset != 0)\n+\t\tpr_info(\"PHYS_OFFSET != 0 => MPU Region size constrained by alignment requirements\\n\");\n+\n+\t/*\n+\t * Maximum aligned region might overflow phys_addr_t if phys_offset is\n+\t * 0. Hence we keep everything below 4G until we take the smaller of\n+\t * the aligned_region_size and rounded_mem_size, one of which is\n+\t * guaranteed to be smaller than the maximum physical address.\n+\t */\n+\taligned_region_size = (phys_offset - 1) ^ (phys_offset);\n+\t/* Find the max power-of-two sized region that fits inside our bank */\n+\trounded_mem_size = (1 <<  __fls(specified_mem_size)) - 1;\n+\n+\t/* The actual region size is the smaller of the two */\n+\taligned_region_size = aligned_region_size < rounded_mem_size\n+\t\t\t\t? aligned_region_size + 1\n+\t\t\t\t: rounded_mem_size + 1;\n+\n+\tif (aligned_region_size != specified_mem_size) {\n+\t\tpr_warn(\"Truncating memory from %pa to %pa (MPU region constraints)\",\n+\t\t\t\t&specified_mem_size, &aligned_region_size);\n+\t\tmemblock_remove(mem_start + aligned_region_size,\n+\t\t\t\tspecified_mem_size - aligned_region_size);\n+\n+\t\tmem_end = mem_start + aligned_region_size;\n+\t}\n+\n+\tpr_debug(\"MPU Region from %pa size %pa (end %pa))\\n\",\n+\t\t&phys_offset, &aligned_region_size, &mem_end);\n+\n+}\n+\n+static int mpu_present(void)\n+{\n+\treturn ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);\n+}\n+\n+static int mpu_max_regions(void)\n+{\n+\t/*\n+\t * We don't support a different number of I/D side regions so if we\n+\t * have separate instruction and data memory maps then return\n+\t * whichever side has a smaller number of supported regions.\n+\t */\n+\tu32 dregions, iregions, mpuir;\n+\tmpuir = read_cpuid(CPUID_MPUIR);\n+\n+\tdregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;\n+\n+\t/* Check for separate d-side and i-side memory maps */\n+\tif (mpuir & MPUIR_nU)\n+\t\tiregions = (mpuir & MPUIR_IREGION_SZMASK) >> MPUIR_IREGION;\n+\n+\t/* Use the smallest of the two maxima */\n+\treturn min(dregions, iregions);\n+}\n+\n+static int mpu_iside_independent(void)\n+{\n+\t/* MPUIR.nU specifies whether there is *not* a unified memory map */\n+\treturn read_cpuid(CPUID_MPUIR) & MPUIR_nU;\n+}\n+\n+static int mpu_min_region_order(void)\n+{\n+\tu32 drbar_result, irbar_result;\n+\t/* We've kept a region free for this probing */\n+\trgnr_write(MPU_PROBE_REGION);\n+\tisb();\n+\t/*\n+\t * As per ARM ARM, write 0xFFFFFFFC to DRBAR to find the minimum\n+\t * region order\n+\t*/\n+\tdrbar_write(0xFFFFFFFC);\n+\tdrbar_result = irbar_result = drbar_read();\n+\tdrbar_write(0x0);\n+\t/* If the MPU is non-unified, we use the larger of the two minima*/\n+\tif (mpu_iside_independent()) {\n+\t\tirbar_write(0xFFFFFFFC);\n+\t\tirbar_result = irbar_read();\n+\t\tirbar_write(0x0);\n+\t}\n+\tisb(); /* Ensure that MPU region operations have completed */\n+\t/* Return whichever result is larger */\n+\treturn __ffs(max(drbar_result, irbar_result));\n+}\n+\n+static int mpu_setup_region(unsigned int number, phys_addr_t start,\n+\t\t\tunsigned int size_order, unsigned int properties)\n+{\n+\tu32 size_data;\n+\n+\t/* We kept a region free for probing resolution of MPU regions*/\n+\tif (number > mpu_max_regions() || number == MPU_PROBE_REGION)\n+\t\treturn -ENOENT;\n+\n+\tif (size_order > 32)\n+\t\treturn -ENOMEM;\n+\n+\tif (size_order < mpu_min_region_order())\n+\t\treturn -ENOMEM;\n+\n+\t/* Writing N to bits 5:1 (RSR_SZ)  specifies region size 2^N+1 */\n+\tsize_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN;\n+\n+\tdsb(); /* Ensure all previous data accesses occur with old mappings */\n+\trgnr_write(number);\n+\tisb();\n+\tdrbar_write(start);\n+\tdracr_write(properties);\n+\tisb(); /* Propagate properties before enabling region */\n+\tdrsr_write(size_data);\n+\n+\t/* Check for independent I-side registers */\n+\tif (mpu_iside_independent()) {\n+\t\tirbar_write(start);\n+\t\tiracr_write(properties);\n+\t\tisb();\n+\t\tirsr_write(size_data);\n+\t}\n+\tisb();\n+\n+\t/* Store region info (we treat i/d side the same, so only store d) */\n+\tmpu_rgn_info.rgns[number].dracr = properties;\n+\tmpu_rgn_info.rgns[number].drbar = start;\n+\tmpu_rgn_info.rgns[number].drsr = size_data;\n+\treturn 0;\n+}\n+\n+/*\n+* Set up default MPU regions, doing nothing if there is no MPU\n+*/\n+void __init mpu_setup(void)\n+{\n+\tint region_err;\n+\tif (!mpu_present())\n+\t\treturn;\n+\n+\tregion_err = mpu_setup_region(MPU_RAM_REGION, PHYS_OFFSET,\n+\t\t\t\t\tilog2(memblock.memory.regions[0].size),\n+\t\t\t\t\tMPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);\n+\tif (region_err) {\n+\t\tpanic(\"MPU region initialization failure! %d\", region_err);\n+\t} else {\n+\t\tpr_info(\"Using ARMv7 PMSA Compliant MPU. \"\n+\t\t\t \"Region independence: %s, Max regions: %d\\n\",\n+\t\t\tmpu_iside_independent() ? \"Yes\" : \"No\",\n+\t\t\tmpu_max_regions());\n+\t}\n+}\n",
    "prefixes": [
        "v3",
        "1/8"
    ]
}