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>
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
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
depends on CPU_SUPPORTS_HUGEPAGES && 64BIT
default y
+config MIPS_HUGE_TLB_SUPPORT
+ def_bool HUGETLB_PAGE || TRANSPARENT_HUGEPAGE
+
config IRQ_CPU
bool
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.
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.
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"
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.
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
+ select CPU_SUPPORTS_HUGEPAGES
help
MIPS Technologies R10000-series processors.
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
+ select CPU_SUPPORTS_HUGEPAGES
config CPU_RM9000
bool "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
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
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.
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
+ select CPU_SUPPORTS_HUGEPAGES
config CPU_LOONGSON1
bool
/*
* 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
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
* 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>
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;
}
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);
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
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
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
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
*/
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,
/*
#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
#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__
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;
/* 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 */
#ifndef _ASM_PGTABLE_H
#define _ASM_PGTABLE_H
+#include <linux/mmzone.h>
#ifdef CONFIG_32BIT
#include <asm/pgtable-32.h>
#endif
* 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)
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);
__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
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>
/*
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)));
.cp0_badvaddr = 0, \
.cp0_baduaddr = 0, \
.error_code = 0, \
- .irix_trampoline = 0, \
- .irix_oldctx = 0, \
/* \
* Cavium Octeon specifics (null if not Octeon) \
*/ \
* 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
* TLB debugging functions:
*/
extern void dump_tlb_all(void);
+extern void dump_current_addr(unsigned long addr);
#endif /* __ASM_TLBDEBUG_H */
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();
}
#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>
#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
}
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. */
}
* 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)
{
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");
+}
*
* Copyright (C) 2005-2007 Cavium Networks
*/
+#include <linux/export.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#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
* 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");
}
#include <asm/fixmap.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
void pgd_init(unsigned long page)
{
}
#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;
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;
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)
{
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
};
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
}
/*
- * 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. */
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 */
case CPU_R4600:
case CPU_R4700:
case CPU_R5000:
- case CPU_R5000A:
case CPU_NEVADA:
uasm_i_nop(p);
uasm_i_tlbp(p);
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 */
}
}
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
static __cpuinit void build_restore_pagemask(u32 **p,
struct uasm_reloc **r,
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
/*
/* 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
*/
if (use_lwx_insns())
uasm_i_nop(p);
-#endif /* CONFIG_HUGETLB_PAGE */
+#endif /* CONFIG_MIPS_HUGE_TLB_SUPPORT */
/* build_update_entries */
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
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,
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;
memcpy((void *)ebase, final_handler, 0x100);
- dump_handler((u32 *)ebase, 64);
+ dump_handler("r4000_tlb_refill", (u32 *)ebase, 64);
}
/*
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
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)
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)
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 */
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
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.
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)
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.
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)
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.
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)
*/
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
#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>
*/
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;
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
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"
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
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
--- /dev/null
+/*
+ * 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>");
--- /dev/null
+/*
+ * 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>");
--- /dev/null
+/*
+ * 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;
+ };
+};
--- /dev/null
+/*
+ * 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>");
--- /dev/null
+/*
+ * 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>");