162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 1996, 1997, 1998, 1999, 2000 by Ralf Baechle
762306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Protected memory access.  Used for everything that might take revenge
1062306a36Sopenharmony_ci * by sending a DBE error like accessing possibly non-existent memory or
1162306a36Sopenharmony_ci * devices.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#ifndef _ASM_PACCESS_H
1462306a36Sopenharmony_ci#define _ASM_PACCESS_H
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/errno.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#ifdef CONFIG_32BIT
1962306a36Sopenharmony_ci#define __PA_ADDR	".word"
2062306a36Sopenharmony_ci#endif
2162306a36Sopenharmony_ci#ifdef CONFIG_64BIT
2262306a36Sopenharmony_ci#define __PA_ADDR	".dword"
2362306a36Sopenharmony_ci#endif
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciextern asmlinkage void handle_ibe(void);
2662306a36Sopenharmony_ciextern asmlinkage void handle_dbe(void);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define put_dbe(x, ptr) __put_dbe((x), (ptr), sizeof(*(ptr)))
2962306a36Sopenharmony_ci#define get_dbe(x, ptr) __get_dbe((x), (ptr), sizeof(*(ptr)))
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct __large_pstruct { unsigned long buf[100]; };
3262306a36Sopenharmony_ci#define __mp(x) (*(struct __large_pstruct *)(x))
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define __get_dbe(x, ptr, size)						\
3562306a36Sopenharmony_ci({									\
3662306a36Sopenharmony_ci	long __gu_err;							\
3762306a36Sopenharmony_ci	__typeof__(*(ptr)) __gu_val;					\
3862306a36Sopenharmony_ci	unsigned long __gu_addr;					\
3962306a36Sopenharmony_ci	__asm__("":"=r" (__gu_val));					\
4062306a36Sopenharmony_ci	__gu_addr = (unsigned long) (ptr);				\
4162306a36Sopenharmony_ci	__asm__("":"=r" (__gu_err));					\
4262306a36Sopenharmony_ci	switch (size) {							\
4362306a36Sopenharmony_ci	case 1: __get_dbe_asm("lb"); break;				\
4462306a36Sopenharmony_ci	case 2: __get_dbe_asm("lh"); break;				\
4562306a36Sopenharmony_ci	case 4: __get_dbe_asm("lw"); break;				\
4662306a36Sopenharmony_ci	case 8:	 __get_dbe_asm("ld"); break;				\
4762306a36Sopenharmony_ci	default: __get_dbe_unknown(); break;				\
4862306a36Sopenharmony_ci	}								\
4962306a36Sopenharmony_ci	x = (__typeof__(*(ptr))) __gu_val;				\
5062306a36Sopenharmony_ci	__gu_err;							\
5162306a36Sopenharmony_ci})
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define __get_dbe_asm(insn)						\
5462306a36Sopenharmony_ci{									\
5562306a36Sopenharmony_ci	__asm__ __volatile__(						\
5662306a36Sopenharmony_ci	"1:\t" insn "\t%1,%2\n\t"					\
5762306a36Sopenharmony_ci	"move\t%0,$0\n"							\
5862306a36Sopenharmony_ci	"2:\n\t"							\
5962306a36Sopenharmony_ci	".insn\n\t"							\
6062306a36Sopenharmony_ci	".section\t.fixup,\"ax\"\n"					\
6162306a36Sopenharmony_ci	"3:\tli\t%0,%3\n\t"						\
6262306a36Sopenharmony_ci	"move\t%1,$0\n\t"						\
6362306a36Sopenharmony_ci	"j\t2b\n\t"							\
6462306a36Sopenharmony_ci	".previous\n\t"							\
6562306a36Sopenharmony_ci	".section\t__dbe_table,\"a\"\n\t"				\
6662306a36Sopenharmony_ci	__PA_ADDR "\t1b, 3b\n\t"					\
6762306a36Sopenharmony_ci	".previous"							\
6862306a36Sopenharmony_ci	:"=r" (__gu_err), "=r" (__gu_val)				\
6962306a36Sopenharmony_ci	:"o" (__mp(__gu_addr)), "i" (-EFAULT));				\
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ciextern void __get_dbe_unknown(void);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define __put_dbe(x, ptr, size)						\
7562306a36Sopenharmony_ci({									\
7662306a36Sopenharmony_ci	long __pu_err;							\
7762306a36Sopenharmony_ci	__typeof__(*(ptr)) __pu_val;					\
7862306a36Sopenharmony_ci	long __pu_addr;							\
7962306a36Sopenharmony_ci	__pu_val = (x);							\
8062306a36Sopenharmony_ci	__pu_addr = (long) (ptr);					\
8162306a36Sopenharmony_ci	__asm__("":"=r" (__pu_err));					\
8262306a36Sopenharmony_ci	switch (size) {							\
8362306a36Sopenharmony_ci	case 1: __put_dbe_asm("sb"); break;				\
8462306a36Sopenharmony_ci	case 2: __put_dbe_asm("sh"); break;				\
8562306a36Sopenharmony_ci	case 4: __put_dbe_asm("sw"); break;				\
8662306a36Sopenharmony_ci	case 8: __put_dbe_asm("sd"); break;				\
8762306a36Sopenharmony_ci	default: __put_dbe_unknown(); break;				\
8862306a36Sopenharmony_ci	}								\
8962306a36Sopenharmony_ci	__pu_err;							\
9062306a36Sopenharmony_ci})
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define __put_dbe_asm(insn)						\
9362306a36Sopenharmony_ci{									\
9462306a36Sopenharmony_ci	__asm__ __volatile__(						\
9562306a36Sopenharmony_ci	"1:\t" insn "\t%1,%2\n\t"					\
9662306a36Sopenharmony_ci	"move\t%0,$0\n"							\
9762306a36Sopenharmony_ci	"2:\n\t"							\
9862306a36Sopenharmony_ci	".insn\n\t"							\
9962306a36Sopenharmony_ci	".section\t.fixup,\"ax\"\n"					\
10062306a36Sopenharmony_ci	"3:\tli\t%0,%3\n\t"						\
10162306a36Sopenharmony_ci	"j\t2b\n\t"							\
10262306a36Sopenharmony_ci	".previous\n\t"							\
10362306a36Sopenharmony_ci	".section\t__dbe_table,\"a\"\n\t"				\
10462306a36Sopenharmony_ci	__PA_ADDR "\t1b, 3b\n\t"					\
10562306a36Sopenharmony_ci	".previous"							\
10662306a36Sopenharmony_ci	: "=r" (__pu_err)						\
10762306a36Sopenharmony_ci	: "r" (__pu_val), "o" (__mp(__pu_addr)), "i" (-EFAULT));	\
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciextern void __put_dbe_unknown(void);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciextern unsigned long search_dbe_table(unsigned long addr);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#endif /* _ASM_PACCESS_H */
115