From patchwork Sun Mar 28 20:09:08 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Fleming X-Patchwork-Id: 88814 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2SK8WmE015830 for ; Sun, 28 Mar 2010 20:09:14 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755164Ab0C1UJN (ORCPT ); Sun, 28 Mar 2010 16:09:13 -0400 Received: from 124x34x33x190.ap124.ftth.ucom.ne.jp ([124.34.33.190]:52174 "EHLO master.linux-sh.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755146Ab0C1UJM (ORCPT ); Sun, 28 Mar 2010 16:09:12 -0400 Received: from localhost (unknown [127.0.0.1]) by master.linux-sh.org (Postfix) with ESMTP id F411A6375A; Sun, 28 Mar 2010 20:07:54 +0000 (UTC) X-Virus-Scanned: amavisd-new at linux-sh.org Received: from master.linux-sh.org ([127.0.0.1]) by localhost (master.linux-sh.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zrcY7yCle6Jt; Mon, 29 Mar 2010 05:07:54 +0900 (JST) Received: from localhost (cpc5-brad6-0-0-cust25.barn.cable.virginmedia.com [82.38.64.26]) by master.linux-sh.org (Postfix) with ESMTP id CE5CE63758; Mon, 29 Mar 2010 05:07:53 +0900 (JST) From: Matt Fleming To: linux-sh@vger.kernel.org Cc: Paul Mundt , Matt Fleming Subject: [PATCH] sh: pteaex tlb debugfs support Date: Sun, 28 Mar 2010 21:09:08 +0100 Message-Id: <5710cd68d399fc83734fcde7116ab91a3cfd624d.1269806831.git.matt@console-pimps.org> X-Mailer: git-send-email 1.6.4.rc0 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Sun, 28 Mar 2010 20:09:14 +0000 (UTC) diff --git a/arch/sh/include/cpu-sh4/cpu/mmu_context.h b/arch/sh/include/cpu-sh4/cpu/mmu_context.h index 5963124..2941be6 100644 --- a/arch/sh/include/cpu-sh4/cpu/mmu_context.h +++ b/arch/sh/include/cpu-sh4/cpu/mmu_context.h @@ -19,10 +19,17 @@ #define MMUCR 0xFF000010 /* MMU Control Register */ +#define MMU_TLB_ENTRY_SHIFT 8 + #define MMU_ITLB_ADDRESS_ARRAY 0xF2000000 #define MMU_ITLB_ADDRESS_ARRAY2 0xF2800000 +#define MMU_ITLB_DATA_ARRAY 0xF3000000 +#define MMU_ITLB_DATA_ARRAY2 0xF3800000 + #define MMU_UTLB_ADDRESS_ARRAY 0xF6000000 #define MMU_UTLB_ADDRESS_ARRAY2 0xF6800000 +#define MMU_UTLB_DATA_ARRAY 0xF7000000 +#define MMU_UTLB_DATA_ARRAY2 0xF7800000 #define MMU_PAGE_ASSOC_BIT 0x80 #define MMUCR_TI (1<<2) diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c index bdd0982..f706576 100644 --- a/arch/sh/mm/tlb-pteaex.c +++ b/arch/sh/mm/tlb-pteaex.c @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -77,3 +80,144 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) __raw_writel(asid, MMU_ITLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT); back_to_cached(); } + +enum tlb_type { + TLB_TYPE_ITLB, + TLB_TYPE_UTLB, +}; + +struct _tlb_size { + int bits; + const char *size; +}; + +static struct _tlb_size tlb_sizes[] = { + { 0x0, " 1KB" }, + { 0x1, " 4KB" }, + { 0x2, " 8KB" }, + { 0x4, " 64KB" }, + { 0x5, "256KB" }, + { 0x7, " 1MB" }, + { 0x8, " 4MB" }, + { 0xc, " 64MB" }, +}; + +static int tlb_seq_show(struct seq_file *file, void *iter) +{ + unsigned int tlb_type = (unsigned int)file->private; + unsigned long addr1, addr2, data1, data2; + unsigned int nentries, entry; + unsigned int urb; + unsigned long flags; + + local_irq_save(flags); + jump_to_uncached(); + + urb = __raw_readl(MMUCR); + urb = (urb & MMUCR_URB) >> MMUCR_URB_SHIFT; + + /* Make the "entry >= urb" test fail. */ + if (urb == 0) + urb = MMUCR_URB_NENTRIES + 1; + + if (tlb_type == TLB_TYPE_ITLB) { + addr1 = MMU_ITLB_ADDRESS_ARRAY; + addr2 = MMU_ITLB_ADDRESS_ARRAY2; + data1 = MMU_ITLB_DATA_ARRAY; + data2 = MMU_ITLB_DATA_ARRAY2; + nentries = 4; + } else { + addr1 = MMU_UTLB_ADDRESS_ARRAY; + addr2 = MMU_UTLB_ADDRESS_ARRAY2; + data1 = MMU_UTLB_DATA_ARRAY; + data2 = MMU_UTLB_DATA_ARRAY2; + nentries = 64; + } + + seq_printf(file, "entry: vpn ppn asid size valid wired\n"); + + for (entry = 0; entry < nentries; entry++) { + unsigned long vpn, ppn, asid, size; + unsigned long valid; + unsigned long val; + const char *sz = " ?"; + int i; + + val = __raw_readl(addr1 | (entry << MMU_TLB_ENTRY_SHIFT)); + ctrl_barrier(); + vpn = val & 0xfffffc00; + valid = val & 0x100; + + val = __raw_readl(addr2 | (entry << MMU_TLB_ENTRY_SHIFT)); + ctrl_barrier(); + asid = val & MMU_CONTEXT_ASID_MASK; + + val = __raw_readl(data1 | (entry << MMU_TLB_ENTRY_SHIFT)); + ctrl_barrier(); + ppn = (val & 0x0ffffc00) << 4; + + val = __raw_readl(data2 | (entry << MMU_TLB_ENTRY_SHIFT)); + ctrl_barrier(); + size = (val & 0xf0) >> 4; + + for (i = 0; i < ARRAY_SIZE(tlb_sizes); i++) { + if (tlb_sizes[i].bits == size) + break; + } + + if (i != ARRAY_SIZE(tlb_sizes)) + sz = tlb_sizes[i].size; + + seq_printf(file, "%2d: 0x%08lx 0x%08lx %5lu %s %s %s\n", + entry, vpn, ppn, asid, + sz, valid ? "V" : "-", + (urb <= entry) ? "W" : "-"); + } + + back_to_cached(); + local_irq_restore(flags); + + return 0; +} + +static int tlb_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, tlb_seq_show, inode->i_private); +} + +static const struct file_operations tlb_debugfs_fops = { + .owner = THIS_MODULE, + .open = tlb_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init tlb_debugfs_init(void) +{ + struct dentry *utlb_dentry, *itlb_dentry; + + utlb_dentry = debugfs_create_file("utlb", S_IRUSR, sh_debugfs_root, + (unsigned int *)TLB_TYPE_UTLB, + &tlb_debugfs_fops); + if (!utlb_dentry) + return -ENOMEM; + + if (IS_ERR(utlb_dentry)) + return PTR_ERR(utlb_dentry); + + itlb_dentry = debugfs_create_file("itlb", S_IRUSR, sh_debugfs_root, + (unsigned int *)TLB_TYPE_ITLB, + &tlb_debugfs_fops); + if (!itlb_dentry) { + debugfs_remove(utlb_dentry); + return -ENOMEM; + } + if (IS_ERR(itlb_dentry)) { + debugfs_remove(utlb_dentry); + return PTR_ERR(itlb_dentry); + } + + return 0; +} +module_init(tlb_debugfs_init);