Patchwork [2/2] MIPS: mm: Use scratch for PGD when !CONFIG_MIPS_PGD_C0_CONTEXT

login
register
mail settings
Submitter Jayachandran C
Date Aug. 11, 2013, 11:40 a.m.
Message ID <1376221217-9335-3-git-send-email-jchandra@broadcom.com>
Download mbox | patch
Permalink /patch/5709/
State Rejected
Delegated to: Ralf Baechle
Headers show

Comments

Jayachandran C - Aug. 11, 2013, 11:40 a.m.
Allow usage of scratch register for current pgd even when
MIPS_PGD_C0_CONTEXT is not configured. MIPS_PGD_C0_CONTEXT is set
for 64r2 platforms to indicate availability of Xcontext for saving
cpuid, thus freeing Context to be used for saving PGD. This option
was also tied to using a scratch register for storing PGD.

This commit will allow usage of scratch register to store the current
pgd if one can be allocated for the platform, even when
MIPS_PGD_C0_CONTEXT is not set. The cpuid will be kept in the CP0
Context register in this case.

The code to store the current pgd for the TLB miss handler is now
generated in all cases. When scratch register is available, the PGD
is also stored in the scratch register.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 arch/mips/include/asm/mmu_context.h |    6 +--
 arch/mips/mm/tlbex.c                |   88 +++++++++++++++++++++++------------
 2 files changed, 58 insertions(+), 36 deletions(-)
root - Sept. 17, 2013, 9:21 p.m.
On Sun, Aug 11, 2013 at 05:10:17PM +0530, Jayachandran C wrote:

> Allow usage of scratch register for current pgd even when
> MIPS_PGD_C0_CONTEXT is not configured. MIPS_PGD_C0_CONTEXT is set
> for 64r2 platforms to indicate availability of Xcontext for saving
> cpuid, thus freeing Context to be used for saving PGD. This option
> was also tied to using a scratch register for storing PGD.
> 
> This commit will allow usage of scratch register to store the current
> pgd if one can be allocated for the platform, even when
> MIPS_PGD_C0_CONTEXT is not set. The cpuid will be kept in the CP0
> Context register in this case.
> 
> The code to store the current pgd for the TLB miss handler is now
> generated in all cases. When scratch register is available, the PGD
> is also stored in the scratch register.

This patch breaks the build for almost all platforms.  Amusingly it
doesn't break Cavium however which is why I didn't notice it right away.

The build error is the same for all platforms:

[...]
  LD      init/built-in.o
arch/mips/built-in.o: In function `per_cpu_trap_init':
(.text+0x80e4): undefined reference to `tlbmiss_handler_setup_pgd'
arch/mips/built-in.o: In function `build_setup_pgd':
tlbex.c:(.text+0xe31c): undefined reference to `tlbmiss_handler_setup_pgd'
tlbex.c:(.text+0xe328): undefined reference to `tlbmiss_handler_setup_pgd'
tlbex.c:(.text+0xe324): undefined reference to `tlbmiss_handler_setup_pgd_end'
tlbex.c:(.text+0xe32c): undefined reference to `tlbmiss_handler_setup_pgd_end'
kernel/built-in.o: In function `__schedule':
core.c:(.sched.text+0x1b74): undefined reference to `tlbmiss_handler_setup_pgd'
mm/built-in.o: In function `use_mm':
(.text+0x1a530): undefined reference to `tlbmiss_handler_setup_pgd'
fs/built-in.o: In function `flush_old_exec':
(.text+0x8da8): undefined reference to `tlbmiss_handler_setup_pgd'
make[2]: *** [vmlinux] Error 1
make[1]: *** [sub-make] Error 2
make: *** [all] Error 2
make: Leaving directory `/home/ralf/src/linux/obj/cobalt-build'

I'm reverting the patch now.

  Ralf
Jayachandran C - Sept. 18, 2013, 7:59 a.m.
On Tue, Sep 17, 2013 at 11:21:13PM +0200, Ralf Baechle wrote:
> On Sun, Aug 11, 2013 at 05:10:17PM +0530, Jayachandran C wrote:
> 
> > Allow usage of scratch register for current pgd even when
> > MIPS_PGD_C0_CONTEXT is not configured. MIPS_PGD_C0_CONTEXT is set
> > for 64r2 platforms to indicate availability of Xcontext for saving
> > cpuid, thus freeing Context to be used for saving PGD. This option
> > was also tied to using a scratch register for storing PGD.
> > 
> > This commit will allow usage of scratch register to store the current
> > pgd if one can be allocated for the platform, even when
> > MIPS_PGD_C0_CONTEXT is not set. The cpuid will be kept in the CP0
> > Context register in this case.
> > 
> > The code to store the current pgd for the TLB miss handler is now
> > generated in all cases. When scratch register is available, the PGD
> > is also stored in the scratch register.
> 
> This patch breaks the build for almost all platforms.  Amusingly it
> doesn't break Cavium however which is why I didn't notice it right away.
> 
> The build error is the same for all platforms:
> 
> [...]
>   LD      init/built-in.o
> arch/mips/built-in.o: In function `per_cpu_trap_init':
> (.text+0x80e4): undefined reference to `tlbmiss_handler_setup_pgd'
> arch/mips/built-in.o: In function `build_setup_pgd':
> tlbex.c:(.text+0xe31c): undefined reference to `tlbmiss_handler_setup_pgd'
> tlbex.c:(.text+0xe328): undefined reference to `tlbmiss_handler_setup_pgd'
> tlbex.c:(.text+0xe324): undefined reference to `tlbmiss_handler_setup_pgd_end'
> tlbex.c:(.text+0xe32c): undefined reference to `tlbmiss_handler_setup_pgd_end'
> kernel/built-in.o: In function `__schedule':
> core.c:(.sched.text+0x1b74): undefined reference to `tlbmiss_handler_setup_pgd'
> mm/built-in.o: In function `use_mm':
> (.text+0x1a530): undefined reference to `tlbmiss_handler_setup_pgd'
> fs/built-in.o: In function `flush_old_exec':
> (.text+0x8da8): undefined reference to `tlbmiss_handler_setup_pgd'
> make[2]: *** [vmlinux] Error 1
> make[1]: *** [sub-make] Error 2
> make: *** [all] Error 2
> make: Leaving directory `/home/ralf/src/linux/obj/cobalt-build'
> 
> I'm reverting the patch now.

The commit 774b6175 "MIPS: tlbex: Guard tlbmiss_handler_setup_pgd" that
went into 3.12-rc1 takes out tlbmiss_handler_setup_pgd definition when
CONFIG_MIPS_PGD_C0_CONTEXT is not defined. That clashes with this change
and caused the failure.

You can revert 774b6175 before applying this and things should work, I
had tested it with qemu on malta as well as on XLP.

JC.
root - Sept. 18, 2013, 11:02 a.m.
On Wed, Sep 18, 2013 at 01:29:41PM +0530, Jayachandran C. wrote:

> The commit 774b6175 "MIPS: tlbex: Guard tlbmiss_handler_setup_pgd" that
> went into 3.12-rc1 takes out tlbmiss_handler_setup_pgd definition when
> CONFIG_MIPS_PGD_C0_CONTEXT is not defined. That clashes with this change
> and caused the failure.
> 
> You can revert 774b6175 before applying this and things should work, I
> had tested it with qemu on malta as well as on XLP.

Done.  Thanks!

  Ralf
Hauke Mehrtens - Sept. 24, 2013, 9:49 p.m.
On 08/11/2013 01:40 PM, Jayachandran C wrote:
> Allow usage of scratch register for current pgd even when
> MIPS_PGD_C0_CONTEXT is not configured. MIPS_PGD_C0_CONTEXT is set
> for 64r2 platforms to indicate availability of Xcontext for saving
> cpuid, thus freeing Context to be used for saving PGD. This option
> was also tied to using a scratch register for storing PGD.
> 
> This commit will allow usage of scratch register to store the current
> pgd if one can be allocated for the platform, even when
> MIPS_PGD_C0_CONTEXT is not set. The cpuid will be kept in the CP0
> Context register in this case.
> 
> The code to store the current pgd for the TLB miss handler is now
> generated in all cases. When scratch register is available, the PGD
> is also stored in the scratch register.
> 
> Signed-off-by: Jayachandran C <jchandra@broadcom.com>

This patch breaks booting for me on bcm47xx. I found this commit by
bisecting and then reverted it and it made bcm47xx boot again. The boot
process stops after: [    0.000000] Inode-cache hash table entries: 4096
(order: 2, 16384 bytes)

The next message would be: [    0.000000] Writing ErrCtl register=00000000

This issue was seen on bcm4716.

This is the boot log:

CFE> boot -tftp -elf
192.168.1.195:/brcm47xx/openwrt-brcm47xx-vmlinux-initramfs.elf
Loader:elf Filesys:tftp Dev:eth0
File:192.168.1.195:/brcm47xx/openwrt-brcm47xx-vmlinux-initramfs.elf
Options:(null)
Loading: 0x80001000/4593328 0x804626b0/279760 Entry at 0x80264800
Closing network.
Starting program at 0x80264800
[    0.000000] Linux version 3.12.0-rc1+ (hauke@hauke-desktop) (gcc
version 4.6.4 (OpenWrt/Linaro GCC 4.6-2013.05 r37948) ) #151 Tue Sep 24
23:35:35 CEST 2013
[    0.000000] bootconsole [early0] enabled
[    0.000000] CPU revision is: 00019740 (MIPS 74Kc)
[    0.000000] bcm47xx: using bcma bus
[    0.000000] bcma: bus0: Found chip with id 0x4716, rev 0x01 and
package 0x0A
[    0.000000] bcma: bus0: Core 0 found: ChipCommon (manuf 0x4BF, id
0x800, rev 0x1F, class 0x0)
[    0.000000] bcma: bus0: Core 3 found: MIPS 74K (manuf 0x4A7, id
0x82C, rev 0x01, class 0x0)
[    0.000000] bcma: bus0: Found M25P64 serial flash (size: 8192KiB,
blocksize: 0x10000, blocks: 128)
[    0.000000] bcma: bus0: Early bus registered
[    0.000000] MIPS: machine is Netgear WNDR3400 V1
[    0.000000] Determined physical RAM map:
[    0.000000]  memory: 04000000 @ 00000000 (usable)
[    0.000000] Initrd not found or empty - disabling initrd
[    0.000000] Zone ranges:
[    0.000000]   Normal   [mem 0x00000000-0x03ffffff]
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x00000000-0x03ffffff]
[    0.000000] Primary instruction cache 32kB, VIPT, 4-way, linesize 32
bytes.
[    0.000000] Primary data cache 32kB, 4-way, VIPT, cache aliases,
linesize 32 bytes
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.
Total pages: 16256
[    0.000000] Kernel command line:  noinitrd console=ttyS0,115200
[    0.000000] PID hash table entries: 256 (order: -2, 1024 bytes)
[    0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)

Patch

diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h
index ab8e260..e277bba 100644
--- a/arch/mips/include/asm/mmu_context.h
+++ b/arch/mips/include/asm/mmu_context.h
@@ -24,14 +24,13 @@ 
 #endif /* SMTC */
 #include <asm-generic/mm_hooks.h>
 
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
-
 #define TLBMISS_HANDLER_SETUP_PGD(pgd)					\
 do {									\
 	extern void tlbmiss_handler_setup_pgd(unsigned long);		\
 	tlbmiss_handler_setup_pgd((unsigned long)(pgd));		\
 } while (0)
 
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
 #define TLBMISS_HANDLER_SETUP()						\
 	do {								\
 		TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir);		\
@@ -48,9 +47,6 @@  do {									\
  */
 extern unsigned long pgd_current[];
 
-#define TLBMISS_HANDLER_SETUP_PGD(pgd) \
-	pgd_current[smp_processor_id()] = (unsigned long)(pgd)
-
 #define TLBMISS_HANDLER_SETUP()						\
 	write_c0_context((unsigned long) smp_processor_id() <<		\
 						SMP_CPUID_REGSHIFT);	\
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 54f3270..40efded 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -796,11 +796,11 @@  build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
 	}
 	/* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */
 
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
 	if (pgd_reg != -1) {
 		/* pgd is in pgd_reg */
 		UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg);
 	} else {
+#if defined(CONFIG_MIPS_PGD_C0_CONTEXT)
 		/*
 		 * &pgd << 11 stored in CONTEXT [23..63].
 		 */
@@ -812,18 +812,18 @@  build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
 		/* 1 0	1 0 1  << 6  xkphys cached */
 		uasm_i_ori(p, ptr, ptr, 0x540);
 		uasm_i_drotr(p, ptr, ptr, 11);
-	}
 #elif defined(CONFIG_SMP)
-	UASM_i_CPUID_MFC0(p, ptr, SMP_CPUID_REG);
-	uasm_i_dsrl_safe(p, ptr, ptr, SMP_CPUID_PTRSHIFT);
-	UASM_i_LA_mostly(p, tmp, pgdc);
-	uasm_i_daddu(p, ptr, ptr, tmp);
-	uasm_i_dmfc0(p, tmp, C0_BADVADDR);
-	uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
+		UASM_i_CPUID_MFC0(p, ptr, SMP_CPUID_REG);
+		uasm_i_dsrl_safe(p, ptr, ptr, SMP_CPUID_PTRSHIFT);
+		UASM_i_LA_mostly(p, tmp, pgdc);
+		uasm_i_daddu(p, ptr, ptr, tmp);
+		uasm_i_dmfc0(p, tmp, C0_BADVADDR);
+		uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
 #else
-	UASM_i_LA_mostly(p, ptr, pgdc);
-	uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
+		UASM_i_LA_mostly(p, ptr, pgdc);
+		uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
 #endif
+	}
 
 	uasm_l_vmalloc_done(l, *p);
 
@@ -918,19 +918,25 @@  build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
 static void __maybe_unused
 build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
 {
-	long pgdc = (long)pgd_current;
+	if (pgd_reg != -1) {
+		/* pgd is in pgd_reg */
+		uasm_i_mfc0(p, ptr, c0_kscratch(), pgd_reg);
+		uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+	} else {
+		long pgdc = (long)pgd_current;
 
-	/* 32 bit SMP has smp_processor_id() stored in CONTEXT. */
+		/* 32 bit SMP has smp_processor_id() stored in CONTEXT. */
 #ifdef CONFIG_SMP
-	uasm_i_mfc0(p, ptr, SMP_CPUID_REG);
-	UASM_i_LA_mostly(p, tmp, pgdc);
-	uasm_i_srl(p, ptr, ptr, SMP_CPUID_PTRSHIFT);
-	uasm_i_addu(p, ptr, tmp, ptr);
+		uasm_i_mfc0(p, ptr, SMP_CPUID_REG);
+		UASM_i_LA_mostly(p, tmp, pgdc);
+		uasm_i_srl(p, ptr, ptr, SMP_CPUID_PTRSHIFT);
+		uasm_i_addu(p, ptr, tmp, ptr);
 #else
-	UASM_i_LA_mostly(p, ptr, pgdc);
+		UASM_i_LA_mostly(p, ptr, pgdc);
 #endif
-	uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
-	uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
+		uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+		uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
+	}
 	uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
 	uasm_i_sll(p, tmp, tmp, PGD_T_LOG2);
 	uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
@@ -1404,28 +1410,30 @@  static void build_r4000_tlb_refill_handler(void)
 extern u32 handle_tlbl[], handle_tlbl_end[];
 extern u32 handle_tlbs[], handle_tlbs_end[];
 extern u32 handle_tlbm[], handle_tlbm_end[];
-
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
 extern u32 tlbmiss_handler_setup_pgd[], tlbmiss_handler_setup_pgd_end[];
 
-static void build_r4000_setup_pgd(void)
+static void build_setup_pgd(void)
 {
 	const int a0 = 4;
-	const int a1 = 5;
+	const int __maybe_unused a1 = 5;
+	const int __maybe_unused a2 = 6;
 	u32 *p = tlbmiss_handler_setup_pgd;
 	const int tlbmiss_handler_setup_pgd_size =
 		tlbmiss_handler_setup_pgd_end - tlbmiss_handler_setup_pgd;
-	struct uasm_label *l = labels;
-	struct uasm_reloc *r = relocs;
+#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
+	long pgdc = (long)pgd_current;
+#endif
 
 	memset(tlbmiss_handler_setup_pgd, 0, tlbmiss_handler_setup_pgd_size *
 					sizeof(tlbmiss_handler_setup_pgd[0]));
 	memset(labels, 0, sizeof(labels));
 	memset(relocs, 0, sizeof(relocs));
-
 	pgd_reg = allocate_kscratch();
-
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
 	if (pgd_reg == -1) {
+		struct uasm_label *l = labels;
+		struct uasm_reloc *r = relocs;
+
 		/* PGD << 11 in c0_Context */
 		/*
 		 * If it is a ckseg0 address, convert to a physical
@@ -1447,6 +1455,26 @@  static void build_r4000_setup_pgd(void)
 		uasm_i_jr(&p, 31);
 		UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
 	}
+#else
+#ifdef CONFIG_SMP
+	/* Save PGD to pgd_current[smp_processor_id()] */
+	UASM_i_CPUID_MFC0(&p, a1, SMP_CPUID_REG);
+	UASM_i_SRL_SAFE(&p, a1, a1, SMP_CPUID_PTRSHIFT);
+	UASM_i_LA_mostly(&p, a2, pgdc);
+	UASM_i_ADDU(&p, a2, a2, a1);
+	UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2);
+#else
+	UASM_i_LA_mostly(&p, a2, pgdc);
+	UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2);
+#endif /* SMP */
+	uasm_i_jr(&p, 31);
+
+	/* if pgd_reg is allocated, save PGD also to scratch register */
+	if (pgd_reg != -1)
+		UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
+	else
+		uasm_i_nop(&p);
+#endif
 	if (p >= tlbmiss_handler_setup_pgd_end)
 		panic("tlbmiss_handler_setup_pgd space exceeded");
 
@@ -1457,7 +1485,6 @@  static void build_r4000_setup_pgd(void)
 	dump_handler("tlbmiss_handler", tlbmiss_handler_setup_pgd,
 					tlbmiss_handler_setup_pgd_size);
 }
-#endif
 
 static void
 iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr)
@@ -2185,6 +2212,7 @@  void build_tlb_refill_handler(void)
 		if (!run_once) {
 			if (!cpu_has_local_ebase)
 				build_r3000_tlb_refill_handler();
+			build_setup_pgd();
 			build_r3000_tlb_load_handler();
 			build_r3000_tlb_store_handler();
 			build_r3000_tlb_modify_handler();
@@ -2208,9 +2236,7 @@  void build_tlb_refill_handler(void)
 	default:
 		if (!run_once) {
 			scratch_reg = allocate_kscratch();
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
-			build_r4000_setup_pgd();
-#endif
+			build_setup_pgd();
 			build_r4000_tlb_load_handler();
 			build_r4000_tlb_store_handler();
 			build_r4000_tlb_modify_handler();