
Date: Wed, 21 Mar 2012 15:50:28 +0900
Subject: [PATCH 2/5] ppc32: add special vtop for FSL BOOKE

FSL BOOKE MMU architecture own special address translation with TLBCAM
which do not require the basic page table setup for memory access.
Since the most kernel virtual address is set as TLBCAM region,
those vtop can not resolve physical address from basic ppc vtop routine.
Try to resolve it via TLBCAM if pgd entry is null.

[before] kvtop failed because of no page table
crash> vtop c0000000
VIRTUAL   PHYSICAL
c0000000  0

PAGE DIRECTORY: c08d1000
  PGD: c08d2800 => 0

  PAGE     PHYSICAL   MAPPING    INDEX CNT FLAGS
d0000000          0         0         0  1 400

[after] kvtop search from TLBCAM if mapped

crash> vtop c0000000
VIRTUAL   PHYSICAL
c0000000  0

PAGE DIRECTORY: c08d1000
  PGD: c08d2800 => 0

  TLBCAM[0]: MAS0     MAS1     MAS2     MAS3     MAS7
             10000001 c0000900 c0000004 15       0
             VIRTUAL RANGE : c0000000 - cfffffff
             PHYSICAL RANGE: 0 - fffffff
  => VIRTUAL  PHYSICAL TLBCAM-OFFSET
     c0000000 0        0

  PAGE     PHYSICAL   MAPPING    INDEX CNT FLAGS
d0000000          0         0         0  1 400

Signed-off-by: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
---
 defs.h |    7 ++++
 ppc.c  |  112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 118 insertions(+), 1 deletions(-)

diff --git a/defs.h b/defs.h
index c742f21..a3a40e0 100755
--- a/defs.h
+++ b/defs.h
@@ -2661,6 +2661,10 @@ struct machine_specific {
 	ulong _page_accessed;
 	ulong _page_hwwrite;
 	ulong _page_shared;
+
+	/* platform special vtop */
+	int (*vtop_special)(ulong vaddr, physaddr_t *paddr, int verbose);
+	void *mmu_special;
 };
 
 /* machdep flags for ppc32 specific */
@@ -2676,6 +2680,9 @@ struct machine_specific {
 #define PGDIR_SHIFT		(PAGE_SHIFT + PTE_SHIFT)
 #define PTRS_PER_PGD		(1 << (32 - PGDIR_SHIFT))
 #define PTRS_PER_PTE		(1 << PTE_SHIFT)
+/* special vtop */
+#define VTOP_SPECIAL		(machdep->machspec->vtop_special)
+#define MMU_SPECIAL		(machdep->machspec->mmu_special)
 
 /* PFN shifts */
 #define BOOKE3E_PTE_RPN_SHIFT	(24)
diff --git a/ppc.c b/ppc.c
index 17d4218..11fe22f 100755
--- a/ppc.c
+++ b/ppc.c
@@ -113,6 +113,107 @@ probe_ppc44x_platform(char *name)
 	return FALSE;
 }
 
+struct fsl_booke_tlbcam {
+#define NUM_TLBCAMS	(64)
+#define LAST_TLBCAM	(0x40)
+	uint index;
+	struct {
+		ulong start;
+		ulong limit;
+		physaddr_t phys;
+	} tlbcamrange;
+	struct {
+		uint MAS0;
+		uint MAS1;
+		ulong MAS2;
+		uint MAS3;
+		uint MAS7;
+	} tlbcam;
+};
+
+static int
+fsl_booke_vtop(ulong vaddr, physaddr_t *paddr, int verbose)
+{
+	struct fsl_booke_tlbcam *fsl_mmu;
+	int i, found;
+
+	if (CRASHDEBUG(1))
+		fprintf(fp, "[Searching tlbcam address mapping]\n");
+	fsl_mmu = MMU_SPECIAL;
+	for (i = 0, found = FALSE;;i++, fsl_mmu++) {
+		if (vaddr >= fsl_mmu->tlbcamrange.start &&
+		    vaddr < fsl_mmu->tlbcamrange.limit) {
+			*paddr = fsl_mmu->tlbcamrange.phys +
+				 (vaddr - fsl_mmu->tlbcamrange.start);
+			found = TRUE;
+			break;
+		}
+		if (fsl_mmu->index & LAST_TLBCAM)
+			break;
+	}
+	if (found && verbose) {
+		/* TLBCAM segment attributes */
+		fprintf(fp, "\n  TLBCAM[%u]: MAS0     MAS1     MAS2     "
+			"MAS3     MAS7\n",
+			(fsl_mmu->index & ~LAST_TLBCAM));
+		fprintf(fp, "             %-8lx %-8lx %-8lx %-8lx %-8lx\n",
+			fsl_mmu->tlbcam.MAS0, fsl_mmu->tlbcam.MAS1,
+			fsl_mmu->tlbcam.MAS2, fsl_mmu->tlbcam.MAS3,
+			fsl_mmu->tlbcam.MAS7);
+		/* TLBCAM range */
+		fprintf(fp, "             VIRTUAL RANGE : %lx - %lx\n",
+			fsl_mmu->tlbcamrange.start, fsl_mmu->tlbcamrange.limit);
+		fprintf(fp, "             PHYSICAL RANGE: %llx - %llx\n",
+			fsl_mmu->tlbcamrange.phys,
+			fsl_mmu->tlbcamrange.phys + (fsl_mmu->tlbcamrange.limit
+				- fsl_mmu->tlbcamrange.start));
+		/* translated addr and its tlbcam's offset. */
+		fprintf(fp, "  => VIRTUAL  PHYSICAL TLBCAM-OFFSET\n");
+		fprintf(fp, "     %-8lx %-8llx %lu\n", vaddr, *paddr,
+			vaddr - fsl_mmu->tlbcamrange.start);
+	}
+	if (CRASHDEBUG(1))
+		fprintf(fp, "[tlbcam search end]\n");
+
+	return found;
+}
+
+static void
+fsl_booke_mmu_setup(void)
+{
+	struct fsl_booke_tlbcam *fsl_mmu;
+	uint i, tlbcam_index;
+	ulong tlbcam_addrs, TLBCAM;
+
+	readmem(symbol_value("tlbcam_index"), KVADDR, &tlbcam_index,
+		sizeof(uint), "tlbcam_index", FAULT_ON_ERROR);
+	if (tlbcam_index != 0 && tlbcam_index < NUM_TLBCAMS) {
+		fsl_mmu = calloc(tlbcam_index, sizeof(*fsl_mmu));
+		if (!fsl_mmu) {
+			error(FATAL, "fsl_mmu calloc() failed\n");
+			return;
+		}
+		tlbcam_addrs = symbol_value("tlbcam_addrs");
+		TLBCAM = symbol_value("TLBCAM");
+		for (i = 0; i < tlbcam_index; i++) {
+			fsl_mmu[i].index = i;
+			readmem(tlbcam_addrs +
+					i * sizeof(fsl_mmu[i].tlbcamrange),
+				KVADDR, &fsl_mmu[i].tlbcamrange,
+				sizeof(fsl_mmu[i].tlbcamrange), "tlbcam_addrs",
+				FAULT_ON_ERROR);
+			readmem(TLBCAM + i * sizeof(fsl_mmu[i].tlbcam), KVADDR,
+				&fsl_mmu[i].tlbcam, sizeof(fsl_mmu[i].tlbcam),
+				"TLBCAM", FAULT_ON_ERROR);
+		}
+		fsl_mmu[i - 1].index |= LAST_TLBCAM;
+		MMU_SPECIAL = fsl_mmu;
+		VTOP_SPECIAL = fsl_booke_vtop;
+	} else
+		error(INFO, "[%s]: can't setup tlbcam: tlbcam_index=%u\n",
+			PPC_PLATFORM, tlbcam_index);
+}
+
 static int
 probe_ppce500_platform(char *name)
 {
@@ -123,6 +224,7 @@ probe_ppce500_platform(char *name)
 			PLATFORM_PAGE_FLAGS_SETUP(BOOK3E);
 		} else
 			PLATFORM_PAGE_FLAGS_SETUP(FSL_BOOKE);
+		fsl_booke_mmu_setup();
 
 		return TRUE;
 	}
@@ -423,8 +525,16 @@ ppc_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
 	if (verbose)
 		fprintf(fp, "  PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
 
-	if (!pgd_pte)
+	if (!pgd_pte) {
+		if (VTOP_SPECIAL)
+			/*
+			 * This ppc platform have special address mapping
+			 * between vaddr and paddr which can not search from
+			 * standard page table.
+			 */
+			return VTOP_SPECIAL(vaddr, paddr, verbose);
 		goto no_page;
+	}
 
 	page_middle = (ulong *)pgd_pte;
 
-- 
1.7.0.4

