Commit 44786880 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'parisc-4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc updates from Helge Deller:
 "Lots of small fixes and enhancements, most noteably:

   - Many TLB and cache flush optimizations (Dave)

   - Fixed HPMC/crash handler on 64-bit kernel (Dave and myself)

   - Added alternative infrastructre. The kernel now live-patches itself
     for various situations, e.g. replace SMP code when running on one
     CPU only or drop cache flushes when system has no cache installed.

   - vmlinuz now contains a full copy of the compressed vmlinux file.
     This simplifies debugging the currently booted kernel.

   - Unused driver removal (Christoph)

   - Reduced warnings of Dino PCI bridge when running in qemu

   - Removed gcc version check (Masahiro)"

* 'parisc-4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux: (23 commits)
  parisc: Retrieve and display the PDC PAT capabilities
  parisc: Optimze cache flush algorithms
  parisc: Remove pte_inserted define
  parisc: Add PDC PAT cell_info() and pd_get_pdc_revisions() functions
  parisc: Drop two instructions from pte lookup code
  parisc: Use zdep for shlw macro on PA1.1 and PA2.0
  parisc: Add alternative coding infrastructure
  parisc: Include compressed vmlinux file in vmlinuz boot kernel
  extract-vmlinux: Check for uncompressed image as fallback
  parisc: Fix address in HPMC IVA
  parisc: Fix exported address of os_hpmc handler
  parisc: Fix map_pages() to not overwrite existing pte entries
  parisc: Purge TLB entries after updating page table entry and set page accessed flag in TLB handler
  parisc: Release spinlocks using ordered store
  parisc: Ratelimit dino stuck interrupt warnings
  parisc: dino: Utilize DINO_MASK_IRQ() macro
  parisc: Clean up crash header output
  parisc: Add SYSTEM_INFO and REGISTER TOC PAT functions
  parisc: Remove PTE load and fault check from L2_ptep macro
  parisc: Reorder TLB flush timing calculation
  ...
parents 07171da2 e543b3a6
......@@ -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
......@@ -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)
......
......@@ -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;
}
......@@ -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)
......
/* 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 */
......@@ -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 */
......
......@@ -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__ */
......
......@@ -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)
......
......@@ -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
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......@@ -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));
}
}
}
......
......@@ -38,6 +38,7 @@
#include <asm/ldcw.h>
#include <asm/traps.h>
#include <asm/thread_info.h>
#include <asm/alternative.h>
#include <linux/linkage.h>
......@@ -186,7 +187,7 @@
bv,n 0(%r3)
nop
.word 0 /* checksum (will be patched) */
.word PA(os_hpmc) /* address of handler */
.word 0 /* address of handler */
.word 0 /* length of handler */
.endm
......@@ -426,13 +427,10 @@
ldw,s \index(\pmd),\pmd
bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault
dep %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
copy \pmd,%r9
SHLREG %r9,PxD_VALUE_SHIFT,\pmd
SHLREG \pmd,PxD_VALUE_SHIFT,\pmd
extru \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
dep %r0,31,PAGE_SHIFT,\pmd /* clear offset */
shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd /* pmd is now pte */
LDREG %r0(\pmd),\pte
bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault
.endm
/* Look up PTE in a 3-Level scheme.
......@@ -448,7 +446,6 @@
.macro L3_ptep pgd,pte,index,va,fault
#if CONFIG_PGTABLE_LEVELS == 3 /* we might have a 2-Level scheme, e.g. with 16kb page size */
extrd,u \va,63-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
copy %r0,\pte
extrd,u,*= \va,63-ASM_PGDIR_SHIFT,64-ASM_PGDIR_SHIFT,%r0
ldw,s \index(\pgd),\pgd
extrd,u,*= \va,63-ASM_PGDIR_SHIFT,64-ASM_PGDIR_SHIFT,%r0
......@@ -463,36 +460,39 @@
L2_ptep \pgd,\pte,\index,\va,\fault
.endm
/* Acquire pa_tlb_lock lock and recheck page is still present. */
/* Acquire pa_tlb_lock lock and check page is present. */
.macro tlb_lock spc,ptp,pte,tmp,tmp1,fault
#ifdef CONFIG_SMP
cmpib,COND(=),n 0,\spc,2f
98: cmpib,COND(=),n 0,\spc,2f
load_pa_tlb_lock \tmp
1: LDCW 0(\tmp),\tmp1
cmpib,COND(=) 0,\tmp1,1b
nop
LDREG 0(\ptp),\pte
bb,<,n \pte,_PAGE_PRESENT_BIT,2f
bb,<,n \pte,_PAGE_PRESENT_BIT,3f
b \fault
stw \spc,0(\tmp)
2:
stw,ma \spc,0(\tmp)
99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
#endif
2: LDREG 0(\ptp),\pte
bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault
3:
.endm
/* Release pa_tlb_lock lock without reloading lock address. */
.macro tlb_unlock0 spc,tmp
#ifdef CONFIG_SMP
or,COND(=) %r0,\spc,%r0
sync
or,COND(=) %r0,\spc,%r0
stw \spc,0(\tmp)
98: or,COND(=) %r0,\spc,%r0
stw,ma \spc,0(\tmp)
99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
#endif
.endm
/* Release pa_tlb_lock lock. */
.macro tlb_unlock1 spc,tmp
#ifdef CONFIG_SMP
load_pa_tlb_lock \tmp
98: load_pa_tlb_lock \tmp
99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
tlb_unlock0 \spc,\tmp
#endif
.endm
......@@ -1658,7 +1658,7 @@ dbit_fault:
itlb_fault:
b intr_save
ldi 6,%r8
ldi PARISC_ITLB_TRAP,%r8
nadtlb_fault:
b intr_save
......
......@@ -1325,6 +1325,36 @@ int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long
return retval;
}
/**
* pdc_pat_cell_info - Retrieve the cell's information.
* @info: The pointer to a struct pdc_pat_cell_info_rtn_block.
* @actcnt: The number of bytes which should be written to info.
* @offset: offset of the structure.
* @cell_number: The cell number which should be asked, or -1 for current cell.
*
* This PDC call returns information about the given cell (or all cells).
*/
int pdc_pat_cell_info(struct pdc_pat_cell_info_rtn_block *info,
unsigned long *actcnt, unsigned long offset,
unsigned long cell_number)
{
int retval;
unsigned long flags;
struct pdc_pat_cell_info_rtn_block result;
spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_GET_INFO,
__pa(pdc_result), __pa(&result), *actcnt,
offset, cell_number);
if (!retval) {
*actcnt = pdc_result[0];
memcpy(info, &result, *actcnt);
}
spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
/**
* pdc_pat_cpu_get_number - Retrieve the cpu number.
* @cpu_info: The return buffer.
......@@ -1412,6 +1442,33 @@ int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr,
return retval;
}
/**
* pdc_pat_pd_get_PDC_interface_revisions - Retrieve PDC interface revisions.
* @legacy_rev: The legacy revision.
* @pat_rev: The PAT revision.
* @pdc_cap: The PDC capabilities.
*
*/
int pdc_pat_pd_get_pdc_revisions(unsigned long *legacy_rev,
unsigned long *pat_rev, unsigned long *pdc_cap)
{
int retval;
unsigned long flags;
spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_PD, PDC_PAT_PD_GET_PDC_INTERF_REV,
__pa(pdc_result));
if (retval == PDC_OK) {
*legacy_rev = pdc_result[0];
*pat_rev = pdc_result[1];
*pdc_cap = pdc_result[2];
}
spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
/**
* pdc_pat_io_pci_cfg_read - Read PCI configuration space.
* @pci_addr: PCI configuration space address for which the read request is being made.
......
......@@ -85,7 +85,7 @@ END(hpmc_pim_data)
.import intr_save, code
.align 16
ENTRY_CFI(os_hpmc)
ENTRY(os_hpmc)
.os_hpmc:
/*
......@@ -302,7 +302,6 @@ os_hpmc_6:
b .
nop
.align 16 /* make function length multiple of 16 bytes */
ENDPROC_CFI(os_hpmc)
.os_hpmc_end:
......
......@@ -43,6 +43,7 @@ int pdc_type __read_mostly = PDC_TYPE_ILLEGAL;
/* cell number and location (PAT firmware only) */
unsigned long parisc_cell_num __read_mostly;
unsigned long parisc_cell_loc __read_mostly;
unsigned long parisc_pat_pdc_cap __read_mostly;
void __init setup_pdc(void)
......@@ -81,12 +82,21 @@ void __init setup_pdc(void)
#ifdef CONFIG_64BIT
status = pdc_pat_cell_get_number(&cell_info);
if (status == PDC_OK) {
unsigned long legacy_rev, pat_rev;
pdc_type = PDC_TYPE_PAT;
pr_cont("64 bit PAT.\n");
parisc_cell_num = cell_info.cell_num;
parisc_cell_loc = cell_info.cell_loc;
pr_info("PAT: Running on cell %lu and location %lu.\n",
parisc_cell_num, parisc_cell_loc);
status = pdc_pat_pd_get_pdc_revisions(&legacy_rev,
&pat_rev, &parisc_pat_pdc_cap);
pr_info("PAT: legacy revision 0x%lx, pat_rev 0x%lx, pdc_cap 0x%lx, S-PTLB %d, HPMC_RENDEZ %d.\n",
legacy_rev, pat_rev, parisc_pat_pdc_cap,
parisc_pat_pdc_cap
& PDC_PAT_CAPABILITY_BIT_SIMULTANEOUS_PTLB ? 1:0,
parisc_pat_pdc_cap
& PDC_PAT_CAPABILITY_BIT_PDC_HPMC_RENDEZ ? 1:0);
return;
}
#endif
......
This diff is collapsed.
......@@ -305,6 +305,86 @@ static int __init parisc_init_resources(void)
return 0;
}
static int no_alternatives __initdata;
static int __init setup_no_alternatives(char *str)
{
no_alternatives = 1;
return 1;
}
__setup("no-alternatives", setup_no_alternatives);
static void __init apply_alternatives_all(void)
{
struct alt_instr *entry;
int index = 0, applied = 0;
pr_info("alternatives: %spatching kernel code\n",
no_alternatives ? "NOT " : "");
if (no_alternatives)
return;
set_kernel_text_rw(1);
for (entry = (struct alt_instr *) &__alt_instructions;
entry < (struct alt_instr *) &__alt_instructions_end;
entry++, index++) {
u32 *from, len, cond, replacement;
from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
len = entry->len;
cond = entry->cond;
replacement = entry->replacement;
WARN_ON(!cond);
pr_debug("Check %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
index, cond, len, from, replacement);
if ((cond & ALT_COND_NO_SMP) && (num_online_cpus() != 1))
continue;
if ((cond & ALT_COND_NO_DCACHE) && (cache_info.dc_size != 0))
continue;
if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0))
continue;
/*
* If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit
* set (bit #61, big endian), we have to flush and sync every
* time IO-PDIR is changed in Ike/Astro.
*/
if ((cond & ALT_COND_NO_IOC_FDC) &&
(boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC))
continue;
/* Want to replace pdtlb by a pdtlb,l instruction? */
if (replacement == INSN_PxTLB) {
replacement = *from;
if (boot_cpu_data.cpu_type >= pcxu) /* >= pa2.0 ? */
replacement |= (1 << 10); /* set el bit */
}
/*
* Replace instruction with NOPs?
* For long distance insert a branch instruction instead.
*/
if (replacement == INSN_NOP && len > 1)
replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
pr_debug("Do %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
index, cond, len, from, replacement);
/* Replace instruction */
*from = replacement;
applied++;
}
pr_info("alternatives: applied %d out of %d patches\n", applied, index);
set_kernel_text_rw(0);
}
extern void gsc_init(void);
extern void processor_init(void);
extern void ccio_init(void);
......@@ -346,6 +426,7 @@ static int __init parisc_init(void)
boot_cpu_data.cpu_hz / 1000000,
boot_cpu_data.cpu_hz % 1000000 );
apply_alternatives_all();
parisc_setup_cache_timing();
/* These are in a non-obvious order, will fix when we have an iotree */
......
......@@ -65,7 +65,6 @@
#define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */
#define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */
#define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */
#define INSN_NOP 0x08000240 /* nop */
/* For debugging */
#define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */
......
......@@ -640,8 +640,7 @@ cas_action:
sub,<> %r28, %r25, %r0
2: stw %r24, 0(%r26)
/* Free lock */
sync
stw %r20, 0(%sr2,%r20)
stw,ma %r20, 0(%sr2,%r20)
#if ENABLE_LWS_DEBUG
/* Clear thread register indicator */
stw %r0, 4(%sr2,%r20)
......@@ -655,8 +654,7 @@ cas_action:
3:
/* Error occurred on load or store */
/* Free lock */
sync
stw %r20, 0(%sr2,%r20)
stw,ma %r20, 0(%sr2,%r20)
#if ENABLE_LWS_DEBUG
stw %r0, 4(%sr2,%r20)
#endif
......@@ -857,8 +855,7 @@ cas2_action:
cas2_end:
/* Free lock */
sync
stw %r20, 0(%sr2,%r20)
stw,ma %r20, 0(%sr2,%r20)
/* Enable interrupts */
ssm PSW_SM_I, %r0
/* Return to userspace, set no error */
......@@ -868,8 +865,7 @@ cas2_end:
22:
/* Error occurred on load or store */
/* Free lock */
sync
stw %r20, 0(%sr2,%r20)
stw,ma %r20, 0(%sr2,%r20)
ssm PSW_SM_I, %r0
ldo 1(%r0),%r28
b lws_exit
......
......@@ -430,8 +430,8 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
}
printk("\n");
pr_crit("%s: Code=%d (%s) regs=%p (Addr=" RFMT ")\n",
msg, code, trap_name(code), regs, offset);
pr_crit("%s: Code=%d (%s) at addr " RFMT "\n",
msg, code, trap_name(code), offset);
show_regs(regs);
spin_unlock(&terminate_lock);
......@@ -802,7 +802,8 @@ void __init initialize_ivt(const void *iva)
* the Length/4 words starting at Address is zero.
*/
/* Compute Checksum for HPMC handler */
/* Setup IVA and compute checksum for HPMC handler */
ivap[6] = (u32)__pa(os_hpmc);
length = os_hpmc_size;
ivap[7] = length;
......
......@@ -61,6 +61,12 @@ SECTIONS
EXIT_DATA
}
PERCPU_SECTION(8)
. = ALIGN(4);
.altinstructions : {
__alt_instructions = .;
*(.altinstructions)
__alt_instructions_end = .;
}
. = ALIGN(HUGEPAGE_SIZE);
__init_end = .;
/* freed after init ends here */
......
......@@ -494,12 +494,8 @@ static void __init map_pages(unsigned long start_vaddr,
pte = pte_mkhuge(pte);
}
if (address >= end_paddr) {
if (force)
break;
else
pte_val(pte) = 0;
}
if (address >= end_paddr)
break;
set_pte(pg_table, pte);
......@@ -515,6 +511,21 @@ static void __init map_pages(unsigned long start_vaddr,
}
}
void __init set_kernel_text_rw(int enable_read_write)
{
unsigned long start = (unsigned long)_stext;
unsigned long end = (unsigned long)_etext;
map_pages(start, __pa(start), end-start,
PAGE_KERNEL_RWX, enable_read_write ? 1:0);
/* force the kernel to see the new TLB entries */
__flush_tlb_range(0, start, end);
/* dump old cached instructions */
flush_icache_range(start, end);
}
void __ref free_initmem(void)
{
unsigned long init_begin = (unsigned long)__init_begin;
......
......@@ -8,9 +8,6 @@
obj-$(CONFIG_IOSAPIC) += iosapic.o
obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o
obj-$(CONFIG_PCI_LBA) += lba_pci.o
# Only use one of them: ccio-rm-dma is for PCX-W systems *only*
# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o
obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
obj-$(CONFIG_GSC) += gsc.o
......
......@@ -609,14 +609,13 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
** PCX-T'? Don't know. (eg C110 or similar K-class)
**
** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit".
** Hopefully we can patch (NOP) these out at boot time somehow.
**
** "Since PCX-U employs an offset hash that is incompatible with
** the real mode coherence index generation of U2, the PDIR entry
** must be flushed to memory to retain coherence."
*/
asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
asm volatile("sync");
asm_io_fdc(pdir_ptr);
asm_io_sync();
}
/**
......@@ -682,17 +681,14 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
** PCX-U/U+ do. (eg C200/C240)
** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit".
**
** Hopefully someone figures out how to patch (NOP) the
** FDC/SYNC out at boot time.
*/
asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7]));
asm_io_fdc(pdir_ptr);
iovp += IOVP_SIZE;
byte_cnt -= IOVP_SIZE;
}
asm volatile("sync");
asm_io_sync();
ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt);
}
......
/*
* ccio-rm-dma.c:
* DMA management routines for first generation cache-coherent machines.
* "Real Mode" operation refers to U2/Uturn chip operation. The chip
* can perform coherency checks w/o using the I/O MMU. That's all we
* need until support for more than 4GB phys mem is needed.
*
* This is the trivial case - basically what x86 does.
*
* Drawbacks of using Real Mode are:
* o outbound DMA is slower since one isn't using the prefetching
* U2 can do for outbound DMA.
* o Ability to do scatter/gather in HW is also lost.
* o only known to work with PCX-W processor. (eg C360)
* (PCX-U/U+ are not coherent with U2 in real mode.)
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* Original version/author:
* CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc
* cvs -z3 co linux/arch/parisc/kernel/dma-rm.c
*
* (C) Copyright 2000 Philipp Rumpf <prumpf@tux.org>
*
*
* Adopted for The Puffin Group's parisc-linux port by Grant Grundler.
* (C) Copyright 2000 Grant Grundler <grundler@puffin.external.hp.com>
*
*/
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/gfp.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/page.h>
/* Only chose "ccio" since that's what HP-UX calls it....
** Make it easier for folks to migrate from one to the other :^)
*/
#define MODULE_NAME "ccio"
#define U2_IOA_RUNWAY 0x580
#define U2_BC_GSC 0x501
#define UTURN_IOA_RUNWAY 0x581
#define UTURN_BC_GSC 0x502
#define IS_U2(id) ( \
(((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \
(((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \
)
#define IS_UTURN(id) ( \
(((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \
(((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \
)
static int ccio_dma_supported( struct pci_dev *dev, u64 mask)
{
if (dev == NULL) {
printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
BUG();
return(0);
}
/* only support 32-bit devices (ie PCI/GSC) */
return((int) (mask >= 0xffffffffUL));
}
static void *ccio_alloc_consistent(struct pci_dev *dev, size_t size,
dma_addr_t *handle)
{
void *ret;
ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
if (ret != NULL) {
memset(ret, 0, size);
*handle = virt_to_phys(ret);
}
return ret;
}
static void ccio_free_consistent(struct pci_dev *dev, size_t size,
void *vaddr, dma_addr_t handle)
{
free_pages((unsigned long)vaddr, get_order(size));
}
static dma_addr_t ccio_map_single(struct pci_dev *dev, void *ptr, size_t size,
int direction)
{
return virt_to_phys(ptr);
}
static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t dma_addr,
size_t size, int direction)
{
/* Nothing to do */
}
static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
{
int tmp = nents;
/* KISS: map each buffer separately. */
while (nents) {
sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction);
sg_dma_len(sglist) = sglist->length;
nents--;
sglist++;
}
return tmp;
}
static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
{
#if 0
while (nents) {
ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
nents--;
sglist++;
}
return;
#else
/* Do nothing (copied from current ccio_unmap_single() :^) */
#endif
}
static struct pci_dma_ops ccio_ops = {
ccio_dma_supported,
ccio_alloc_consistent,
ccio_free_consistent,
ccio_map_single,
ccio_unmap_single,
ccio_map_sg,
ccio_unmap_sg,
NULL, /* dma_sync_single_for_cpu : NOP for U2 */
NULL, /* dma_sync_single_for_device : NOP for U2 */
NULL, /* dma_sync_sg_for_cpu : ditto */
NULL, /* dma_sync_sg_for_device : ditto */
};
/*
** Determine if u2 should claim this chip (return 0) or not (return 1).
** If so, initialize the chip and tell other partners in crime they
** have work to do.
*/
static int __init
ccio_probe(struct parisc_device *dev)
{
printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME,
dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn",
dev->hpa.start);
/*
** FIXME - should check U2 registers to verify it's really running
** in "Real Mode".
*/
#if 0
/* will need this for "Virtual Mode" operation */
ccio_hw_init(ccio_dev);
ccio_common_init(ccio_dev);
#endif
hppa_dma_ops = &ccio_ops;
return 0;
}
static const struct parisc_device_id ccio_tbl[] __initconst = {
{ HPHW_BCPORT, HVERSION_REV_ANY_ID, U2_BC_GSC, 0xc },
{ HPHW_BCPORT, HVERSION_REV_ANY_ID, UTURN_BC_GSC, 0xc },
{ 0, }
};
static struct parisc_driver ccio_driver __refdata = {
.name = "U2/Uturn",
.id_table = ccio_tbl,
.probe = ccio_probe,
};
void __init ccio_init(void)
{
register_parisc_driver(&ccio_driver);
}
......@@ -382,7 +382,7 @@ static irqreturn_t dino_isr(int irq, void *intr_dev)
DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
__func__, irq, intr_dev, mask);
generic_handle_irq(irq);
mask &= ~(1 << local_irq);
mask &= ~DINO_MASK_IRQ(local_irq);
} while (mask);
/* Support for level triggered IRQ lines.
......@@ -396,9 +396,8 @@ static irqreturn_t dino_isr(int irq, void *intr_dev)
if (mask) {
if (--ilr_loop > 0)
goto ilr_again;
printk(KERN_ERR "Dino 0x%px: stuck interrupt %d\n",
pr_warn_ratelimited("Dino 0x%px: stuck interrupt %d\n",
dino_dev->hba.base_addr, mask);
return IRQ_NONE;
}
return IRQ_HANDLED;
}
......
......@@ -587,8 +587,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
* (bit #61, big endian), we have to flush and sync every time
* IO-PDIR is changed in Ike/Astro.
*/
if (ioc_needs_fdc)
asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
asm_io_fdc(pdir_ptr);
}
......@@ -641,8 +640,8 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
do {
/* clear I/O Pdir entry "valid" bit first */
((u8 *) pdir_ptr)[7] = 0;
asm_io_fdc(pdir_ptr);
if (ioc_needs_fdc) {
asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
#if 0
entries_per_cacheline = L1_CACHE_SHIFT - 3;
#endif
......@@ -661,8 +660,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
** could dump core on HPMC.
*/
((u8 *) pdir_ptr)[7] = 0;
if (ioc_needs_fdc)
asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
asm_io_fdc(pdir_ptr);
WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM);
}
......@@ -773,8 +771,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
}
/* force FDC ops in io_pdir_entry() to be visible to IOMMU */
if (ioc_needs_fdc)
asm volatile("sync" : : );
asm_io_sync();
#ifdef ASSERT_PDIR_SANITY
sba_check_pdir(ioc,"Check after sba_map_single()");
......@@ -858,8 +855,7 @@ sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
sba_free_range(ioc, iova, size);
/* If fdc's were issued, force fdc's to be visible now */
if (ioc_needs_fdc)
asm volatile("sync" : : );
asm_io_sync();
READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
#endif /* DELAYED_RESOURCE_CNT == 0 */
......@@ -1008,8 +1004,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry);
/* force FDC ops in io_pdir_entry() to be visible to IOMMU */
if (ioc_needs_fdc)
asm volatile("sync" : : );
asm_io_sync();
#ifdef ASSERT_PDIR_SANITY
if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
......
......@@ -48,9 +48,6 @@ fi
tmp=$(mktemp /tmp/vmlinux-XXX)
trap "rm -f $tmp" 0
# Initial attempt for uncompressed images or objects:
check_vmlinux $img
# That didn't work, so retry after decompression.
try_decompress '\037\213\010' xy gunzip
try_decompress '\3757zXZ\000' abcde unxz
......@@ -60,5 +57,8 @@ try_decompress '\211\114\132' xy 'lzop -d'
try_decompress '\002!L\030' xxx 'lz4 -d'
try_decompress '(\265/\375' xxx unzstd
# Finally check for uncompressed images or objects:
check_vmlinux $img
# Bail out:
echo "$me: Cannot find vmlinux." >&2
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment