]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'mips/mips-for-linux-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 8 Nov 2012 22:16:47 +0000 (09:16 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 8 Nov 2012 22:16:47 +0000 (09:16 +1100)
31 files changed:
MAINTAINERS
arch/mips/Kconfig
arch/mips/cavium-octeon/octeon-memcpy.S
arch/mips/cavium-octeon/setup.c
arch/mips/configs/cavium_octeon_defconfig
arch/mips/include/asm/cpu.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/page.h
arch/mips/include/asm/pgtable-64.h
arch/mips/include/asm/pgtable-bits.h
arch/mips/include/asm/pgtable.h
arch/mips/include/asm/processor.h
arch/mips/include/asm/sparsemem.h
arch/mips/include/asm/tlbdebug.h
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/mips_ksyms.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/signal.c
arch/mips/lib/dump_tlb.c
arch/mips/mm/c-octeon.c
arch/mips/mm/pgtable-64.c
arch/mips/mm/tlb-r4k.c
arch/mips/mm/tlbex.c
arch/mips/pci/pci-octeon.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/octeon_edac-l2c.c [new file with mode: 0644]
drivers/edac/octeon_edac-lmc.c [new file with mode: 0644]
drivers/edac/octeon_edac-lmc.h [new file with mode: 0644]
drivers/edac/octeon_edac-pc.c [new file with mode: 0644]
drivers/edac/octeon_edac-pci.c [new file with mode: 0644]

index 59203e77ce9ef8f1a5639e2cad19a006b4e59696..07152f6ecb2bcccdc5a2893156666bff7ba572af 100644 (file)
@@ -2714,6 +2714,15 @@ W:       bluesmoke.sourceforge.net
 S:     Supported
 F:     drivers/edac/amd64_edac*
 
+EDAC-CAVIUM
+M:     Ralf Baechle <ralf@linux-mips.org>
+M:     David Daney <david.daney@cavium.com>
+L:     linux-edac@vger.kernel.org
+L:     linux-mips@linux-mips.org
+W:     bluesmoke.sourceforge.net
+S:     Supported
+F:     drivers/edac/octeon_edac*
+
 EDAC-E752X
 M:     Mark Gross <mark.gross@intel.com>
 M:     Doug Thompson <dougthompson@xmission.com>
index dba9390d37cf2c0d1672ca6dfb2b1453fb4294cf..9934a4687ac4ffa74745759af03936f57b16f6d8 100644 (file)
@@ -19,6 +19,7 @@ config MIPS
        select HAVE_KRETPROBES
        select HAVE_DEBUG_KMEMLEAK
        select ARCH_BINFMT_ELF_RANDOMIZE_PIE
+       select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select RTC_LIB if !MACH_LOONGSON
        select GENERIC_ATOMIC64 if !64BIT
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
@@ -774,6 +775,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
        select DMA_COHERENT
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
+       select EDAC_SUPPORT
        select SYS_SUPPORTS_HOTPLUG_CPU
        select SYS_HAS_EARLY_PRINTK
        select SYS_HAS_CPU_CAVIUM_OCTEON
@@ -1077,6 +1079,9 @@ config SYS_SUPPORTS_HUGETLBFS
        depends on CPU_SUPPORTS_HUGEPAGES && 64BIT
        default y
 
+config MIPS_HUGE_TLB_SUPPORT
+       def_bool HUGETLB_PAGE || TRANSPARENT_HUGEPAGE
+
 config IRQ_CPU
        bool
 
@@ -1368,6 +1373,7 @@ config CPU_R4X00
        depends on SYS_HAS_CPU_R4X00
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
+       select CPU_SUPPORTS_HUGEPAGES
        help
          MIPS Technologies R4000-series processors other than 4300, including
          the R4000, R4400, R4600, and 4700.
@@ -1378,12 +1384,14 @@ config CPU_TX49XX
        select CPU_HAS_PREFETCH
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
+       select CPU_SUPPORTS_HUGEPAGES
 
 config CPU_R5000
        bool "R5000"
        depends on SYS_HAS_CPU_R5000
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
+       select CPU_SUPPORTS_HUGEPAGES
        help
          MIPS Technologies R5000-series processors other than the Nevada.
 
@@ -1392,6 +1400,7 @@ config CPU_R5432
        depends on SYS_HAS_CPU_R5432
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
+       select CPU_SUPPORTS_HUGEPAGES
 
 config CPU_R5500
        bool "R5500"
@@ -1417,6 +1426,7 @@ config CPU_NEVADA
        depends on SYS_HAS_CPU_NEVADA
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
+       select CPU_SUPPORTS_HUGEPAGES
        help
          QED / PMC-Sierra RM52xx-series ("Nevada") processors.
 
@@ -1437,6 +1447,7 @@ config CPU_R10000
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
+       select CPU_SUPPORTS_HUGEPAGES
        help
          MIPS Technologies R10000-series processors.
 
@@ -1447,6 +1458,7 @@ config CPU_RM7000
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
+       select CPU_SUPPORTS_HUGEPAGES
 
 config CPU_RM9000
        bool "RM9000"
@@ -1455,6 +1467,7 @@ config CPU_RM9000
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
+       select CPU_SUPPORTS_HUGEPAGES
        select WEAK_ORDERING
 
 config CPU_SB1
@@ -1463,6 +1476,7 @@ config CPU_SB1
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
+       select CPU_SUPPORTS_HUGEPAGES
        select WEAK_ORDERING
 
 config CPU_CAVIUM_OCTEON
@@ -1526,9 +1540,9 @@ config CPU_XLR
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
+       select CPU_SUPPORTS_HUGEPAGES
        select WEAK_ORDERING
        select WEAK_REORDERING_BEYOND_LLSC
-       select CPU_SUPPORTS_HUGEPAGES
        help
          Netlogic Microsystems XLR/XLS processors.
 
@@ -1589,6 +1603,7 @@ config CPU_LOONGSON2
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
+       select CPU_SUPPORTS_HUGEPAGES
 
 config CPU_LOONGSON1
        bool
index db478dbb9c7beb87c1cef87932e9a5e107ce8991..0ba0eb96d9ac1e3706c613335fd14104ff1c62b5 100644 (file)
 /*
  * Only on the 64-bit kernel we can made use of 64-bit registers.
  */
-#ifdef CONFIG_64BIT
-#define USE_DOUBLE
-#endif
-
-#ifdef USE_DOUBLE
 
 #define LOAD   ld
 #define LOADL  ldl
 #define t6     $14
 #define t7     $15
 
-#else
-
-#define LOAD   lw
-#define LOADL  lwl
-#define LOADR  lwr
-#define STOREL swl
-#define STORER swr
-#define STORE  sw
-#define ADD    addu
-#define SUB    subu
-#define SRL    srl
-#define SLL    sll
-#define SRA    sra
-#define SLLV   sllv
-#define SRLV   srlv
-#define NBYTES 4
-#define LOG_NBYTES 2
-
-#endif /* USE_DOUBLE */
-
 #ifdef CONFIG_CPU_LITTLE_ENDIAN
 #define LDFIRST LOADR
 #define LDREST  LOADL
@@ -395,12 +370,10 @@ EXC(       sb     t0, N(dst), s_exc_p1)
 
        COPY_BYTE(0)
        COPY_BYTE(1)
-#ifdef USE_DOUBLE
        COPY_BYTE(2)
        COPY_BYTE(3)
        COPY_BYTE(4)
        COPY_BYTE(5)
-#endif
 EXC(   lb      t0, NBYTES-2(src), l_exc)
        SUB     len, len, 1
        jr      ra
index 04dd8ff0e0d8979b639c60b932be4eabee951903..67aa3b942f06d623f759f083e568ee7931bf86e6 100644 (file)
@@ -4,9 +4,11 @@
  * for more details.
  *
  * Copyright (C) 2004-2007 Cavium Networks
- * Copyright (C) 2008 Wind River Systems
+ * Copyright (C) 2008, 2009 Wind River Systems
+ *   written by Ralf Baechle <ralf@linux-mips.org>
  */
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/export.h>
@@ -664,20 +666,10 @@ void __init plat_mem_setup(void)
        cvmx_bootmem_lock();
        while ((boot_mem_map.nr_map < BOOT_MEM_MAP_MAX)
                && (total < MAX_MEMORY)) {
-#if defined(CONFIG_64BIT) || defined(CONFIG_64BIT_PHYS_ADDR)
                memory = cvmx_bootmem_phy_alloc(mem_alloc_size,
                                                __pa_symbol(&__init_end), -1,
                                                0x100000,
                                                CVMX_BOOTMEM_FLAG_NO_LOCKING);
-#elif defined(CONFIG_HIGHMEM)
-               memory = cvmx_bootmem_phy_alloc(mem_alloc_size, 0, 1ull << 31,
-                                               0x100000,
-                                               CVMX_BOOTMEM_FLAG_NO_LOCKING);
-#else
-               memory = cvmx_bootmem_phy_alloc(mem_alloc_size, 0, 512 << 20,
-                                               0x100000,
-                                               CVMX_BOOTMEM_FLAG_NO_LOCKING);
-#endif
                if (memory >= 0) {
                        u64 size = mem_alloc_size;
 
@@ -821,3 +813,29 @@ void __init device_tree_init(void)
        }
        unflatten_device_tree();
 }
+
+static char *edac_device_names[] = {
+       "co_l2c_edac",
+       "co_lmc_edac",
+       "co_pc_edac",
+};
+
+static int __init edac_devinit(void)
+{
+       struct platform_device *dev;
+       int i, err = 0;
+       char *name;
+
+       for (i = 0; i < ARRAY_SIZE(edac_device_names); i++) {
+               name = edac_device_names[i];
+               dev = platform_device_register_simple(name, -1, NULL, 0);
+               if (IS_ERR(dev)) {
+                       pr_err("Registation of %s failed!\n", name);
+                       err = PTR_ERR(dev);
+               }
+       }
+
+       return err;
+}
+
+device_initcall(edac_devinit);
index 75165dfa60c10990216691c95c2f25530b0a1fdf..014ba4bbba7d25ff8c2662852955c193da8c7b0d 100644 (file)
@@ -1,7 +1,11 @@
 CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD=y
+CONFIG_CAVIUM_CN63XXP1=y
 CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE=2
 CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
 CONFIG_SMP=y
+CONFIG_NR_CPUS=32
+CONFIG_HZ_100=y
 CONFIG_PREEMPT=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
@@ -11,16 +15,15 @@ CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_PCSPKR_PLATFORM is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_MIPS32_O32=y
 CONFIG_MIPS32_N32=y
@@ -42,22 +45,68 @@ CONFIG_IP_PIMSM_V1=y
 CONFIG_IP_PIMSM_V2=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_OF_PARTS is not set
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_SLRAM=y
+CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_LOOP=y
-# CONFIG_MISC_DEVICES is not set
+CONFIG_EEPROM_AT24=y
+CONFIG_EEPROM_AT25=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_PATA_OCTEON_CF=y
+CONFIG_SATA_SIL=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_TOSHIBA is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_MARVELL_PHY=y
+CONFIG_BROADCOM_PHY=y
+CONFIG_BCM87XX_PHY=y
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -66,24 +115,39 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=2
 CONFIG_SERIAL_8250_RUNTIME_UARTS=2
 # CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_OCTEON=y
+CONFIG_SPI=y
+CONFIG_SPI_OCTEON=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_STAGING=y
+CONFIG_OCTEON_ETHERNET=y
+# CONFIG_NET_VENDOR_SILICOM is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
-CONFIG_NLS=y
+CONFIG_HUGETLBFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_SCHED_DEBUG is not set
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-# CONFIG_EARLY_PRINTK is not set
 CONFIG_SECURITY=y
 CONFIG_SECURITY_NETWORK=y
 CONFIG_CRYPTO_CBC=y
index 52c4e914f95aef97ce72af5fd186678cc7ce9081..90112adb194082a1e41b945d45a7c7091962e3bc 100644 (file)
@@ -243,9 +243,9 @@ enum cpu_type_enum {
         */
        CPU_R4000PC, CPU_R4000SC, CPU_R4000MC, CPU_R4200, CPU_R4300, CPU_R4310,
        CPU_R4400PC, CPU_R4400SC, CPU_R4400MC, CPU_R4600, CPU_R4640, CPU_R4650,
-       CPU_R4700, CPU_R5000, CPU_R5000A, CPU_R5500, CPU_NEVADA, CPU_R5432,
-       CPU_R10000, CPU_R12000, CPU_R14000, CPU_VR41XX, CPU_VR4111, CPU_VR4121,
-       CPU_VR4122, CPU_VR4131, CPU_VR4133, CPU_VR4181, CPU_VR4181A, CPU_RM7000,
+       CPU_R4700, CPU_R5000, CPU_R5500, CPU_NEVADA, CPU_R5432, CPU_R10000,
+       CPU_R12000, CPU_R14000, CPU_VR41XX, CPU_VR4111, CPU_VR4121, CPU_VR4122,
+       CPU_VR4131, CPU_VR4133, CPU_VR4181, CPU_VR4181A, CPU_RM7000,
        CPU_SR71000, CPU_RM9000, CPU_TX49XX,
 
        /*
index eb742895dcbe97a3e7c81813c76eeec2e41bac02..881b980c72d29865ac3ff633f15c7e396ddec76c 100644 (file)
 #define PM_HUGE_MASK   PM_64M
 #elif defined(CONFIG_PAGE_SIZE_64KB)
 #define PM_HUGE_MASK   PM_256M
-#elif defined(CONFIG_HUGETLB_PAGE)
+#elif defined(CONFIG_MIPS_HUGE_TLB_SUPPORT)
 #error Bad page size configuration for hugetlbfs!
 #endif
 
index da9bd7d270d18a761f74f6168653d2eb16da7118..31ab10f02bad555724dffa1e58556bd6508cd79b 100644 (file)
 #define PAGE_SHIFT     16
 #endif
 #define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK       (~((1 << PAGE_SHIFT) - 1))
+#define PAGE_MASK       (~(PAGE_SIZE - 1))
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
 #define HPAGE_SHIFT    (PAGE_SHIFT + PAGE_SHIFT - 3)
 #define HPAGE_SIZE     (_AC(1,UL) << HPAGE_SHIFT)
 #define HPAGE_MASK     (~(HPAGE_SIZE - 1))
 #define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
-#else /* !CONFIG_HUGETLB_PAGE */
+#else /* !CONFIG_MIPS_HUGE_TLB_SUPPORT */
 #define HPAGE_SHIFT    ({BUILD_BUG(); 0; })
 #define HPAGE_SIZE     ({BUILD_BUG(); 0; })
 #define HPAGE_MASK     ({BUILD_BUG(); 0; })
 #define HUGETLB_PAGE_ORDER     ({BUILD_BUG(); 0; })
-#endif /* CONFIG_HUGETLB_PAGE */
+#endif /* CONFIG_MIPS_HUGE_TLB_SUPPORT */
 
 #ifndef __ASSEMBLY__
 
index f5b521d5a67d744e3f250c5a99e5023c77deaee0..c63191055e695c5a49812f3f32ed0c913d941a0a 100644 (file)
@@ -175,7 +175,7 @@ static inline int pmd_none(pmd_t pmd)
 
 static inline int pmd_bad(pmd_t pmd)
 {
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
        /* pmd_huge(pmd) but inline */
        if (unlikely(pmd_val(pmd) & _PAGE_HUGE))
                return 0;
index da4ba49adcf652fb9522c8c0b171f14aa4ab5247..260c0988b5f0b4c6f8d376cd9800c8a8d754b818 100644 (file)
@@ -94,7 +94,7 @@
 /* set:pagecache unset:swap */
 #define _PAGE_FILE             (_PAGE_MODIFIED)
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
 /* huge tlb page */
 #define _PAGE_HUGE_SHIFT       (_PAGE_MODIFIED_SHIFT + 1)
 #define _PAGE_HUGE             (1 << _PAGE_HUGE_SHIFT)
 #define _PAGE_HUGE             ({BUG(); 1; })  /* Dummy value */
 #endif
 
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
+/* huge tlb page */
+#define _PAGE_SPLITTING_SHIFT  (_PAGE_HUGE_SHIFT + 1)
+#define _PAGE_SPLITTING                (1 << _PAGE_SPLITTING_SHIFT)
+#else
+#define _PAGE_SPLITTING_SHIFT  (_PAGE_HUGE_SHIFT)
+#define _PAGE_SPLITTING                ({BUG(); 1; })  /* Dummy value */
+#endif
+
 /* Page cannot be executed */
-#define _PAGE_NO_EXEC_SHIFT    (cpu_has_rixi ? _PAGE_HUGE_SHIFT + 1 : _PAGE_HUGE_SHIFT)
+#define _PAGE_NO_EXEC_SHIFT    (cpu_has_rixi ? _PAGE_SPLITTING_SHIFT + 1 : _PAGE_SPLITTING_SHIFT)
 #define _PAGE_NO_EXEC          ({BUG_ON(!cpu_has_rixi); 1 << _PAGE_NO_EXEC_SHIFT; })
 
 /* Page cannot be read */
index c02158be836cc6793393eb4f3f3c094b3df1043f..252202d24a84f50c467f11dff8937863150aedab 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef _ASM_PGTABLE_H
 #define _ASM_PGTABLE_H
 
+#include <linux/mmzone.h>
 #ifdef CONFIG_32BIT
 #include <asm/pgtable-32.h>
 #endif
@@ -94,7 +95,12 @@ extern void paging_init(void);
  * and a page entry and page directory to the page they refer to.
  */
 #define pmd_phys(pmd)          virt_to_phys((void *)pmd_val(pmd))
-#define pmd_page(pmd)          (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
+
+#define __pmd_page(pmd)                (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
+#ifndef CONFIG_TRANSPARENT_HUGEPAGE
+#define pmd_page(pmd)          __pmd_page(pmd)
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE  */
+
 #define pmd_page_vaddr(pmd)    pmd_val(pmd)
 
 #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
@@ -107,7 +113,6 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
        ptep->pte_high = pte.pte_high;
        smp_wmb();
        ptep->pte_low = pte.pte_low;
-       //printk("pte_high %x pte_low %x\n", ptep->pte_high, ptep->pte_low);
 
        if (pte.pte_low & _PAGE_GLOBAL) {
                pte_t *buddy = ptep_buddy(ptep);
@@ -375,6 +380,14 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
        __update_cache(vma, address, pte);
 }
 
+static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
+       unsigned long address, pmd_t *pmdp)
+{
+       pte_t pte = *(pte_t *)pmdp;
+
+       __update_tlb(vma, address, pte);
+}
+
 #define kern_addr_valid(addr)  (1)
 
 #ifdef CONFIG_64BIT_PHYS_ADDR
@@ -394,6 +407,157 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 #endif
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+
+extern int has_transparent_hugepage(void);
+
+static inline int pmd_trans_huge(pmd_t pmd)
+{
+       return !!(pmd_val(pmd) & _PAGE_HUGE);
+}
+
+static inline pmd_t pmd_mkhuge(pmd_t pmd)
+{
+       pmd_val(pmd) |= _PAGE_HUGE;
+
+       return pmd;
+}
+
+static inline int pmd_trans_splitting(pmd_t pmd)
+{
+       return !!(pmd_val(pmd) & _PAGE_SPLITTING);
+}
+
+static inline pmd_t pmd_mksplitting(pmd_t pmd)
+{
+       pmd_val(pmd) |= _PAGE_SPLITTING;
+
+       return pmd;
+}
+
+extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+                      pmd_t *pmdp, pmd_t pmd);
+
+#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
+/* Extern to avoid header file madness */
+extern void pmdp_splitting_flush(struct vm_area_struct *vma,
+                                       unsigned long address,
+                                       pmd_t *pmdp);
+
+#define __HAVE_ARCH_PMD_WRITE
+static inline int pmd_write(pmd_t pmd)
+{
+       return !!(pmd_val(pmd) & _PAGE_WRITE);
+}
+
+static inline pmd_t pmd_wrprotect(pmd_t pmd)
+{
+       pmd_val(pmd) &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE);
+       return pmd;
+}
+
+static inline pmd_t pmd_mkwrite(pmd_t pmd)
+{
+       pmd_val(pmd) |= _PAGE_WRITE;
+       if (pmd_val(pmd) & _PAGE_MODIFIED)
+               pmd_val(pmd) |= _PAGE_SILENT_WRITE;
+
+       return pmd;
+}
+
+static inline int pmd_dirty(pmd_t pmd)
+{
+       return !!(pmd_val(pmd) & _PAGE_MODIFIED);
+}
+
+static inline pmd_t pmd_mkclean(pmd_t pmd)
+{
+       pmd_val(pmd) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE);
+       return pmd;
+}
+
+static inline pmd_t pmd_mkdirty(pmd_t pmd)
+{
+       pmd_val(pmd) |= _PAGE_MODIFIED;
+       if (pmd_val(pmd) & _PAGE_WRITE)
+               pmd_val(pmd) |= _PAGE_SILENT_WRITE;
+
+       return pmd;
+}
+
+static inline int pmd_young(pmd_t pmd)
+{
+       return !!(pmd_val(pmd) & _PAGE_ACCESSED);
+}
+
+static inline pmd_t pmd_mkold(pmd_t pmd)
+{
+       pmd_val(pmd) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ);
+
+       return pmd;
+}
+
+static inline pmd_t pmd_mkyoung(pmd_t pmd)
+{
+       pmd_val(pmd) |= _PAGE_ACCESSED;
+
+       if (cpu_has_rixi) {
+               if (!(pmd_val(pmd) & _PAGE_NO_READ))
+                       pmd_val(pmd) |= _PAGE_SILENT_READ;
+       } else {
+               if (pmd_val(pmd) & _PAGE_READ)
+                       pmd_val(pmd) |= _PAGE_SILENT_READ;
+       }
+
+       return pmd;
+}
+
+/* Extern to avoid header file madness */
+extern pmd_t mk_pmd(struct page *page, pgprot_t prot);
+
+static inline unsigned long pmd_pfn(pmd_t pmd)
+{
+       return pmd_val(pmd) >> _PFN_SHIFT;
+}
+
+static inline struct page *pmd_page(pmd_t pmd)
+{
+       if (pmd_trans_huge(pmd))
+               return pfn_to_page(pmd_pfn(pmd));
+
+       return pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT);
+}
+
+static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+       pmd_val(pmd) = (pmd_val(pmd) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+       return pmd;
+}
+
+static inline pmd_t pmd_mknotpresent(pmd_t pmd)
+{
+       pmd_val(pmd) &= ~(_PAGE_PRESENT | _PAGE_VALID | _PAGE_DIRTY);
+
+       return pmd;
+}
+
+/*
+ * The generic version pmdp_get_and_clear uses a version of pmd_clear() with a
+ * different prototype.
+ */
+#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
+static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
+                                      unsigned long address, pmd_t *pmdp)
+{
+       pmd_t old = *pmdp;
+
+       pmd_clear(pmdp);
+
+       return old;
+}
+
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
 #include <asm-generic/pgtable.h>
 
 /*
index 5e33fabe354de7e12e11dc4f64aa5d0be7464090..8481c1a5219e53fada0b343ca4219fa414fa81d2 100644 (file)
@@ -226,8 +226,6 @@ struct thread_struct {
        unsigned long cp0_badvaddr;     /* Last user fault */
        unsigned long cp0_baduaddr;     /* Last kernel fault accessing USEG */
        unsigned long error_code;
-       unsigned long irix_trampoline;  /* Wheee... */
-       unsigned long irix_oldctx;
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
     struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128)));
     struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128)));
@@ -297,8 +295,6 @@ struct thread_struct {
        .cp0_badvaddr           = 0,                            \
        .cp0_baduaddr           = 0,                            \
        .error_code             = 0,                            \
-       .irix_trampoline        = 0,                            \
-       .irix_oldctx            = 0,                            \
        /*                                                      \
         * Cavium Octeon specifics (null if not Octeon)         \
         */                                                     \
index 4461198361c9760fa5afed8a101af0fa89207bc0..65900dab3ad382825143d66d7f206f93d561e34d 100644 (file)
@@ -6,7 +6,7 @@
  * SECTION_SIZE_BITS           2^N: how big each section will be
  * MAX_PHYSMEM_BITS            2^N: how much memory we can have in that space
  */
-#if defined(CONFIG_HUGETLB_PAGE) && defined(CONFIG_PAGE_SIZE_64KB)
+#if defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) && defined(CONFIG_PAGE_SIZE_64KB)
 # define SECTION_SIZE_BITS     29
 #else
 # define SECTION_SIZE_BITS     28
index bb8f5c29c3d9f9a5e0c72c4497993fec46fcfae2..89571466524e00a94e2574797814966017a31196 100644 (file)
@@ -12,5 +12,6 @@
  * TLB debugging functions:
  */
 extern void dump_tlb_all(void);
+extern void dump_current_addr(unsigned long addr);
 
 #endif /* __ASM_TLBDEBUG_H */
index 0c4bce4882a6621d18ff0450b3f464e3722059b6..9690998d4ef3e9e99b5628cbb4bf297c90158a10 100644 (file)
@@ -125,10 +125,6 @@ void output_thread_defines(void)
               thread.cp0_baduaddr);
        OFFSET(THREAD_ECODE, task_struct, \
               thread.error_code);
-       OFFSET(THREAD_TRAMP, task_struct, \
-              thread.irix_trampoline);
-       OFFSET(THREAD_OLDCTX, task_struct, \
-              thread.irix_oldctx);
        BLANK();
 }
 
index 3fc1691110dc52f82e8ec1271054c1411c122658..1ba8933683aaead539bf5beefb2f273f150e1ba8 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/export.h>
 #include <asm/checksum.h>
-#include <asm/pgtable.h>
+#include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/ftrace.h>
 
index f6ba8381ee0186c5dfc1f19879ae4c39d15d52e9..9c721dd84ba101885bd710d284ce46d9251a7672 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
 
-/* This duplicates the definition from <linux/sched.h> */
-#define PT_TRACESYS    0x00000002      /* tracing system calls */
-
-/* This duplicates the definition from <asm/signal.h> */
-#define SIGILL         4               /* Illegal instruction (ANSI).  */
-
 #ifndef CONFIG_MIPS32_O32
 /* No O32, so define handle_sys here */
 #define handle_sysn32 handle_sys
index 0e1a5b8ae817c4c69f417f3aff2d9aade7a5cad0..b6aa77035019bc4913468fbf551f21ef9e9898aa 100644 (file)
@@ -568,17 +568,20 @@ static void do_signal(struct pt_regs *regs)
        }
 
        if (regs->regs[0]) {
-               if (regs->regs[2] == ERESTARTNOHAND ||
-                   regs->regs[2] == ERESTARTSYS ||
-                   regs->regs[2] == ERESTARTNOINTR) {
+               switch (regs->regs[2]) {
+               case ERESTARTNOHAND:
+               case ERESTARTSYS:
+               case ERESTARTNOINTR:
                        regs->regs[2] = regs->regs[0];
                        regs->regs[7] = regs->regs[26];
                        regs->cp0_epc -= 4;
-               }
-               if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
+                       break;
+
+               case ERESTART_RESTARTBLOCK:
                        regs->regs[2] = current->thread.abi->restart;
                        regs->regs[7] = regs->regs[26];
                        regs->cp0_epc -= 4;
+                       break;
                }
                regs->regs[0] = 0;      /* Don't deal with this again.  */
        }
index a99c1d3fc56769dc91f58ce64e117e0eb8533b44..2d7a91aa83607c67c11616443bf45109ddc9b14f 100644 (file)
@@ -5,11 +5,14 @@
  * Copyright (C) 1999 by Silicon Graphics, Inc.
  */
 #include <linux/kernel.h>
+#include <linux/hugetlb.h>
 #include <linux/mm.h>
+#include <linux/sched.h>
 
 #include <asm/mipsregs.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/current.h>
 #include <asm/tlbdebug.h>
 
 static inline const char *msk2str(unsigned int mask)
@@ -111,3 +114,47 @@ void dump_tlb_all(void)
 {
        dump_tlb(0, current_cpu_data.tlbsize - 1);
 }
+
+void dump_current_addr(unsigned long addr)
+{
+       pgd_t *pgdp;
+       pud_t *pudp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+       pte_t pte;
+
+       printk("Dumping for address %lx\n", addr);
+       pgdp = pgd_offset(current->mm, addr);
+       printk("pgd %lx\n", pgd_val(*pgdp));
+
+       pudp = pud_offset(pgdp, addr);
+       printk("pud %lx", pud_val(*pudp));
+#ifndef __PAGETABLE_PMD_FOLDED
+       if (pud_val(*pudp) == (unsigned long) invalid_pmd_table) {
+               printk("  (invalid_pmd_table)\n");
+
+               return;
+       }
+#endif
+       printk("\n");
+
+       pmdp = pmd_offset(pudp, addr);
+       printk("pmd  %lx", pmd_val(*pmdp));
+       if (pmd_huge(*pmdp)) {
+               printk("  pmd is huge\n");
+
+               return;
+       }
+       if (pmd_val(*pmdp) == (unsigned long) invalid_pte_table) {
+               printk("  (invalid_pte_table)\n");
+
+               return;
+       }
+       printk("\n");
+
+       ptep = pte_offset_map(pmdp, addr);
+       pte = *ptep;
+       printk("pte %lx\n", pte_val(pte));
+       if (pte_huge(pte))
+               printk("  pte is huge\n");
+}
index 44e69e7a4519110b3efd1e30a755a8ec3e0692ea..9f67553762d5e606bb8aeced4766598d4f86d455 100644 (file)
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2005-2007 Cavium Networks
  */
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -28,6 +29,7 @@
 #include <asm/octeon/octeon.h>
 
 unsigned long long cache_err_dcache[NR_CPUS];
+EXPORT_SYMBOL_GPL(cache_err_dcache);
 
 /**
  * Octeon automatically flushes the dcache on tlb changes, so
@@ -288,42 +290,42 @@ void __cpuinit octeon_cache_init(void)
  * Handle a cache error exception
  */
 
-static void  cache_parity_error_octeon(int non_recoverable)
+static RAW_NOTIFIER_HEAD(co_cache_error_chain);
+
+int register_co_cache_error_notifier(struct notifier_block *nb)
 {
-       unsigned long coreid = cvmx_get_core_num();
-       uint64_t icache_err = read_octeon_c0_icacheerr();
-
-       pr_err("Cache error exception:\n");
-       pr_err("cp0_errorepc == %lx\n", read_c0_errorepc());
-       if (icache_err & 1) {
-               pr_err("CacheErr (Icache) == %llx\n",
-                      (unsigned long long)icache_err);
-               write_octeon_c0_icacheerr(0);
-       }
-       if (cache_err_dcache[coreid] & 1) {
-               pr_err("CacheErr (Dcache) == %llx\n",
-                      (unsigned long long)cache_err_dcache[coreid]);
-               cache_err_dcache[coreid] = 0;
-       }
+       return raw_notifier_chain_register(&co_cache_error_chain, nb);
+}
+EXPORT_SYMBOL_GPL(register_co_cache_error_notifier);
 
-       if (non_recoverable)
-               panic("Can't handle cache error: nested exception");
+int unregister_co_cache_error_notifier(struct notifier_block *nb)
+{
+       return raw_notifier_chain_unregister(&co_cache_error_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_co_cache_error_notifier);
+
+static inline int co_cache_error_call_notifiers(unsigned long val)
+{
+       return raw_notifier_call_chain(&co_cache_error_chain, val, NULL);
 }
 
 /**
  * Called when the the exception is recoverable
  */
-
 asmlinkage void cache_parity_error_octeon_recoverable(void)
 {
-       cache_parity_error_octeon(0);
+       co_cache_error_call_notifiers(0);
 }
 
 /**
  * Called when the the exception is not recoverable
+ *
+ * The issue not that the cache error exception itself was non-recoverable
+ * but that due to nesting of exception may have lost some state so can't
+ * continue.
  */
-
 asmlinkage void cache_parity_error_octeon_non_recoverable(void)
 {
-       cache_parity_error_octeon(1);
+       co_cache_error_call_notifiers(1);
+       panic("Can't handle cache error: nested exception");
 }
index 25407794edb4ff875bba1acb9ac5c4fa632ae78c..ee331bbd8f8aa13c263b8aa31c6bfdbab75e1101 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/fixmap.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
 
 void pgd_init(unsigned long page)
 {
@@ -61,6 +62,36 @@ void pmd_init(unsigned long addr, unsigned long pagetable)
 }
 #endif
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+
+void pmdp_splitting_flush(struct vm_area_struct *vma,
+                        unsigned long address,
+                        pmd_t *pmdp)
+{
+       if (!pmd_trans_splitting(*pmdp)) {
+               pmd_t pmd = pmd_mksplitting(*pmdp);
+               set_pmd_at(vma->vm_mm, address, pmdp, pmd);
+       }
+}
+
+#endif
+
+pmd_t mk_pmd(struct page *page, pgprot_t prot)
+{
+       pmd_t pmd;
+
+       pmd_val(pmd) = (page_to_pfn(page) << _PFN_SHIFT) | pgprot_val(prot);
+
+       return pmd;
+}
+
+void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+               pmd_t *pmdp, pmd_t pmd)
+{
+       *pmdp = pmd;
+       flush_tlb_all();
+}
+
 void __init pagetable_init(void)
 {
        unsigned long vaddr;
index 4b9b935a070e0c4d0160f2c259c3dc553c40b35e..94ad86d055c5e15df38d4748824870804a3aedfc 100644 (file)
@@ -305,7 +305,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
        pudp = pud_offset(pgdp, address);
        pmdp = pmd_offset(pudp, address);
        idx = read_c0_index();
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
        /* this could be a huge page  */
        if (pmd_huge(*pmdp)) {
                unsigned long lo;
@@ -377,6 +377,26 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
        EXIT_CRITICAL(flags);
 }
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+
+int __init has_transparent_hugepage(void)
+{
+       unsigned int mask;
+       unsigned long flags;
+
+       ENTER_CRITICAL(flags);
+       write_c0_pagemask(PM_HUGE_MASK);
+       back_to_back_c0_hazard();
+       mask = read_c0_pagemask();
+       write_c0_pagemask(PM_DEFAULT_MASK);
+
+       EXIT_CRITICAL(flags);
+
+       return mask == PM_HUGE_MASK;
+}
+
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE  */
+
 static int __cpuinitdata ntlb;
 static int __init set_ntlb(char *str)
 {
index 2833dcb67b5adeaf838536580728176bbc715a77..852ea95da10573ec07f3fd43f61a22a96d9154a3 100644 (file)
@@ -158,7 +158,7 @@ enum label_id {
        label_smp_pgtable_change,
        label_r3000_write_probe_fail,
        label_large_segbits_fault,
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
        label_tlb_huge_update,
 #endif
 };
@@ -177,7 +177,7 @@ UASM_L_LA(_nopage_tlbm)
 UASM_L_LA(_smp_pgtable_change)
 UASM_L_LA(_r3000_write_probe_fail)
 UASM_L_LA(_large_segbits_fault)
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
 UASM_L_LA(_tlb_huge_update)
 #endif
 
@@ -206,19 +206,55 @@ static void uasm_bgezl_label(struct uasm_label **l, u32 **p, int instance)
 }
 
 /*
- * For debug purposes.
+ * pgtable bits are assigned dynamically depending on processor feature
+ * and statically based on kernel configuration.  This spits out the actual
+ * values the kernel is using.  Required to make sense from disassembled
+ * TLB exception handlers.
  */
-static inline void dump_handler(const u32 *handler, int count)
+static void output_pgtable_bits_defines(void)
+{
+#define pr_define(fmt, ...)                                    \
+       pr_debug("#define " fmt, ##__VA_ARGS__)
+
+       pr_debug("#include <asm/asm.h>\n");
+       pr_debug("#include <asm/regdef.h>\n");
+       pr_debug("\n");
+
+       pr_define("_PAGE_PRESENT_SHIFT %d\n", _PAGE_PRESENT_SHIFT);
+       pr_define("_PAGE_READ_SHIFT %d\n", _PAGE_READ_SHIFT);
+       pr_define("_PAGE_WRITE_SHIFT %d\n", _PAGE_WRITE_SHIFT);
+       pr_define("_PAGE_ACCESSED_SHIFT %d\n", _PAGE_ACCESSED_SHIFT);
+       pr_define("_PAGE_MODIFIED_SHIFT %d\n", _PAGE_MODIFIED_SHIFT);
+       pr_define("_PAGE_HUGE_SHIFT %d\n", _PAGE_HUGE_SHIFT);
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
+       pr_define("_PAGE_SPLITTING_SHIFT %d\n", _PAGE_SPLITTING_SHIFT);
+#endif
+       if (cpu_has_rixi) {
+               pr_define("_PAGE_NO_EXEC_SHIFT %d\n", _PAGE_NO_EXEC_SHIFT);
+               pr_define("_PAGE_NO_READ_SHIFT %d\n", _PAGE_NO_READ_SHIFT);
+       }
+       pr_define("_PAGE_GLOBAL_SHIFT %d\n", _PAGE_GLOBAL_SHIFT);
+       pr_define("_PAGE_VALID_SHIFT %d\n", _PAGE_VALID_SHIFT);
+       pr_define("_PAGE_DIRTY_SHIFT %d\n", _PAGE_DIRTY_SHIFT);
+       pr_define("_PFN_SHIFT %d\n", _PFN_SHIFT);
+       pr_debug("\n");
+}
+
+static inline void dump_handler(const char *symbol, const u32 *handler, int count)
 {
        int i;
 
+       pr_debug("LEAF(%s)\n", symbol);
+
        pr_debug("\t.set push\n");
        pr_debug("\t.set noreorder\n");
 
        for (i = 0; i < count; i++)
-               pr_debug("\t%p\t.word 0x%08x\n", &handler[i], handler[i]);
+               pr_debug("\t.word\t0x%08x\t\t# %p\n", handler[i], &handler[i]);
 
-       pr_debug("\t.set pop\n");
+       pr_debug("\t.set\tpop\n");
+
+       pr_debug("\tEND(%s)\n", symbol);
 }
 
 /* The only general purpose registers allowed in TLB handlers. */
@@ -401,7 +437,7 @@ static void __cpuinit build_r3000_tlb_refill_handler(void)
 
        memcpy((void *)ebase, tlb_handler, 0x80);
 
-       dump_handler((u32 *)ebase, 32);
+       dump_handler("r3000_tlb_refill", (u32 *)ebase, 32);
 }
 #endif /* CONFIG_MIPS_PGD_C0_CONTEXT */
 
@@ -443,7 +479,6 @@ static void __cpuinit __maybe_unused build_tlb_probe_entry(u32 **p)
        case CPU_R4600:
        case CPU_R4700:
        case CPU_R5000:
-       case CPU_R5000A:
        case CPU_NEVADA:
                uasm_i_nop(p);
                uasm_i_tlbp(p);
@@ -517,7 +552,6 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
                break;
 
        case CPU_R5000:
-       case CPU_R5000A:
        case CPU_NEVADA:
                uasm_i_nop(p); /* QED specifies 2 nops hazard */
                uasm_i_nop(p); /* QED specifies 2 nops hazard */
@@ -629,7 +663,7 @@ static __cpuinit __maybe_unused void build_convert_pte_to_entrylo(u32 **p,
        }
 }
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
 
 static __cpuinit void build_restore_pagemask(u32 **p,
                                             struct uasm_reloc **r,
@@ -755,7 +789,7 @@ static __cpuinit void build_huge_handler_tail(u32 **p,
        build_huge_update_entries(p, pte, ptr);
        build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed, 0);
 }
-#endif /* CONFIG_HUGETLB_PAGE */
+#endif /* CONFIG_MIPS_HUGE_TLB_SUPPORT */
 
 #ifdef CONFIG_64BIT
 /*
@@ -1200,7 +1234,7 @@ build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
        /* Adjust the context during the load latency. */
        build_adjust_context(p, tmp);
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
        uasm_il_bbit1(p, r, scratch, ilog2(_PAGE_HUGE), label_tlb_huge_update);
        /*
         * The in the LWX case we don't want to do the load in the
@@ -1209,7 +1243,7 @@ build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
         */
        if (use_lwx_insns())
                uasm_i_nop(p);
-#endif /* CONFIG_HUGETLB_PAGE */
+#endif /* CONFIG_MIPS_HUGE_TLB_SUPPORT */
 
 
        /* build_update_entries */
@@ -1312,7 +1346,7 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
                build_get_pgde32(&p, K0, K1); /* get pgd in K1 */
 #endif
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
                build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update);
 #endif
 
@@ -1322,7 +1356,7 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
                uasm_l_leave(&l, p);
                uasm_i_eret(&p); /* return from trap */
        }
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
        uasm_l_tlb_huge_update(&l, p);
        build_huge_update_entries(&p, htlb_info.huge_pte, K1);
        build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random,
@@ -1367,7 +1401,7 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
                uasm_copy_handler(relocs, labels, tlb_handler, p, f);
                final_len = p - tlb_handler;
        } else {
-#if defined(CONFIG_HUGETLB_PAGE)
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
                const enum label_id ls = label_tlb_huge_update;
 #else
                const enum label_id ls = label_vmalloc;
@@ -1436,7 +1470,7 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
 
        memcpy((void *)ebase, final_handler, 0x100);
 
-       dump_handler((u32 *)ebase, 64);
+       dump_handler("r4000_tlb_refill", (u32 *)ebase, 64);
 }
 
 /*
@@ -1493,7 +1527,8 @@ static void __cpuinit build_r4000_setup_pgd(void)
        pr_debug("Wrote tlbmiss_handler_setup_pgd (%u instructions).\n",
                 (unsigned int)(p - tlbmiss_handler_setup_pgd));
 
-       dump_handler(tlbmiss_handler_setup_pgd,
+       dump_handler("tlbmiss_handler",
+                    tlbmiss_handler_setup_pgd,
                     ARRAY_SIZE(tlbmiss_handler_setup_pgd));
 }
 #endif
@@ -1763,7 +1798,7 @@ static void __cpuinit build_r3000_tlb_load_handler(void)
        pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbl));
 
-       dump_handler(handle_tlbl, ARRAY_SIZE(handle_tlbl));
+       dump_handler("r3000_tlb_load", handle_tlbl, ARRAY_SIZE(handle_tlbl));
 }
 
 static void __cpuinit build_r3000_tlb_store_handler(void)
@@ -1793,7 +1828,7 @@ static void __cpuinit build_r3000_tlb_store_handler(void)
        pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbs));
 
-       dump_handler(handle_tlbs, ARRAY_SIZE(handle_tlbs));
+       dump_handler("r3000_tlb_store", handle_tlbs, ARRAY_SIZE(handle_tlbs));
 }
 
 static void __cpuinit build_r3000_tlb_modify_handler(void)
@@ -1823,7 +1858,7 @@ static void __cpuinit build_r3000_tlb_modify_handler(void)
        pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbm));
 
-       dump_handler(handle_tlbm, ARRAY_SIZE(handle_tlbm));
+       dump_handler("r3000_tlb_modify", handle_tlbm, ARRAY_SIZE(handle_tlbm));
 }
 #endif /* CONFIG_MIPS_PGD_C0_CONTEXT */
 
@@ -1842,7 +1877,7 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
        build_get_pgde32(p, wr.r1, wr.r2); /* get pgd in ptr */
 #endif
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
        /*
         * For huge tlb entries, pmd doesn't contain an address but
         * instead contains the tlb pte. Check the PAGE_HUGE bit and
@@ -1958,7 +1993,7 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
        build_make_valid(&p, &r, wr.r1, wr.r2);
        build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2);
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
        /*
         * This is the entry point when build_r4000_tlbchange_handler_head
         * spots a huge page.
@@ -2030,7 +2065,7 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
        pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbl));
 
-       dump_handler(handle_tlbl, ARRAY_SIZE(handle_tlbl));
+       dump_handler("r4000_tlb_load", handle_tlbl, ARRAY_SIZE(handle_tlbl));
 }
 
 static void __cpuinit build_r4000_tlb_store_handler(void)
@@ -2051,7 +2086,7 @@ static void __cpuinit build_r4000_tlb_store_handler(void)
        build_make_write(&p, &r, wr.r1, wr.r2);
        build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2);
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
        /*
         * This is the entry point when
         * build_r4000_tlbchange_handler_head spots a huge page.
@@ -2077,7 +2112,7 @@ static void __cpuinit build_r4000_tlb_store_handler(void)
        pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbs));
 
-       dump_handler(handle_tlbs, ARRAY_SIZE(handle_tlbs));
+       dump_handler("r4000_tlb_store", handle_tlbs, ARRAY_SIZE(handle_tlbs));
 }
 
 static void __cpuinit build_r4000_tlb_modify_handler(void)
@@ -2099,7 +2134,7 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
        build_make_write(&p, &r, wr.r1, wr.r2);
        build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2);
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
        /*
         * This is the entry point when
         * build_r4000_tlbchange_handler_head spots a huge page.
@@ -2125,7 +2160,7 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
        pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbm));
 
-       dump_handler(handle_tlbm, ARRAY_SIZE(handle_tlbm));
+       dump_handler("r4000_tlb_modify", handle_tlbm, ARRAY_SIZE(handle_tlbm));
 }
 
 void __cpuinit build_tlb_refill_handler(void)
@@ -2137,6 +2172,8 @@ void __cpuinit build_tlb_refill_handler(void)
         */
        static int run_once = 0;
 
+       output_pgtable_bits_defines();
+
 #ifdef CONFIG_64BIT
        check_for_high_segbits = current_cpu_data.vmbits > (PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3);
 #endif
index 4b0c347d7a8241d1279a11efc84c873ee2a85650..8eb2ee345d0322dfc326e8b64769ce89aedd19f1 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/time.h>
 #include <linux/delay.h>
+#include <linux/platform_device.h>
 #include <linux/swiotlb.h>
 
 #include <asm/time.h>
@@ -704,6 +705,9 @@ static int __init octeon_pci_setup(void)
         */
        cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, -1);
 
+       if (IS_ERR(platform_device_register_simple("co_pci_edac", 0, NULL, 0)))
+               pr_err("Registation of co_pci_edac failed!\n");
+
        octeon_pci_dma_init();
 
        return 0;
index 409b92b8d346087b4ec292bda8790d03cc764224..a9db20815a39152ed130a41ebf9e6c4b79bcb829 100644 (file)
@@ -7,7 +7,7 @@
 menuconfig EDAC
        bool "EDAC (Error Detection And Correction) reporting"
        depends on HAS_IOMEM
-       depends on X86 || PPC || TILE || ARM
+       depends on X86 || PPC || TILE || ARM || EDAC_SUPPORT
        help
          EDAC is designed to report errors in the core system.
          These are low-level errors that are reported in the CPU or
@@ -27,6 +27,9 @@ menuconfig EDAC
          There is also a mailing list for the EDAC project, which can
          be found via the sourceforge page.
 
+config EDAC_SUPPORT
+       bool
+
 if EDAC
 
 comment "Reporting subsystems"
@@ -316,4 +319,32 @@ config EDAC_HIGHBANK_L2
          Support for error detection and correction on the
          Calxeda Highbank memory controller.
 
+config EDAC_OCTEON_PC
+       tristate "Cavium Octeon Primary Caches"
+       depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
+       help
+         Support for error detection and correction on the primary caches of
+         the cnMIPS cores of Cavium Octeon family SOCs.
+
+config EDAC_OCTEON_L2C
+       tristate "Cavium Octeon Secondary Caches (L2C)"
+       depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
+       help
+         Support for error detection and correction on the
+         Cavium Octeon family of SOCs.
+
+config EDAC_OCTEON_LMC
+       tristate "Cavium Octeon DRAM Memory Controller (LMC)"
+       depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
+       help
+         Support for error detection and correction on the
+         Cavium Octeon family of SOCs.
+
+config EDAC_OCTEON_PCI
+       tristate "Cavium Octeon PCI Controller"
+       depends on EDAC_MM_EDAC && PCI && CPU_CAVIUM_OCTEON
+       help
+         Support for error detection and correction on the
+         Cavium Octeon family of SOCs.
+
 endif # EDAC
index 7e5129a733f8cc6b8afdc7dac91228167949512d..5608a9ba61b7aaf442564feac6e586c6a26588cf 100644 (file)
@@ -58,3 +58,8 @@ obj-$(CONFIG_EDAC_TILE)                       += tile_edac.o
 
 obj-$(CONFIG_EDAC_HIGHBANK_MC) += highbank_mc_edac.o
 obj-$(CONFIG_EDAC_HIGHBANK_L2) += highbank_l2_edac.o
+
+obj-$(CONFIG_EDAC_OCTEON_PC)           += octeon_edac-pc.o
+obj-$(CONFIG_EDAC_OCTEON_L2C)          += octeon_edac-l2c.o
+obj-$(CONFIG_EDAC_OCTEON_LMC)          += octeon_edac-lmc.o
+obj-$(CONFIG_EDAC_OCTEON_PCI)          += octeon_edac-pci.o
diff --git a/drivers/edac/octeon_edac-l2c.c b/drivers/edac/octeon_edac-l2c.c
new file mode 100644 (file)
index 0000000..5f459aa
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Wind River Systems,
+ *   written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/edac.h>
+
+#include <asm/octeon/cvmx.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_MOD_STR "octeon-l2c"
+
+static void co_l2c_poll(struct edac_device_ctl_info *l2c)
+{
+       union cvmx_l2t_err l2t_err;
+
+       l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
+       if (l2t_err.s.sec_err) {
+               edac_device_handle_ce(l2c, 0, 0,
+                                     "Single bit error (corrected)");
+               l2t_err.s.sec_err = 1;          /* Reset */
+               cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
+       }
+       if (l2t_err.s.ded_err) {
+               edac_device_handle_ue(l2c, 0, 0,
+                                     "Double bit error (corrected)");
+               l2t_err.s.ded_err = 1;          /* Reset */
+               cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
+       }
+}
+
+static int __devinit co_l2c_probe(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *l2c;
+       union cvmx_l2t_err l2t_err;
+       int res = 0;
+
+       l2c = edac_device_alloc_ctl_info(0, "l2c", 1, NULL, 0, 0,
+                                        NULL, 0, edac_device_alloc_index());
+       if (!l2c)
+               return -ENOMEM;
+
+       l2c->dev = &pdev->dev;
+       platform_set_drvdata(pdev, l2c);
+       l2c->dev_name = dev_name(&pdev->dev);
+
+       l2c->mod_name = "octeon-l2c";
+       l2c->ctl_name = "octeon_l2c_err";
+       l2c->edac_check = co_l2c_poll;
+
+       if (edac_device_add_device(l2c) > 0) {
+               pr_err("%s: edac_device_add_device() failed\n", __func__);
+               goto err;
+       }
+
+       l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
+       l2t_err.s.sec_intena = 0;       /* We poll */
+       l2t_err.s.ded_intena = 0;
+       l2t_err.s.sec_err = 1;          /* Clear, just in case */
+       l2t_err.s.ded_err = 1;
+       cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
+
+       return 0;
+
+err:
+       edac_device_free_ctl_info(l2c);
+
+       return res;
+}
+
+static int co_l2c_remove(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *l2c = platform_get_drvdata(pdev);
+
+       edac_device_del_device(&pdev->dev);
+       edac_device_free_ctl_info(l2c);
+
+       return 0;
+}
+
+static struct platform_driver co_l2c_driver = {
+       .probe = co_l2c_probe,
+       .remove = co_l2c_remove,
+       .driver = {
+                  .name = "co_l2c_edac",
+       }
+};
+
+static int __init co_edac_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&co_l2c_driver);
+       if (ret)
+               pr_warning(EDAC_MOD_STR " EDAC failed to register\n");
+
+       return ret;
+}
+
+static void __exit co_edac_exit(void)
+{
+       platform_driver_unregister(&co_l2c_driver);
+}
+
+module_init(co_edac_init);
+module_exit(co_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c
new file mode 100644 (file)
index 0000000..e0c1e44
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Wind River Systems,
+ *   written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/edac.h>
+
+#include <asm/octeon/cvmx.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+#include "octeon_edac-lmc.h"
+
+#define EDAC_MOD_STR "octeon"
+
+static struct mem_ctl_info *mc_cavium;
+static void *lmc_base;
+
+static void co_lmc_poll(struct mem_ctl_info *mci)
+{
+       union lmc_mem_cfg0 cfg0;
+       union lmc_fadr fadr;
+       char msg[64];
+
+       fadr.u64 = readq(lmc_base + LMC_FADR);
+       cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0);
+       snprintf(msg, sizeof(msg), "DIMM %d rank %d bank %d row %d col %d",
+               fadr.fdimm, fadr.fbunk, fadr.fbank, fadr.frow, fadr.fcol);
+
+       if (cfg0.sec_err) {
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
+                                    msg, "");
+
+               cfg0.intr_sec_ena = -1;         /* Done, re-arm */
+       }
+
+       if (cfg0.ded_err) {
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
+                                    msg, "");
+               cfg0.intr_ded_ena = -1;         /* Done, re-arm */
+       }
+
+       writeq(cfg0.u64, lmc_base + LMC_MEM_CFG0);
+}
+
+static int __devinit co_lmc_probe(struct platform_device *pdev)
+{
+       struct mem_ctl_info *mci;
+       union lmc_mem_cfg0 cfg0;
+       int res = 0;
+
+       mci = edac_mc_alloc(0, 0, 0, 0);
+       if (!mci)
+               return -ENOMEM;
+
+       mci->pdev = &pdev->dev;
+       platform_set_drvdata(pdev, mci);
+       mci->dev_name = dev_name(&pdev->dev);
+
+       mci->mod_name = "octeon-lmc";
+       mci->ctl_name = "co_lmc_err";
+       mci->edac_check = co_lmc_poll;
+
+       if (edac_mc_add_mc(mci) > 0) {
+               pr_err("%s: edac_mc_add_mc() failed\n", __func__);
+               goto err;
+       }
+
+       cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0);      /* We poll */
+       cfg0.intr_ded_ena = 0;
+       cfg0.intr_sec_ena = 0;
+       writeq(cfg0.u64, lmc_base + LMC_MEM_CFG0);
+
+       mc_cavium = mci;
+
+       return 0;
+
+err:
+       edac_mc_free(mci);
+
+       return res;
+}
+
+static int co_lmc_remove(struct platform_device *pdev)
+{
+       struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+       mc_cavium = NULL;
+       edac_mc_del_mc(&pdev->dev);
+       edac_mc_free(mci);
+
+       return 0;
+}
+
+static struct platform_driver co_lmc_driver = {
+       .probe = co_lmc_probe,
+       .remove = co_lmc_remove,
+       .driver = {
+                  .name = "co_lmc_edac",
+       }
+};
+
+static int __init co_edac_init(void)
+{
+       union lmc_mem_cfg0 cfg0;
+       int ret;
+
+       lmc_base = ioremap_nocache(LMC_BASE, LMC_SIZE);
+       if (!lmc_base)
+               return -ENOMEM;
+
+       cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0);
+       if (!cfg0.ecc_ena) {
+               pr_info(EDAC_MOD_STR " LMC EDAC: ECC disabled, good bye\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       ret = platform_driver_register(&co_lmc_driver);
+       if (ret) {
+               pr_warning(EDAC_MOD_STR " LMC EDAC failed to register\n");
+               goto out;
+       }
+
+       return ret;
+
+out:
+       iounmap(lmc_base);
+
+       return ret;
+}
+
+static void __exit co_edac_exit(void)
+{
+       platform_driver_unregister(&co_lmc_driver);
+       iounmap(lmc_base);
+}
+
+module_init(co_edac_init);
+module_exit(co_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
diff --git a/drivers/edac/octeon_edac-lmc.h b/drivers/edac/octeon_edac-lmc.h
new file mode 100644 (file)
index 0000000..246dc52
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * LMC Registers, see chapter 2.5
+ *
+ * These are RSL Type registers and are accessed indirectly across the
+ * I/O bus, so accesses are slowish.  Not that it matters.  Any size load is
+ * ok but stores must be 64-bit.
+ */
+#define LMC_BASE               0x0001180088000000
+#define LMC_SIZE               0xb8
+
+#define LMC_MEM_CFG0           0x0000000000000000
+#define LMC_MEM_CFG1           0x0000000000000008
+#define LMC_CTL                        0x0000000000000010
+#define LMC_DDR2_CTL           0x0000000000000018
+#define LMC_FADR               0x0000000000000020
+#define   LMC_FADR_FDIMM
+#define   LMC_FADR_FBUNK
+#define   LMC_FADR_FBANK
+#define   LMC_FADR_FROW
+#define   LMC_FADR_FCOL
+#define LMC_COMP_CTL           0x0000000000000028
+#define LMC_WODT_CTL           0x0000000000000030
+#define LMC_ECC_SYND           0x0000000000000038
+#define LMC_IFB_CNT_LO         0x0000000000000048
+#define LMC_IFB_CNT_HI         0x0000000000000050
+#define LMC_OPS_CNT_LO         0x0000000000000058
+#define LMC_OPS_CNT_HI         0x0000000000000060
+#define LMC_DCLK_CNT_LO                0x0000000000000068
+#define LMC_DCLK_CNT_HI                0x0000000000000070
+#define LMC_DELAY_CFG          0x0000000000000088
+#define LMC_CTL1               0x0000000000000090
+#define LMC_DUAL_MEM_CONFIG    0x0000000000000098
+#define LMC_RODT_COMP_CTL      0x00000000000000A0
+#define LMC_PLL_CTL            0x00000000000000A8
+#define LMC_PLL_STATUS         0x00000000000000B0
+
+union lmc_mem_cfg0 {
+       uint64_t u64;
+       struct {
+               uint64_t reserved_32_63:32;
+               uint64_t reset:1;
+               uint64_t silo_qc:1;
+               uint64_t bunk_ena:1;
+               uint64_t ded_err:4;
+               uint64_t sec_err:4;
+               uint64_t intr_ded_ena:1;
+               uint64_t intr_sec_ena:1;
+               uint64_t reserved_15_18:4;
+               uint64_t ref_int:5;
+               uint64_t pbank_lsb:4;
+               uint64_t row_lsb:3;
+               uint64_t ecc_ena:1;
+               uint64_t init_start:1;
+       };
+};
+
+union lmc_fadr {
+       uint64_t u64;
+       struct {
+               uint64_t reserved_32_63:32;
+               uint64_t fdimm:2;
+               uint64_t fbunk:1;
+               uint64_t fbank:3;
+               uint64_t frow:14;
+               uint64_t fcol:12;
+       };
+};
+
+union lmc_ecc_synd {
+       uint64_t u64;
+       struct {
+               uint64_t reserved_32_63:32;
+               uint64_t mrdsyn3:8;
+               uint64_t mrdsyn2:8;
+               uint64_t mrdsyn1:8;
+               uint64_t mrdsyn0:8;
+       };
+};
diff --git a/drivers/edac/octeon_edac-pc.c b/drivers/edac/octeon_edac-pc.c
new file mode 100644 (file)
index 0000000..9d13061
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Wind River Systems,
+ *   written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/edac.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#include <asm/octeon/cvmx.h>
+#include <asm/mipsregs.h>
+
+#define EDAC_MOD_STR "octeon"
+
+extern int register_co_cache_error_notifier(struct notifier_block *nb);
+extern int unregister_co_cache_error_notifier(struct notifier_block *nb);
+
+extern unsigned long long cache_err_dcache[NR_CPUS];
+
+static struct edac_device_ctl_info *ed_cavium;
+
+/*
+ * EDAC CPU cache error callback
+ *
+ */
+
+static int  co_cache_error_event(struct notifier_block *this,
+       unsigned long event, void *ptr)
+{
+       unsigned int core = cvmx_get_core_num();
+       unsigned int cpu = smp_processor_id();
+       uint64_t icache_err = read_octeon_c0_icacheerr();
+       struct edac_device_ctl_info *ed = ed_cavium;
+
+       edac_device_printk(ed, KERN_ERR,
+                          "Cache error exception on core %d / processor %d:\n",
+                          core, cpu);
+       edac_device_printk(ed, KERN_ERR,
+                          "cp0_errorepc == %lx\n", read_c0_errorepc());
+       if (icache_err & 1) {
+               edac_device_printk(ed, KERN_ERR, "CacheErr (Icache) == %llx\n",
+                                  (unsigned long long)icache_err);
+               write_octeon_c0_icacheerr(0);
+               edac_device_handle_ce(ed, 0, 0, ed->ctl_name);
+       }
+       if (cache_err_dcache[core] & 1) {
+               edac_device_printk(ed, KERN_ERR, "CacheErr (Dcache) == %llx\n",
+                                  (unsigned long long)cache_err_dcache[core]);
+               cache_err_dcache[core] = 0;
+               edac_device_handle_ue(ed, 0, 0, ed->ctl_name);
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block co_cache_error_notifier = {
+       .notifier_call = co_cache_error_event,
+};
+
+static int __devinit co_cache_error_probe(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *ed;
+       int res = 0;
+
+       ed = edac_device_alloc_ctl_info(0, "cpu", 1, NULL, 0, 0, NULL, 0,
+                                       edac_device_alloc_index());
+
+       ed->dev = &pdev->dev;
+       platform_set_drvdata(pdev, ed);
+       ed->dev_name = dev_name(&pdev->dev);
+
+       ed->mod_name = "octeon-cpu";
+       ed->ctl_name = "co_cpu_err";
+
+       if (edac_device_add_device(ed) > 0) {
+               pr_err("%s: edac_device_add_device() failed\n", __func__);
+               goto err;
+       }
+
+       register_co_cache_error_notifier(&co_cache_error_notifier);
+       ed_cavium = ed;
+
+       return 0;
+
+err:
+       edac_device_free_ctl_info(ed);
+
+       return res;
+}
+
+static int co_cache_error_remove(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *ed = platform_get_drvdata(pdev);
+
+       unregister_co_cache_error_notifier(&co_cache_error_notifier);
+       ed_cavium = NULL;
+       edac_device_del_device(&pdev->dev);
+       edac_device_free_ctl_info(ed);
+
+       return 0;
+}
+
+static struct platform_driver co_cache_error_driver = {
+       .probe = co_cache_error_probe,
+       .remove = co_cache_error_remove,
+       .driver = {
+                  .name = "co_pc_edac",
+       }
+};
+
+static int __init co_edac_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&co_cache_error_driver);
+       if (ret)
+               pr_warning(EDAC_MOD_STR "CPU err failed to register\n");
+
+       return ret;
+}
+
+static void __exit co_edac_exit(void)
+{
+       platform_driver_unregister(&co_cache_error_driver);
+}
+
+module_init(co_edac_init);
+module_exit(co_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
diff --git a/drivers/edac/octeon_edac-pci.c b/drivers/edac/octeon_edac-pci.c
new file mode 100644 (file)
index 0000000..e72b96e
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Wind River Systems,
+ *   written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/edac.h>
+
+#include <asm/octeon/cvmx.h>
+#include <asm/octeon/cvmx-npi-defs.h>
+#include <asm/octeon/cvmx-pci-defs.h>
+#include <asm/octeon/octeon.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_MOD_STR "octeon"
+
+static void co_pci_poll(struct edac_pci_ctl_info *pci)
+{
+       union cvmx_pci_cfg01 cfg01;
+
+       cfg01.u32 = octeon_npi_read32(CVMX_NPI_PCI_CFG01);
+       if (cfg01.s.dpe) {              /* Detected parity error */
+               edac_pci_handle_pe(pci, pci->ctl_name);
+               cfg01.s.dpe = 1;                /* Reset  */
+               octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
+       }
+       if (cfg01.s.sse) {
+               edac_pci_handle_npe(pci, "Signaled System Error");
+               cfg01.s.sse = 1;                /* Reset */
+               octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
+       }
+       if (cfg01.s.rma) {
+               edac_pci_handle_npe(pci, "Received Master Abort");
+               cfg01.s.rma = 1;                /* Reset */
+               octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
+       }
+       if (cfg01.s.rta) {
+               edac_pci_handle_npe(pci, "Received Target Abort");
+               cfg01.s.rta = 1;                /* Reset */
+               octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
+       }
+       if (cfg01.s.sta) {
+               edac_pci_handle_npe(pci, "Signaled Target Abort");
+               cfg01.s.sta = 1;                /* Reset */
+               octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
+       }
+       if (cfg01.s.mdpe) {
+               edac_pci_handle_npe(pci, "Master Data Parity Error");
+               cfg01.s.mdpe = 1;               /* Reset */
+               octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
+       }
+       if (cfg01.s.mdpe) {
+               edac_pci_handle_npe(pci, "Master Data Parity Error");
+               cfg01.s.mdpe = 1;               /* Reset */
+               octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
+       }
+}
+
+static int __devinit co_pci_probe(struct platform_device *pdev)
+{
+       struct edac_pci_ctl_info *pci;
+       int res = 0;
+
+       pci = edac_pci_alloc_ctl_info(0, "octeon_pci_err");
+       if (!pci)
+               return -ENOMEM;
+
+       pci->dev = &pdev->dev;
+       platform_set_drvdata(pdev, pci);
+       pci->dev_name = dev_name(&pdev->dev);
+
+       pci->mod_name = "octeon-pci";
+       pci->ctl_name = "octeon_pci_err";
+       pci->edac_check = co_pci_poll;
+
+       if (edac_pci_add_device(pci, 0) > 0) {
+               pr_err("%s: edac_pci_add_device() failed\n", __func__);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       edac_pci_free_ctl_info(pci);
+
+       return res;
+}
+
+static int co_pci_remove(struct platform_device *pdev)
+{
+       struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
+
+       edac_pci_del_device(&pdev->dev);
+       edac_pci_free_ctl_info(pci);
+
+       return 0;
+}
+
+static struct platform_driver co_pci_driver = {
+       .probe = co_pci_probe,
+       .remove = co_pci_remove,
+       .driver = {
+                  .name = "co_pci_edac",
+       }
+};
+
+static int __init co_edac_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&co_pci_driver);
+       if (ret)
+               pr_warning(EDAC_MOD_STR " PCI EDAC failed to register\n");
+
+       return ret;
+}
+
+static void __exit co_edac_exit(void)
+{
+       platform_driver_unregister(&co_pci_driver);
+}
+
+module_init(co_edac_init);
+module_exit(co_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");