summaryrefslogtreecommitdiffstats
path: root/arch/parisc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/parisc')
-rw-r--r--arch/parisc/Kconfig2
-rw-r--r--arch/parisc/Makefile9
-rw-r--r--arch/parisc/boot/compressed/Makefile4
-rw-r--r--arch/parisc/boot/compressed/misc.c95
-rw-r--r--arch/parisc/boot/compressed/vmlinux.lds.S10
-rw-r--r--arch/parisc/include/asm/alternative.h47
-rw-r--r--arch/parisc/include/asm/assembly.h9
-rw-r--r--arch/parisc/include/asm/cache.h22
-rw-r--r--arch/parisc/include/asm/page.h12
-rw-r--r--arch/parisc/include/asm/pdc.h1
-rw-r--r--arch/parisc/include/asm/pdcpat.h62
-rw-r--r--arch/parisc/include/asm/pgtable.h33
-rw-r--r--arch/parisc/include/asm/sections.h2
-rw-r--r--arch/parisc/include/asm/spinlock.h4
-rw-r--r--arch/parisc/include/asm/tlbflush.h3
-rw-r--r--arch/parisc/kernel/cache.c63
-rw-r--r--arch/parisc/kernel/entry.S34
-rw-r--r--arch/parisc/kernel/firmware.c57
-rw-r--r--arch/parisc/kernel/hpmc.S3
-rw-r--r--arch/parisc/kernel/inventory.c10
-rw-r--r--arch/parisc/kernel/pacache.S280
-rw-r--r--arch/parisc/kernel/setup.c83
-rw-r--r--arch/parisc/kernel/signal.c1
-rw-r--r--arch/parisc/kernel/syscall.S12
-rw-r--r--arch/parisc/kernel/traps.c7
-rw-r--r--arch/parisc/kernel/unwind.c2
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S6
-rw-r--r--arch/parisc/mm/init.c23
28 files changed, 709 insertions, 187 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 8e6d83f79e72..f1cd12afd943 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -186,7 +186,7 @@ config PA11
depends on PA7000 || PA7100LC || PA7200 || PA7300LC
select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
- select DMA_NONCOHERENT_OPS
+ select DMA_DIRECT_OPS
select DMA_NONCOHERENT_CACHE_SYNC
config PREFETCH
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
index 5ce030266e7d..d047a09d660f 100644
--- a/arch/parisc/Makefile
+++ b/arch/parisc/Makefile
@@ -156,12 +156,3 @@ define archhelp
@echo ' copy to $$(INSTALL_PATH)'
@echo ' zinstall - Install compressed vmlinuz kernel'
endef
-
-# we require gcc 3.3 or above to compile the kernel
-archprepare: checkbin
-checkbin:
- @if test "$(cc-version)" -lt "0303"; then \
- echo -n "Sorry, GCC v3.3 or above is required to build " ; \
- echo "the kernel." ; \
- false ; \
- fi
diff --git a/arch/parisc/boot/compressed/Makefile b/arch/parisc/boot/compressed/Makefile
index 7d7e594bda36..777533cdea31 100644
--- a/arch/parisc/boot/compressed/Makefile
+++ b/arch/parisc/boot/compressed/Makefile
@@ -14,7 +14,7 @@ targets += misc.o piggy.o sizes.h head.o real2.o firmware.o
KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
-KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks
+KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks -fno-builtin-printf
KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os
ifndef CONFIG_64BIT
KBUILD_CFLAGS += -mfast-indirect-calls
@@ -22,7 +22,6 @@ endif
OBJECTS += $(obj)/head.o $(obj)/real2.o $(obj)/firmware.o $(obj)/misc.o $(obj)/piggy.o
-# LDFLAGS_vmlinux := -X --whole-archive -e startup -T
LDFLAGS_vmlinux := -X -e startup --as-needed -T
$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(LIBGCC)
$(call if_changed,ld)
@@ -55,7 +54,6 @@ $(obj)/misc.o: $(obj)/sizes.h
CPPFLAGS_vmlinux.lds += -I$(objtree)/$(obj) -DBOOTLOADER
$(obj)/vmlinux.lds: $(obj)/sizes.h
-OBJCOPYFLAGS_vmlinux.bin := -O binary -R .comment -S
$(obj)/vmlinux.bin: vmlinux
$(call if_changed,objcopy)
diff --git a/arch/parisc/boot/compressed/misc.c b/arch/parisc/boot/compressed/misc.c
index f57118e1f6b4..2556bb181813 100644
--- a/arch/parisc/boot/compressed/misc.c
+++ b/arch/parisc/boot/compressed/misc.c
@@ -5,6 +5,7 @@
*/
#include <linux/uaccess.h>
+#include <linux/elf.h>
#include <asm/unaligned.h>
#include <asm/page.h>
#include "sizes.h"
@@ -227,13 +228,62 @@ static void flush_data_cache(char *start, unsigned long length)
asm ("sync");
}
+static void parse_elf(void *output)
+{
+#ifdef CONFIG_64BIT
+ Elf64_Ehdr ehdr;
+ Elf64_Phdr *phdrs, *phdr;
+#else
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr *phdrs, *phdr;
+#endif
+ void *dest;
+ int i;
+
+ memcpy(&ehdr, output, sizeof(ehdr));
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr.e_ident[EI_MAG3] != ELFMAG3) {
+ error("Kernel is not a valid ELF file");
+ return;
+ }
+
+#ifdef DEBUG
+ printf("Parsing ELF... ");
+#endif
+
+ phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
+ if (!phdrs)
+ error("Failed to allocate space for phdrs");
+
+ memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
+
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ phdr = &phdrs[i];
+
+ switch (phdr->p_type) {
+ case PT_LOAD:
+ dest = (void *)((unsigned long) phdr->p_paddr &
+ (__PAGE_OFFSET_DEFAULT-1));
+ memmove(dest, output + phdr->p_offset, phdr->p_filesz);
+ break;
+ default:
+ break;
+ }
+ }
+
+ free(phdrs);
+}
+
unsigned long decompress_kernel(unsigned int started_wide,
unsigned int command_line,
const unsigned int rd_start,
const unsigned int rd_end)
{
char *output;
- unsigned long len, len_all;
+ unsigned long vmlinux_addr, vmlinux_len;
+ unsigned long kernel_addr, kernel_len;
#ifdef CONFIG_64BIT
parisc_narrow_firmware = 0;
@@ -241,27 +291,29 @@ unsigned long decompress_kernel(unsigned int started_wide,
set_firmware_width_unlocked();
- putchar('U'); /* if you get this p and no more, string storage */
+ putchar('D'); /* if you get this D and no more, string storage */
/* in $GLOBAL$ is wrong or %dp is wrong */
- puts("ncompressing ...\n");
-
- output = (char *) KERNEL_BINARY_TEXT_START;
- len_all = __pa(SZ_end) - __pa(SZparisc_kernel_start);
+ puts("ecompressing Linux... ");
- if ((unsigned long) &_startcode_end > (unsigned long) output)
+ /* where the final bits are stored */
+ kernel_addr = KERNEL_BINARY_TEXT_START;
+ kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start);
+ if ((unsigned long) &_startcode_end > kernel_addr)
error("Bootcode overlaps kernel code");
- len = get_unaligned_le32(&output_len);
- if (len > len_all)
- error("Output len too big.");
- else
- memset(&output[len], 0, len_all - len);
+ /*
+ * Calculate addr to where the vmlinux ELF file shall be decompressed.
+ * Assembly code in head.S positioned the stack directly behind bss, so
+ * leave 2 MB for the stack.
+ */
+ vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024;
+ vmlinux_len = get_unaligned_le32(&output_len);
+ output = (char *) vmlinux_addr;
/*
* Initialize free_mem_ptr and free_mem_end_ptr.
*/
- free_mem_ptr = (unsigned long) &_ebss;
- free_mem_ptr += 2*1024*1024; /* leave 2 MB for stack */
+ free_mem_ptr = vmlinux_addr + vmlinux_len;
/* Limit memory for bootoader to 1GB */
#define ARTIFICIAL_LIMIT (1*1024*1024*1024)
@@ -275,7 +327,11 @@ unsigned long decompress_kernel(unsigned int started_wide,
free_mem_end_ptr = rd_start;
#endif
+ if (free_mem_ptr >= free_mem_end_ptr)
+ error("Kernel too big for machine.");
+
#ifdef DEBUG
+ printf("\n");
printf("startcode_end = %x\n", &_startcode_end);
printf("commandline = %x\n", command_line);
printf("rd_start = %x\n", rd_start);
@@ -287,16 +343,19 @@ unsigned long decompress_kernel(unsigned int started_wide,
printf("input_data = %x\n", input_data);
printf("input_len = %x\n", input_len);
printf("output = %x\n", output);
- printf("output_len = %x\n", len);
- printf("output_max = %x\n", len_all);
+ printf("output_len = %x\n", vmlinux_len);
+ printf("kernel_addr = %x\n", kernel_addr);
+ printf("kernel_len = %x\n", kernel_len);
#endif
__decompress(input_data, input_len, NULL, NULL,
output, 0, NULL, error);
+ parse_elf(output);
- flush_data_cache(output, len);
+ output = (char *) kernel_addr;
+ flush_data_cache(output, kernel_len);
- printf("Booting kernel ...\n\n");
+ printf("done.\nBooting the kernel.\n");
return (unsigned long) output;
}
diff --git a/arch/parisc/boot/compressed/vmlinux.lds.S b/arch/parisc/boot/compressed/vmlinux.lds.S
index 4ebd4e65524c..bfd7872739a3 100644
--- a/arch/parisc/boot/compressed/vmlinux.lds.S
+++ b/arch/parisc/boot/compressed/vmlinux.lds.S
@@ -42,6 +42,12 @@ SECTIONS
#endif
_startcode_end = .;
+ /* vmlinux.bin.gz is here */
+ . = ALIGN(8);
+ .rodata.compressed : {
+ *(.rodata.compressed)
+ }
+
/* bootloader code and data starts behind area of extracted kernel */
. = (SZ_end - SZparisc_kernel_start + KERNEL_BINARY_TEXT_START);
@@ -68,10 +74,6 @@ SECTIONS
_erodata = . ;
}
. = ALIGN(8);
- .rodata.compressed : {
- *(.rodata.compressed)
- }
- . = ALIGN(8);
.bss : {
_bss = . ;
*(.bss)
diff --git a/arch/parisc/include/asm/alternative.h b/arch/parisc/include/asm/alternative.h
new file mode 100644
index 000000000000..bf485a94d0b4
--- /dev/null
+++ b/arch/parisc/include/asm/alternative.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_PARISC_ALTERNATIVE_H
+#define __ASM_PARISC_ALTERNATIVE_H
+
+#define ALT_COND_NO_SMP 0x01 /* when running UP instead of SMP */
+#define ALT_COND_NO_DCACHE 0x02 /* if system has no d-cache */
+#define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */
+#define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */
+#define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */
+
+#define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */
+#define INSN_NOP 0x08000240 /* nop */
+
+#ifndef __ASSEMBLY__
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/stringify.h>
+
+struct alt_instr {
+ s32 orig_offset; /* offset to original instructions */
+ u32 len; /* end of original instructions */
+ u32 cond; /* see ALT_COND_XXX */
+ u32 replacement; /* replacement instruction or code */
+};
+
+void set_kernel_text_rw(int enable_read_write);
+
+/* Alternative SMP implementation. */
+#define ALTERNATIVE(cond, replacement) "!0:" \
+ ".section .altinstructions, \"aw\" !" \
+ ".word (0b-4-.), 1, " __stringify(cond) "," \
+ __stringify(replacement) " !" \
+ ".previous"
+
+#else
+
+#define ALTERNATIVE(from, to, cond, replacement)\
+ .section .altinstructions, "aw" ! \
+ .word (from - .), (to - from)/4 ! \
+ .word cond, replacement ! \
+ .previous
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_PARISC_ALTERNATIVE_H */
diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h
index e9c6385ef0d1..c17ec0ee6e7c 100644
--- a/arch/parisc/include/asm/assembly.h
+++ b/arch/parisc/include/asm/assembly.h
@@ -129,15 +129,8 @@
.macro debug value
.endm
-
- /* Shift Left - note the r and t can NOT be the same! */
- .macro shl r, sa, t
- dep,z \r, 31-(\sa), 32-(\sa), \t
- .endm
-
- /* The PA 2.0 shift left */
.macro shlw r, sa, t
- depw,z \r, 31-(\sa), 32-(\sa), \t
+ zdep \r, 31-(\sa), 32-(\sa), \t
.endm
/* And the PA 2.0W shift left */
diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h
index 150b7f30ea90..006fb939cac8 100644
--- a/arch/parisc/include/asm/cache.h
+++ b/arch/parisc/include/asm/cache.h
@@ -6,6 +6,7 @@
#ifndef __ARCH_PARISC_CACHE_H
#define __ARCH_PARISC_CACHE_H
+#include <asm/alternative.h>
/*
* PA 2.0 processors have 64 and 128-byte L2 cachelines; PA 1.1 processors
@@ -41,9 +42,24 @@ extern int icache_stride;
extern struct pdc_cache_info cache_info;
void parisc_setup_cache_timing(void);
-#define pdtlb(addr) asm volatile("pdtlb 0(%%sr1,%0)" : : "r" (addr));
-#define pitlb(addr) asm volatile("pitlb 0(%%sr1,%0)" : : "r" (addr));
-#define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" : : "r" (addr));
+#define pdtlb(addr) asm volatile("pdtlb 0(%%sr1,%0)" \
+ ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \
+ : : "r" (addr))
+#define pitlb(addr) asm volatile("pitlb 0(%%sr1,%0)" \
+ ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \
+ ALTERNATIVE(ALT_COND_NO_SPLIT_TLB, INSN_NOP) \
+ : : "r" (addr))
+#define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" \
+ ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \
+ : : "r" (addr))
+
+#define asm_io_fdc(addr) asm volatile("fdc %%r0(%0)" \
+ ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \
+ ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) \
+ : : "r" (addr))
+#define asm_io_sync() asm volatile("sync" \
+ ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \
+ ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) :: )
#endif /* ! __ASSEMBLY__ */
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index af00fe9bf846..b77f49ce6220 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -117,14 +117,16 @@ extern int npmem_ranges;
/* This governs the relationship between virtual and physical addresses.
* If you alter it, make sure to take care of our various fixed mapping
* segments in fixmap.h */
-#if defined(BOOTLOADER)
-#define __PAGE_OFFSET (0) /* bootloader uses physical addresses */
-#else
#ifdef CONFIG_64BIT
-#define __PAGE_OFFSET (0x40000000) /* 1GB */
+#define __PAGE_OFFSET_DEFAULT (0x40000000) /* 1GB */
#else
-#define __PAGE_OFFSET (0x10000000) /* 256MB */
+#define __PAGE_OFFSET_DEFAULT (0x10000000) /* 256MB */
#endif
+
+#if defined(BOOTLOADER)
+#define __PAGE_OFFSET (0) /* bootloader uses physical addresses */
+#else
+#define __PAGE_OFFSET __PAGE_OFFSET_DEFAULT
#endif /* BOOTLOADER */
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
diff --git a/arch/parisc/include/asm/pdc.h b/arch/parisc/include/asm/pdc.h
index 339e83ddb39e..5b187d40d604 100644
--- a/arch/parisc/include/asm/pdc.h
+++ b/arch/parisc/include/asm/pdc.h
@@ -11,6 +11,7 @@ extern int parisc_narrow_firmware;
extern int pdc_type;
extern unsigned long parisc_cell_num; /* cell number the CPU runs on (PAT) */
extern unsigned long parisc_cell_loc; /* cell location of CPU (PAT) */
+extern unsigned long parisc_pat_pdc_cap; /* PDC capabilities (PAT) */
/* Values for pdc_type */
#define PDC_TYPE_ILLEGAL -1
diff --git a/arch/parisc/include/asm/pdcpat.h b/arch/parisc/include/asm/pdcpat.h
index a468a172ee33..bce9ee1c1c99 100644
--- a/arch/parisc/include/asm/pdcpat.h
+++ b/arch/parisc/include/asm/pdcpat.h
@@ -173,6 +173,16 @@
/* PDC PAT PD */
#define PDC_PAT_PD 74L /* Protection Domain Info */
#define PDC_PAT_PD_GET_ADDR_MAP 0L /* Get Address Map */
+#define PDC_PAT_PD_GET_PDC_INTERF_REV 1L /* Get PDC Interface Revisions */
+
+#define PDC_PAT_CAPABILITY_BIT_PDC_SERIALIZE (1UL << 0)
+#define PDC_PAT_CAPABILITY_BIT_PDC_POLLING (1UL << 1)
+#define PDC_PAT_CAPABILITY_BIT_PDC_NBC (1UL << 2) /* non-blocking calls */
+#define PDC_PAT_CAPABILITY_BIT_PDC_UFO (1UL << 3)
+#define PDC_PAT_CAPABILITY_BIT_PDC_IODC_32 (1UL << 4)
+#define PDC_PAT_CAPABILITY_BIT_PDC_IODC_64 (1UL << 5)
+#define PDC_PAT_CAPABILITY_BIT_PDC_HPMC_RENDEZ (1UL << 6)
+#define PDC_PAT_CAPABILITY_BIT_SIMULTANEOUS_PTLB (1UL << 7)
/* PDC_PAT_PD_GET_ADDR_MAP entry types */
#define PAT_MEMORY_DESCRIPTOR 1
@@ -186,6 +196,14 @@
#define PAT_MEMUSE_GI 128
#define PAT_MEMUSE_GNI 129
+/* PDC PAT REGISTER TOC */
+#define PDC_PAT_REGISTER_TOC 75L
+#define PDC_PAT_TOC_REGISTER_VECTOR 0L /* Register TOC Vector */
+#define PDC_PAT_TOC_READ_VECTOR 1L /* Read TOC Vector */
+
+/* PDC PAT SYSTEM_INFO */
+#define PDC_PAT_SYSTEM_INFO 76L
+/* PDC_PAT_SYSTEM_INFO uses the same options as PDC_SYSTEM_INFO function. */
#ifndef __ASSEMBLY__
#include <linux/types.h>
@@ -297,18 +315,29 @@ struct pdc_pat_pd_addr_map_entry {
** PDC_PAT_CELL_GET_INFO return block
*/
typedef struct pdc_pat_cell_info_rtn_block {
- unsigned long cpu_info;
- unsigned long cell_info;
- unsigned long cell_location;
- unsigned long reo_location;
- unsigned long mem_size;
- unsigned long dimm_status;
unsigned long pdc_rev;
- unsigned long fabric_info0;
- unsigned long fabric_info1;
- unsigned long fabric_info2;
- unsigned long fabric_info3;
- unsigned long reserved[21];
+ unsigned long capabilities; /* see PDC_PAT_CAPABILITY_BIT_* */
+ unsigned long reserved0[2];
+ unsigned long cell_info; /* 0x20 */
+ unsigned long cell_phys_location;
+ unsigned long cpu_info;
+ unsigned long cpu_speed;
+ unsigned long io_chassis_phys_location;
+ unsigned long cell_io_information;
+ unsigned long reserved1[2];
+ unsigned long io_slot_info_size; /* 0x60 */
+ struct {
+ unsigned long header, info0, info1;
+ unsigned long phys_loc, hw_path;
+ } io_slot[16];
+ unsigned long cell_mem_size; /* 0x2e8 */
+ unsigned long cell_dimm_info_size;
+ unsigned long dimm_info[16];
+ unsigned long fabric_info_size; /* 0x3f8 */
+ struct { /* 0x380 */
+ unsigned long fabric_info_xbc_port;
+ unsigned long rc_attached_to_xbc;
+ } xbc[8*4];
} pdc_pat_cell_info_rtn_block_t;
@@ -326,12 +355,19 @@ typedef struct pdc_pat_cell_mod_maddr_block pdc_pat_cell_mod_maddr_block_t;
extern int pdc_pat_chassis_send_log(unsigned long status, unsigned long data);
extern int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info);
-extern int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod, unsigned long view_type, void *mem_addr);
+extern int pdc_pat_cell_info(struct pdc_pat_cell_info_rtn_block *info,
+ unsigned long *actcnt, unsigned long offset,
+ unsigned long cell_number);
+extern int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc,
+ unsigned long mod, unsigned long view_type, void *mem_addr);
extern int pdc_pat_cell_num_to_loc(void *, unsigned long);
extern int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, unsigned long hpa);
-extern int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, unsigned long count, unsigned long offset);
+extern int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr,
+ unsigned long count, unsigned long offset);
+extern int pdc_pat_pd_get_pdc_revisions(unsigned long *legacy_rev,
+ unsigned long *pat_rev, unsigned long *pdc_cap);
extern int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *val);
extern int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 val);
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index fa6b7c78f18a..b941ac7d4e70 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -43,8 +43,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
{
mtsp(mm->context, 1);
pdtlb(addr);
- if (unlikely(split_tlb))
- pitlb(addr);
+ pitlb(addr);
}
/* Certain architectures need to do special things when PTEs
@@ -56,19 +55,14 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
*(pteptr) = (pteval); \
} while(0)
-#define pte_inserted(x) \
- ((pte_val(x) & (_PAGE_PRESENT|_PAGE_ACCESSED)) \
- == (_PAGE_PRESENT|_PAGE_ACCESSED))
-
#define set_pte_at(mm, addr, ptep, pteval) \
do { \
pte_t old_pte; \
unsigned long flags; \
spin_lock_irqsave(&pa_tlb_lock, flags); \
old_pte = *ptep; \
- if (pte_inserted(old_pte)) \
- purge_tlb_entries(mm, addr); \
set_pte(ptep, pteval); \
+ purge_tlb_entries(mm, addr); \
spin_unlock_irqrestore(&pa_tlb_lock, flags); \
} while (0)
@@ -202,7 +196,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
#define _PAGE_HUGE (1 << xlate_pabit(_PAGE_HPAGE_BIT))
#define _PAGE_USER (1 << xlate_pabit(_PAGE_USER_BIT))
-#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _PAGE_KERNEL_RO (_PAGE_PRESENT | _PAGE_READ | _PAGE_DIRTY | _PAGE_ACCESSED)
#define _PAGE_KERNEL_EXEC (_PAGE_KERNEL_RO | _PAGE_EXEC)
@@ -227,22 +221,22 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
#ifndef __ASSEMBLY__
-#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_ACCESSED)
+#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_USER)
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE)
/* Others seem to make this executable, I don't know if that's correct
or not. The stack is mapped this way though so this is necessary
in the short term - dhd@linuxcare.com, 2000-08-08 */
-#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_ACCESSED)
-#define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITE | _PAGE_ACCESSED)
-#define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_EXEC |_PAGE_ACCESSED)
+#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ)
+#define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITE)
+#define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_EXEC)
#define PAGE_COPY PAGE_EXECREAD
-#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC |_PAGE_ACCESSED)
+#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)
#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC)
#define PAGE_KERNEL_RWX __pgprot(_PAGE_KERNEL_RWX)
#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO)
#define PAGE_KERNEL_UNC __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
-#define PAGE_GATEWAY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_GATEWAY| _PAGE_READ)
+#define PAGE_GATEWAY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_GATEWAY| _PAGE_READ)
/*
@@ -479,8 +473,8 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
spin_unlock_irqrestore(&pa_tlb_lock, flags);
return 0;
}
- purge_tlb_entries(vma->vm_mm, addr);
set_pte(ptep, pte_mkold(pte));
+ purge_tlb_entries(vma->vm_mm, addr);
spin_unlock_irqrestore(&pa_tlb_lock, flags);
return 1;
}
@@ -493,9 +487,8 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
spin_lock_irqsave(&pa_tlb_lock, flags);
old_pte = *ptep;
- if (pte_inserted(old_pte))
- purge_tlb_entries(mm, addr);
set_pte(ptep, __pte(0));
+ purge_tlb_entries(mm, addr);
spin_unlock_irqrestore(&pa_tlb_lock, flags);
return old_pte;
@@ -505,8 +498,8 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
{
unsigned long flags;
spin_lock_irqsave(&pa_tlb_lock, flags);
- purge_tlb_entries(mm, addr);
set_pte(ptep, pte_wrprotect(*ptep));
+ purge_tlb_entries(mm, addr);
spin_unlock_irqrestore(&pa_tlb_lock, flags);
}
diff --git a/arch/parisc/include/asm/sections.h b/arch/parisc/include/asm/sections.h
index 5a40b51df80c..bb52aea0cb21 100644
--- a/arch/parisc/include/asm/sections.h
+++ b/arch/parisc/include/asm/sections.h
@@ -5,6 +5,8 @@
/* nothing to see, move along */
#include <asm-generic/sections.h>
+extern char __alt_instructions[], __alt_instructions_end[];
+
#ifdef CONFIG_64BIT
#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h
index 8a63515f03bf..16aec9ba2580 100644
--- a/arch/parisc/include/asm/spinlock.h
+++ b/arch/parisc/include/asm/spinlock.h
@@ -37,8 +37,8 @@ static inline void arch_spin_unlock(arch_spinlock_t *x)
volatile unsigned int *a;
a = __ldcw_align(x);
- mb();
- *a = 1;
+ /* Release with ordered store. */
+ __asm__ __volatile__("stw,ma %0,0(%1)" : : "r"(1), "r"(a) : "memory");
}
static inline int arch_spin_trylock(arch_spinlock_t *x)
diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h
index 14668bd52d60..6804374efa66 100644
--- a/arch/parisc/include/asm/tlbflush.h
+++ b/arch/parisc/include/asm/tlbflush.h
@@ -85,8 +85,7 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
purge_tlb_start(flags);
mtsp(sid, 1);
pdtlb(addr);
- if (unlikely(split_tlb))
- pitlb(addr);
+ pitlb(addr);
purge_tlb_end(flags);
}
#endif
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index bddd2acebdcc..804880efa11e 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -36,6 +36,7 @@ EXPORT_SYMBOL(dcache_stride);
void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
EXPORT_SYMBOL(flush_dcache_page_asm);
+void purge_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
void flush_icache_page_asm(unsigned long phys_addr, unsigned long vaddr);
@@ -303,6 +304,17 @@ __flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
preempt_enable();
}
+static inline void
+__purge_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
+ unsigned long physaddr)
+{
+ preempt_disable();
+ purge_dcache_page_asm(physaddr, vmaddr);
+ if (vma->vm_flags & VM_EXEC)
+ flush_icache_page_asm(physaddr, vmaddr);
+ preempt_enable();
+}
+
void flush_dcache_page(struct page *page)
{
struct address_space *mapping = page_mapping_file(page);
@@ -364,7 +376,7 @@ EXPORT_SYMBOL(flush_kernel_icache_range_asm);
#define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
static unsigned long parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
-#define FLUSH_TLB_THRESHOLD (2*1024*1024) /* 2MB initial TLB threshold */
+#define FLUSH_TLB_THRESHOLD (16*1024) /* 16 KiB minimum TLB threshold */
static unsigned long parisc_tlb_flush_threshold __read_mostly = FLUSH_TLB_THRESHOLD;
void __init parisc_setup_cache_timing(void)
@@ -404,10 +416,6 @@ void __init parisc_setup_cache_timing(void)
goto set_tlb_threshold;
}
- alltime = mfctl(16);
- flush_tlb_all();
- alltime = mfctl(16) - alltime;
-
size = 0;
start = (unsigned long) _text;
rangetime = mfctl(16);
@@ -418,13 +426,19 @@ void __init parisc_setup_cache_timing(void)
}
rangetime = mfctl(16) - rangetime;
- printk(KERN_DEBUG "Whole TLB flush %lu cycles, flushing %lu bytes %lu cycles\n",
+ alltime = mfctl(16);
+ flush_tlb_all();
+ alltime = mfctl(16) - alltime;
+
+ printk(KERN_INFO "Whole TLB flush %lu cycles, Range flush %lu bytes %lu cycles\n",
alltime, size, rangetime);
- threshold = PAGE_ALIGN(num_online_cpus() * size * alltime / rangetime);
+ threshold = PAGE_ALIGN((num_online_cpus() * size * alltime) / rangetime);
+ printk(KERN_INFO "Calculated TLB flush threshold %lu KiB\n",
+ threshold/1024);
set_tlb_threshold:
- if (threshold)
+ if (threshold > parisc_tlb_flush_threshold)
parisc_tlb_flush_threshold = threshold;
printk(KERN_INFO "TLB flush threshold set to %lu KiB\n",
parisc_tlb_flush_threshold/1024);
@@ -477,18 +491,6 @@ int __flush_tlb_range(unsigned long sid, unsigned long start,
/* Purge TLB entries for small ranges using the pdtlb and
pitlb instructions. These instructions execute locally
but cause a purge request to be broadcast to other TLBs. */
- if (likely(!split_tlb)) {
- while (start < end) {
- purge_tlb_start(flags);
- mtsp(sid, 1);
- pdtlb(start);
- purge_tlb_end(flags);
- start += PAGE_SIZE;
- }
- return 0;
- }
-
- /* split TLB case */
while (start < end) {
purge_tlb_start(flags);
mtsp(sid, 1);
@@ -573,9 +575,12 @@ void flush_cache_mm(struct mm_struct *mm)
pfn = pte_pfn(*ptep);
if (!pfn_valid(pfn))
continue;
- if (unlikely(mm->context))
+ if (unlikely(mm->context)) {
flush_tlb_page(vma, addr);
- __flush_cache_page(vma, addr, PFN_PHYS(pfn));
+ __flush_cache_page(vma, addr, PFN_PHYS(pfn));
+ } else {
+ __purge_cache_page(vma, addr, PFN_PHYS(pfn));
+ }
}
}
}
@@ -610,9 +615,12 @@ void flush_cache_range(struct vm_area_struct *vma,
continue;
pfn = pte_pfn(*ptep);
if (pfn_valid(pfn)) {
- if (unlikely(vma->vm_mm->context))
+ if (unlikely(vma->vm_mm->context)) {
flush_tlb_page(vma, addr);
- __flush_cache_page(vma, addr, PFN_PHYS(pfn));
+ __flush_cache_page(vma, addr, PFN_PHYS(pfn));
+ } else {
+ __purge_cache_page(vma, addr, PFN_PHYS(pfn));
+ }
}
}
}
@@ -621,9 +629,12 @@ void
flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
{
if (pfn_valid(pfn)) {
- if (likely(vma->vm_mm->context))
+ if (likely(vma->vm_mm->context)) {
flush_tlb_page(vma, vmaddr);
- __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
+ __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
+ } else {
+ __purge_cache_page(vma, vmaddr, PFN_PHYS(pfn));
+ }
}
}
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 242c5ab65611..1c60408a64ad 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/pari