From 62c4f0a2d5a188f73a94f2cb8ea0dba3e7cf0a7f Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Apr 2006 12:56:16 +0100 Subject: Don't include linux/config.h from anywhere else in include/ Signed-off-by: David Woodhouse --- include/asm-sparc64/atomic.h | 1 - include/asm-sparc64/bitops.h | 1 - include/asm-sparc64/bugs.h | 1 - include/asm-sparc64/cacheflush.h | 1 - include/asm-sparc64/delay.h | 1 - include/asm-sparc64/dma-mapping.h | 1 - include/asm-sparc64/dma.h | 1 - include/asm-sparc64/floppy.h | 1 - include/asm-sparc64/ide.h | 1 - include/asm-sparc64/irq.h | 1 - include/asm-sparc64/kprobes.h | 1 - include/asm-sparc64/mc146818rtc.h | 1 - include/asm-sparc64/mmu.h | 1 - include/asm-sparc64/oplib.h | 1 - include/asm-sparc64/page.h | 1 - include/asm-sparc64/param.h | 1 - include/asm-sparc64/pgalloc.h | 1 - include/asm-sparc64/pgtable.h | 1 - include/asm-sparc64/processor.h | 1 - include/asm-sparc64/siginfo.h | 1 - include/asm-sparc64/signal.h | 1 - include/asm-sparc64/smp.h | 1 - include/asm-sparc64/spinlock.h | 1 - include/asm-sparc64/system.h | 1 - include/asm-sparc64/timer.h | 1 - include/asm-sparc64/tlb.h | 1 - include/asm-sparc64/tlbflush.h | 1 - include/asm-sparc64/ttable.h | 1 - 28 files changed, 28 deletions(-) (limited to 'include/asm-sparc64') diff --git a/include/asm-sparc64/atomic.h b/include/asm-sparc64/atomic.h index 468eb48d814..2f0bec26a69 100644 --- a/include/asm-sparc64/atomic.h +++ b/include/asm-sparc64/atomic.h @@ -8,7 +8,6 @@ #ifndef __ARCH_SPARC64_ATOMIC__ #define __ARCH_SPARC64_ATOMIC__ -#include #include typedef struct { volatile int counter; } atomic_t; diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h index 71944b0f09d..3d5e1af8472 100644 --- a/include/asm-sparc64/bitops.h +++ b/include/asm-sparc64/bitops.h @@ -7,7 +7,6 @@ #ifndef _SPARC64_BITOPS_H #define _SPARC64_BITOPS_H -#include #include #include diff --git a/include/asm-sparc64/bugs.h b/include/asm-sparc64/bugs.h index 360dd04ed8e..120422fdb02 100644 --- a/include/asm-sparc64/bugs.h +++ b/include/asm-sparc64/bugs.h @@ -4,7 +4,6 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ -#include extern unsigned long loops_per_jiffy; diff --git a/include/asm-sparc64/cacheflush.h b/include/asm-sparc64/cacheflush.h index b3f61659ba8..745d1ab6037 100644 --- a/include/asm-sparc64/cacheflush.h +++ b/include/asm-sparc64/cacheflush.h @@ -1,7 +1,6 @@ #ifndef _SPARC64_CACHEFLUSH_H #define _SPARC64_CACHEFLUSH_H -#include #include #ifndef __ASSEMBLY__ diff --git a/include/asm-sparc64/delay.h b/include/asm-sparc64/delay.h index 2901ea0c342..a4aae6f8062 100644 --- a/include/asm-sparc64/delay.h +++ b/include/asm-sparc64/delay.h @@ -11,7 +11,6 @@ #ifndef __SPARC64_DELAY_H #define __SPARC64_DELAY_H -#include #include #include diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h index c7d5804ba76..c902a96d1d4 100644 --- a/include/asm-sparc64/dma-mapping.h +++ b/include/asm-sparc64/dma-mapping.h @@ -1,7 +1,6 @@ #ifndef _ASM_SPARC64_DMA_MAPPING_H #define _ASM_SPARC64_DMA_MAPPING_H -#include #ifdef CONFIG_PCI #include diff --git a/include/asm-sparc64/dma.h b/include/asm-sparc64/dma.h index 1aab3c8dce2..27f65972b3b 100644 --- a/include/asm-sparc64/dma.h +++ b/include/asm-sparc64/dma.h @@ -7,7 +7,6 @@ #ifndef _ASM_SPARC64_DMA_H #define _ASM_SPARC64_DMA_H -#include #include #include #include diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index 6a95d5d0c57..07ccd6f04b5 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -10,7 +10,6 @@ #ifndef __ASM_SPARC64_FLOPPY_H #define __ASM_SPARC64_FLOPPY_H -#include #include #include diff --git a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h index c393f815b0b..55149cf933c 100644 --- a/include/asm-sparc64/ide.h +++ b/include/asm-sparc64/ide.h @@ -10,7 +10,6 @@ #ifdef __KERNEL__ -#include #include #include #include diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index de33d6e1afb..fa164d37ee3 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -8,7 +8,6 @@ #ifndef _SPARC64_IRQ_H #define _SPARC64_IRQ_H -#include #include #include #include diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h index e4efe652b54..e9bb26f770e 100644 --- a/include/asm-sparc64/kprobes.h +++ b/include/asm-sparc64/kprobes.h @@ -1,7 +1,6 @@ #ifndef _SPARC64_KPROBES_H #define _SPARC64_KPROBES_H -#include #include #include diff --git a/include/asm-sparc64/mc146818rtc.h b/include/asm-sparc64/mc146818rtc.h index 75bd572b35f..e9c0fcc25c6 100644 --- a/include/asm-sparc64/mc146818rtc.h +++ b/include/asm-sparc64/mc146818rtc.h @@ -4,7 +4,6 @@ #ifndef __ASM_SPARC64_MC146818RTC_H #define __ASM_SPARC64_MC146818RTC_H -#include #include #ifndef RTC_PORT diff --git a/include/asm-sparc64/mmu.h b/include/asm-sparc64/mmu.h index 2d4f2ea9568..70af4b6ce13 100644 --- a/include/asm-sparc64/mmu.h +++ b/include/asm-sparc64/mmu.h @@ -1,7 +1,6 @@ #ifndef __MMU_H #define __MMU_H -#include #include #include #include diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h index c754676e13e..dea3e73f095 100644 --- a/include/asm-sparc64/oplib.h +++ b/include/asm-sparc64/oplib.h @@ -9,7 +9,6 @@ #ifndef __SPARC64_OPLIB_H #define __SPARC64_OPLIB_H -#include #include /* OBP version string. */ diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h index aabb2190672..fdf0ceb7602 100644 --- a/include/asm-sparc64/page.h +++ b/include/asm-sparc64/page.h @@ -3,7 +3,6 @@ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H -#include #include #if defined(CONFIG_SPARC64_PAGE_SIZE_8KB) diff --git a/include/asm-sparc64/param.h b/include/asm-sparc64/param.h index a1cd4974630..f0125cf5a9d 100644 --- a/include/asm-sparc64/param.h +++ b/include/asm-sparc64/param.h @@ -1,7 +1,6 @@ #ifndef _ASMSPARC64_PARAM_H #define _ASMSPARC64_PARAM_H -#include #ifdef __KERNEL__ # define HZ CONFIG_HZ /* Internal kernel timer frequency */ diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h index 12e4a273bd4..010f9cd0a67 100644 --- a/include/asm-sparc64/pgalloc.h +++ b/include/asm-sparc64/pgalloc.h @@ -2,7 +2,6 @@ #ifndef _SPARC64_PGALLOC_H #define _SPARC64_PGALLOC_H -#include #include #include #include diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index c44e7466534..72f9a524dc6 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -14,7 +14,6 @@ #include -#include #include #include #include diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h index c6896b88283..66dd2fa0e31 100644 --- a/include/asm-sparc64/processor.h +++ b/include/asm-sparc64/processor.h @@ -13,7 +13,6 @@ */ #define current_text_addr() ({ void *pc; __asm__("rd %%pc, %0" : "=r" (pc)); pc; }) -#include #include #include #include diff --git a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h index df17e47abc1..c96e6c30f8b 100644 --- a/include/asm-sparc64/siginfo.h +++ b/include/asm-sparc64/siginfo.h @@ -11,7 +11,6 @@ #ifdef __KERNEL__ -#include #include #ifdef CONFIG_COMPAT diff --git a/include/asm-sparc64/signal.h b/include/asm-sparc64/signal.h index e3059bb4a46..fdc42a14d4e 100644 --- a/include/asm-sparc64/signal.h +++ b/include/asm-sparc64/signal.h @@ -6,7 +6,6 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -#include #include #include #include diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index 89d86ecaab2..388249b751c 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -6,7 +6,6 @@ #ifndef _SPARC64_SMP_H #define _SPARC64_SMP_H -#include #include #include #include diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h index 508c416e9d6..bd5ffc76bc7 100644 --- a/include/asm-sparc64/spinlock.h +++ b/include/asm-sparc64/spinlock.h @@ -6,7 +6,6 @@ #ifndef __SPARC64_SPINLOCK_H #define __SPARC64_SPINLOCK_H -#include #include /* For NR_CPUS */ #ifndef __ASSEMBLY__ diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index a18ec87a52c..4ca68600c67 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -2,7 +2,6 @@ #ifndef __SPARC64_SYSTEM_H #define __SPARC64_SYSTEM_H -#include #include #include #include diff --git a/include/asm-sparc64/timer.h b/include/asm-sparc64/timer.h index edc8e08c3a3..d435594df78 100644 --- a/include/asm-sparc64/timer.h +++ b/include/asm-sparc64/timer.h @@ -9,7 +9,6 @@ #include -#include struct sparc64_tick_ops { void (*init_tick)(unsigned long); diff --git a/include/asm-sparc64/tlb.h b/include/asm-sparc64/tlb.h index 61c01882b56..7af1e1109c4 100644 --- a/include/asm-sparc64/tlb.h +++ b/include/asm-sparc64/tlb.h @@ -1,7 +1,6 @@ #ifndef _SPARC64_TLB_H #define _SPARC64_TLB_H -#include #include #include #include diff --git a/include/asm-sparc64/tlbflush.h b/include/asm-sparc64/tlbflush.h index 9ad5d9c51d4..0386014ecf2 100644 --- a/include/asm-sparc64/tlbflush.h +++ b/include/asm-sparc64/tlbflush.h @@ -1,7 +1,6 @@ #ifndef _SPARC64_TLBFLUSH_H #define _SPARC64_TLBFLUSH_H -#include #include #include diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h index 2d5e3c464df..f2352606a79 100644 --- a/include/asm-sparc64/ttable.h +++ b/include/asm-sparc64/ttable.h @@ -2,7 +2,6 @@ #ifndef _SPARC64_TTABLE_H #define _SPARC64_TTABLE_H -#include #include #ifdef __ASSEMBLY__ -- cgit v1.2.3-70-g09d2 From 56142536868a2be34f261ed8fdca1610f8a73fbd Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 29 Apr 2006 01:51:47 +0100 Subject: Remove unneeded _syscallX macros from user view in asm-*/unistd.h These aren't needed by glibc or klibc, and they're broken in some cases anyway. The uClibc folks are apparently switching over to stop using them too (now that we agreed that they should be dropped, at least). Signed-off-by: David Woodhouse --- include/asm-alpha/unistd.h | 7 ++++--- include/asm-arm/unistd.h | 10 +++++----- include/asm-arm26/unistd.h | 10 +++++----- include/asm-cris/unistd.h | 9 ++++----- include/asm-frv/unistd.h | 7 ++++--- include/asm-h8300/unistd.h | 7 ++++--- include/asm-i386/unistd.h | 7 ++++--- include/asm-m32r/unistd.h | 5 +++-- include/asm-m68k/unistd.h | 7 ++++--- include/asm-m68knommu/unistd.h | 7 ++++--- include/asm-mips/unistd.h | 6 +++--- include/asm-parisc/unistd.h | 4 ++-- include/asm-powerpc/unistd.h | 7 +++---- include/asm-s390/unistd.h | 7 ++++--- include/asm-sh/unistd.h | 7 ++++--- include/asm-sh64/unistd.h | 7 ++++--- include/asm-sparc/unistd.h | 4 ++-- include/asm-sparc64/unistd.h | 4 ++-- include/asm-v850/unistd.h | 12 ++++-------- include/asm-x86_64/unistd.h | 7 ++++--- include/asm-xtensa/unistd.h | 21 +++------------------ 21 files changed, 76 insertions(+), 86 deletions(-) (limited to 'include/asm-sparc64') diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h index ef25b658511..bc6e6a9259d 100644 --- a/include/asm-alpha/unistd.h +++ b/include/asm-alpha/unistd.h @@ -383,6 +383,8 @@ #define __NR_inotify_add_watch 445 #define __NR_inotify_rm_watch 446 +#ifdef __KERNEL__ + #define NR_SYSCALLS 447 #if defined(__GNUC__) @@ -565,9 +567,8 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, type6 arg6)\ _syscall_return(type); \ } -#endif /* __LIBRARY__ && __GNUC__ */ +#endif /* __GNUC__ */ -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_STAT64 @@ -578,7 +579,6 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, type6 arg6)\ #define __ARCH_WANT_SYS_OLD_GETRLIMIT #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING -#endif #ifdef __KERNEL_SYSCALLS__ @@ -661,4 +661,5 @@ asmlinkage long sys_rt_sigaction(int sig, #define cond_syscall(x) asm(".weak\t" #x "\n" #x " = sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* _ALPHA_UNISTD_H */ diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index ee8dfea549b..a5896d94e1a 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -13,8 +13,6 @@ #ifndef __ASM_ARM_UNISTD_H #define __ASM_ARM_UNISTD_H -#include - #define __NR_OABI_SYSCALL_BASE 0x900000 #if defined(__thumb__) || defined(__ARM_EABI__) @@ -378,6 +376,9 @@ #undef __NR_ipc #endif +#ifdef __KERNEL__ +#include + #define __sys2(x) #x #define __sys1(x) __sys2(x) @@ -519,7 +520,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 __syscall_return(type,__res); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_GETHOSTNAME @@ -540,7 +540,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_SYS_SOCKETCALL #endif -#endif #ifdef __KERNEL_SYSCALLS__ @@ -564,7 +563,7 @@ asmlinkage long sys_rt_sigaction(int sig, struct sigaction __user *oact, size_t sigsetsize); -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -574,4 +573,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* __ASM_ARM_UNISTD_H */ diff --git a/include/asm-arm26/unistd.h b/include/asm-arm26/unistd.h index be4c2fb9c04..70eb6d91cfd 100644 --- a/include/asm-arm26/unistd.h +++ b/include/asm-arm26/unistd.h @@ -14,8 +14,6 @@ #ifndef __ASM_ARM_UNISTD_H #define __ASM_ARM_UNISTD_H -#include - #define __NR_SYSCALL_BASE 0x900000 /* @@ -312,6 +310,9 @@ #define __ARM_NR_cacheflush (__ARM_NR_BASE+2) #define __ARM_NR_usr26 (__ARM_NR_BASE+3) +#ifdef __KERNEL__ +#include + #define __sys2(x) #x #define __sys1(x) __sys2(x) @@ -443,7 +444,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 __syscall_return(type,__res); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_STAT64 @@ -462,7 +462,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#endif #ifdef __KERNEL_SYSCALLS__ @@ -486,7 +485,7 @@ asmlinkage long sys_rt_sigaction(int sig, struct sigaction __user *oact, size_t sigsetsize); -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -496,4 +495,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* __ASM_ARM_UNISTD_H */ diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h index bb2dfe48021..c2954e90aa2 100644 --- a/include/asm-cris/unistd.h +++ b/include/asm-cris/unistd.h @@ -295,11 +295,11 @@ #define __NR_request_key 287 #define __NR_keyctl 288 -#define NR_syscalls 289 +#ifdef __KERNEL__ +#define NR_syscalls 289 -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT @@ -379,12 +379,10 @@ asmlinkage long sys_rt_sigaction(int sig, * complaints. We don't want to use -fno-builtin, so just use a * different name when in the kernel. */ -#ifdef __KERNEL__ #define _exit kernel_syscall_exit -#endif static inline _syscall1(int,_exit,int,exitcode) static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* @@ -395,4 +393,5 @@ static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* _ASM_CRIS_UNISTD_H_ */ diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h index 2662a3e12dc..7c2e712c3b7 100644 --- a/include/asm-frv/unistd.h +++ b/include/asm-frv/unistd.h @@ -317,6 +317,8 @@ #define __NR_pselect6 308 #define __NR_ppoll 309 +#ifdef __KERNEL__ + #define NR_syscalls 310 /* @@ -477,9 +479,8 @@ static inline pid_t wait(int * wait_stat) return waitpid(-1,wait_stat,0); } -#endif +#endif /* __KERNEL_SYSCALLS__ */ -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION /* #define __ARCH_WANT_OLD_READDIR */ #define __ARCH_WANT_OLD_STAT @@ -503,7 +504,6 @@ static inline pid_t wait(int * wait_stat) #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND -#endif /* * "Conditional" syscalls @@ -515,4 +515,5 @@ static inline pid_t wait(int * wait_stat) #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") #endif +#endif /* __KERNEL__ */ #endif /* _ASM_UNISTD_H_ */ diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h index adb05159379..226dd596c2d 100644 --- a/include/asm-h8300/unistd.h +++ b/include/asm-h8300/unistd.h @@ -292,6 +292,8 @@ #define __NR_request_key 287 #define __NR_keyctl 288 +#ifdef __KERNEL__ + #define NR_syscalls 289 @@ -460,7 +462,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e, ftype f) \ __syscall_return(type, __res); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT @@ -483,7 +484,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e, ftype f) \ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#endif #ifdef __KERNEL_SYSCALLS__ @@ -534,7 +534,7 @@ asmlinkage long sys_rt_sigaction(int sig, struct sigaction __user *oact, size_t sigsetsize); -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -543,4 +543,5 @@ asmlinkage long sys_rt_sigaction(int sig, asm (".weak\t_" #name "\n" \ ".set\t_" #name ",_sys_ni_syscall"); +#endif /* __KERNEL__ */ #endif /* _ASM_H8300_UNISTD_H_ */ diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index eb4b152c82f..de2ccc149e3 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -323,6 +323,8 @@ #define __NR_tee 315 #define __NR_vmsplice 316 +#ifdef __KERNEL__ + #define NR_syscalls 317 /* @@ -422,7 +424,6 @@ __asm__ volatile ("push %%ebp ; push %%ebx ; movl 4(%2),%%ebp ; " \ __syscall_return(type,__res); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT @@ -446,7 +447,6 @@ __syscall_return(type,__res); \ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND -#endif #ifdef __KERNEL_SYSCALLS__ @@ -485,7 +485,7 @@ asmlinkage long sys_rt_sigaction(int sig, struct sigaction __user *oact, size_t sigsetsize); -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -497,4 +497,5 @@ asmlinkage long sys_rt_sigaction(int sig, #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") #endif +#endif /* __KERNEL__ */ #endif /* _ASM_I386_UNISTD_H_ */ diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h index be0eb014c3b..cc31790d807 100644 --- a/include/asm-m32r/unistd.h +++ b/include/asm-m32r/unistd.h @@ -295,6 +295,8 @@ #define __NR_kexec_load 283 #define __NR_waitid 284 +#ifdef __KERNEL__ + #define NR_syscalls 285 /* user-visible error numbers are in the range -1 - -124: see @@ -405,7 +407,6 @@ __asm__ __volatile__ (\ __syscall_return(type,__res); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_ALARM @@ -421,7 +422,6 @@ __syscall_return(type,__res); \ #define __ARCH_WANT_SYS_OLD_GETRLIMIT /*will be unused*/ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_RT_SIGACTION -#endif #ifdef __KERNEL_SYSCALLS__ @@ -470,4 +470,5 @@ asmlinkage long sys_rt_sigaction(int sig, #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") #endif +#endif /* __KERNEL__ */ #endif /* _ASM_M32R_UNISTD_H */ diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index c2554bcd174..f236fe92156 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h @@ -285,6 +285,8 @@ #define __NR_request_key 280 #define __NR_keyctl 281 +#ifdef __KERNEL__ + #define NR_syscalls 282 /* user-visible error numbers are in the range -1 - -124: see @@ -383,7 +385,6 @@ __asm__ __volatile__ ("trap #0" \ __syscall_return(type,__res); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT @@ -406,7 +407,6 @@ __syscall_return(type,__res); \ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#endif #ifdef __KERNEL_SYSCALLS__ @@ -451,7 +451,7 @@ asmlinkage long sys_rt_sigaction(int sig, struct sigaction __user *oact, size_t sigsetsize); -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -461,4 +461,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* _ASM_M68K_UNISTD_H_ */ diff --git a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h index 5373988a7e5..1b2abdf281e 100644 --- a/include/asm-m68knommu/unistd.h +++ b/include/asm-m68knommu/unistd.h @@ -286,6 +286,8 @@ #define __NR_request_key 280 #define __NR_keyctl 281 +#ifdef __KERNEL__ + #define NR_syscalls 282 /* user-visible error numbers are in the range -1 - -122: see @@ -437,7 +439,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e) \ return (type)__res; \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT @@ -460,7 +461,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e) \ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#endif #ifdef __KERNEL_SYSCALLS__ @@ -515,7 +515,7 @@ asmlinkage long sys_rt_sigaction(int sig, struct sigaction __user *oact, size_t sigsetsize); -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -525,4 +525,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* _ASM_M68K_UNISTD_H_ */ diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h index e71f161a489..8bb0bb9b2e6 100644 --- a/include/asm-mips/unistd.h +++ b/include/asm-mips/unistd.h @@ -905,6 +905,8 @@ #define __NR_N32_Linux 6000 #define __NR_N32_Linux_syscalls 268 +#ifdef __KERNEL__ + #ifndef __ASSEMBLY__ /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ @@ -1168,8 +1170,6 @@ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \ #endif /* (_MIPS_SIM == _MIPS_SIM_NABI32) || (_MIPS_SIM == _MIPS_SIM_ABI64) */ -#ifdef __KERNEL__ - #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR @@ -1196,7 +1196,6 @@ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \ # ifdef CONFIG_MIPS32_O32 # define __ARCH_WANT_COMPAT_SYS_TIME # endif -#endif #ifdef __KERNEL_SYSCALLS__ @@ -1247,4 +1246,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* _ASM_UNISTD_H */ diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h index 0e1a30be2e3..12b867238a4 100644 --- a/include/asm-parisc/unistd.h +++ b/include/asm-parisc/unistd.h @@ -792,6 +792,7 @@ #define HPUX_GATEWAY_ADDR 0xC0000004 #define LINUX_GATEWAY_ADDR 0x100 +#ifdef __KERNEL__ #ifndef __ASSEMBLY__ #define SYS_ify(syscall_name) __NR_##syscall_name @@ -934,7 +935,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ return K_INLINE_SYSCALL(name, 5, arg1, arg2, arg3, arg4, arg5); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_ALARM @@ -956,7 +956,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#endif /* mmap & mmap2 take 6 arguments */ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \ @@ -1056,4 +1055,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* _ASM_PARISC_UNISTD_H_ */ diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h index ef932f1cddc..bd3c6b6cc50 100644 --- a/include/asm-powerpc/unistd.h +++ b/include/asm-powerpc/unistd.h @@ -305,12 +305,12 @@ #define __NR_tee 284 #define __NR_vmsplice 285 +#ifdef __KERNEL__ + #define __NR_syscalls 286 -#ifdef __KERNEL__ #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls -#endif #ifndef __ASSEMBLY__ @@ -422,7 +422,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 __syscall_nr(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \ } -#ifdef __KERNEL__ #include #include @@ -478,8 +477,8 @@ extern int execve(const char *file, char **argv, char **envp); #define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",.sys_ni_syscall") #endif -#endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ #endif /* _ASM_PPC_UNISTD_H_ */ diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index ac790bf4455..40efbe84221 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -386,6 +386,8 @@ #endif +#ifdef __KERNEL__ + /* user-visible error numbers are in the range -1 - -122: see */ #define __syscall_return(type, res) \ @@ -540,7 +542,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ __syscall_return(type,__res); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_SYS_ALARM @@ -567,7 +568,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ # define __ARCH_WANT_COMPAT_SYS_TIME # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND # endif -#endif #ifdef __KERNEL_SYSCALLS__ @@ -618,7 +618,7 @@ asmlinkage long sys_rt_sigaction(int sig, struct sigaction __user *oact, size_t sigsetsize); -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -628,4 +628,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* _ASM_S390_UNISTD_H_ */ diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index 05520cebda1..76b5430cb45 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h @@ -304,6 +304,8 @@ #define NR_syscalls 293 +#ifdef __KERNEL__ + /* user-visible error numbers are in the range -1 - -124: see */ #define __syscall_return(type, res) \ @@ -420,7 +422,6 @@ __asm__ __volatile__ ("trapa #0x16" \ __syscall_return(type,__sc0); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT @@ -443,7 +444,6 @@ __syscall_return(type,__sc0); \ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#endif #ifdef __KERNEL_SYSCALLS__ @@ -513,7 +513,7 @@ asmlinkage long sys_rt_sigaction(int sig, struct sigaction __user *oact, size_t sigsetsize); -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -525,4 +525,5 @@ asmlinkage long sys_rt_sigaction(int sig, #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") #endif +#endif /* __KERNEL__ */ #endif /* __ASM_SH_UNISTD_H */ diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h index 1f8f394ae37..9a1590fffc1 100644 --- a/include/asm-sh64/unistd.h +++ b/include/asm-sh64/unistd.h @@ -344,6 +344,8 @@ #define __NR_inotify_add_watch 319 #define __NR_inotify_rm_watch 320 +#ifdef __KERNEL__ + #define NR_syscalls 321 /* user-visible error numbers are in the range -1 - -125: see */ @@ -486,7 +488,6 @@ __asm__ __volatile__ ("!dummy %0 %1 %2 %3 %4 %5 %6" \ __syscall_return(type,__sc0); \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT @@ -509,7 +510,6 @@ __syscall_return(type,__sc0); \ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#endif #ifdef __KERNEL_SYSCALLS__ @@ -550,7 +550,7 @@ static inline pid_t wait(int * wait_stat) { return waitpid(-1,wait_stat,0); } -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -562,4 +562,5 @@ static inline pid_t wait(int * wait_stat) #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") #endif +#endif /* __KERNEL__ */ #endif /* __ASM_SH64_UNISTD_H */ diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index 32a48f623e2..7bd5a7dd678 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h @@ -317,6 +317,7 @@ #define __NR_ppoll 298 #define __NR_unshare 299 +#ifdef __KERNEL__ /* WARNING: You MAY NOT add syscall numbers larger than 299, since * all of the syscall tables in the Sparc kernel are * sized to have 299 entries (starting at zero). Therefore @@ -453,7 +454,6 @@ errno = -__res; \ return -1; \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_STAT64 @@ -475,7 +475,6 @@ return -1; \ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGSUSPEND -#endif #ifdef __KERNEL_SYSCALLS__ @@ -532,4 +531,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* _SPARC_UNISTD_H */ diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h index ca80e8aca12..18f7b1a2517 100644 --- a/include/asm-sparc64/unistd.h +++ b/include/asm-sparc64/unistd.h @@ -319,6 +319,7 @@ #define __NR_ppoll 298 #define __NR_unshare 299 +#ifdef __KERNEL__ /* WARNING: You MAY NOT add syscall numbers larger than 299, since * all of the syscall tables in the Sparc kernel are * sized to have 299 entries (starting at zero). Therefore @@ -485,7 +486,6 @@ asmlinkage long sys_rt_sigaction(int sig, #endif /* __KERNEL_SYSCALLS__ */ -#ifdef __KERNEL__ /* sysconf options, for SunOS compatibility */ #define _SC_ARG_MAX 1 #define _SC_CHILD_MAX 2 @@ -519,7 +519,6 @@ asmlinkage long sys_rt_sigaction(int sig, #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGSUSPEND #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND -#endif /* * "Conditional" syscalls @@ -529,4 +528,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif /* _SPARC64_UNISTD_H */ diff --git a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h index 82460a7bb23..bcb44bfe577 100644 --- a/include/asm-v850/unistd.h +++ b/include/asm-v850/unistd.h @@ -14,8 +14,6 @@ #ifndef __V850_UNISTD_H__ #define __V850_UNISTD_H__ -#include - #define __NR_restart_syscall 0 #define __NR_exit 1 #define __NR_fork 2 @@ -237,10 +235,9 @@ except the syscall number (r12). */ #define SYSCALL_SHORT_CLOBBERS SYSCALL_CLOBBERS, "r13", "r14" +#ifdef __KERNEL__ -/* User programs sometimes end up including this header file - (indirectly, via uClibc header files), so I'm a bit nervous just - including . */ +#include #define __syscall_return(type, res) \ do { \ @@ -368,7 +365,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e, ftype f) \ } -#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_STAT64 @@ -389,7 +385,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e, ftype f) \ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION -#endif #ifdef __KERNEL_SYSCALLS__ @@ -440,7 +435,7 @@ asmlinkage long sys_rt_sigaction(int sig, struct sigaction __user *oact, size_t sigsetsize); -#endif +#endif /* __KERNEL_SYSCALLS__ */ /* * "Conditional" syscalls @@ -455,4 +450,5 @@ asmlinkage long sys_rt_sigaction(int sig, void name (void) __attribute__ ((weak, alias ("sys_ni_syscall"))); #endif +#endif /* __KERNEL__ */ #endif /* __V850_UNISTD_H__ */ diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index feb77cb8c04..0aff22bdbb2 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -618,6 +618,8 @@ __SYSCALL(__NR_sync_file_range, sys_sync_file_range) #define __NR_vmsplice 278 __SYSCALL(__NR_vmsplice, sys_vmsplice) +#ifdef __KERNEL__ + #define __NR_syscall_max __NR_vmsplice #ifndef __NO_STUBS @@ -635,7 +637,6 @@ do { \ return (type) (res); \ } while (0) -#ifdef __KERNEL__ #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT #define __ARCH_WANT_SYS_ALARM @@ -657,7 +658,6 @@ do { \ #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_TIME #define __ARCH_WANT_COMPAT_SYS_TIME -#endif #ifndef __KERNEL_SYSCALLS__ @@ -821,7 +821,7 @@ asmlinkage long sys_pipe(int *fildes); #endif /* __KERNEL_SYSCALLS__ */ -#if !defined(__ASSEMBLY__) && defined(__KERNEL__) +#ifndef __ASSEMBLY__ #include #include @@ -848,4 +848,5 @@ asmlinkage long sys_rt_sigaction(int sig, */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") +#endif /* __KERNEL__ */ #endif diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h index 6b39d6609d9..5e1b99dc4ab 100644 --- a/include/asm-xtensa/unistd.h +++ b/include/asm-xtensa/unistd.h @@ -11,8 +11,6 @@ #ifndef _XTENSA_UNISTD_H #define _XTENSA_UNISTD_H -#include - #define __NR_spill 0 #define __NR_exit 1 #define __NR_read 3 @@ -221,21 +219,9 @@ #define SYSXTENSA_COUNT 5 /* count of syscall0 functions*/ #ifdef __KERNEL__ -#define __syscall_return(type, res) return ((type)(res)) -#else -#define __syscall_return(type, res) \ -do { \ - if ((unsigned long)(res) >= (unsigned long)(-125)) { \ - /* Avoid using "res" which is declared to be in register r2; \ - * errno might expand to a function call and clobber it. */ \ - int __err = -(res); \ - errno = __err; \ - res = -1; \ - } \ - return (type) (res); \ -} while (0) -#endif +#include +#define __syscall_return(type, res) return ((type)(res)) /* Tensilica's xt-xcc compiler is much more agressive at code * optimization than gcc. Multiple __asm__ statements are @@ -429,11 +415,10 @@ static __inline__ _syscall3(int,execve,const char*,file,char**,argv,char**,envp) */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); -#ifdef __KERNEL__ #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_UTIME #define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_RT_SIGACTION -#endif +#endif /* __KERNEL__ */ #endif /* _XTENSA_UNISTD_H */ -- cgit v1.2.3-70-g09d2 From fd0504c3217d6d1bc8f33f53fb536299cae8feda Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:20:00 -0700 Subject: [SPARC64]: Send all device interrupts via one PIL. This is the first in a series of cleanups that will hopefully allow a seamless attempt at using the generic IRQ handling infrastructure in the Linux kernel. Define PIL_DEVICE_IRQ and vector all device interrupts through there. Get rid of the ugly pil0_dummy_{bucket,desc}, instead vector the timer interrupt directly to a specific handler since the timer interrupt is the only event that will be signaled on PIL 14. The irq_worklist is now in the per-cpu trap_block[]. Signed-off-by: David S. Miller --- arch/sparc64/kernel/entry.S | 11 +-- arch/sparc64/kernel/irq.c | 163 +++++++++++++++++---------------------- arch/sparc64/kernel/sun4v_ivec.S | 13 +--- arch/sparc64/kernel/time.c | 16 +--- arch/sparc64/kernel/traps.c | 4 +- arch/sparc64/kernel/ttable.S | 10 +-- include/asm-sparc64/cpudata.h | 19 ++--- include/asm-sparc64/pil.h | 7 +- 8 files changed, 101 insertions(+), 142 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 6d0b3ed77a0..c87365e59e7 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -22,6 +22,7 @@ #include #include #include +#include #define curptr g6 @@ -434,17 +435,13 @@ do_ivec: sllx %g3, 5, %g3 or %g2, %lo(ivector_table), %g2 add %g2, %g3, %g3 - ldub [%g3 + 0x04], %g4 /* pil */ - mov 1, %g2 - sllx %g2, %g4, %g2 - sllx %g4, 2, %g4 TRAP_LOAD_IRQ_WORK(%g6, %g1) - lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */ + lduw [%g6], %g5 /* g5 = irq_work(cpu) */ stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ - stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */ - wr %g2, 0x0, %set_softint + stw %g3, [%g6] /* irq_work(cpu) = bucket */ + wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint retry do_ivec_xcall: mov 0x50, %g1 diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 11e645c9ec5..0fb1738a4f3 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -68,11 +68,7 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY * access to this structure takes a TLB miss it could cause * the 5-level sparc v9 trap stack to overflow. */ -struct irq_work_struct { - unsigned int irq_worklists[16]; -}; -struct irq_work_struct __irq_work[NR_CPUS]; -#define irq_work(__cpu, __pil) &(__irq_work[(__cpu)].irq_worklists[(__pil)]) +#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) static struct irqaction *irq_action[NR_IRQS+1]; @@ -91,10 +87,8 @@ static void register_irq_proc (unsigned int irq); */ #define put_ino_in_irqaction(action, irq) \ action->flags &= 0xffffffffffffUL; \ - if (__bucket(irq) == &pil0_dummy_bucket) \ - action->flags |= 0xdeadUL << 48; \ - else \ - action->flags |= __irq_ino(irq) << 48; + action->flags |= __irq_ino(irq) << 48; + #define get_ino_in_irqaction(action) (action->flags >> 48) #define put_smpaff_in_irqaction(action, smpaff) (action)->mask = (smpaff) @@ -251,15 +245,6 @@ void disable_irq(unsigned int irq) } } -/* The timer is the one "weird" interrupt which is generated by - * the CPU %tick register and not by some normal vectored interrupt - * source. To handle this special case, we use this dummy INO bucket. - */ -static struct irq_desc pil0_dummy_desc; -static struct ino_bucket pil0_dummy_bucket = { - .irq_info = &pil0_dummy_desc, -}; - static void build_irq_error(const char *msg, unsigned int ino, int pil, int inofixup, unsigned long iclr, unsigned long imap, struct ino_bucket *bucket) @@ -276,15 +261,7 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long struct ino_bucket *bucket; int ino; - if (pil == 0) { - if (iclr != 0UL || imap != 0UL) { - prom_printf("Invalid dummy bucket for PIL0 (%lx:%lx)\n", - iclr, imap); - prom_halt(); - } - return __irq(&pil0_dummy_bucket); - } - + BUG_ON(pil == 0); BUG_ON(tlb_type == hypervisor); /* RULE: Both must be specified in all other cases. */ @@ -371,7 +348,7 @@ static void atomic_bucket_insert(struct ino_bucket *bucket) __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); __asm__ __volatile__("wrpr %0, %1, %%pstate" : : "r" (pstate), "i" (PSTATE_IE)); - ent = irq_work(smp_processor_id(), bucket->pil); + ent = irq_work(smp_processor_id()); bucket->irq_chain = *ent; *ent = __irq(bucket); __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); @@ -437,7 +414,7 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ if (unlikely(!bucket->irq_info)) return -ENODEV; - if ((bucket != &pil0_dummy_bucket) && (irqflags & SA_SAMPLE_RANDOM)) { + if (irqflags & SA_SAMPLE_RANDOM) { /* * This function might sleep, we want to call it first, * outside of the atomic block. In SA_STATIC_ALLOC case, @@ -465,12 +442,9 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ } bucket->flags |= IBF_ACTIVE; - pending = 0; - if (bucket != &pil0_dummy_bucket) { - pending = bucket->pending; - if (pending) - bucket->pending = 0; - } + pending = bucket->pending; + if (pending) + bucket->pending = 0; action->handler = handler; action->flags = irqflags; @@ -487,13 +461,12 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ /* We ate the IVEC already, this makes sure it does not get lost. */ if (pending) { atomic_bucket_insert(bucket); - set_softint(1 << bucket->pil); + set_softint(1 << PIL_DEVICE_IRQ); } spin_unlock_irqrestore(&irq_action_lock, flags); - if (bucket != &pil0_dummy_bucket) - register_irq_proc(__irq_ino(irq)); + register_irq_proc(__irq_ino(irq)); #ifdef CONFIG_SMP distribute_irqs(); @@ -533,7 +506,9 @@ void free_irq(unsigned int irq, void *dev_id) { struct irqaction *action; struct ino_bucket *bucket; + struct irq_desc *desc; unsigned long flags; + int ent, i; spin_lock_irqsave(&irq_action_lock, flags); @@ -549,42 +524,39 @@ void free_irq(unsigned int irq, void *dev_id) spin_lock_irqsave(&irq_action_lock, flags); bucket = __bucket(irq); - if (bucket != &pil0_dummy_bucket) { - struct irq_desc *desc = bucket->irq_info; - int ent, i; + desc = bucket->irq_info; - for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { - struct irqaction *p = &desc->action[i]; + for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { + struct irqaction *p = &desc->action[i]; - if (p == action) { - desc->action_active_mask &= ~(1 << i); - break; - } + if (p == action) { + desc->action_active_mask &= ~(1 << i); + break; } + } - if (!desc->action_active_mask) { - unsigned long imap = bucket->imap; - - /* This unique interrupt source is now inactive. */ - bucket->flags &= ~IBF_ACTIVE; + if (!desc->action_active_mask) { + unsigned long imap = bucket->imap; - /* See if any other buckets share this bucket's IMAP - * and are still active. - */ - for (ent = 0; ent < NUM_IVECS; ent++) { - struct ino_bucket *bp = &ivector_table[ent]; - if (bp != bucket && - bp->imap == imap && - (bp->flags & IBF_ACTIVE) != 0) - break; - } + /* This unique interrupt source is now inactive. */ + bucket->flags &= ~IBF_ACTIVE; - /* Only disable when no other sub-irq levels of - * the same IMAP are active. - */ - if (ent == NUM_IVECS) - disable_irq(irq); + /* See if any other buckets share this bucket's IMAP + * and are still active. + */ + for (ent = 0; ent < NUM_IVECS; ent++) { + struct ino_bucket *bp = &ivector_table[ent]; + if (bp != bucket && + bp->imap == imap && + (bp->flags & IBF_ACTIVE) != 0) + break; } + + /* Only disable when no other sub-irq levels of + * the same IMAP are active. + */ + if (ent == NUM_IVECS) + disable_irq(irq); } spin_unlock_irqrestore(&irq_action_lock, flags); @@ -625,7 +597,7 @@ void synchronize_irq(unsigned int irq) } #endif /* CONFIG_SMP */ -static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs) +static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) { struct irq_desc *desc = bp->irq_info; unsigned char flags = bp->flags; @@ -676,51 +648,54 @@ static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs) /* Test and add entropy */ if (random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); + add_interrupt_randomness(bp->pil); } out: bp->flags &= ~IBF_INPROGRESS; } +#ifndef CONFIG_SMP +extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *); + +void timer_irq(int irq, struct pt_regs *regs) +{ + unsigned long clr_mask = 1 << irq; + unsigned long tick_mask = tick_ops->softint_mask; + + if (get_softint() & tick_mask) { + irq = 0; + clr_mask = tick_mask; + } + clear_softint(clr_mask); + + irq_enter(); + kstat_this_cpu.irqs[irq]++; + timer_interrupt(irq, NULL, regs); + irq_exit(); +} +#endif + void handler_irq(int irq, struct pt_regs *regs) { struct ino_bucket *bp; int cpu = smp_processor_id(); -#ifndef CONFIG_SMP - /* - * Check for TICK_INT on level 14 softint. + /* XXX at this point we should be able to assert that + * XXX irq is PIL_DEVICE_IRQ... */ - { - unsigned long clr_mask = 1 << irq; - unsigned long tick_mask = tick_ops->softint_mask; - - if ((irq == 14) && (get_softint() & tick_mask)) { - irq = 0; - clr_mask = tick_mask; - } - clear_softint(clr_mask); - } -#else clear_softint(1 << irq); -#endif irq_enter(); - kstat_this_cpu.irqs[irq]++; /* Sliiiick... */ -#ifndef CONFIG_SMP - bp = ((irq != 0) ? - __bucket(xchg32(irq_work(cpu, irq), 0)) : - &pil0_dummy_bucket); -#else - bp = __bucket(xchg32(irq_work(cpu, irq), 0)); -#endif + bp = __bucket(xchg32(irq_work(cpu), 0)); while (bp) { struct ino_bucket *nbp = __bucket(bp->irq_chain); + kstat_this_cpu.irqs[bp->pil]++; + bp->irq_chain = 0; - process_bucket(irq, bp, regs); + process_bucket(bp, regs); bp = nbp; } irq_exit(); @@ -929,7 +904,7 @@ void init_irqwork_curcpu(void) { int cpu = hard_smp_processor_id(); - memset(__irq_work + cpu, 0, sizeof(struct irq_work_struct)); + trap_block[cpu].irq_worklist = 0; } static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type) diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S index b49a68bdda4..f70e4774649 100644 --- a/arch/sparc64/kernel/sun4v_ivec.S +++ b/arch/sparc64/kernel/sun4v_ivec.S @@ -5,6 +5,7 @@ #include #include +#include .text .align 32 @@ -106,19 +107,13 @@ sun4v_dev_mondo: or %g4, %lo(ivector_table), %g4 add %g4, %g3, %g4 - /* Load IRQ %pil into %g5. */ - ldub [%g4 + 0x04], %g5 - /* Insert ivector_table[] entry into __irq_work[] queue. */ - sllx %g5, 2, %g3 - lduw [%g1 + %g3], %g2 /* g2 = irq_work(cpu, pil) */ + lduw [%g1], %g2 /* g2 = irq_work(cpu) */ stw %g2, [%g4 + 0x00] /* bucket->irq_chain = g2 */ - stw %g4, [%g1 + %g3] /* irq_work(cpu, pil) = bucket */ + stw %g4, [%g1] /* irq_work(cpu) = bucket */ /* Signal the interrupt by setting (1 << pil) in %softint. */ - mov 1, %g2 - sllx %g2, %g5, %g2 - wr %g2, 0x0, %set_softint + wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint sun4v_dev_mondo_queue_empty: retry diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index e55b5c6ece0..0f00a99927e 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -457,7 +457,7 @@ static inline void timer_check_rtc(void) } } -static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { unsigned long ticks, compare, pstate; @@ -1020,19 +1020,9 @@ static unsigned long sparc64_init_timers(void) return clock; } -static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *)) +static void sparc64_start_timers(void) { unsigned long pstate; - int err; - - /* Register IRQ handler. */ - err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, 0, - "timer", NULL); - - if (err) { - prom_printf("Serious problem, cannot register TICK_INT\n"); - prom_halt(); - } /* Guarantee that the following sequences execute * uninterrupted. @@ -1116,7 +1106,7 @@ void __init time_init(void) /* Now that the interpolator is registered, it is * safe to start the timer ticking. */ - sparc64_start_timers(timer_interrupt); + sparc64_start_timers(); timer_ticks_per_nsec_quotient = (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) + diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 563db528e03..5059cbd4fee 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -2544,7 +2544,9 @@ void __init trap_init(void) (TRAP_PER_CPU_TSB_HUGE != offsetof(struct trap_per_cpu, tsb_huge)) || (TRAP_PER_CPU_TSB_HUGE_TEMP != - offsetof(struct trap_per_cpu, tsb_huge_temp))) + offsetof(struct trap_per_cpu, tsb_huge_temp)) || + (TRAP_PER_CPU_IRQ_WORKLIST != + offsetof(struct trap_per_cpu, irq_worklist))) trap_per_cpu_offsets_are_bolixed_dave(); if ((TSB_CONFIG_TSB != diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 5d901519db5..ee45ca2d7a0 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -58,13 +58,11 @@ tl0_irq2: BTRAP(0x42) tl0_irq3: BTRAP(0x43) tl0_irq4: BTRAP(0x44) #endif -tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6) -tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8) -tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10) -tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12) -tl0_irq13: TRAP_IRQ(handler_irq, 13) +tl0_irq5: TRAP_IRQ(handler_irq, 5) +tl0_irq6: BTRAP(0x46) BTRAP(0x47) BTRAP(0x48) BTRAP(0x49) +tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d) #ifndef CONFIG_SMP -tl0_irq14: TRAP_IRQ(handler_irq, 14) +tl0_irq14: TRAP_IRQ(timer_irq, 14) #else tl0_irq14: TICK_SMP_IRQ #endif diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h index 9d6a6dbaf12..f2cc9411b4c 100644 --- a/include/asm-sparc64/cpudata.h +++ b/include/asm-sparc64/cpudata.h @@ -74,8 +74,10 @@ struct trap_per_cpu { unsigned long tsb_huge; unsigned long tsb_huge_temp; -/* Dcache line 8: Unused, needed to keep trap_block a power-of-2 in size. */ - unsigned long __pad2[4]; +/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size. */ + unsigned int irq_worklist; + unsigned int __pad1; + unsigned long __pad2[3]; } __attribute__((aligned(64))); extern struct trap_per_cpu trap_block[NR_CPUS]; extern void init_cur_cpu_trap(struct thread_info *); @@ -119,6 +121,7 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, #define TRAP_PER_CPU_CPU_LIST_PA 0xc8 #define TRAP_PER_CPU_TSB_HUGE 0xd0 #define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8 +#define TRAP_PER_CPU_IRQ_WORKLIST 0xe0 #define TRAP_BLOCK_SZ_SHIFT 8 @@ -171,11 +174,8 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, /* Clobbers TMP, loads local processor's IRQ work area into DEST. */ #define TRAP_LOAD_IRQ_WORK(DEST, TMP) \ - __GET_CPUID(TMP) \ - sethi %hi(__irq_work), DEST; \ - sllx TMP, 6, TMP; \ - or DEST, %lo(__irq_work), DEST; \ - add DEST, TMP, DEST; + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + add DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST; /* Clobbers TMP, loads DEST with current thread info pointer. */ #define TRAP_LOAD_THREAD_REG(DEST, TMP) \ @@ -211,9 +211,10 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; +/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ #define TRAP_LOAD_IRQ_WORK(DEST, TMP) \ - sethi %hi(__irq_work), DEST; \ - or DEST, %lo(__irq_work), DEST; + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + add DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST; #define TRAP_LOAD_THREAD_REG(DEST, TMP) \ TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ diff --git a/include/asm-sparc64/pil.h b/include/asm-sparc64/pil.h index 79f827eb3f5..72927749aeb 100644 --- a/include/asm-sparc64/pil.h +++ b/include/asm-sparc64/pil.h @@ -5,9 +5,9 @@ /* To avoid some locking problems, we hard allocate certain PILs * for SMP cross call messages that must do a etrap/rtrap. * - * A cli() does not block the cross call delivery, so when SMP - * locking is an issue we reschedule the event into a PIL interrupt - * which is blocked by cli(). + * A local_irq_disable() does not block the cross call delivery, so + * when SMP locking is an issue we reschedule the event into a PIL + * interrupt which is blocked by local_irq_disable(). * * In fact any XCALL which has to etrap/rtrap has a problem because * it is difficult to prevent rtrap from running BH's, and that would @@ -17,6 +17,7 @@ #define PIL_SMP_RECEIVE_SIGNAL 2 #define PIL_SMP_CAPTURE 3 #define PIL_SMP_CTX_NEW_VERSION 4 +#define PIL_DEVICE_IRQ 5 #ifndef __ASSEMBLY__ #define PIL_RESERVED(PIL) ((PIL) == PIL_SMP_CALL_FUNC || \ -- cgit v1.2.3-70-g09d2 From c6387a48cf5958e43c201fc27a158c328927531a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:21:29 -0700 Subject: [SPARC]: Kill __irq_itoa(). This ugly hack was long overdue to die. It was a way to print out Sparc interrupts in a more freindly format, since IRQ numbers were arbitrary opaque 32-bit integers which vectored into PIL levels. These 32-bit integers were not necessarily in the 0-->NR_IRQS range, but the PILs they vectored to were. The idea now is that we will increase NR_IRQS a little bit and use a virtual<-->real IRQ number mapping scheme similar to PowerPC. That makes this IRQ printing hack irrelevant, and furthermore only a handful of drivers actually used __irq_itoa() making it even less useful. Signed-off-by: David S. Miller --- arch/sparc/kernel/pcic.c | 8 -------- arch/sparc/kernel/sparc_ksyms.c | 1 - arch/sparc/kernel/sun4c_irq.c | 3 --- arch/sparc/kernel/sun4d_irq.c | 12 ------------ arch/sparc/kernel/sun4m_irq.c | 8 -------- drivers/atm/fore200e.c | 4 ---- drivers/char/rtc.c | 4 ---- drivers/fc4/soc.c | 2 +- drivers/fc4/socal.c | 2 +- drivers/ide/ide-probe.c | 7 +------ drivers/ide/setup-pci.c | 5 ----- drivers/ieee1394/ohci1394.c | 4 ---- drivers/ieee1394/pcilynx.c | 4 ---- drivers/message/fusion/mptbase.c | 16 ---------------- drivers/net/3c59x.c | 5 ----- drivers/net/acenic.c | 6 +----- drivers/net/sunhme.c | 5 ----- drivers/net/sunlance.c | 2 +- drivers/sbus/char/cpwatchdog.c | 4 ++-- drivers/sbus/char/uctrl.c | 2 +- drivers/scsi/esp.c | 4 ++-- drivers/scsi/qlogicpti.c | 6 +++--- drivers/scsi/sym53c8xx_2/sym_glue.c | 6 ------ drivers/serial/sunsu.c | 4 ++-- drivers/serial/sunzilog.c | 4 ++-- drivers/usb/core/hcd.c | 12 ++---------- drivers/usb/gadget/goku_udc.c | 11 ++--------- drivers/usb/gadget/net2280.c | 14 ++++---------- include/asm-sparc/irq.h | 2 -- include/asm-sparc64/irq.h | 8 -------- sound/sparc/amd7930.c | 8 ++++---- sound/sparc/cs4231.c | 13 ++++++------- sound/sparc/dbri.c | 4 ++-- 33 files changed, 37 insertions(+), 163 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 42002b742de..bcdf5ad0f03 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -896,13 +896,6 @@ static inline unsigned long get_irqmask(int irq_nr) return 1 << irq_nr; } -static inline char *pcic_irq_itoa(unsigned int irq) -{ - static char buff[16]; - sprintf(buff, "%d", irq); - return buff; -} - static void pcic_disable_irq(unsigned int irq_nr) { unsigned long mask, flags; @@ -955,7 +948,6 @@ void __init sun4m_pci_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM); } int pcibios_assign_resource(struct pci_dev *pdev, int resource) diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 4b376fae752..fd7deabf998 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -163,7 +163,6 @@ EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id)); #endif EXPORT_SYMBOL(BTFIXUP_CALL(enable_irq)); EXPORT_SYMBOL(BTFIXUP_CALL(disable_irq)); -EXPORT_SYMBOL(BTFIXUP_CALL(__irq_itoa)); EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea)); EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea)); EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl)); diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index 3d6a99073c4..0f2d8d9cbdb 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c @@ -198,8 +198,6 @@ static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *, stru static void sun4c_nop(void) {} #endif -extern char *sun4m_irq_itoa(unsigned int irq); - void __init sun4c_init_IRQ(void) { struct linux_prom_registers int_regs[2]; @@ -238,7 +236,6 @@ void __init sun4c_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4c_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index ca656d9bd6f..9c30e35c88f 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -560,17 +560,6 @@ void __init sun4d_init_sbi_irq(void) } } -static char *sun4d_irq_itoa(unsigned int irq) -{ - static char buff[16]; - - if (irq < (1 << 5)) - sprintf(buff, "%d", irq); - else - sprintf(buff, "%d,%x", sbus_to_pil[(irq >> 2) & 7], irq); - return buff; -} - void __init sun4d_init_IRQ(void) { local_irq_disable(); @@ -581,7 +570,6 @@ void __init sun4d_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(__irq_itoa, sun4d_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4d_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM); diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 39d712c3c80..a296c13ac18 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -229,13 +229,6 @@ static void sun4m_load_profile_irq(int cpu, unsigned int limit) sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; } -char *sun4m_irq_itoa(unsigned int irq) -{ - static char buff[16]; - sprintf(buff, "%d", irq); - return buff; -} - static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *)) { int reg_count, irq, cpu; @@ -388,7 +381,6 @@ void __init sun4m_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4m_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 05983a312d5..92923bf2723 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -167,13 +167,9 @@ fore200e_atm2fore_aal(int aal) static char* fore200e_irq_itoa(int irq) { -#if defined(__sparc_v9__) - return __irq_itoa(irq); -#else static char str[8]; sprintf(str, "%d", irq); return str; -#endif } diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 7cac6d05d72..f6686fcce80 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -960,10 +960,6 @@ found: * PCI Slot 2 INTA# (and some INTx# in Slot 1). */ if (request_irq(rtc_irq, rtc_interrupt, SA_SHIRQ, "rtc", (void *)&rtc_port)) { - /* - * Standard way for sparc to print irq's is to use - * __irq_itoa(). I think for EBus it's ok to use %d. - */ printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); return -EIO; } diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c index ec1f94738c5..cf8768b8d1f 100644 --- a/drivers/fc4/soc.c +++ b/drivers/fc4/soc.c @@ -643,7 +643,7 @@ static inline void soc_init(struct sbus_dev *sdev, int no) return; } - SOD(("SOC uses IRQ%s\n", __irq_itoa(irq))) + SOD(("SOC uses IRQ %d\n", irq)) s->port[0].fc.irq = irq; s->port[1].fc.irq = irq; diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c index 922e9613b2c..f52d1e5bd5a 100644 --- a/drivers/fc4/socal.c +++ b/drivers/fc4/socal.c @@ -767,7 +767,7 @@ static inline void socal_init(struct sbus_dev *sdev, int no) return; } - SOD(("SOCAL uses IRQ %s\n", __irq_itoa(irq))) + SOD(("SOCAL uses IRQ %d\n", irq)) s->port[0].fc.irq = irq; s->port[1].fc.irq = irq; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 1b7b4c531bc..9ebf8ae2a5e 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1138,16 +1138,11 @@ static int init_irq (ide_hwif_t *hwif) spin_unlock_irq(&ide_lock); } -#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__) +#if !defined(__mc68000__) && !defined(CONFIG_APUS) printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name, hwif->io_ports[IDE_DATA_OFFSET], hwif->io_ports[IDE_DATA_OFFSET]+7, hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq); -#elif defined(__sparc__) - printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", hwif->name, - hwif->io_ports[IDE_DATA_OFFSET], - hwif->io_ports[IDE_DATA_OFFSET]+7, - hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq)); #else printk("%s at 0x%08lx on irq %d", hwif->name, hwif->io_ports[IDE_DATA_OFFSET], hwif->irq); diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 462ed3006c3..c11e3b2e67a 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -694,13 +694,8 @@ static int do_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d, goto out; } if (noisy) -#ifdef __sparc__ - printk(KERN_INFO "%s: 100%% native mode on irq %s\n", - d->name, __irq_itoa(pciirq)); -#else printk(KERN_INFO "%s: 100%% native mode on irq %d\n", d->name, pciirq); -#endif } /* FIXME: silent failure can happen */ diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 11f13778f13..c031650a1c7 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -586,11 +586,7 @@ static void ohci_initialize(struct ti_ohci *ohci) reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable); buf = reg_read(ohci, OHCI1394_Version); -#ifndef __sparc__ sprintf (irq_buf, "%d", ohci->dev->irq); -#else - sprintf (irq_buf, "%s", __irq_itoa(ohci->dev->irq)); -#endif PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%s] " "MMIO=[%lx-%lx] Max Packet=[%d] IR/IT contexts=[%d/%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index e2edc41e1b6..e29dfd280be 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -1252,11 +1252,7 @@ static int __devinit add_card(struct pci_dev *dev, /* Fix buggy cards with autoboot pin not tied low: */ reg_write(lynx, DMA0_CHAN_CTRL, 0); -#ifndef __sparc__ sprintf (irq_buf, "%d", dev->irq); -#else - sprintf (irq_buf, "%s", __irq_itoa(dev->irq)); -#endif if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, PCILYNX_DRIVER_NAME, lynx)) { diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index a30084076ac..59690cbabfc 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -63,9 +63,6 @@ #ifdef CONFIG_MTRR #include #endif -#ifdef __sparc__ -#include /* needed for __irq_itoa() proto */ -#endif #include "mptbase.h" @@ -1394,13 +1391,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc); if (r < 0) { -#ifndef __sparc__ printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n", ioc->name, pdev->irq); -#else - printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n", - ioc->name, __irq_itoa(pdev->irq)); -#endif list_del(&ioc->list); iounmap(mem); kfree(ioc); @@ -1412,11 +1404,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); /* ?? */ pci_set_drvdata(pdev, ioc); -#ifndef __sparc__ dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq)); -#else - dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq))); -#endif } /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. @@ -5647,11 +5635,7 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh a[5], a[4], a[3], a[2], a[1], a[0]); } -#ifndef __sparc__ y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq); -#else - y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq)); -#endif if (!ioc->active) y += sprintf(buffer+len+y, " (disabled)"); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 274b0138d44..e27778926eb 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1382,17 +1382,12 @@ static int __devinit vortex_probe1(struct device *gendev, for (i = 0; i < 6; i++) iowrite8(dev->dev_addr[i], ioaddr + i); -#ifdef __sparc__ - if (print_info) - printk(", IRQ %s\n", __irq_itoa(dev->irq)); -#else if (print_info) printk(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (dev->irq <= 0 || dev->irq >= NR_IRQS) printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n", dev->irq); -#endif EL3WINDOW(4); step = (ioread8(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index b508812e97a..23ff22ba5d3 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -579,11 +579,7 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, } printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); -#ifdef __sparc__ - printk("irq %s\n", __irq_itoa(pdev->irq)); -#else - printk("irq %i\n", pdev->irq); -#endif + printk("irq %d\n", pdev->irq); #ifdef CONFIG_ACENIC_OMIT_TIGON_I if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 9f046cae2f7..bd5d2668a36 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2221,13 +2221,8 @@ static int happy_meal_open(struct net_device *dev) if (request_irq(dev->irq, &happy_meal_interrupt, SA_SHIRQ, dev->name, (void *)dev)) { HMD(("EAGAIN\n")); -#ifdef __sparc__ - printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n", - __irq_itoa(dev->irq)); -#else printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n", dev->irq); -#endif return -EAGAIN; } diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index b7d87d4690b..6381243d8d0 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -936,7 +936,7 @@ static int lance_open(struct net_device *dev) if (request_irq(dev->irq, &lance_interrupt, SA_SHIRQ, lancestr, (void *) dev)) { - printk(KERN_ERR "Lance: Can't get irq %s\n", __irq_itoa(dev->irq)); + printk(KERN_ERR "Lance: Can't get irq %d\n", dev->irq); return -EAGAIN; } diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index fd2cc7782f7..5bf3dd901b6 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -304,8 +304,8 @@ static int wd_open(struct inode *inode, struct file *f) SA_SHIRQ, WD_OBPNAME, (void *)wd_dev.regs)) { - printk("%s: Cannot register IRQ %s\n", - WD_OBPNAME, __irq_itoa(wd_dev.irq)); + printk("%s: Cannot register IRQ %d\n", + WD_OBPNAME, wd_dev.irq); return(-EBUSY); } wd_dev.initialized = 1; diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index e2d9a7c8542..575b1f7ed41 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -400,7 +400,7 @@ static int __init ts102_uctrl_init(void) } driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK; - printk("uctrl: 0x%x (irq %s)\n", driver->regs, __irq_itoa(driver->irq)); + printk("uctrl: 0x%x (irq %d)\n", driver->regs, driver->irq); uctrl_get_event_status(); uctrl_get_external_status(); return 0; diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 87a8c3d2072..0a3e45d7a97 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -821,8 +821,8 @@ static int __init esp_register_irq(struct esp *esp) return -1; } - printk("esp%d: IRQ %s ", esp->esp_id, - __irq_itoa(esp->ehost->irq)); + printk("esp%d: IRQ %d ", esp->esp_id, + esp->ehost->irq); return 0; } diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index c7e78dcf09d..7c27ecc6fb5 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -725,7 +725,7 @@ static int __init qpti_register_irq(struct qlogicpti *qpti) SA_SHIRQ, "Qlogic/PTI", qpti)) goto fail; - printk("qpti%d: IRQ %s ", qpti->qpti_id, __irq_itoa(qpti->irq)); + printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->irq); return 0; @@ -988,8 +988,8 @@ const char *qlogicpti_info(struct Scsi_Host *host) static char buf[80]; struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %p", - __irq_itoa(qpti->qhost->irq), qpti->qregs); + sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %d regs at %p", + qpti->qhost->irq, qpti->qregs); return buf; } diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 9c83b4d39a2..7677fba2ceb 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -54,14 +54,8 @@ #define NAME53C "sym53c" #define NAME53C8XX "sym53c8xx" -/* SPARC just has to be different ... */ -#ifdef __sparc__ -#define IRQ_FMT "%s" -#define IRQ_PRM(x) __irq_itoa(x) -#else #define IRQ_FMT "%d" #define IRQ_PRM(x) (x) -#endif struct sym_driver_setup sym_driver_setup = SYM_LINUX_DRIVER_SETUP; unsigned int sym_debug_flags = 0; diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 2b4f96541b8..4cdb610cdd3 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1295,9 +1295,9 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) if (up->port.type == PORT_UNKNOWN) return -1; - printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", + printk(KERN_INFO "su%d at 0x%p (irq = %d) is a %s\n", channel, - up->port.membase, __irq_itoa(up->port.irq), + up->port.membase, up->port.irq, sunsu_type(&up->port)); #ifdef CONFIG_SERIO diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index cd49ebbf4a4..5b6569728a9 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1540,8 +1540,8 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe up->cflag = B4800 | CS8 | CLOCAL | CREAD; baud = 4800; } - printk(KERN_INFO "zs%d at 0x%p (irq = %s) is a SunZilog\n", - channel, up->port.membase, __irq_itoa(zilog_irq)); + printk(KERN_INFO "zs%d at 0x%p (irq = %d) is a SunZilog\n", + channel, up->port.membase, zilog_irq); up->curregs[R15] = BRKIE; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e2e00ba4e1e..4bf914d00a1 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1826,24 +1826,16 @@ int usb_add_hcd(struct usb_hcd *hcd, /* enable irqs just before we start the controller */ if (hcd->driver->irq) { - char buf[8], *bufp = buf; - -#ifdef __sparc__ - bufp = __irq_itoa(irqnum); -#else - sprintf(buf, "%d", irqnum); -#endif - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", hcd->driver->description, hcd->self.busnum); if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags, hcd->irq_descr, hcd)) != 0) { dev_err(hcd->self.controller, - "request interrupt %s failed\n", bufp); + "request interrupt %d failed\n", irqnum); goto err_request_irq; } hcd->irq = irqnum; - dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp, + dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum, (hcd->driver->flags & HCD_MEMORY) ? "io mem" : "io base", (unsigned long long)hcd->rsrc_start); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 66b81bbf6be..5378c175729 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1850,7 +1850,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) unsigned long resource, len; void __iomem *base = NULL; int retval; - char buf [8], *bufp; /* if you want to support more than one controller in a system, * usb_gadget_driver_{register,unregister}() must change. @@ -1913,20 +1912,14 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, dev); INFO(dev, "%s\n", driver_desc); INFO(dev, "version: " DRIVER_VERSION " %s\n", dmastr()); -#ifndef __sparc__ - scnprintf(buf, sizeof buf, "%d", pdev->irq); - bufp = buf; -#else - bufp = __irq_itoa(pdev->irq); -#endif - INFO(dev, "irq %s, pci mem %p\n", bufp, base); + INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base); /* init to known state, then setup irqs */ udc_reset(dev); udc_reinit (dev); if (request_irq(pdev->irq, goku_irq, SA_SHIRQ/*|SA_SAMPLE_RANDOM*/, driver_name, dev) != 0) { - DBG(dev, "request interrupt %s failed\n", bufp); + DBG(dev, "request interrupt %d failed\n", pdev->irq); retval = -EBUSY; goto done; } diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 0b929349395..020d3c42b1a 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2822,7 +2822,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) unsigned long resource, len; void __iomem *base = NULL; int retval, i; - char buf [8], *bufp; /* if you want to support more than one controller in a system, * usb_gadget_driver_{register,unregister}() must change. @@ -2896,15 +2895,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) retval = -ENODEV; goto done; } -#ifndef __sparc__ - scnprintf (buf, sizeof buf, "%d", pdev->irq); - bufp = buf; -#else - bufp = __irq_itoa(pdev->irq); -#endif + if (request_irq (pdev->irq, net2280_irq, SA_SHIRQ, driver_name, dev) != 0) { - ERROR (dev, "request interrupt %s failed\n", bufp); + ERROR (dev, "request interrupt %d failed\n", pdev->irq); retval = -EBUSY; goto done; } @@ -2953,8 +2947,8 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) /* done */ INFO (dev, "%s\n", driver_desc); - INFO (dev, "irq %s, pci mem %p, chip rev %04x\n", - bufp, base, dev->chiprev); + INFO (dev, "irq %d, pci mem %p, chip rev %04x\n", + pdev->irq, base, dev->chiprev); INFO (dev, "version: " DRIVER_VERSION "; dma %s\n", use_dma ? (use_dma_chaining ? "chaining" : "enabled") diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h index cee356b0dae..a6115c6ed6e 100644 --- a/include/asm-sparc/irq.h +++ b/include/asm-sparc/irq.h @@ -17,8 +17,6 @@ #define __irq_ino(irq) irq #define __irq_pil(irq) irq -BTFIXUPDEF_CALL(char *, __irq_itoa, unsigned int) -#define __irq_itoa(irq) BTFIXUP_CALL(__irq_itoa)(irq) #define NR_IRQS 16 diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index de33d6e1afb..bbdf89e6faa 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -99,14 +99,6 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; #define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) #define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) -static __inline__ char *__irq_itoa(unsigned int irq) -{ - static char buff[16]; - - sprintf(buff, "%d,%x", __irq_pil(irq), (unsigned int)__irq_ino(irq)); - return buff; -} - #define NR_IRQS 16 #define irq_canonicalize(irq) (irq) diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 55493340f46..dfe9bac7fa3 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -977,9 +977,9 @@ static int __init snd_amd7930_create(struct snd_card *card, if (request_irq(irq_prop->pri, snd_amd7930_interrupt, SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) { - snd_printk("amd7930-%d: Unable to grab IRQ %s\n", + snd_printk("amd7930-%d: Unable to grab IRQ %d\n", dev, - __irq_itoa(irq_prop->pri)); + irq_prop->pri); snd_amd7930_free(amd); return -EBUSY; } @@ -1063,11 +1063,11 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev) strcpy(card->driver, "AMD7930"); strcpy(card->shortname, "Sun AMD7930"); - sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s", + sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d", card->shortname, rp->flags & 0xffL, rp->start, - __irq_itoa(irq_prop.pri)); + irq_prop.pri); if ((err = snd_amd7930_create(card, sdev, rp, reg_prop.reg_size, &irq_prop, dev, &amd)) < 0) diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 8804f26ddb3..b3efc9aa291 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -2003,9 +2003,8 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card, if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, SA_SHIRQ, "cs4231", chip)) { - snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n", - dev, - __irq_itoa(sdev->irqs[0])); + snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n", + dev, sdev->irqs[0]); snd_cs4231_sbus_free(chip); return -EBUSY; } @@ -2038,11 +2037,11 @@ static int __init cs4231_sbus_attach(struct sbus_dev *sdev) if (err) return err; - sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s", + sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d", card->shortname, rp->flags & 0xffL, rp->start, - __irq_itoa(sdev->irqs[0])); + sdev->irqs[0]); if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) { snd_card_free(card); @@ -2244,10 +2243,10 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev) if (err) return err; - sprintf(card->longname, "%s at 0x%lx, irq %s", + sprintf(card->longname, "%s at 0x%lx, irq %d", card->shortname, edev->resource[0].start, - __irq_itoa(edev->irqs[0])); + edev->irqs[0]); if ((err = snd_cs4231_ebus_create(card, edev, dev, &chip)) < 0) { snd_card_free(card); diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 2164b7d290c..e622d08215c 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2645,9 +2645,9 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) strcpy(card->driver, "DBRI"); strcpy(card->shortname, "Sun DBRI"); rp = &sdev->resource[0]; - sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s", + sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d", card->shortname, - rp->flags & 0xffL, rp->start, __irq_itoa(irq.pri)); + rp->flags & 0xffL, rp->start, irq.pri); if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) { snd_card_free(card); -- cgit v1.2.3-70-g09d2 From 37cdcd9e82108f9b899f1631f66ade2e45738a6e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:21:57 -0700 Subject: [SPARC64]: Kill ino_bucket->pil And reuse that struct member for virt_irq, which will be used in future changesets for the implementation of mapping between real and virtual IRQ numbers. This nicely kills off a ton of SBUS and PCI controller PIL assignment code which is no longer necessary. Signed-off-by: David S. Miller --- arch/sparc64/kernel/devices.c | 2 +- arch/sparc64/kernel/irq.c | 70 ++++++++++---------------- arch/sparc64/kernel/pci_psycho.c | 77 +---------------------------- arch/sparc64/kernel/pci_sabre.c | 81 +----------------------------- arch/sparc64/kernel/pci_schizo.c | 104 +-------------------------------------- arch/sparc64/kernel/pci_sun4v.c | 32 +----------- arch/sparc64/kernel/sbus.c | 47 ++---------------- include/asm-sparc64/irq.h | 11 ++--- 8 files changed, 43 insertions(+), 381 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 007e8922cd1..0684899d998 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -157,7 +157,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) return 0; } - return sun4v_build_irq(sun4v_vdev_devhandle, irq, 5, 0); + return sun4v_build_irq(sun4v_vdev_devhandle, irq, 0); } static const char *cpu_mid_prop(void) diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index ad134bbc151..f2668f2bed9 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -70,7 +70,7 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY */ #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) -static struct irqaction *irq_action[NR_IRQS+1]; +static struct irqaction *irq_action[NR_IRQS]; /* This only synchronizes entities which modify IRQ handler * state and some selected user-level spots that want to @@ -116,12 +116,9 @@ int show_interrupts(struct seq_file *p, void *v) kstat_cpu(j).irqs[i]); } #endif - seq_printf(p, " %s:%lx", action->name, - get_ino_in_irqaction(action)); - for (action = action->next; action; action = action->next) { - seq_printf(p, ", %s:%lx", action->name, - get_ino_in_irqaction(action)); - } + seq_printf(p, " %s", action->name); + for (action = action->next; action; action = action->next) + seq_printf(p, ", %s", action->name); seq_putc(p, '\n'); } out_unlock: @@ -245,48 +242,47 @@ void disable_irq(unsigned int irq) } } -static void build_irq_error(const char *msg, unsigned int ino, int pil, int inofixup, +static void build_irq_error(const char *msg, unsigned int ino, int inofixup, unsigned long iclr, unsigned long imap, struct ino_bucket *bucket) { - prom_printf("IRQ: INO %04x (%d:%016lx:%016lx) --> " - "(%d:%d:%016lx:%016lx), halting...\n", - ino, bucket->pil, bucket->iclr, bucket->imap, - pil, inofixup, iclr, imap); + prom_printf("IRQ: INO %04x (%016lx:%016lx) --> " + "(%d:%016lx:%016lx), halting...\n", + ino, bucket->iclr, bucket->imap, + inofixup, iclr, imap); prom_halt(); } -unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap) +unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) { struct ino_bucket *bucket; int ino; - BUG_ON(pil == 0); BUG_ON(tlb_type == hypervisor); /* RULE: Both must be specified in all other cases. */ if (iclr == 0UL || imap == 0UL) { - prom_printf("Invalid build_irq %d %d %016lx %016lx\n", - pil, inofixup, iclr, imap); + prom_printf("Invalid build_irq %d %016lx %016lx\n", + inofixup, iclr, imap); prom_halt(); } ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; if (ino > NUM_IVECS) { - prom_printf("Invalid INO %04x (%d:%d:%016lx:%016lx)\n", - ino, pil, inofixup, iclr, imap); + prom_printf("Invalid INO %04x (%d:%016lx:%016lx)\n", + ino, inofixup, iclr, imap); prom_halt(); } bucket = &ivector_table[ino]; if (bucket->flags & IBF_ACTIVE) build_irq_error("IRQ: Trying to build active INO bucket.\n", - ino, pil, inofixup, iclr, imap, bucket); + ino, inofixup, iclr, imap, bucket); if (bucket->irq_info) { if (bucket->imap != imap || bucket->iclr != iclr) build_irq_error("IRQ: Trying to reinit INO bucket.\n", - ino, pil, inofixup, iclr, imap, bucket); + ino, inofixup, iclr, imap, bucket); goto out; } @@ -302,14 +298,13 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long */ bucket->imap = imap; bucket->iclr = iclr; - bucket->pil = pil; bucket->flags = 0; out: return __irq(bucket); } -unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags) +unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags) { struct ino_bucket *bucket; unsigned long sysino; @@ -328,7 +323,6 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsign bucket->imap = ~0UL - sysino; bucket->iclr = ~0UL - sysino; - bucket->pil = pil; bucket->flags = flags; bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); @@ -356,16 +350,12 @@ static void atomic_bucket_insert(struct ino_bucket *bucket) static int check_irq_sharing(int pil, unsigned long irqflags) { - struct irqaction *action, *tmp; + struct irqaction *action; action = *(irq_action + pil); if (action) { - if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) { - for (tmp = action; tmp->next; tmp = tmp->next) - ; - } else { + if (!(action->flags & SA_SHIRQ) || !(irqflags & SA_SHIRQ)) return -EBUSY; - } } return 0; } @@ -425,12 +415,12 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ * installing a new handler, but is this really a problem, * only the sysadmin is able to do this. */ - rand_initialize_irq(irq); + rand_initialize_irq(PIL_DEVICE_IRQ); } spin_lock_irqsave(&irq_action_lock, flags); - if (check_irq_sharing(bucket->pil, irqflags)) { + if (check_irq_sharing(PIL_DEVICE_IRQ, irqflags)) { spin_unlock_irqrestore(&irq_action_lock, flags); return -EBUSY; } @@ -454,7 +444,7 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ put_ino_in_irqaction(action, irq); put_smpaff_in_irqaction(action, CPU_MASK_NONE); - append_irq_action(bucket->pil, action); + append_irq_action(PIL_DEVICE_IRQ, action); enable_irq(irq); @@ -478,16 +468,15 @@ EXPORT_SYMBOL(request_irq); static struct irqaction *unlink_irq_action(unsigned int irq, void *dev_id) { - struct ino_bucket *bucket = __bucket(irq); struct irqaction *action, **pp; - pp = irq_action + bucket->pil; + pp = irq_action + PIL_DEVICE_IRQ; action = *pp; if (unlikely(!action)) return NULL; if (unlikely(!action->handler)) { - printk("Freeing free IRQ %d\n", bucket->pil); + printk("Freeing free IRQ %d\n", PIL_DEVICE_IRQ); return NULL; } @@ -648,7 +637,7 @@ static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) /* Test and add entropy */ if (random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(bp->pil); + add_interrupt_randomness(PIL_DEVICE_IRQ); out: bp->flags &= ~IBF_INPROGRESS; } @@ -691,7 +680,7 @@ void handler_irq(int irq, struct pt_regs *regs) while (bp) { struct ino_bucket *nbp = __bucket(bp->irq_chain); - kstat_this_cpu.irqs[bp->pil]++; + kstat_this_cpu.irqs[bp->virt_irq]++; bp->irq_chain = 0; process_bucket(bp, regs); @@ -817,16 +806,9 @@ static void distribute_irqs(void) spin_lock_irqsave(&irq_action_lock, flags); cpu = 0; - /* - * Skip the timer at [0], and very rare error/power intrs at [15]. - * Also level [12], it causes problems on Ex000 systems. - */ for (level = 1; level < NR_IRQS; level++) { struct irqaction *p = irq_action[level]; - if (level == 12) - continue; - while(p) { cpu = retarget_one_irq(p, cpu); p = p->next; diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index d17878b145c..5743e1316a9 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -276,74 +276,6 @@ static unsigned long __onboard_imap_off[] = { ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) -/* PCI PSYCHO INO number to Sparc PIL level. */ -static unsigned char psycho_pil_table[] = { -/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */ -/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */ -/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */ -/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */ -/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */ -/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ -/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ -/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ -/*0x20*/5, /* SCSI */ -/*0x21*/5, /* Ethernet */ -/*0x22*/8, /* Parallel Port */ -/*0x23*/13, /* Audio Record */ -/*0x24*/14, /* Audio Playback */ -/*0x25*/15, /* PowerFail */ -/*0x26*/5, /* second SCSI */ -/*0x27*/11, /* Floppy */ -/*0x28*/5, /* Spare Hardware */ -/*0x29*/9, /* Keyboard */ -/*0x2a*/5, /* Mouse */ -/*0x2b*/12, /* Serial */ -/*0x2c*/10, /* Timer 0 */ -/*0x2d*/11, /* Timer 1 */ -/*0x2e*/15, /* Uncorrectable ECC */ -/*0x2f*/15, /* Correctable ECC */ -/*0x30*/15, /* PCI Bus A Error */ -/*0x31*/15, /* PCI Bus B Error */ -/*0x32*/15, /* Power Management */ -}; - -static int psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) -{ - int ret; - - ret = psycho_pil_table[ino]; - if (ret == 0 && pdev == NULL) { - ret = 5; - } else if (ret == 0) { - switch ((pdev->class >> 16) & 0xff) { - case PCI_BASE_CLASS_STORAGE: - ret = 5; - break; - - case PCI_BASE_CLASS_NETWORK: - ret = 6; - break; - - case PCI_BASE_CLASS_DISPLAY: - ret = 9; - break; - - case PCI_BASE_CLASS_MULTIMEDIA: - case PCI_BASE_CLASS_MEMORY: - case PCI_BASE_CLASS_BRIDGE: - case PCI_BASE_CLASS_SERIAL: - ret = 10; - break; - - default: - ret = 5; - break; - }; - } - - return ret; -} - static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) @@ -351,7 +283,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; - int pil, inofixup = 0; + int inofixup = 0; ino &= PCI_IRQ_INO; if (ino < PSYCHO_ONBOARD_IRQ_BASE) { @@ -367,11 +299,6 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, } /* Now build the IRQ bucket. */ - pil = psycho_ino_to_pil(pdev, ino); - - if (PIL_RESERVED(pil)) - BUG(); - imap = pbm->controller_regs + imap_off; imap += 4; @@ -382,7 +309,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + bucket = __bucket(build_irq(inofixup, iclr, imap)); bucket->flags |= IBF_PCI; return __irq(bucket); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index f67bb7f078c..caa7aeed5d1 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -523,78 +523,6 @@ static unsigned long __onboard_imap_off[] = { ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) -/* PCI SABRE INO number to Sparc PIL level. */ -static unsigned char sabre_pil_table[] = { -/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */ -/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */ -/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */ -/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */ -/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */ -/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ -/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ -/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ -/*0x20*/5, /* SCSI */ -/*0x21*/5, /* Ethernet */ -/*0x22*/8, /* Parallel Port */ -/*0x23*/13, /* Audio Record */ -/*0x24*/14, /* Audio Playback */ -/*0x25*/15, /* PowerFail */ -/*0x26*/5, /* second SCSI */ -/*0x27*/11, /* Floppy */ -/*0x28*/5, /* Spare Hardware */ -/*0x29*/9, /* Keyboard */ -/*0x2a*/5, /* Mouse */ -/*0x2b*/12, /* Serial */ -/*0x2c*/10, /* Timer 0 */ -/*0x2d*/11, /* Timer 1 */ -/*0x2e*/15, /* Uncorrectable ECC */ -/*0x2f*/15, /* Correctable ECC */ -/*0x30*/15, /* PCI Bus A Error */ -/*0x31*/15, /* PCI Bus B Error */ -/*0x32*/15, /* Power Management */ -}; - -static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) -{ - int ret; - - if (pdev && - pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_RIO_USB) - return 9; - - ret = sabre_pil_table[ino]; - if (ret == 0 && pdev == NULL) { - ret = 5; - } else if (ret == 0) { - switch ((pdev->class >> 16) & 0xff) { - case PCI_BASE_CLASS_STORAGE: - ret = 5; - break; - - case PCI_BASE_CLASS_NETWORK: - ret = 6; - break; - - case PCI_BASE_CLASS_DISPLAY: - ret = 9; - break; - - case PCI_BASE_CLASS_MULTIMEDIA: - case PCI_BASE_CLASS_MEMORY: - case PCI_BASE_CLASS_BRIDGE: - case PCI_BASE_CLASS_SERIAL: - ret = 10; - break; - - default: - ret = 5; - break; - }; - } - return ret; -} - /* When a device lives behind a bridge deeper in the PCI bus topology * than APB, a special sequence must run to make sure all pending DMA * transfers at the time of IRQ delivery are visible in the coherency @@ -619,7 +547,7 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; - int pil, inofixup = 0; + int inofixup = 0; ino &= PCI_IRQ_INO; if (ino < SABRE_ONBOARD_IRQ_BASE) { @@ -635,11 +563,6 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, } /* Now build the IRQ bucket. */ - pil = sabre_ino_to_pil(pdev, ino); - - if (PIL_RESERVED(pil)) - BUG(); - imap = pbm->controller_regs + imap_off; imap += 4; @@ -650,7 +573,7 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + bucket = __bucket(build_irq(inofixup, iclr, imap)); bucket->flags |= IBF_PCI; if (pdev) { diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 7fe4de03ac2..ca49ef08236 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -232,101 +232,6 @@ static unsigned long schizo_iclr_offset(unsigned long ino) return SCHIZO_ICLR_BASE + (ino * 8UL); } -/* PCI SCHIZO INO number to Sparc PIL level. This table only matters for - * INOs which will not have an associated PCI device struct, ie. onboard - * EBUS devices and PCI controller internal error interrupts. - */ -static unsigned char schizo_pil_table[] = { -/*0x00*/0, 0, 0, 0, /* PCI slot 0 Int A, B, C, D */ -/*0x04*/0, 0, 0, 0, /* PCI slot 1 Int A, B, C, D */ -/*0x08*/0, 0, 0, 0, /* PCI slot 2 Int A, B, C, D */ -/*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */ -/*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */ -/*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */ -/*0x18*/5, /* SCSI */ -/*0x19*/5, /* second SCSI */ -/*0x1a*/0, /* UNKNOWN */ -/*0x1b*/0, /* UNKNOWN */ -/*0x1c*/8, /* Parallel */ -/*0x1d*/5, /* Ethernet */ -/*0x1e*/8, /* Firewire-1394 */ -/*0x1f*/9, /* USB */ -/*0x20*/13, /* Audio Record */ -/*0x21*/14, /* Audio Playback */ -/*0x22*/12, /* Serial */ -/*0x23*/5, /* EBUS I2C */ -/*0x24*/10, /* RTC Clock */ -/*0x25*/11, /* Floppy */ -/*0x26*/0, /* UNKNOWN */ -/*0x27*/0, /* UNKNOWN */ -/*0x28*/0, /* UNKNOWN */ -/*0x29*/0, /* UNKNOWN */ -/*0x2a*/10, /* UPA 1 */ -/*0x2b*/10, /* UPA 2 */ -/*0x2c*/0, /* UNKNOWN */ -/*0x2d*/0, /* UNKNOWN */ -/*0x2e*/0, /* UNKNOWN */ -/*0x2f*/0, /* UNKNOWN */ -/*0x30*/15, /* Uncorrectable ECC */ -/*0x31*/15, /* Correctable ECC */ -/*0x32*/15, /* PCI Bus A Error */ -/*0x33*/15, /* PCI Bus B Error */ -/*0x34*/15, /* Safari Bus Error */ -/*0x35*/0, /* Reserved */ -/*0x36*/0, /* Reserved */ -/*0x37*/0, /* Reserved */ -/*0x38*/0, /* Reserved for NewLink */ -/*0x39*/0, /* Reserved for NewLink */ -/*0x3a*/0, /* Reserved for NewLink */ -/*0x3b*/0, /* Reserved for NewLink */ -/*0x3c*/0, /* Reserved for NewLink */ -/*0x3d*/0, /* Reserved for NewLink */ -/*0x3e*/0, /* Reserved for NewLink */ -/*0x3f*/0, /* Reserved for NewLink */ -}; - -static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) -{ - int ret; - - if (pdev && - pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_RIO_USB) - return 9; - - ret = schizo_pil_table[ino]; - if (ret == 0 && pdev == NULL) { - ret = 5; - } else if (ret == 0) { - switch ((pdev->class >> 16) & 0xff) { - case PCI_BASE_CLASS_STORAGE: - ret = 5; - break; - - case PCI_BASE_CLASS_NETWORK: - ret = 6; - break; - - case PCI_BASE_CLASS_DISPLAY: - ret = 9; - break; - - case PCI_BASE_CLASS_MULTIMEDIA: - case PCI_BASE_CLASS_MEMORY: - case PCI_BASE_CLASS_BRIDGE: - case PCI_BASE_CLASS_SERIAL: - ret = 10; - break; - - default: - ret = 5; - break; - }; - } - - return ret; -} - static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2) { unsigned long sync_reg = (unsigned long) _arg2; @@ -372,17 +277,12 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; - int pil, ign_fixup; + int ign_fixup; ino &= PCI_IRQ_INO; imap_off = schizo_imap_offset(ino); /* Now build the IRQ bucket. */ - pil = schizo_ino_to_pil(pdev, ino); - - if (PIL_RESERVED(pil)) - BUG(); - imap = pbm->pbm_regs + imap_off; imap += 4; @@ -405,7 +305,7 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, ign_fixup = (1 << 6); } - bucket = __bucket(build_irq(pil, ign_fixup, iclr, imap)); + bucket = __bucket(build_irq(ign_fixup, iclr, imap)); bucket->flags |= IBF_PCI; if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 0c089520297..b97c81ba883 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -843,38 +843,8 @@ static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, unsigned int devino) { u32 devhandle = pbm->devhandle; - int pil; - pil = 5; - if (pdev) { - switch ((pdev->class >> 16) & 0xff) { - case PCI_BASE_CLASS_STORAGE: - pil = 5; - break; - - case PCI_BASE_CLASS_NETWORK: - pil = 6; - break; - - case PCI_BASE_CLASS_DISPLAY: - pil = 9; - break; - - case PCI_BASE_CLASS_MULTIMEDIA: - case PCI_BASE_CLASS_MEMORY: - case PCI_BASE_CLASS_BRIDGE: - case PCI_BASE_CLASS_SERIAL: - pil = 10; - break; - - default: - pil = 5; - break; - }; - } - BUG_ON(PIL_RESERVED(pil)); - - return sun4v_build_irq(devhandle, devino, pil, IBF_PCI); + return sun4v_build_irq(devhandle, devino, IBF_PCI); } static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 1d6ffdeabd4..8812417247d 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -691,36 +691,6 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) upa_writeq(val, cfg_reg); } -/* SBUS SYSIO INO number to Sparc PIL level. */ -static unsigned char sysio_ino_to_pil[] = { - 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 0 */ - 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 1 */ - 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 2 */ - 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 3 */ - 5, /* Onboard SCSI */ - 5, /* Onboard Ethernet */ -/*XXX*/ 8, /* Onboard BPP */ - 0, /* Bogon */ - 13, /* Audio */ -/*XXX*/15, /* PowerFail */ - 0, /* Bogon */ - 0, /* Bogon */ - 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */ - 11, /* Floppy */ - 0, /* Spare Hardware (bogon for now) */ - 0, /* Keyboard (bogon for now) */ - 0, /* Mouse (bogon for now) */ - 0, /* Serial (bogon for now) */ - 0, 0, /* Bogon, Bogon */ - 10, /* Timer 0 */ - 11, /* Timer 1 */ - 0, 0, /* Bogon, Bogon */ - 15, /* Uncorrectable SBUS Error */ - 15, /* Correctable SBUS Error */ - 15, /* SBUS Error */ -/*XXX*/ 0, /* Power Management (bogon for now) */ -}; - /* INO number to IMAP register offset for SYSIO external IRQ's. * This should conform to both Sunfire/Wildfire server and Fusion * desktop designs. @@ -812,21 +782,12 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) struct sbus_iommu *iommu = sbus->iommu; unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; unsigned long imap, iclr; - int pil, sbus_level = 0; - - pil = sysio_ino_to_pil[ino]; - if (!pil) { - printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino); - panic("Bad SYSIO IRQ translations..."); - } - - if (PIL_RESERVED(pil)) - BUG(); + int sbus_level = 0; imap = sysio_irq_offsets[ino]; if (imap == ((unsigned long)-1)) { - prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n", - ino, pil); + prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n", + ino); prom_halt(); } imap += reg_base; @@ -860,7 +821,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) iclr += ((unsigned long)sbus_level - 1UL) * 8UL; } - return build_irq(pil, sbus_level, iclr, imap); + return build_irq(sbus_level, iclr, imap); } /* Error interrupt handling. */ diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index bbdf89e6faa..d66c7cd820c 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -37,14 +37,14 @@ struct irq_desc { * line. Keep this in mind please. */ struct ino_bucket { - /* Next handler in per-CPU PIL worklist. We know that + /* Next handler in per-CPU IRQ worklist. We know that * bucket pointers have the high 32-bits clear, so to * save space we only store the bits we need. */ /*0x00*/unsigned int irq_chain; - /* PIL to schedule this IVEC at. */ -/*0x04*/unsigned char pil; + /* Virtual interrupt number assigned to this INO. */ +/*0x04*/unsigned char virt_irq; /* If an IVEC arrives while irq_info is NULL, we * set this to notify request_irq() about the event. @@ -95,7 +95,6 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; #define __irq_ino(irq) \ (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0]) -#define __irq_pil(irq) ((struct ino_bucket *)(unsigned long)(irq))->pil #define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) #define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) @@ -105,8 +104,8 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; extern void disable_irq(unsigned int); #define disable_irq_nosync disable_irq extern void enable_irq(unsigned int); -extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap); -extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags); +extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap); +extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags); extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); static __inline__ void set_softint(unsigned long bits) -- cgit v1.2.3-70-g09d2 From 8047e247c899f80c33a23ad7e9e250224f0d26a5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:22:35 -0700 Subject: [SPARC64]: Virtualize IRQ numbers. Inspired by PowerPC XICS interrupt support code. All IRQs are virtualized in order to keep NR_IRQS from needing to be too large. Interrupts on sparc64 are arbitrary 11-bit values, but we don't need to define NR_IRQS to 2048 if we virtualize the IRQs. As PCI and SBUS controller drivers build device IRQs, we divy out virtual IRQ numbers incrementally starting at 1. Zero is a special virtual IRQ used for the timer interrupt. So device drivers all see virtual IRQs, and all the normal interfaces such as request_irq(), enable_irq(), etc. translate that into a real IRQ number in order to configure the IRQ. At this point knowledge of the struct ino_bucket is almost entirely contained within arch/sparc64/kernel/irq.c There are a few small bits in the PCI controller drivers that need to be swept away before we can remove ino_bucket's definition out of asm-sparc64/irq.h and privately into kernel/irq.c Signed-off-by: David S. Miller --- arch/sparc64/kernel/irq.c | 263 ++++++++++++++++++++++++++------------- arch/sparc64/kernel/pci_psycho.c | 6 +- arch/sparc64/kernel/pci_sabre.c | 18 +-- arch/sparc64/kernel/pci_schizo.c | 86 ++++++------- arch/sparc64/kernel/sbus.c | 2 +- include/asm-sparc64/irq.h | 13 +- 6 files changed, 242 insertions(+), 146 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index f2668f2bed9..49ad9cd0f8c 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -70,7 +70,10 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY */ #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) -static struct irqaction *irq_action[NR_IRQS]; +static struct irqaction timer_irq_action = { + .name = "timer", +}; +static struct irqaction *irq_action[NR_IRQS] = { &timer_irq_action, }; /* This only synchronizes entities which modify IRQ handler * state and some selected user-level spots that want to @@ -79,6 +82,59 @@ static struct irqaction *irq_action[NR_IRQS]; */ static DEFINE_SPINLOCK(irq_action_lock); +static unsigned int virt_to_real_irq_table[NR_IRQS]; +static unsigned char virt_irq_cur = 1; + +static unsigned char virt_irq_alloc(unsigned int real_irq) +{ + unsigned char ent; + + BUILD_BUG_ON(NR_IRQS >= 256); + + ent = virt_irq_cur; + if (ent >= NR_IRQS) { + printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); + return 0; + } + + virt_irq_cur = ent + 1; + virt_to_real_irq_table[ent] = real_irq; + + return ent; +} + +#if 0 /* Currently unused. */ +static unsigned char real_to_virt_irq(unsigned int real_irq) +{ + struct ino_bucket *bucket = __bucket(real_irq); + + return bucket->virt_irq; +} +#endif + +static unsigned int virt_to_real_irq(unsigned char virt_irq) +{ + return virt_to_real_irq_table[virt_irq]; +} + +void irq_install_pre_handler(int virt_irq, + void (*func)(struct ino_bucket *, void *, void *), + void *arg1, void *arg2) +{ + unsigned int real_irq = virt_to_real_irq(virt_irq); + struct ino_bucket *bucket; + struct irq_desc *d; + + if (unlikely(!real_irq)) + return; + + bucket = __bucket(real_irq); + d = bucket->irq_info; + d->pre_handler = func; + d->pre_handler_arg1 = arg1; + d->pre_handler_arg2 = arg2; +} + static void register_irq_proc (unsigned int irq); /* @@ -164,14 +220,18 @@ static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid) return tid; } -/* Now these are always passed a true fully specified sun4u INO. */ -void enable_irq(unsigned int irq) +void enable_irq(unsigned int virt_irq) { - struct ino_bucket *bucket = __bucket(irq); + unsigned int real_irq = virt_to_real_irq(virt_irq); + struct ino_bucket *bucket; unsigned long imap, cpuid; + if (unlikely(!real_irq)) + return; + + bucket = __bucket(real_irq); imap = bucket->imap; - if (imap == 0UL) + if (unlikely(imap == 0UL)) return; preempt_disable(); @@ -182,7 +242,7 @@ void enable_irq(unsigned int irq) cpuid = real_hard_smp_processor_id(); if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(irq); + unsigned int ino = __irq_ino(real_irq); int err; err = sun4v_intr_settarget(ino, cpuid); @@ -211,34 +271,39 @@ void enable_irq(unsigned int irq) preempt_enable(); } -/* This now gets passed true ino's as well. */ -void disable_irq(unsigned int irq) +void disable_irq(unsigned int virt_irq) { - struct ino_bucket *bucket = __bucket(irq); + unsigned int real_irq = virt_to_real_irq(virt_irq); + struct ino_bucket *bucket; unsigned long imap; + if (unlikely(!real_irq)) + return; + + bucket = __bucket(real_irq); imap = bucket->imap; - if (imap != 0UL) { - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(irq); - int err; - - err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); - if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): " - "err(%d)\n", ino, err); - } else { - u32 tmp; - - /* NOTE: We do not want to futz with the IRQ clear registers - * and move the state to IDLE, the SCSI code does call - * disable_irq() to assure atomicity in the queue cmd - * SCSI adapter driver code. Thus we'd lose interrupts. - */ - tmp = upa_readl(imap); - tmp &= ~IMAP_VALID; - upa_writel(tmp, imap); - } + if (unlikely(imap == 0UL)) + return; + + if (tlb_type == hypervisor) { + unsigned int ino = __irq_ino(real_irq); + int err; + + err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); + if (err != HV_EOK) + printk("sun4v_intr_setenabled(%x): " + "err(%d)\n", ino, err); + } else { + u32 tmp; + + /* NOTE: We do not want to futz with the IRQ clear registers + * and move the state to IDLE, the SCSI code does call + * disable_irq() to assure atomicity in the queue cmd + * SCSI adapter driver code. Thus we'd lose interrupts. + */ + tmp = upa_readl(imap); + tmp &= ~IMAP_VALID; + upa_writel(tmp, imap); } } @@ -253,14 +318,14 @@ static void build_irq_error(const char *msg, unsigned int ino, int inofixup, prom_halt(); } -unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) +unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap, unsigned char flags) { struct ino_bucket *bucket; int ino; BUG_ON(tlb_type == hypervisor); - /* RULE: Both must be specified in all other cases. */ + /* RULE: Both must be specified. */ if (iclr == 0UL || imap == 0UL) { prom_printf("Invalid build_irq %d %016lx %016lx\n", inofixup, iclr, imap); @@ -298,10 +363,12 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) */ bucket->imap = imap; bucket->iclr = iclr; - bucket->flags = 0; + if (!bucket->virt_irq) + bucket->virt_irq = virt_irq_alloc(__irq(bucket)); + bucket->flags = flags; out: - return __irq(bucket); + return bucket->virt_irq; } unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags) @@ -322,7 +389,8 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char f */ bucket->imap = ~0UL - sysino; bucket->iclr = ~0UL - sysino; - + if (!bucket->virt_irq) + bucket->virt_irq = virt_irq_alloc(__irq(bucket)); bucket->flags = flags; bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); @@ -331,7 +399,7 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char f prom_halt(); } - return __irq(bucket); + return bucket->virt_irq; } static void atomic_bucket_insert(struct ino_bucket *bucket) @@ -390,37 +458,42 @@ static struct irqaction *get_action_slot(struct ino_bucket *bucket) return NULL; } -int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), +int request_irq(unsigned int virt_irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *name, void *dev_id) { struct irqaction *action; - struct ino_bucket *bucket = __bucket(irq); + struct ino_bucket *bucket; unsigned long flags; + unsigned int real_irq; int pending = 0; + real_irq = virt_to_real_irq(virt_irq); + if (unlikely(!real_irq)) + return -EINVAL; + if (unlikely(!handler)) return -EINVAL; + bucket = __bucket(real_irq); if (unlikely(!bucket->irq_info)) return -ENODEV; if (irqflags & SA_SAMPLE_RANDOM) { /* - * This function might sleep, we want to call it first, - * outside of the atomic block. In SA_STATIC_ALLOC case, - * random driver's kmalloc will fail, but it is safe. - * If already initialized, random driver will not reinit. - * Yes, this might clear the entropy pool if the wrong - * driver is attempted to be loaded, without actually - * installing a new handler, but is this really a problem, - * only the sysadmin is able to do this. - */ - rand_initialize_irq(PIL_DEVICE_IRQ); + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(virt_irq); } spin_lock_irqsave(&irq_action_lock, flags); - if (check_irq_sharing(PIL_DEVICE_IRQ, irqflags)) { + if (check_irq_sharing(virt_irq, irqflags)) { spin_unlock_irqrestore(&irq_action_lock, flags); return -EBUSY; } @@ -441,12 +514,12 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ action->name = name; action->next = NULL; action->dev_id = dev_id; - put_ino_in_irqaction(action, irq); + put_ino_in_irqaction(action, __irq_ino(real_irq)); put_smpaff_in_irqaction(action, CPU_MASK_NONE); - append_irq_action(PIL_DEVICE_IRQ, action); + append_irq_action(virt_irq, action); - enable_irq(irq); + enable_irq(virt_irq); /* We ate the IVEC already, this makes sure it does not get lost. */ if (pending) { @@ -456,7 +529,7 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ spin_unlock_irqrestore(&irq_action_lock, flags); - register_irq_proc(__irq_ino(irq)); + register_irq_proc(virt_irq); #ifdef CONFIG_SMP distribute_irqs(); @@ -466,17 +539,17 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ EXPORT_SYMBOL(request_irq); -static struct irqaction *unlink_irq_action(unsigned int irq, void *dev_id) +static struct irqaction *unlink_irq_action(unsigned int virt_irq, void *dev_id) { struct irqaction *action, **pp; - pp = irq_action + PIL_DEVICE_IRQ; + pp = irq_action + virt_irq; action = *pp; if (unlikely(!action)) return NULL; if (unlikely(!action->handler)) { - printk("Freeing free IRQ %d\n", PIL_DEVICE_IRQ); + printk("Freeing free IRQ %d\n", virt_irq); return NULL; } @@ -491,28 +564,33 @@ static struct irqaction *unlink_irq_action(unsigned int irq, void *dev_id) return action; } -void free_irq(unsigned int irq, void *dev_id) +void free_irq(unsigned int virt_irq, void *dev_id) { struct irqaction *action; struct ino_bucket *bucket; struct irq_desc *desc; unsigned long flags; + unsigned int real_irq; int ent, i; + real_irq = virt_to_real_irq(virt_irq); + if (unlikely(!real_irq)) + return; + spin_lock_irqsave(&irq_action_lock, flags); - action = unlink_irq_action(irq, dev_id); + action = unlink_irq_action(virt_irq, dev_id); spin_unlock_irqrestore(&irq_action_lock, flags); if (unlikely(!action)) return; - synchronize_irq(irq); + synchronize_irq(virt_irq); spin_lock_irqsave(&irq_action_lock, flags); - bucket = __bucket(irq); + bucket = __bucket(real_irq); desc = bucket->irq_info; for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { @@ -545,7 +623,7 @@ void free_irq(unsigned int irq, void *dev_id) * the same IMAP are active. */ if (ent == NUM_IVECS) - disable_irq(irq); + disable_irq(virt_irq); } spin_unlock_irqrestore(&irq_action_lock, flags); @@ -554,10 +632,15 @@ void free_irq(unsigned int irq, void *dev_id) EXPORT_SYMBOL(free_irq); #ifdef CONFIG_SMP -void synchronize_irq(unsigned int irq) +void synchronize_irq(unsigned int virt_irq) { - struct ino_bucket *bucket = __bucket(irq); + unsigned int real_irq = virt_to_real_irq(virt_irq); + struct ino_bucket *bucket; + + if (unlikely(!real_irq)) + return; + bucket = __bucket(real_irq); #if 0 /* The following is how I wish I could implement this. * Unfortunately the ICLR registers are read-only, you can @@ -616,7 +699,7 @@ static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) action_mask &= ~mask; - if (p->handler(__irq(bp), p->dev_id, regs) == IRQ_HANDLED) + if (p->handler(bp->virt_irq, p->dev_id, regs) == IRQ_HANDLED) random |= p->flags; if (!action_mask) @@ -637,7 +720,7 @@ static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) /* Test and add entropy */ if (random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(PIL_DEVICE_IRQ); + add_interrupt_randomness(bp->virt_irq); out: bp->flags &= ~IBF_INPROGRESS; } @@ -657,7 +740,7 @@ void timer_irq(int irq, struct pt_regs *regs) clear_softint(clr_mask); irq_enter(); - kstat_this_cpu.irqs[irq]++; + kstat_this_cpu.irqs[0]++; timer_interrupt(irq, NULL, regs); irq_exit(); } @@ -1022,13 +1105,13 @@ void __init init_IRQ(void) : "g1"); } -static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NUM_IVECS]; +static struct proc_dir_entry *root_irq_dir; +static struct proc_dir_entry *irq_dir[NR_IRQS]; #ifdef CONFIG_SMP -static int irq_affinity_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) +static int irq_affinity_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { struct ino_bucket *bp = ivector_table + (long)data; struct irq_desc *desc = bp->irq_info; @@ -1047,11 +1130,20 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off, return len; } -static inline void set_intr_affinity(int irq, cpumask_t hw_aff) +static inline void set_intr_affinity(int virt_irq, cpumask_t hw_aff) { - struct ino_bucket *bp = ivector_table + irq; - struct irq_desc *desc = bp->irq_info; - struct irqaction *ap = desc->action; + struct ino_bucket *bp; + struct irq_desc *desc; + struct irqaction *ap; + unsigned int real_irq; + + real_irq = virt_to_real_irq(virt_irq); + if (unlikely(!real_irq)) + return; + + bp = __bucket(real_irq); + desc = bp->irq_info; + ap = desc->action; /* Users specify affinity in terms of hw cpu ids. * As soon as we do this, handler_irq() might see and take action. @@ -1060,13 +1152,16 @@ static inline void set_intr_affinity(int irq, cpumask_t hw_aff) /* Migration is simply done by the next cpu to service this * interrupt. + * + * XXX Broken, this doesn't happen anymore... */ } -static int irq_affinity_write_proc (struct file *file, const char __user *buffer, - unsigned long count, void *data) +static int irq_affinity_write_proc(struct file *file, + const char __user *buffer, + unsigned long count, void *data) { - int irq = (long) data, full_count = count, err; + int virt_irq = (long) data, full_count = count, err; cpumask_t new_value; err = cpumask_parse(buffer, count, new_value); @@ -1080,7 +1175,7 @@ static int irq_affinity_write_proc (struct file *file, const char __user *buffer if (cpus_empty(new_value)) return -EINVAL; - set_intr_affinity(irq, new_value); + set_intr_affinity(virt_irq, new_value); return full_count; } @@ -1089,18 +1184,18 @@ static int irq_affinity_write_proc (struct file *file, const char __user *buffer #define MAX_NAMELEN 10 -static void register_irq_proc (unsigned int irq) +static void register_irq_proc(unsigned int virt_irq) { char name [MAX_NAMELEN]; - if (!root_irq_dir || irq_dir[irq]) + if (!root_irq_dir || irq_dir[virt_irq]) return; memset(name, 0, MAX_NAMELEN); - sprintf(name, "%x", irq); + sprintf(name, "%d", virt_irq); /* create /proc/irq/1234 */ - irq_dir[irq] = proc_mkdir(name, root_irq_dir); + irq_dir[virt_irq] = proc_mkdir(name, root_irq_dir); #ifdef CONFIG_SMP /* XXX SMP affinity not supported on starfire yet. */ @@ -1112,7 +1207,7 @@ static void register_irq_proc (unsigned int irq) if (entry) { entry->nlink = 1; - entry->data = (void *)(long)irq; + entry->data = (void *)(long)virt_irq; entry->read_proc = irq_affinity_read_proc; entry->write_proc = irq_affinity_write_proc; } @@ -1120,7 +1215,7 @@ static void register_irq_proc (unsigned int irq) #endif } -void init_irq_proc (void) +void init_irq_proc(void) { /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 5743e1316a9..f2d1097f541 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -280,7 +280,6 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) { - struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; int inofixup = 0; @@ -309,10 +308,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - bucket = __bucket(build_irq(inofixup, iclr, imap)); - bucket->flags |= IBF_PCI; - - return __irq(bucket); + return build_irq(inofixup, iclr, imap, IBF_PCI); } /* PSYCHO error handling support. */ diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index caa7aeed5d1..846c1205aa9 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -544,10 +544,10 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) { - struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; int inofixup = 0; + int virt_irq; ino &= PCI_IRQ_INO; if (ino < SABRE_ONBOARD_IRQ_BASE) { @@ -573,23 +573,23 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - bucket = __bucket(build_irq(inofixup, iclr, imap)); - bucket->flags |= IBF_PCI; + virt_irq = build_irq(inofixup, iclr, imap, IBF_PCI); if (pdev) { struct pcidev_cookie *pcp = pdev->sysdata; if (pdev->bus->number != pcp->pbm->pci_first_busno) { struct pci_controller_info *p = pcp->pbm->parent; - struct irq_desc *d = bucket->irq_info; - d->pre_handler = sabre_wsync_handler; - d->pre_handler_arg1 = pdev; - d->pre_handler_arg2 = (void *) - p->pbm_A.controller_regs + SABRE_WRSYNC; + irq_install_pre_handler(virt_irq, + sabre_wsync_handler, + pdev, + (void *) + p->pbm_A.controller_regs + + SABRE_WRSYNC); } } - return __irq(bucket); + return virt_irq; } /* SABRE error handling support. */ diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index ca49ef08236..0c400b5fa5b 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -270,25 +270,33 @@ static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void } } +static unsigned long schizo_ino_to_iclr(struct pci_pbm_info *pbm, + unsigned int ino) +{ + ino &= PCI_IRQ_INO; + return pbm->pbm_regs + schizo_iclr_offset(ino) + 4; +} + +static unsigned long schizo_ino_to_imap(struct pci_pbm_info *pbm, + unsigned int ino) +{ + ino &= PCI_IRQ_INO; + return pbm->pbm_regs + schizo_imap_offset(ino) + 4; +} + static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) { - struct ino_bucket *bucket; unsigned long imap, iclr; - unsigned long imap_off, iclr_off; int ign_fixup; + int virt_irq; ino &= PCI_IRQ_INO; - imap_off = schizo_imap_offset(ino); /* Now build the IRQ bucket. */ - imap = pbm->pbm_regs + imap_off; - imap += 4; - - iclr_off = schizo_iclr_offset(ino); - iclr = pbm->pbm_regs + iclr_off; - iclr += 4; + imap = schizo_ino_to_imap(pbm, ino); + iclr = schizo_ino_to_iclr(pbm, ino); /* On Schizo, no inofixup occurs. This is because each * INO has it's own IMAP register. On Psycho and Sabre @@ -305,19 +313,17 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, ign_fixup = (1 << 6); } - bucket = __bucket(build_irq(ign_fixup, iclr, imap)); - bucket->flags |= IBF_PCI; + virt_irq = build_irq(ign_fixup, iclr, imap, IBF_PCI); if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { - struct irq_desc *p = bucket->irq_info; - - p->pre_handler = tomatillo_wsync_handler; - p->pre_handler_arg1 = ((pbm->chip_version <= 4) ? - (void *) 1 : (void *) 0); - p->pre_handler_arg2 = (void *) pbm->sync_reg; + irq_install_pre_handler(virt_irq, + tomatillo_wsync_handler, + ((pbm->chip_version <= 4) ? + (void *) 1 : (void *) 0), + (void *) pbm->sync_reg); } - return __irq(bucket); + return virt_irq; } /* SCHIZO error handling support. */ @@ -358,7 +364,6 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino) static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq) { struct pci_pbm_info *pbm; - struct ino_bucket *bucket; unsigned long iclr; /* Do not clear the interrupt for the other PCI bus. @@ -376,11 +381,11 @@ static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq) else pbm = &p->pbm_A; - irq = schizo_irq_build(pbm, NULL, - (pbm->portid << 6) | (irq & IMAP_INO)); - bucket = __bucket(irq); - iclr = bucket->iclr; + schizo_irq_build(pbm, NULL, + (pbm->portid << 6) | (irq & IMAP_INO)); + iclr = schizo_ino_to_iclr(pbm, + (pbm->portid << 6) | (irq & IMAP_INO)); upa_writel(ICLR_IDLE, iclr); } @@ -1125,7 +1130,6 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; unsigned int irq; - struct ino_bucket *bucket; u64 tmp, err_mask, err_no_mask; /* Build IRQs and register handlers. */ @@ -1137,8 +1141,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); @@ -1150,8 +1153,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); @@ -1164,8 +1166,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | + SCHIZO_PCIERR_A_INO))); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); @@ -1178,8 +1180,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | + SCHIZO_PCIERR_B_INO))); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); @@ -1191,8 +1193,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | + SCHIZO_SERR_INO))); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); @@ -1263,7 +1265,6 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; unsigned int irq; - struct ino_bucket *bucket; u64 tmp, err_mask, err_no_mask; /* Build IRQs and register handlers. */ @@ -1275,8 +1276,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_CE_INO); @@ -1287,8 +1287,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); @@ -1299,8 +1298,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); @@ -1311,8 +1309,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); @@ -1323,8 +1320,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_SERR_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); /* Enable UE and CE interrupts for controller. */ diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 8812417247d..5544cf5d38b 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -821,7 +821,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) iclr += ((unsigned long)sbus_level - 1UL) * 8UL; } - return build_irq(sbus_level, iclr, imap); + return build_irq(sbus_level, iclr, imap, 0); } /* Error interrupt handling. */ diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index d66c7cd820c..9edcd90495f 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -98,13 +98,22 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; #define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) #define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) -#define NR_IRQS 16 +/* The largest number of unique interrupt sources we support. + * If this needs to ever be larger than 255, you need to change + * the type of ino_bucket->virt_irq as appropriate. + * + * ino_bucket->virt_irq allocation is made during {sun4v_,}build_irq(). + */ +#define NR_IRQS 255 +extern void irq_install_pre_handler(int virt_irq, + void (*func)(struct ino_bucket *, void *, void *), + void *arg1, void *arg2); #define irq_canonicalize(irq) (irq) extern void disable_irq(unsigned int); #define disable_irq_nosync disable_irq extern void enable_irq(unsigned int); -extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap); +extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap, unsigned char flags); extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags); extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); -- cgit v1.2.3-70-g09d2 From e18e2a00efc8352c131eb8d5a460149fb5776f1c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:23:32 -0700 Subject: [SPARC64]: Move over to GENERIC_HARDIRQS. This is the long overdue conversion of sparc64 over to the generic IRQ layer. The kernel image is slightly larger, but the BSS is ~60K smaller due to the reduced size of struct ino_bucket. A lot of IRQ implementation details, including ino_bucket, were moved out of asm-sparc64/irq.h and are now private to arch/sparc64/kernel/irq.c, and most of the code in irq.c totally disappeared. One thing that's different at the moment is IRQ distribution, we do it at enable_irq() time. If the cpu mask is ALL then we round-robin using a global rotating cpu counter, else we pick the first cpu in the mask to support single cpu targetting. This is similar to what powerpc's XICS IRQ support code does. This works fine on my UP SB1000, and the SMP build goes fine and runs on that machine, but lots of testing on different setups is needed. Signed-off-by: David S. Miller --- arch/sparc64/Kconfig | 4 + arch/sparc64/kernel/devices.c | 2 +- arch/sparc64/kernel/entry.S | 2 +- arch/sparc64/kernel/irq.c | 957 +++++++++++------------------------- arch/sparc64/kernel/pci.c | 38 -- arch/sparc64/kernel/pci_psycho.c | 2 +- arch/sparc64/kernel/pci_sabre.c | 4 +- arch/sparc64/kernel/pci_schizo.c | 6 +- arch/sparc64/kernel/pci_sun4v.c | 2 +- arch/sparc64/kernel/sbus.c | 2 +- arch/sparc64/kernel/sparc64_ksyms.c | 4 - arch/sparc64/kernel/sun4v_ivec.S | 2 +- include/asm-sparc64/hardirq.h | 2 + include/asm-sparc64/hw_irq.h | 2 +- include/asm-sparc64/irq.h | 78 +-- 15 files changed, 305 insertions(+), 802 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 43a66f5407f..a7a111db25b 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -87,6 +87,10 @@ config SYSVIPC_COMPAT depends on COMPAT && SYSVIPC default y +config GENERIC_HARDIRQS + bool + default y + menu "General machine setup" config SMP diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 0684899d998..0dd95ae50e1 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -157,7 +157,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) return 0; } - return sun4v_build_irq(sun4v_vdev_devhandle, irq, 0); + return sun4v_build_irq(sun4v_vdev_devhandle, irq); } static const char *cpu_mid_prop(void) diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index c87365e59e7..be85ce2a4ad 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -432,7 +432,7 @@ do_ivec: membar #Sync sethi %hi(ivector_table), %g2 - sllx %g3, 5, %g3 + sllx %g3, 3, %g3 or %g2, %lo(ivector_table), %g2 add %g2, %g3, %g3 diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 49ad9cd0f8c..a8c9dc8d195 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -42,10 +43,6 @@ #include #include -#ifdef CONFIG_SMP -static void distribute_irqs(void); -#endif - /* UPA nodes send interrupt packet to UltraSparc with first data reg * value low 5 (7 on Starfire) bits holding the IRQ identifier being * delivered. We must translate this into a non-vector IRQ so we can @@ -57,10 +54,29 @@ static void distribute_irqs(void); * The IVEC handler does not need to act atomically, the PIL dispatch * code uses CAS to get an atomic snapshot of the list and clear it * at the same time. + * + * If you make changes to ino_bucket, please update hand coded assembler + * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S */ +struct ino_bucket { + /* Next handler in per-CPU IRQ worklist. We know that + * bucket pointers have the high 32-bits clear, so to + * save space we only store the bits we need. + */ +/*0x00*/unsigned int irq_chain; + /* Virtual interrupt number assigned to this INO. */ +/*0x04*/unsigned int virt_irq; +}; + +#define NUM_IVECS (IMAP_INR + 1) struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES))); +#define __irq_ino(irq) \ + (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0]) +#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) +#define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) + /* This has to be in the main kernel image, it cannot be * turned into per-cpu data. The reason is that the main * kernel image is locked into the TLB and this structure @@ -70,18 +86,6 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY */ #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) -static struct irqaction timer_irq_action = { - .name = "timer", -}; -static struct irqaction *irq_action[NR_IRQS] = { &timer_irq_action, }; - -/* This only synchronizes entities which modify IRQ handler - * state and some selected user-level spots that want to - * read things in the table. IRQ handler processing orders - * its' accesses such that no locking is needed. - */ -static DEFINE_SPINLOCK(irq_action_lock); - static unsigned int virt_to_real_irq_table[NR_IRQS]; static unsigned char virt_irq_cur = 1; @@ -117,69 +121,45 @@ static unsigned int virt_to_real_irq(unsigned char virt_irq) return virt_to_real_irq_table[virt_irq]; } -void irq_install_pre_handler(int virt_irq, - void (*func)(struct ino_bucket *, void *, void *), - void *arg1, void *arg2) -{ - unsigned int real_irq = virt_to_real_irq(virt_irq); - struct ino_bucket *bucket; - struct irq_desc *d; - - if (unlikely(!real_irq)) - return; - - bucket = __bucket(real_irq); - d = bucket->irq_info; - d->pre_handler = func; - d->pre_handler_arg1 = arg1; - d->pre_handler_arg2 = arg2; -} - -static void register_irq_proc (unsigned int irq); - /* - * Upper 2b of irqaction->flags holds the ino. - * irqaction->mask holds the smp affinity information. + * /proc/interrupts printing: */ -#define put_ino_in_irqaction(action, irq) \ - action->flags &= 0xffffffffffffUL; \ - action->flags |= __irq_ino(irq) << 48; - -#define get_ino_in_irqaction(action) (action->flags >> 48) - -#define put_smpaff_in_irqaction(action, smpaff) (action)->mask = (smpaff) -#define get_smpaff_in_irqaction(action) ((action)->mask) int show_interrupts(struct seq_file *p, void *v) { + int i = *(loff_t *) v, j; + struct irqaction * action; unsigned long flags; - int i = *(loff_t *) v; - struct irqaction *action; -#ifdef CONFIG_SMP - int j; -#endif - spin_lock_irqsave(&irq_action_lock, flags); - if (i <= NR_IRQS) { - if (!(action = *(i + irq_action))) - goto out_unlock; - seq_printf(p, "%3d: ", i); + if (i == 0) { + seq_printf(p, " "); + for_each_online_cpu(j) + seq_printf(p, "CPU%d ",j); + seq_putc(p, '\n'); + } + + if (i < NR_IRQS) { + spin_lock_irqsave(&irq_desc[i].lock, flags); + action = irq_desc[i].action; + if (!action) + goto skip; + seq_printf(p, "%3d: ",i); #ifndef CONFIG_SMP seq_printf(p, "%10u ", kstat_irqs(i)); #else - for_each_online_cpu(j) { - seq_printf(p, "%10u ", - kstat_cpu(j).irqs[i]); - } + for_each_online_cpu(j) + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif - seq_printf(p, " %s", action->name); - for (action = action->next; action; action = action->next) + seq_printf(p, " %9s", irq_desc[i].handler->typename); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) seq_printf(p, ", %s", action->name); + seq_putc(p, '\n'); +skip: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); } -out_unlock: - spin_unlock_irqrestore(&irq_action_lock, flags); - return 0; } @@ -220,509 +200,321 @@ static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid) return tid; } -void enable_irq(unsigned int virt_irq) -{ - unsigned int real_irq = virt_to_real_irq(virt_irq); - struct ino_bucket *bucket; - unsigned long imap, cpuid; - - if (unlikely(!real_irq)) - return; +struct irq_handler_data { + unsigned long iclr; + unsigned long imap; - bucket = __bucket(real_irq); - imap = bucket->imap; - if (unlikely(imap == 0UL)) - return; - - preempt_disable(); - - /* This gets the physical processor ID, even on uniprocessor, - * so we can always program the interrupt target correctly. - */ - cpuid = real_hard_smp_processor_id(); - - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(real_irq); - int err; - - err = sun4v_intr_settarget(ino, cpuid); - if (err != HV_EOK) - printk("sun4v_intr_settarget(%x,%lu): err(%d)\n", - ino, cpuid, err); - err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED); - if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): err(%d)\n", - ino, err); - } else { - unsigned int tid = sun4u_compute_tid(imap, cpuid); - - /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product - * of this SYSIO's preconfigured IGN in the SYSIO Control - * Register, the hardware just mirrors that value here. - * However for Graphics and UPA Slave devices the full - * IMAP_INR field can be set by the programmer here. - * - * Things like FFB can now be handled via the new IRQ - * mechanism. - */ - upa_writel(tid | IMAP_VALID, imap); - } - - preempt_enable(); -} + void (*pre_handler)(unsigned int, void *, void *); + void *pre_handler_arg1; + void *pre_handler_arg2; +}; -void disable_irq(unsigned int virt_irq) +static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq) { unsigned int real_irq = virt_to_real_irq(virt_irq); - struct ino_bucket *bucket; - unsigned long imap; + struct ino_bucket *bucket = NULL; - if (unlikely(!real_irq)) - return; - - bucket = __bucket(real_irq); - imap = bucket->imap; - if (unlikely(imap == 0UL)) - return; - - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(real_irq); - int err; + if (likely(real_irq)) + bucket = __bucket(real_irq); - err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); - if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): " - "err(%d)\n", ino, err); - } else { - u32 tmp; - - /* NOTE: We do not want to futz with the IRQ clear registers - * and move the state to IDLE, the SCSI code does call - * disable_irq() to assure atomicity in the queue cmd - * SCSI adapter driver code. Thus we'd lose interrupts. - */ - tmp = upa_readl(imap); - tmp &= ~IMAP_VALID; - upa_writel(tmp, imap); - } + return bucket; } -static void build_irq_error(const char *msg, unsigned int ino, int inofixup, - unsigned long iclr, unsigned long imap, - struct ino_bucket *bucket) +#ifdef CONFIG_SMP +static int irq_choose_cpu(unsigned int virt_irq) { - prom_printf("IRQ: INO %04x (%016lx:%016lx) --> " - "(%d:%016lx:%016lx), halting...\n", - ino, bucket->iclr, bucket->imap, - inofixup, iclr, imap); - prom_halt(); -} + cpumask_t mask = irq_affinity[virt_irq]; + int cpuid; -unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap, unsigned char flags) -{ - struct ino_bucket *bucket; - int ino; + if (cpus_equal(mask, CPU_MASK_ALL)) { + static int irq_rover; + static DEFINE_SPINLOCK(irq_rover_lock); + unsigned long flags; - BUG_ON(tlb_type == hypervisor); + /* Round-robin distribution... */ + do_round_robin: + spin_lock_irqsave(&irq_rover_lock, flags); - /* RULE: Both must be specified. */ - if (iclr == 0UL || imap == 0UL) { - prom_printf("Invalid build_irq %d %016lx %016lx\n", - inofixup, iclr, imap); - prom_halt(); - } - - ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; - if (ino > NUM_IVECS) { - prom_printf("Invalid INO %04x (%d:%016lx:%016lx)\n", - ino, inofixup, iclr, imap); - prom_halt(); - } + while (!cpu_online(irq_rover)) { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } + cpuid = irq_rover; + do { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } while (!cpu_online(irq_rover)); - bucket = &ivector_table[ino]; - if (bucket->flags & IBF_ACTIVE) - build_irq_error("IRQ: Trying to build active INO bucket.\n", - ino, inofixup, iclr, imap, bucket); + spin_unlock_irqrestore(&irq_rover_lock, flags); + } else { + cpumask_t tmp; - if (bucket->irq_info) { - if (bucket->imap != imap || bucket->iclr != iclr) - build_irq_error("IRQ: Trying to reinit INO bucket.\n", - ino, inofixup, iclr, imap, bucket); + cpus_and(tmp, cpu_online_map, mask); - goto out; - } + if (cpus_empty(tmp)) + goto do_round_robin; - bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); - if (!bucket->irq_info) { - prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); - prom_halt(); + cpuid = first_cpu(tmp); } - /* Ok, looks good, set it up. Don't touch the irq_chain or - * the pending flag. - */ - bucket->imap = imap; - bucket->iclr = iclr; - if (!bucket->virt_irq) - bucket->virt_irq = virt_irq_alloc(__irq(bucket)); - bucket->flags = flags; - -out: - return bucket->virt_irq; + return cpuid; +} +#else +static int irq_choose_cpu(unsigned int virt_irq) +{ + return real_hard_smp_processor_id(); } +#endif -unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags) +static void sun4u_irq_enable(unsigned int virt_irq) { - struct ino_bucket *bucket; - unsigned long sysino; + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - sysino = sun4v_devino_to_sysino(devhandle, devino); + if (likely(data)) { + unsigned long cpuid, imap; + unsigned int tid; - bucket = &ivector_table[sysino]; + cpuid = irq_choose_cpu(virt_irq); + imap = data->imap; - /* Catch accidental accesses to these things. IMAP/ICLR handling - * is done by hypervisor calls on sun4v platforms, not by direct - * register accesses. - * - * But we need to make them look unique for the disable_irq() logic - * in free_irq(). - */ - bucket->imap = ~0UL - sysino; - bucket->iclr = ~0UL - sysino; - if (!bucket->virt_irq) - bucket->virt_irq = virt_irq_alloc(__irq(bucket)); - bucket->flags = flags; + tid = sun4u_compute_tid(imap, cpuid); - bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); - if (!bucket->irq_info) { - prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); - prom_halt(); + upa_writel(tid | IMAP_VALID, imap); } - - return bucket->virt_irq; } -static void atomic_bucket_insert(struct ino_bucket *bucket) +static void sun4u_irq_disable(unsigned int virt_irq) { - unsigned long pstate; - unsigned int *ent; + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); - __asm__ __volatile__("wrpr %0, %1, %%pstate" - : : "r" (pstate), "i" (PSTATE_IE)); - ent = irq_work(smp_processor_id()); - bucket->irq_chain = *ent; - *ent = __irq(bucket); - __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); -} + if (likely(data)) { + unsigned long imap = data->imap; + u32 tmp = upa_readl(imap); -static int check_irq_sharing(int pil, unsigned long irqflags) -{ - struct irqaction *action; - - action = *(irq_action + pil); - if (action) { - if (!(action->flags & SA_SHIRQ) || !(irqflags & SA_SHIRQ)) - return -EBUSY; + tmp &= ~IMAP_VALID; + upa_writel(tmp, imap); } - return 0; } -static void append_irq_action(int pil, struct irqaction *action) +static void sun4u_irq_end(unsigned int virt_irq) { - struct irqaction **pp = irq_action + pil; + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - while (*pp) - pp = &((*pp)->next); - *pp = action; + if (likely(data)) + upa_writel(ICLR_IDLE, data->iclr); } -static struct irqaction *get_action_slot(struct ino_bucket *bucket) +static void sun4v_irq_enable(unsigned int virt_irq) { - struct irq_desc *desc = bucket->irq_info; - int max_irq, i; + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; - max_irq = 1; - if (bucket->flags & IBF_PCI) - max_irq = MAX_IRQ_DESC_ACTION; - for (i = 0; i < max_irq; i++) { - struct irqaction *p = &desc->action[i]; - u32 mask = (1 << i); + if (likely(bucket)) { + unsigned long cpuid; + int err; - if (desc->action_active_mask & mask) - continue; + cpuid = irq_choose_cpu(virt_irq); - desc->action_active_mask |= mask; - return p; + err = sun4v_intr_settarget(ino, cpuid); + if (err != HV_EOK) + printk("sun4v_intr_settarget(%x,%lu): err(%d)\n", + ino, cpuid, err); + err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED); + if (err != HV_EOK) + printk("sun4v_intr_setenabled(%x): err(%d)\n", + ino, err); } - return NULL; } -int request_irq(unsigned int virt_irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char *name, void *dev_id) +static void sun4v_irq_disable(unsigned int virt_irq) { - struct irqaction *action; - struct ino_bucket *bucket; - unsigned long flags; - unsigned int real_irq; - int pending = 0; - - real_irq = virt_to_real_irq(virt_irq); - if (unlikely(!real_irq)) - return -EINVAL; - - if (unlikely(!handler)) - return -EINVAL; - - bucket = __bucket(real_irq); - if (unlikely(!bucket->irq_info)) - return -ENODEV; - - if (irqflags & SA_SAMPLE_RANDOM) { - /* - * This function might sleep, we want to call it first, - * outside of the atomic block. - * Yes, this might clear the entropy pool if the wrong - * driver is attempted to be loaded, without actually - * installing a new handler, but is this really a problem, - * only the sysadmin is able to do this. - */ - rand_initialize_irq(virt_irq); - } - - spin_lock_irqsave(&irq_action_lock, flags); + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; - if (check_irq_sharing(virt_irq, irqflags)) { - spin_unlock_irqrestore(&irq_action_lock, flags); - return -EBUSY; - } + if (likely(bucket)) { + int err; - action = get_action_slot(bucket); - if (!action) { - spin_unlock_irqrestore(&irq_action_lock, flags); - return -ENOMEM; + err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); + if (err != HV_EOK) + printk("sun4v_intr_setenabled(%x): " + "err(%d)\n", ino, err); } +} - bucket->flags |= IBF_ACTIVE; - pending = bucket->pending; - if (pending) - bucket->pending = 0; - - action->handler = handler; - action->flags = irqflags; - action->name = name; - action->next = NULL; - action->dev_id = dev_id; - put_ino_in_irqaction(action, __irq_ino(real_irq)); - put_smpaff_in_irqaction(action, CPU_MASK_NONE); - - append_irq_action(virt_irq, action); +static void sun4v_irq_end(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; - enable_irq(virt_irq); + if (likely(bucket)) { + int err; - /* We ate the IVEC already, this makes sure it does not get lost. */ - if (pending) { - atomic_bucket_insert(bucket); - set_softint(1 << PIL_DEVICE_IRQ); + err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE); + if (err != HV_EOK) + printk("sun4v_intr_setstate(%x): " + "err(%d)\n", ino, err); } - - spin_unlock_irqrestore(&irq_action_lock, flags); - - register_irq_proc(virt_irq); - -#ifdef CONFIG_SMP - distribute_irqs(); -#endif - return 0; } -EXPORT_SYMBOL(request_irq); - -static struct irqaction *unlink_irq_action(unsigned int virt_irq, void *dev_id) +static void run_pre_handler(unsigned int virt_irq) { - struct irqaction *action, **pp; - - pp = irq_action + virt_irq; - action = *pp; - if (unlikely(!action)) - return NULL; + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - if (unlikely(!action->handler)) { - printk("Freeing free IRQ %d\n", virt_irq); - return NULL; + if (likely(data->pre_handler)) { + data->pre_handler(__irq_ino(__irq(bucket)), + data->pre_handler_arg1, + data->pre_handler_arg2); } - - while (action && action->dev_id != dev_id) { - pp = &action->next; - action = *pp; - } - - if (likely(action)) - *pp = action->next; - - return action; } -void free_irq(unsigned int virt_irq, void *dev_id) -{ - struct irqaction *action; - struct ino_bucket *bucket; - struct irq_desc *desc; - unsigned long flags; - unsigned int real_irq; - int ent, i; - - real_irq = virt_to_real_irq(virt_irq); - if (unlikely(!real_irq)) - return; +static struct hw_interrupt_type sun4u_irq = { + .typename = "sun4u", + .enable = sun4u_irq_enable, + .disable = sun4u_irq_disable, + .end = sun4u_irq_end, +}; - spin_lock_irqsave(&irq_action_lock, flags); +static struct hw_interrupt_type sun4u_irq_ack = { + .typename = "sun4u+ack", + .enable = sun4u_irq_enable, + .disable = sun4u_irq_disable, + .ack = run_pre_handler, + .end = sun4u_irq_end, +}; - action = unlink_irq_action(virt_irq, dev_id); +static struct hw_interrupt_type sun4v_irq = { + .typename = "sun4v", + .enable = sun4v_irq_enable, + .disable = sun4v_irq_disable, + .end = sun4v_irq_end, +}; - spin_unlock_irqrestore(&irq_action_lock, flags); +static struct hw_interrupt_type sun4v_irq_ack = { + .typename = "sun4v+ack", + .enable = sun4v_irq_enable, + .disable = sun4v_irq_disable, + .ack = run_pre_handler, + .end = sun4v_irq_end, +}; - if (unlikely(!action)) - return; +void irq_install_pre_handler(int virt_irq, + void (*func)(unsigned int, void *, void *), + void *arg1, void *arg2) +{ + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - synchronize_irq(virt_irq); + data->pre_handler = func; + data->pre_handler_arg1 = arg1; + data->pre_handler_arg2 = arg2; - spin_lock_irqsave(&irq_action_lock, flags); + desc->handler = (desc->handler == &sun4u_irq ? + &sun4u_irq_ack : &sun4v_irq_ack); +} - bucket = __bucket(real_irq); - desc = bucket->irq_info; +unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) +{ + struct ino_bucket *bucket; + struct irq_handler_data *data; + irq_desc_t *desc; + int ino; - for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { - struct irqaction *p = &desc->action[i]; + BUG_ON(tlb_type == hypervisor); - if (p == action) { - desc->action_active_mask &= ~(1 << i); - break; - } + ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; + bucket = &ivector_table[ino]; + if (!bucket->virt_irq) { + bucket->virt_irq = virt_irq_alloc(__irq(bucket)); + irq_desc[bucket->virt_irq].handler = &sun4u_irq; } - if (!desc->action_active_mask) { - unsigned long imap = bucket->imap; - - /* This unique interrupt source is now inactive. */ - bucket->flags &= ~IBF_ACTIVE; - - /* See if any other buckets share this bucket's IMAP - * and are still active. - */ - for (ent = 0; ent < NUM_IVECS; ent++) { - struct ino_bucket *bp = &ivector_table[ent]; - if (bp != bucket && - bp->imap == imap && - (bp->flags & IBF_ACTIVE) != 0) - break; - } + desc = irq_desc + bucket->virt_irq; + if (unlikely(desc->handler_data)) + goto out; - /* Only disable when no other sub-irq levels of - * the same IMAP are active. - */ - if (ent == NUM_IVECS) - disable_irq(virt_irq); + data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); + if (unlikely(!data)) { + prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); + prom_halt(); } + desc->handler_data = data; - spin_unlock_irqrestore(&irq_action_lock, flags); -} + data->imap = imap; + data->iclr = iclr; -EXPORT_SYMBOL(free_irq); +out: + return bucket->virt_irq; +} -#ifdef CONFIG_SMP -void synchronize_irq(unsigned int virt_irq) +unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) { - unsigned int real_irq = virt_to_real_irq(virt_irq); struct ino_bucket *bucket; + struct irq_handler_data *data; + unsigned long sysino; + irq_desc_t *desc; - if (unlikely(!real_irq)) - return; + BUG_ON(tlb_type != hypervisor); - bucket = __bucket(real_irq); -#if 0 - /* The following is how I wish I could implement this. - * Unfortunately the ICLR registers are read-only, you can - * only write ICLR_foo values to them. To get the current - * IRQ status you would need to get at the IRQ diag registers - * in the PCI/SBUS controller and the layout of those vary - * from one controller to the next, sigh... -DaveM - */ - unsigned long iclr = bucket->iclr; - - while (1) { - u32 tmp = upa_readl(iclr); - - if (tmp == ICLR_TRANSMIT || - tmp == ICLR_PENDING) { - cpu_relax(); - continue; - } - break; + sysino = sun4v_devino_to_sysino(devhandle, devino); + bucket = &ivector_table[sysino]; + if (!bucket->virt_irq) { + bucket->virt_irq = virt_irq_alloc(__irq(bucket)); + irq_desc[bucket->virt_irq].handler = &sun4v_irq; } -#else - /* So we have to do this with a INPROGRESS bit just like x86. */ - while (bucket->flags & IBF_INPROGRESS) - cpu_relax(); -#endif -} -#endif /* CONFIG_SMP */ - -static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) -{ - struct irq_desc *desc = bp->irq_info; - unsigned char flags = bp->flags; - u32 action_mask, i; - int random; - - bp->flags |= IBF_INPROGRESS; - if (unlikely(!(flags & IBF_ACTIVE))) { - bp->pending = 1; + desc = irq_desc + bucket->virt_irq; + if (unlikely(desc->handler_data)) goto out; - } - - if (desc->pre_handler) - desc->pre_handler(bp, - desc->pre_handler_arg1, - desc->pre_handler_arg2); - action_mask = desc->action_active_mask; - random = 0; - for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { - struct irqaction *p = &desc->action[i]; - u32 mask = (1 << i); + data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); + if (unlikely(!data)) { + prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); + prom_halt(); + } + desc->handler_data = data; - if (!(action_mask & mask)) - continue; + /* Catch accidental accesses to these things. IMAP/ICLR handling + * is done by hypervisor calls on sun4v platforms, not by direct + * register accesses. + */ + data->imap = ~0UL; + data->iclr = ~0UL; - action_mask &= ~mask; +out: + return bucket->virt_irq; +} - if (p->handler(bp->virt_irq, p->dev_id, regs) == IRQ_HANDLED) - random |= p->flags; +void hw_resend_irq(struct hw_interrupt_type *handler, unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned long pstate; + unsigned int *ent; - if (!action_mask) - break; - } + __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); + __asm__ __volatile__("wrpr %0, %1, %%pstate" + : : "r" (pstate), "i" (PSTATE_IE)); + ent = irq_work(smp_processor_id()); + bucket->irq_chain = *ent; + *ent = __irq(bucket); + set_softint(1 << PIL_DEVICE_IRQ); + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); +} - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(bp); - int err; +void ack_bad_irq(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = 0xdeadbeef; - err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE); - if (err != HV_EOK) - printk("sun4v_intr_setstate(%x): " - "err(%d)\n", ino, err); - } else { - upa_writel(ICLR_IDLE, bp->iclr); - } + if (bucket) + ino = bucket - &ivector_table[0]; - /* Test and add entropy */ - if (random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(bp->virt_irq); -out: - bp->flags &= ~IBF_INPROGRESS; + printk(KERN_CRIT "Unexpected IRQ from ino[%x] virt_irq[%u]\n", + ino, virt_irq); } #ifndef CONFIG_SMP @@ -740,35 +532,33 @@ void timer_irq(int irq, struct pt_regs *regs) clear_softint(clr_mask); irq_enter(); + kstat_this_cpu.irqs[0]++; timer_interrupt(irq, NULL, regs); + irq_exit(); } #endif void handler_irq(int irq, struct pt_regs *regs) { - struct ino_bucket *bp; - int cpu = smp_processor_id(); + struct ino_bucket *bucket; - /* XXX at this point we should be able to assert that - * XXX irq is PIL_DEVICE_IRQ... - */ clear_softint(1 << irq); irq_enter(); /* Sliiiick... */ - bp = __bucket(xchg32(irq_work(cpu), 0)); - while (bp) { - struct ino_bucket *nbp = __bucket(bp->irq_chain); + bucket = __bucket(xchg32(irq_work(smp_processor_id()), 0)); + while (bucket) { + struct ino_bucket *next = __bucket(bucket->irq_chain); - kstat_this_cpu.irqs[bp->virt_irq]++; + bucket->irq_chain = 0; + __do_IRQ(bucket->virt_irq, regs); - bp->irq_chain = 0; - process_bucket(bp, regs); - bp = nbp; + bucket = next; } + irq_exit(); } @@ -833,74 +623,6 @@ main_interrupt: EXPORT_SYMBOL(sparc_floppy_irq); #endif -/* We really don't need these at all on the Sparc. We only have - * stubs here because they are exported to modules. - */ -unsigned long probe_irq_on(void) -{ - return 0; -} - -EXPORT_SYMBOL(probe_irq_on); - -int probe_irq_off(unsigned long mask) -{ - return 0; -} - -EXPORT_SYMBOL(probe_irq_off); - -#ifdef CONFIG_SMP -static int retarget_one_irq(struct irqaction *p, int goal_cpu) -{ - struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table; - - while (!cpu_online(goal_cpu)) { - if (++goal_cpu >= NR_CPUS) - goal_cpu = 0; - } - - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(bucket); - - sun4v_intr_settarget(ino, goal_cpu); - sun4v_intr_setenabled(ino, HV_INTR_ENABLED); - } else { - unsigned long imap = bucket->imap; - unsigned int tid = sun4u_compute_tid(imap, goal_cpu); - - upa_writel(tid | IMAP_VALID, imap); - } - - do { - if (++goal_cpu >= NR_CPUS) - goal_cpu = 0; - } while (!cpu_online(goal_cpu)); - - return goal_cpu; -} - -/* Called from request_irq. */ -static void distribute_irqs(void) -{ - unsigned long flags; - int cpu, level; - - spin_lock_irqsave(&irq_action_lock, flags); - cpu = 0; - - for (level = 1; level < NR_IRQS; level++) { - struct irqaction *p = irq_action[level]; - - while(p) { - cpu = retarget_one_irq(p, cpu); - p = p->next; - } - } - spin_unlock_irqrestore(&irq_action_lock, flags); -} -#endif - struct sun5_timer { u64 count0; u64 limit0; @@ -1076,6 +798,10 @@ void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int } } +static struct irqaction timer_irq_action = { + .name = "timer", +}; + /* Only invoked on boot processor. */ void __init init_IRQ(void) { @@ -1103,121 +829,6 @@ void __init init_IRQ(void) : /* No outputs */ : "i" (PSTATE_IE) : "g1"); -} -static struct proc_dir_entry *root_irq_dir; -static struct proc_dir_entry *irq_dir[NR_IRQS]; - -#ifdef CONFIG_SMP - -static int irq_affinity_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct ino_bucket *bp = ivector_table + (long)data; - struct irq_desc *desc = bp->irq_info; - struct irqaction *ap = desc->action; - cpumask_t mask; - int len; - - mask = get_smpaff_in_irqaction(ap); - if (cpus_empty(mask)) - mask = cpu_online_map; - - len = cpumask_scnprintf(page, count, mask); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; + irq_desc[0].action = &timer_irq_action; } - -static inline void set_intr_affinity(int virt_irq, cpumask_t hw_aff) -{ - struct ino_bucket *bp; - struct irq_desc *desc; - struct irqaction *ap; - unsigned int real_irq; - - real_irq = virt_to_real_irq(virt_irq); - if (unlikely(!real_irq)) - return; - - bp = __bucket(real_irq); - desc = bp->irq_info; - ap = desc->action; - - /* Users specify affinity in terms of hw cpu ids. - * As soon as we do this, handler_irq() might see and take action. - */ - put_smpaff_in_irqaction(ap, hw_aff); - - /* Migration is simply done by the next cpu to service this - * interrupt. - * - * XXX Broken, this doesn't happen anymore... - */ -} - -static int irq_affinity_write_proc(struct file *file, - const char __user *buffer, - unsigned long count, void *data) -{ - int virt_irq = (long) data, full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - - /* - * Do not allow disabling IRQs completely - it's a too easy - * way to make the system unusable accidentally :-) At least - * one online CPU still has to be targeted. - */ - cpus_and(new_value, new_value, cpu_online_map); - if (cpus_empty(new_value)) - return -EINVAL; - - set_intr_affinity(virt_irq, new_value); - - return full_count; -} - -#endif - -#define MAX_NAMELEN 10 - -static void register_irq_proc(unsigned int virt_irq) -{ - char name [MAX_NAMELEN]; - - if (!root_irq_dir || irq_dir[virt_irq]) - return; - - memset(name, 0, MAX_NAMELEN); - sprintf(name, "%d", virt_irq); - - /* create /proc/irq/1234 */ - irq_dir[virt_irq] = proc_mkdir(name, root_irq_dir); - -#ifdef CONFIG_SMP - /* XXX SMP affinity not supported on starfire yet. */ - if (this_is_starfire == 0) { - struct proc_dir_entry *entry; - - /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); - - if (entry) { - entry->nlink = 1; - entry->data = (void *)(long)virt_irq; - entry->read_proc = irq_affinity_read_proc; - entry->write_proc = irq_affinity_write_proc; - } - } -#endif -} - -void init_irq_proc(void) -{ - /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", NULL); -} - diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index f97ddeb105a..9472580a431 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -47,12 +47,6 @@ struct pci_controller_info *pci_controller_root = NULL; /* Each PCI controller found gets a unique index. */ int pci_num_controllers = 0; -/* At boot time the user can give the kernel a command - * line option which controls if and how PCI devices - * are reordered at PCI bus probing time. - */ -int pci_device_reorder = 0; - volatile int pci_poke_in_progress; volatile int pci_poke_cpu = -1; volatile int pci_poke_faulted; @@ -316,27 +310,6 @@ static void __init pci_scan_each_controller_bus(void) p->scan_bus(p); } -/* Reorder the pci_dev chain, so that onboard devices come first - * and then come the pluggable cards. - */ -static void __init pci_reorder_devs(void) -{ - struct list_head *pci_onboard = &pci_devices; - struct list_head *walk = pci_onboard->next; - - while (walk != pci_onboard) { - struct pci_dev *pdev = pci_dev_g(walk); - struct list_head *walk_next = walk->next; - - if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) { - list_del(walk); - list_add(walk, pci_onboard); - } - - walk = walk_next; - } -} - extern void clock_probe(void); extern void power_init(void); @@ -348,9 +321,6 @@ static int __init pcibios_init(void) pci_scan_each_controller_bus(); - if (pci_device_reorder) - pci_reorder_devs(); - isa_init(); ebus_init(); clock_probe(); @@ -441,14 +411,6 @@ EXPORT_SYMBOL(pcibios_bus_to_resource); char * __init pcibios_setup(char *str) { - if (!strcmp(str, "onboardfirst")) { - pci_device_reorder = 1; - return NULL; - } - if (!strcmp(str, "noreorder")) { - pci_device_reorder = 0; - return NULL; - } return str; } diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index f2d1097f541..24db22aa972 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -308,7 +308,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - return build_irq(inofixup, iclr, imap, IBF_PCI); + return build_irq(inofixup, iclr, imap); } /* PSYCHO error handling support. */ diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 846c1205aa9..b7d997b55f0 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -530,7 +530,7 @@ static unsigned long __onboard_imap_off[] = { * side of the non-APB bridge, then perform a read of Sabre's DMA * write-sync register. */ -static void sabre_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2) +static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) { struct pci_dev *pdev = _arg1; unsigned long sync_reg = (unsigned long) _arg2; @@ -573,7 +573,7 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - virt_irq = build_irq(inofixup, iclr, imap, IBF_PCI); + virt_irq = build_irq(inofixup, iclr, imap); if (pdev) { struct pcidev_cookie *pcp = pdev->sysdata; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 0c400b5fa5b..cc662e915d3 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -232,10 +232,10 @@ static unsigned long schizo_iclr_offset(unsigned long ino) return SCHIZO_ICLR_BASE + (ino * 8UL); } -static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2) +static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) { unsigned long sync_reg = (unsigned long) _arg2; - u64 mask = 1UL << (__irq_ino(__irq(bucket)) & IMAP_INO); + u64 mask = 1UL << (ino & IMAP_INO); u64 val; int limit; @@ -313,7 +313,7 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, ign_fixup = (1 << 6); } - virt_irq = build_irq(ign_fixup, iclr, imap, IBF_PCI); + virt_irq = build_irq(ign_fixup, iclr, imap); if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { irq_install_pre_handler(virt_irq, diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index b97c81ba883..5419480edf4 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -844,7 +844,7 @@ static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, { u32 devhandle = pbm->devhandle; - return sun4v_build_irq(devhandle, devino, IBF_PCI); + return sun4v_build_irq(devhandle, devino); } static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 5544cf5d38b..8812417247d 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -821,7 +821,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) iclr += ((unsigned long)sbus_level - 1UL) * 8UL; } - return build_irq(sbus_level, iclr, imap, 0); + return build_irq(sbus_level, iclr, imap); } /* Error interrupt handling. */ diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 38e569f786d..af72bf5c3db 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -175,10 +175,6 @@ EXPORT_SYMBOL(set_bit); EXPORT_SYMBOL(clear_bit); EXPORT_SYMBOL(change_bit); -EXPORT_SYMBOL(ivector_table); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); - EXPORT_SYMBOL(__flushw_user); EXPORT_SYMBOL(tlb_type); diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S index f70e4774649..49703c3c576 100644 --- a/arch/sparc64/kernel/sun4v_ivec.S +++ b/arch/sparc64/kernel/sun4v_ivec.S @@ -103,7 +103,7 @@ sun4v_dev_mondo: /* Get &ivector_table[IVEC] into %g4. */ sethi %hi(ivector_table), %g4 - sllx %g3, 5, %g3 + sllx %g3, 3, %g3 or %g4, %lo(ivector_table), %g4 add %g4, %g3, %g4 diff --git a/include/asm-sparc64/hardirq.h b/include/asm-sparc64/hardirq.h index f0cf71376ec..7c29fd1a87a 100644 --- a/include/asm-sparc64/hardirq.h +++ b/include/asm-sparc64/hardirq.h @@ -12,6 +12,8 @@ #define local_softirq_pending() \ (local_cpu_data().__softirq_pending) +void ack_bad_irq(unsigned int irq); + #define HARDIRQ_BITS 8 #endif /* !(__SPARC64_HARDIRQ_H) */ diff --git a/include/asm-sparc64/hw_irq.h b/include/asm-sparc64/hw_irq.h index 153cae2ddae..599b3b07345 100644 --- a/include/asm-sparc64/hw_irq.h +++ b/include/asm-sparc64/hw_irq.h @@ -1,6 +1,6 @@ #ifndef __ASM_SPARC64_HW_IRQ_H #define __ASM_SPARC64_HW_IRQ_H -/* Dummy include. */ +extern void hw_resend_irq(struct hw_interrupt_type *handler, unsigned int virt_irq); #endif diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index 9edcd90495f..77a4f63cba7 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -16,58 +16,6 @@ #include #include -struct ino_bucket; - -#define MAX_IRQ_DESC_ACTION 4 - -struct irq_desc { - void (*pre_handler)(struct ino_bucket *, void *, void *); - void *pre_handler_arg1; - void *pre_handler_arg2; - u32 action_active_mask; - struct irqaction action[MAX_IRQ_DESC_ACTION]; -}; - -/* You should not mess with this directly. That's the job of irq.c. - * - * If you make changes here, please update hand coded assembler of - * the vectored interrupt trap handler in entry.S -DaveM - * - * This is currently one DCACHE line, two buckets per L2 cache - * line. Keep this in mind please. - */ -struct ino_bucket { - /* Next handler in per-CPU IRQ worklist. We know that - * bucket pointers have the high 32-bits clear, so to - * save space we only store the bits we need. - */ -/*0x00*/unsigned int irq_chain; - - /* Virtual interrupt number assigned to this INO. */ -/*0x04*/unsigned char virt_irq; - - /* If an IVEC arrives while irq_info is NULL, we - * set this to notify request_irq() about the event. - */ -/*0x05*/unsigned char pending; - - /* Miscellaneous flags. */ -/*0x06*/unsigned char flags; - - /* Currently unused. */ -/*0x07*/unsigned char __pad; - - /* Reference to IRQ descriptor for this bucket. */ -/*0x08*/struct irq_desc *irq_info; - - /* Sun5 Interrupt Clear Register. */ -/*0x10*/unsigned long iclr; - - /* Sun5 Interrupt Mapping Register. */ -/*0x18*/unsigned long imap; - -}; - /* IMAP/ICLR register defines */ #define IMAP_VALID 0x80000000 /* IRQ Enabled */ #define IMAP_TID_UPA 0x7c000000 /* UPA TargetID */ @@ -85,19 +33,6 @@ struct ino_bucket { #define ICLR_TRANSMIT 0x00000001 /* Transmit state */ #define ICLR_PENDING 0x00000003 /* Pending state */ -/* Only 8-bits are available, be careful. -DaveM */ -#define IBF_PCI 0x02 /* PSYCHO/SABRE/SCHIZO PCI interrupt. */ -#define IBF_ACTIVE 0x04 /* Interrupt is active and has a handler.*/ -#define IBF_INPROGRESS 0x10 /* IRQ is being serviced. */ - -#define NUM_IVECS (IMAP_INR + 1) -extern struct ino_bucket ivector_table[NUM_IVECS]; - -#define __irq_ino(irq) \ - (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0]) -#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) -#define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) - /* The largest number of unique interrupt sources we support. * If this needs to ever be larger than 255, you need to change * the type of ino_bucket->virt_irq as appropriate. @@ -107,14 +42,11 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; #define NR_IRQS 255 extern void irq_install_pre_handler(int virt_irq, - void (*func)(struct ino_bucket *, void *, void *), + void (*func)(unsigned int, void *, void *), void *arg1, void *arg2); #define irq_canonicalize(irq) (irq) -extern void disable_irq(unsigned int); -#define disable_irq_nosync disable_irq -extern void enable_irq(unsigned int); -extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap, unsigned char flags); -extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags); +extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap); +extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino); extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); static __inline__ void set_softint(unsigned long bits) @@ -140,8 +72,4 @@ static __inline__ unsigned long get_softint(void) return retval; } -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif -- cgit v1.2.3-70-g09d2 From 4f1bcaf094ccc512c23e10104c05a6f8e5b7a9e4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 Jun 2006 14:47:32 -0700 Subject: [PATCH] vgacon: make VGA_MAP_MEM take size, remove extra use VGA_MAP_MEM translates to ioremap() on some architectures. It makes sense to do this to vga_vram_base, because we're going to access memory between vga_vram_base and vga_vram_end. But it doesn't really make sense to map starting at vga_vram_end, because we aren't going to access memory starting there. On ia64, which always has to be different, ioremapping vga_vram_end gives you something completely incompatible with ioremapped vga_vram_start, so vga_vram_size ends up being nonsense. As a bonus, we often know the size up front, so we can use ioremap() correctly, rather than giving it a zero size. Signed-off-by: Bjorn Helgaas Cc: "Antonino A. Daplas" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/mdacon.c | 2 +- drivers/video/console/vgacon.c | 19 +++++++++---------- drivers/video/vga16fb.c | 2 +- include/asm-alpha/vga.h | 2 +- include/asm-arm/vga.h | 2 +- include/asm-i386/vga.h | 2 +- include/asm-ia64/vga.h | 2 +- include/asm-m32r/vga.h | 2 +- include/asm-mips/vga.h | 2 +- include/asm-powerpc/vga.h | 4 ++-- include/asm-sparc64/vga.h | 2 +- include/asm-x86_64/vga.h | 2 +- include/asm-xtensa/vga.h | 2 +- 13 files changed, 22 insertions(+), 23 deletions(-) (limited to 'include/asm-sparc64') diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 989e4d49e5b..7f939d066a5 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -313,8 +313,8 @@ static const char __init *mdacon_startup(void) mda_num_columns = 80; mda_num_lines = 25; - mda_vram_base = VGA_MAP_MEM(0xb0000); mda_vram_len = 0x01000; + mda_vram_base = VGA_MAP_MEM(0xb0000, mda_vram_len); mda_index_port = 0x3b4; mda_value_port = 0x3b5; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d5a04b68c4d..e64d42e2449 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -391,7 +391,7 @@ static const char __init *vgacon_startup(void) static struct resource ega_console_resource = { "ega", 0x3B0, 0x3BF }; vga_video_type = VIDEO_TYPE_EGAM; - vga_vram_end = 0xb8000; + vga_vram_size = 0x8000; display_desc = "EGA+"; request_resource(&ioport_resource, &ega_console_resource); @@ -401,7 +401,7 @@ static const char __init *vgacon_startup(void) static struct resource mda2_console_resource = { "mda", 0x3BF, 0x3BF }; vga_video_type = VIDEO_TYPE_MDA; - vga_vram_end = 0xb2000; + vga_vram_size = 0x2000; display_desc = "*MDA"; request_resource(&ioport_resource, &mda1_console_resource); @@ -418,7 +418,7 @@ static const char __init *vgacon_startup(void) if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { int i; - vga_vram_end = 0xc0000; + vga_vram_size = 0x8000; if (!ORIG_VIDEO_ISVGA) { static struct resource ega_console_resource @@ -443,7 +443,7 @@ static const char __init *vgacon_startup(void) * and COE=1 isn't necessarily a good idea) */ vga_vram_base = 0xa0000; - vga_vram_end = 0xb0000; + vga_vram_size = 0x10000; outb_p(6, VGA_GFX_I); outb_p(6, VGA_GFX_D); #endif @@ -475,7 +475,7 @@ static const char __init *vgacon_startup(void) static struct resource cga_console_resource = { "cga", 0x3D4, 0x3D5 }; vga_video_type = VIDEO_TYPE_CGA; - vga_vram_end = 0xba000; + vga_vram_size = 0x2000; display_desc = "*CGA"; request_resource(&ioport_resource, &cga_console_resource); @@ -483,9 +483,8 @@ static const char __init *vgacon_startup(void) } } - vga_vram_base = VGA_MAP_MEM(vga_vram_base); - vga_vram_end = VGA_MAP_MEM(vga_vram_end); - vga_vram_size = vga_vram_end - vga_vram_base; + vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size); + vga_vram_end = vga_vram_base + vga_vram_size; /* * Find out if there is a graphics card present. @@ -1020,14 +1019,14 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) char *charmap; if (vga_video_type != VIDEO_TYPE_EGAM) { - charmap = (char *) VGA_MAP_MEM(colourmap); + charmap = (char *) VGA_MAP_MEM(colourmap, 0); beg = 0x0e; #ifdef VGA_CAN_DO_64KB if (vga_video_type == VIDEO_TYPE_VGAC) beg = 0x06; #endif } else { - charmap = (char *) VGA_MAP_MEM(blackwmap); + charmap = (char *) VGA_MAP_MEM(blackwmap, 0); beg = 0x0a; } diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index f3f16fd9f23..4fd2a272e03 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -1351,7 +1351,7 @@ static int __init vga16fb_probe(struct device *device) } /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ - info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS); + info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0); if (!info->screen_base) { printk(KERN_ERR "vga16fb: unable to map device\n"); diff --git a/include/asm-alpha/vga.h b/include/asm-alpha/vga.h index 8ca4f6b2da1..ed06f59b544 100644 --- a/include/asm-alpha/vga.h +++ b/include/asm-alpha/vga.h @@ -46,6 +46,6 @@ extern void scr_memcpyw(u16 *d, const u16 *s, unsigned int count); #define vga_readb(a) readb((u8 __iomem *)(a)) #define vga_writeb(v,a) writeb(v, (u8 __iomem *)(a)) -#define VGA_MAP_MEM(x) ((unsigned long) ioremap(x, 0)) +#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap(x, s)) #endif diff --git a/include/asm-arm/vga.h b/include/asm-arm/vga.h index 926e5ee128e..1e0b913c3d7 100644 --- a/include/asm-arm/vga.h +++ b/include/asm-arm/vga.h @@ -4,7 +4,7 @@ #include #include -#define VGA_MAP_MEM(x) (PCIMEM_BASE + (x)) +#define VGA_MAP_MEM(x,s) (PCIMEM_BASE + (x)) #define vga_readb(x) (*((volatile unsigned char *)x)) #define vga_writeb(x,y) (*((volatile unsigned char *)y) = (x)) diff --git a/include/asm-i386/vga.h b/include/asm-i386/vga.h index ef0c0e50cc9..0ecf68ac03a 100644 --- a/include/asm-i386/vga.h +++ b/include/asm-i386/vga.h @@ -12,7 +12,7 @@ * access the videoram directly without any black magic. */ -#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) +#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-ia64/vga.h b/include/asm-ia64/vga.h index 091177cda22..02184ecd820 100644 --- a/include/asm-ia64/vga.h +++ b/include/asm-ia64/vga.h @@ -17,7 +17,7 @@ extern unsigned long vga_console_iobase; extern unsigned long vga_console_membase; -#define VGA_MAP_MEM(x) ((unsigned long) ioremap_nocache(vga_console_membase + (x), 0)) +#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap_nocache(vga_console_membase + (x), s)) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-m32r/vga.h b/include/asm-m32r/vga.h index d0f4b6eed7a..533163447cc 100644 --- a/include/asm-m32r/vga.h +++ b/include/asm-m32r/vga.h @@ -14,7 +14,7 @@ * access the videoram directly without any black magic. */ -#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) +#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-mips/vga.h b/include/asm-mips/vga.h index 34755c0a639..c1dd0b10bc2 100644 --- a/include/asm-mips/vga.h +++ b/include/asm-mips/vga.h @@ -13,7 +13,7 @@ * access the videoram directly without any black magic. */ -#define VGA_MAP_MEM(x) (0xb0000000L + (unsigned long)(x)) +#define VGA_MAP_MEM(x,s) (0xb0000000L + (unsigned long)(x)) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-powerpc/vga.h b/include/asm-powerpc/vga.h index eadaf2f3d03..a2eac409c1e 100644 --- a/include/asm-powerpc/vga.h +++ b/include/asm-powerpc/vga.h @@ -41,9 +41,9 @@ static inline u16 scr_readw(volatile const u16 *addr) extern unsigned long vgacon_remap_base; #ifdef __powerpc64__ -#define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0)) +#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s)) #else -#define VGA_MAP_MEM(x) (x + vgacon_remap_base) +#define VGA_MAP_MEM(x,s) (x + vgacon_remap_base) #endif #define vga_readb(x) (*(x)) diff --git a/include/asm-sparc64/vga.h b/include/asm-sparc64/vga.h index 9c57eb363b4..c69d5b2ba19 100644 --- a/include/asm-sparc64/vga.h +++ b/include/asm-sparc64/vga.h @@ -28,6 +28,6 @@ static inline u16 scr_readw(const u16 *addr) return *addr; } -#define VGA_MAP_MEM(x) (x) +#define VGA_MAP_MEM(x,s) (x) #endif diff --git a/include/asm-x86_64/vga.h b/include/asm-x86_64/vga.h index ef0c0e50cc9..0ecf68ac03a 100644 --- a/include/asm-x86_64/vga.h +++ b/include/asm-x86_64/vga.h @@ -12,7 +12,7 @@ * access the videoram directly without any black magic. */ -#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) +#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-xtensa/vga.h b/include/asm-xtensa/vga.h index 23d82f6acb5..1fd8cab3a29 100644 --- a/include/asm-xtensa/vga.h +++ b/include/asm-xtensa/vga.h @@ -11,7 +11,7 @@ #ifndef _XTENSA_VGA_H #define _XTENSA_VGA_H -#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) +#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) -- cgit v1.2.3-70-g09d2 From 8fae097debdf8ac9b66d220ac258535ea09f3898 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 15:23:28 -0700 Subject: [SBUS]: Start cleaning up generic sbus support layer. In particular, move the IRQ probing out to sparc32/sparc64 arch specific code where it belongs. Signed-off-by: David S. Miller --- arch/sparc/kernel/ioport.c | 46 ++++++++++++++- arch/sparc64/kernel/sbus.c | 21 +++++++ drivers/sbus/sbus.c | 143 ++++++--------------------------------------- include/asm-sparc/sbus.h | 1 + include/asm-sparc64/sbus.h | 1 + 5 files changed, 87 insertions(+), 125 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index f9ff2973484..00cf4118291 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -224,10 +224,54 @@ static void _sparc_free_io(struct resource *res) #ifdef CONFIG_SBUS -void sbus_set_sbus64(struct sbus_dev *sdev, int x) { +void sbus_set_sbus64(struct sbus_dev *sdev, int x) +{ printk("sbus_set_sbus64: unsupported\n"); } +extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq); +void __init sbus_fill_device_irq(struct sbus_dev *sdev) +{ + struct linux_prom_irqs irqs[PROMINTR_MAX]; + int len; + + len = prom_getproperty(sdev->prom_node, "intr", + (char *)irqs, sizeof(irqs)); + if (len != -1) { + sdev->num_irqs = len / 8; + if (sdev->num_irqs == 0) { + sdev->irqs[0] = 0; + } else if (sparc_cpu_model == sun4d) { + for (len = 0; len < sdev->num_irqs; len++) + sdev->irqs[len] = + sun4d_build_irq(sdev, irqs[len].pri); + } else { + for (len = 0; len < sdev->num_irqs; len++) + sdev->irqs[len] = irqs[len].pri; + } + } else { + int interrupts[PROMINTR_MAX]; + + /* No "intr" node found-- check for "interrupts" node. + * This node contains SBus interrupt levels, not IPLs + * as in "intr", and no vector values. We convert + * SBus interrupt levels to PILs (platform specific). + */ + len = prom_getproperty(sdev->prom_node, "interrupts", + (char *)interrupts, sizeof(interrupts)); + if (len == -1) { + sdev->irqs[0] = 0; + sdev->num_irqs = 0; + } else { + sdev->num_irqs = len / sizeof(int); + for (len = 0; len < sdev->num_irqs; len++) { + sdev->irqs[len] = + sbint_to_irq(sdev, interrupts[len]); + } + } + } +} + /* * Allocate a chunk of memory suitable for DMA. * Typically devices use them for control blocks. diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 8812417247d..8f7877ac858 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -1225,3 +1225,24 @@ void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus) sysio_register_error_handlers(sbus); } + +void sbus_fill_device_irq(struct sbus_dev *sdev) +{ + struct linux_prom_irqs irqs[PROMINTR_MAX]; + int len; + + len = prom_getproperty(sdev->prom_node, "interrupts", + (char *) irqs, sizeof(irqs)); + if (len == -1 || len == 0) { + sdev->irqs[0] = 0; + sdev->num_irqs = 0; + } else { + unsigned int pri = irqs[0].pri; + + sdev->num_irqs = 1; + if (pri < 0x20) + pri += sdev->slot * 8; + + sdev->irqs[0] = sbus_build_irq(sdev->bus, pri); + } +} diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 5d30a3ebfcc..6e9b2608202 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -1,7 +1,6 @@ -/* $Id: sbus.c,v 1.100 2002/01/24 15:36:24 davem Exp $ - * sbus.c: SBus support routines. +/* sbus.c: SBus support routines. * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net) */ #include @@ -17,29 +16,12 @@ #include #include -struct sbus_bus *sbus_root = NULL; - -static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } }; -#ifdef CONFIG_SPARC32 -static int interrupts[PROMINTR_MAX] __initdata = { 0 }; -#endif +struct sbus_bus *sbus_root; #ifdef CONFIG_PCI extern int pcic_present(void); #endif -/* Perhaps when I figure out more about the iommu we'll put a - * device registration routine here that probe_sbus() calls to - * setup the iommu for each Sbus. - */ - -/* We call this for each SBus device, and fill the structure based - * upon the prom device tree. We return the start of memory after - * the things we have allocated. - */ - -/* #define DEBUG_FILL */ - static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) { unsigned long address, base; @@ -52,117 +34,30 @@ static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) len = prom_getproperty(prom_node, "reg", (char *) sdev->reg_addrs, sizeof(sdev->reg_addrs)); - if (len == -1) { - sdev->num_registers = 0; - goto no_regs; - } - - if (len % sizeof(struct linux_prom_registers)) { - prom_printf("fill_sbus_device: proplen for regs of %s " - " was %d, need multiple of %d\n", - sdev->prom_name, len, - (int) sizeof(struct linux_prom_registers)); - prom_halt(); - } - if (len > (sizeof(struct linux_prom_registers) * PROMREG_MAX)) { - prom_printf("fill_sbus_device: Too many register properties " - "for device %s, len=%d\n", - sdev->prom_name, len); - prom_halt(); - } - sdev->num_registers = len / sizeof(struct linux_prom_registers); - sdev->ranges_applied = 0; + sdev->num_registers = 0; + if (len != -1) { + sdev->num_registers = + len / sizeof(struct linux_prom_registers); + sdev->ranges_applied = 0; - base = (unsigned long) sdev->reg_addrs[0].phys_addr; + base = (unsigned long) sdev->reg_addrs[0].phys_addr; - /* Compute the slot number. */ - if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) { - sdev->slot = sbus_dev_slot(base); - } else { - sdev->slot = sdev->reg_addrs[0].which_io; + /* Compute the slot number. */ + if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) + sdev->slot = sbus_dev_slot(base); + else + sdev->slot = sdev->reg_addrs[0].which_io; } -no_regs: len = prom_getproperty(prom_node, "ranges", (char *)sdev->device_ranges, sizeof(sdev->device_ranges)); - if (len == -1) { - sdev->num_device_ranges = 0; - goto no_ranges; - } - if (len % sizeof(struct linux_prom_ranges)) { - prom_printf("fill_sbus_device: proplen for ranges of %s " - " was %d, need multiple of %d\n", - sdev->prom_name, len, - (int) sizeof(struct linux_prom_ranges)); - prom_halt(); - } - if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) { - prom_printf("fill_sbus_device: Too many range properties " - "for device %s, len=%d\n", - sdev->prom_name, len); - prom_halt(); - } - sdev->num_device_ranges = - len / sizeof(struct linux_prom_ranges); + sdev->num_device_ranges = 0; + if (len != -1) + sdev->num_device_ranges = + len / sizeof(struct linux_prom_ranges); -no_ranges: - /* XXX Unfortunately, IRQ issues are very arch specific. - * XXX Pull this crud out into an arch specific area - * XXX at some point. -DaveM - */ -#ifdef CONFIG_SPARC64 - len = prom_getproperty(prom_node, "interrupts", - (char *) irqs, sizeof(irqs)); - if (len == -1 || len == 0) { - sdev->irqs[0] = 0; - sdev->num_irqs = 0; - } else { - unsigned int pri = irqs[0].pri; - - sdev->num_irqs = 1; - if (pri < 0x20) - pri += sdev->slot * 8; - - sdev->irqs[0] = sbus_build_irq(sdev->bus, pri); - } -#endif /* CONFIG_SPARC64 */ - -#ifdef CONFIG_SPARC32 - len = prom_getproperty(prom_node, "intr", - (char *)irqs, sizeof(irqs)); - if (len != -1) { - sdev->num_irqs = len / 8; - if (sdev->num_irqs == 0) { - sdev->irqs[0] = 0; - } else if (sparc_cpu_model == sun4d) { - extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq); - - for (len = 0; len < sdev->num_irqs; len++) - sdev->irqs[len] = sun4d_build_irq(sdev, irqs[len].pri); - } else { - for (len = 0; len < sdev->num_irqs; len++) - sdev->irqs[len] = irqs[len].pri; - } - } else { - /* No "intr" node found-- check for "interrupts" node. - * This node contains SBus interrupt levels, not IPLs - * as in "intr", and no vector values. We convert - * SBus interrupt levels to PILs (platform specific). - */ - len = prom_getproperty(prom_node, "interrupts", - (char *)interrupts, sizeof(interrupts)); - if (len == -1) { - sdev->irqs[0] = 0; - sdev->num_irqs = 0; - } else { - sdev->num_irqs = len / sizeof(int); - for (len = 0; len < sdev->num_irqs; len++) { - sdev->irqs[len] = sbint_to_irq(sdev, interrupts[len]); - } - } - } -#endif /* CONFIG_SPARC32 */ + sbus_fill_device_irq(sdev); } /* This routine gets called from whoever needs the sbus first, to scan diff --git a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h index a13cddcecec..76654fa2309 100644 --- a/include/asm-sparc/sbus.h +++ b/include/asm-sparc/sbus.h @@ -102,6 +102,7 @@ sbus_is_slave(struct sbus_dev *dev) #define sbus_can_dma_64bit(sdev) (0) /* actually, sparc_cpu_model==sun4d */ #define sbus_can_burst64(sdev) (0) /* actually, sparc_cpu_model==sun4d */ extern void sbus_set_sbus64(struct sbus_dev *, int); +extern void sbus_fill_device_irq(struct sbus_dev *); /* These yield IOMMU mappings in consistent mode. */ extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp); diff --git a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h index 48279e10f38..ca2054da243 100644 --- a/include/asm-sparc64/sbus.h +++ b/include/asm-sparc64/sbus.h @@ -95,6 +95,7 @@ extern struct sbus_bus *sbus_root; #define sbus_can_dma_64bit(sdev) (1) #define sbus_can_burst64(sdev) (1) extern void sbus_set_sbus64(struct sbus_dev *, int); +extern void sbus_fill_device_irq(struct sbus_dev *); /* These yield IOMMU mappings in consistent mode. */ extern void *sbus_alloc_consistent(struct sbus_dev *, size_t, dma_addr_t *dma_addrp); -- cgit v1.2.3-70-g09d2 From 372b07bb5a13f8a1b8a3ce49cd76d39a79dbd3bd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 21 Jun 2006 15:35:28 -0700 Subject: [SPARC64]: Import OBP device tree into kernel data structures. The basic framework is based on the PowerPC OF code. This code even tries to get the device addressing components correct in the full path names. Signed-off-by: David S. Miller --- arch/sparc64/kernel/Makefile | 2 +- arch/sparc64/kernel/prom.c | 543 +++++++++++++++++++++++++++++++++++++++++++ arch/sparc64/mm/init.c | 3 + include/asm-sparc64/prom.h | 79 +++++++ 4 files changed, 626 insertions(+), 1 deletion(-) create mode 100644 arch/sparc64/kernel/prom.c create mode 100644 include/asm-sparc64/prom.h (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 6f6816488b0..7f00189ed29 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := process.o setup.o cpu.o idprom.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ - visemul.o + visemul.o prom.o obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ pci_psycho.o pci_sabre.o pci_schizo.o \ diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c new file mode 100644 index 00000000000..c99b7aae19d --- /dev/null +++ b/arch/sparc64/kernel/prom.c @@ -0,0 +1,543 @@ +/* + * Procedures for creating, accessing and interpreting the device tree. + * + * Paul Mackerras August 1996. + * Copyright (C) 1996-2005 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. + * {engebret|bergner}@us.ibm.com + * + * Adapted for sparc64 by David S. Miller davem@davemloft.net + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include + +static struct device_node *allnodes; + +struct device_node *of_get_parent(const struct device_node *node) +{ + struct device_node *np; + + if (!node) + return NULL; + + np = node->parent; + + return np; +} + +struct device_node *of_get_next_child(const struct device_node *node, + struct device_node *prev) +{ + struct device_node *next; + + next = prev ? prev->sibling : node->child; + for (; next != 0; next = next->sibling) { + break; + } + + return next; +} + +struct device_node *of_find_node_by_path(const char *path) +{ + struct device_node *np = allnodes; + + for (; np != 0; np = np->allnext) { + if (np->full_name != 0 && strcmp(np->full_name, path) == 0) + break; + } + + return np; +} + +struct property *of_find_property(struct device_node *np, const char *name, + int *lenp) +{ + struct property *pp; + + for (pp = np->properties; pp != 0; pp = pp->next) { + if (strcmp(pp->name, name) == 0) { + if (lenp != 0) + *lenp = pp->length; + break; + } + } + return pp; +} + +static unsigned int prom_early_allocated; + +static void * __init prom_early_alloc(unsigned long size) +{ + void *ret; + + ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); + if (ret != NULL) + memset(ret, 0, size); + + prom_early_allocated += size; + + return ret; +} + +static int is_root_node(const struct device_node *dp) +{ + if (!dp) + return 0; + + return (dp->parent == NULL); +} + +/* The following routines deal with the black magic of fully naming a + * node. + * + * Certain well known named nodes are just the simple name string. + * + * Actual devices have an address specifier appended to the base name + * string, like this "foo@addr". The "addr" can be in any number of + * formats, and the platform plus the type of the node determine the + * format and how it is constructed. + * + * For children of the ROOT node, the naming convention is fixed and + * determined by whether this is a sun4u or sun4v system. + * + * For children of other nodes, it is bus type specific. So + * we walk up the tree until we discover a "device_type" property + * we recognize and we go from there. + * + * As an example, the boot device on my workstation has a full path: + * + * /pci@1e,600000/ide@d/disk@0,0:c + */ +static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf) +{ + struct linux_prom64_registers *regs; + struct property *rprop; + u32 high_bits, low_bits, type; + + rprop = of_find_property(dp, "reg", NULL); + if (!rprop) + return; + + regs = rprop->value; + if (!is_root_node(dp->parent)) { + sprintf(tmp_buf, "%s@%x,%x", + dp->name, + (unsigned int) (regs->phys_addr >> 32UL), + (unsigned int) (regs->phys_addr & 0xffffffffUL)); + return; + } + + type = regs->phys_addr >> 60UL; + high_bits = (regs->phys_addr >> 32UL) & 0x0fffffffUL; + low_bits = (regs->phys_addr & 0xffffffffUL); + + if (type == 0 || type == 8) { + const char *prefix = (type == 0) ? "m" : "i"; + + if (low_bits) + sprintf(tmp_buf, "%s@%s%x,%x", + dp->name, prefix, + high_bits, low_bits); + else + sprintf(tmp_buf, "%s@%s%x", + dp->name, + prefix, + high_bits); + } else if (type == 12) { + sprintf(tmp_buf, "%s@%x", + dp->name, high_bits); + } +} + +static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf) +{ + struct linux_prom64_registers *regs; + struct property *prop; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + + regs = prop->value; + if (!is_root_node(dp->parent)) { + sprintf(tmp_buf, "%s@%x,%x", + dp->name, + (unsigned int) (regs->phys_addr >> 32UL), + (unsigned int) (regs->phys_addr & 0xffffffffUL)); + return; + } + + prop = of_find_property(dp, "upa-portid", NULL); + if (!prop) + prop = of_find_property(dp, "portid", NULL); + if (prop) { + unsigned long mask = 0xffffffffUL; + + if (tlb_type >= cheetah) + mask = 0x7fffff; + + sprintf(tmp_buf, "%s@%x,%x", + dp->name, + *(u32 *)prop->value, + (unsigned int) (regs->phys_addr & mask)); + } +} + +/* "name@slot,offset" */ +static void __init sbus_path_component(struct device_node *dp, char *tmp_buf) +{ + struct linux_prom_registers *regs; + struct property *prop; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + + regs = prop->value; + sprintf(tmp_buf, "%s@%x,%x", + dp->name, + regs->which_io, + regs->phys_addr); +} + +/* "name@devnum[,func]" */ +static void __init pci_path_component(struct device_node *dp, char *tmp_buf) +{ + struct linux_prom_pci_registers *regs; + struct property *prop; + unsigned int devfn; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + + regs = prop->value; + devfn = (regs->phys_hi >> 8) & 0xff; + if (devfn & 0x07) { + sprintf(tmp_buf, "%s@%x,%x", + dp->name, + devfn >> 3, + devfn & 0x07); + } else { + sprintf(tmp_buf, "%s@%x", + dp->name, + devfn >> 3); + } +} + +/* "name@UPA_PORTID,offset" */ +static void __init upa_path_component(struct device_node *dp, char *tmp_buf) +{ + struct linux_prom64_registers *regs; + struct property *prop; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + + regs = prop->value; + + prop = of_find_property(dp, "upa-portid", NULL); + if (!prop) + return; + + sprintf(tmp_buf, "%s@%x,%x", + dp->name, + *(u32 *) prop->value, + (unsigned int) (regs->phys_addr & 0xffffffffUL)); +} + +/* "name@reg" */ +static void __init vdev_path_component(struct device_node *dp, char *tmp_buf) +{ + struct property *prop; + u32 *regs; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + + regs = prop->value; + + sprintf(tmp_buf, "%s@%x", dp->name, *regs); +} + +/* "name@addrhi,addrlo" */ +static void __init ebus_path_component(struct device_node *dp, char *tmp_buf) +{ + struct linux_prom64_registers *regs; + struct property *prop; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + + regs = prop->value; + + sprintf(tmp_buf, "%s@%x,%x", + dp->name, + (unsigned int) (regs->phys_addr >> 32UL), + (unsigned int) (regs->phys_addr & 0xffffffffUL)); +} + +/* "name@bus,addr" */ +static void __init i2c_path_component(struct device_node *dp, char *tmp_buf) +{ + struct property *prop; + u32 *regs; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + + regs = prop->value; + + /* This actually isn't right... should look at the #address-cells + * property of the i2c bus node etc. etc. + */ + sprintf(tmp_buf, "%s@%x,%x", + dp->name, regs[0], regs[1]); +} + +/* "name@reg0[,reg1]" */ +static void __init usb_path_component(struct device_node *dp, char *tmp_buf) +{ + struct property *prop; + u32 *regs; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + + regs = prop->value; + + if (prop->length == sizeof(u32) || regs[1] == 1) { + sprintf(tmp_buf, "%s@%x", + dp->name, regs[0]); + } else { + sprintf(tmp_buf, "%s@%x,%x", + dp->name, regs[0], regs[1]); + } +} + +/* "name@reg0reg1[,reg2reg3]" */ +static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf) +{ + struct property *prop; + u32 *regs; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + + regs = prop->value; + + if (regs[2] || regs[3]) { + sprintf(tmp_buf, "%s@%08x%08x,%04x%08x", + dp->name, regs[0], regs[1], regs[2], regs[3]); + } else { + sprintf(tmp_buf, "%s@%08x%08x", + dp->name, regs[0], regs[1]); + } +} + +static void __init __build_path_component(struct device_node *dp, char *tmp_buf) +{ + struct device_node *parent = dp->parent; + + if (parent != NULL) { + if (!strcmp(parent->type, "pci") || + !strcmp(parent->type, "pciex")) + return pci_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "sbus")) + return sbus_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "upa")) + return upa_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "ebus")) + return ebus_path_component(dp, tmp_buf); + if (!strcmp(parent->name, "usb") || + !strcmp(parent->name, "hub")) + return usb_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "i2c")) + return i2c_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "firewire")) + return ieee1394_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "virtual-devices")) + return vdev_path_component(dp, tmp_buf); + + /* "isa" is handled with platform naming */ + } + + /* Use platform naming convention. */ + if (tlb_type == hypervisor) + return sun4v_path_component(dp, tmp_buf); + else + return sun4u_path_component(dp, tmp_buf); +} + +static char * __init build_path_component(struct device_node *dp) +{ + char tmp_buf[64], *n; + + tmp_buf[0] = '\0'; + __build_path_component(dp, tmp_buf); + if (tmp_buf[0] == '\0') + strcpy(tmp_buf, dp->name); + + n = prom_early_alloc(strlen(tmp_buf) + 1); + strcpy(n, tmp_buf); + + return n; +} + +static char * __init build_full_name(struct device_node *dp) +{ + int len, ourlen, plen; + char *n; + + plen = strlen(dp->parent->full_name); + ourlen = strlen(dp->path_component_name); + len = ourlen + plen + 2; + + n = prom_early_alloc(len); + strcpy(n, dp->parent->full_name); + if (!is_root_node(dp->parent)) { + strcpy(n + plen, "/"); + plen++; + } + strcpy(n + plen, dp->path_component_name); + + return n; +} + +static struct property * __init build_one_prop(phandle node, char *prev) +{ + static struct property *tmp = NULL; + struct property *p; + + if (tmp) { + p = tmp; + memset(p, 0, sizeof(*p) + 32); + tmp = NULL; + } else + p = prom_early_alloc(sizeof(struct property) + 32); + + p->name = (char *) (p + 1); + if (prev == NULL) { + prom_firstprop(node, p->name); + } else { + prom_nextprop(node, prev, p->name); + } + if (strlen(p->name) == 0) { + tmp = p; + return NULL; + } + p->length = prom_getproplen(node, p->name); + if (p->length <= 0) { + p->length = 0; + } else { + p->value = prom_early_alloc(p->length); + prom_getproperty(node, p->name, p->value, p->length); + } + return p; +} + +static struct property * __init build_prop_list(phandle node) +{ + struct property *head, *tail; + + head = tail = build_one_prop(node, NULL); + while(tail) { + tail->next = build_one_prop(node, tail->name); + tail = tail->next; + } + + return head; +} + +static char * __init get_one_property(phandle node, const char *name) +{ + char *buf = ""; + int len; + + len = prom_getproplen(node, name); + if (len > 0) { + buf = prom_early_alloc(len); + prom_getproperty(node, name, buf, len); + } + + return buf; +} + +static struct device_node * __init create_node(phandle node) +{ + struct device_node *dp; + + if (!node) + return NULL; + + dp = prom_early_alloc(sizeof(*dp)); + + kref_init(&dp->kref); + + dp->name = get_one_property(node, "name"); + dp->type = get_one_property(node, "device_type"); + dp->node = node; + + /* Build interrupts later... */ + + dp->properties = build_prop_list(node); + + return dp; +} + +static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp) +{ + struct device_node *dp; + + dp = create_node(node); + if (dp) { + *(*nextp) = dp; + *nextp = &dp->allnext; + + dp->parent = parent; + dp->path_component_name = build_path_component(dp); + dp->full_name = build_full_name(dp); + + dp->child = build_tree(dp, prom_getchild(node), nextp); + + dp->sibling = build_tree(parent, prom_getsibling(node), nextp); + } + + return dp; +} + +void __init prom_build_devicetree(void) +{ + struct device_node **nextp; + + allnodes = create_node(prom_root_node); + allnodes->path_component_name = ""; + allnodes->full_name = "/"; + + nextp = &allnodes->allnext; + allnodes->child = build_tree(allnodes, + prom_getchild(allnodes->node), + &nextp); + printk("PROM: Built device tree with %u bytes of memory.\n", + prom_early_allocated); +} diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 1539a8362b6..45a70d677d8 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -42,6 +42,7 @@ #include #include #include +#include extern void device_scan(void); @@ -1339,6 +1340,8 @@ void __init paging_init(void) kernel_physical_mapping_init(); + prom_build_devicetree(); + { unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h new file mode 100644 index 00000000000..44bcc83267f --- /dev/null +++ b/include/asm-sparc64/prom.h @@ -0,0 +1,79 @@ +#ifndef _SPARC64_PROM_H +#define _SPARC64_PROM_H +#ifdef __KERNEL__ + + +/* + * Definitions for talking to the Open Firmware PROM on + * Power Macintosh computers. + * + * Copyright (C) 1996-2005 Paul Mackerras. + * + * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp. + * Updates for SPARC64 by David S. Miller + * + * 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. + */ + +#include +#include +#include + +typedef u32 phandle; +typedef u32 ihandle; + +struct interrupt_info { + int line; + int sense; /* +ve/-ve logic, edge or level, etc. */ +}; + +struct property { + char *name; + int length; + void *value; + struct property *next; +}; + +struct device_node { + char *name; + char *type; + phandle node; + phandle linux_phandle; + int n_intrs; + struct interrupt_info *intrs; + char *path_component_name; + char *full_name; + + struct property *properties; + struct property *deadprops; /* removed properties */ + struct device_node *parent; + struct device_node *child; + struct device_node *sibling; + struct device_node *next; /* next device of same type */ + struct device_node *allnext; /* next in list of all nodes */ + struct proc_dir_entry *pde; /* this node's proc directory */ + struct kref kref; + unsigned long _flags; + void *data; +}; + +static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) +{ + dn->pde = de; +} + +extern struct device_node *of_find_node_by_path(const char *path); +extern struct device_node *of_get_parent(const struct device_node *node); +extern struct device_node *of_get_next_child(const struct device_node *node, + struct device_node *prev); +extern struct property *of_find_property(struct device_node *np, + const char *name, + int *lenp); + +extern void prom_build_devicetree(void); + +#endif /* __KERNEL__ */ +#endif /* _SPARC64_PROM_H */ -- cgit v1.2.3-70-g09d2 From aaf7cec2769942035985716452107fc5ba0b11f6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 21 Jun 2006 16:33:54 -0700 Subject: [SPARC64]: Add of_find_node_by_{name,type}(). Signed-off-by: David S. Miller --- arch/sparc64/kernel/prom.c | 26 ++++++++++++++++++++++++++ include/asm-sparc64/prom.h | 10 ++++++++++ 2 files changed, 36 insertions(+) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index c99b7aae19d..fd46e94ce06 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -63,6 +63,32 @@ struct device_node *of_find_node_by_path(const char *path) return np; } +struct device_node *of_find_node_by_name(struct device_node *from, + const char *name) +{ + struct device_node *np; + + np = from ? from->allnext : allnodes; + for (; np != NULL; np = np->allnext) + if (np->name != NULL && strcmp(np->name, name) == 0) + break; + + return np; +} + +struct device_node *of_find_node_by_type(struct device_node *from, + const char *type) +{ + struct device_node *np; + + np = from ? from->allnext : allnodes; + for (; np != 0; np = np->allnext) + if (np->type != 0 && strcmp(np->type, type) == 0) + break; + + return np; +} + struct property *of_find_property(struct device_node *np, const char *name, int *lenp) { diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 44bcc83267f..eb75d3cbcf4 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -65,6 +65,16 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e dn->pde = de; } +extern struct device_node *of_find_node_by_name(struct device_node *from, + const char *name); +#define for_each_node_by_name(dn, name) \ + for (dn = of_find_node_by_name(NULL, name); dn; \ + dn = of_find_node_by_name(dn, name)) +extern struct device_node *of_find_node_by_type(struct device_node *from, + const char *type); +#define for_each_node_by_type(dn, type) \ + for (dn = of_find_node_by_type(NULL, type); dn; \ + dn = of_find_node_by_type(dn, type)) extern struct device_node *of_find_node_by_path(const char *path); extern struct device_node *of_get_parent(const struct device_node *node); extern struct device_node *of_get_next_child(const struct device_node *node, -- cgit v1.2.3-70-g09d2 From e87dc35020bc555969810452f44bceaf8394eafa Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 21 Jun 2006 18:18:47 -0700 Subject: [SPARC64]: Use in-kernel OBP device tree for PCI controller probing. It can be pushed even further down, but this is a first step. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 53 +++++------ arch/sparc64/kernel/pci_common.c | 15 +-- arch/sparc64/kernel/pci_psycho.c | 108 ++++++++++------------ arch/sparc64/kernel/pci_sabre.c | 192 +++++++++++++++++---------------------- arch/sparc64/kernel/pci_schizo.c | 173 ++++++++++++++++------------------- arch/sparc64/kernel/pci_sun4v.c | 144 +++++++++++++---------------- include/asm-sparc64/pbm.h | 12 +-- 7 files changed, 312 insertions(+), 385 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 9472580a431..a868c3792ef 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -22,6 +22,7 @@ #include #include #include +#include unsigned long pci_memspace_mask = 0xffffffffUL; @@ -177,16 +178,16 @@ void pci_config_write32(u32 *addr, u32 val) } /* Probe for all PCI controllers in the system. */ -extern void sabre_init(int, char *); -extern void psycho_init(int, char *); -extern void schizo_init(int, char *); -extern void schizo_plus_init(int, char *); -extern void tomatillo_init(int, char *); -extern void sun4v_pci_init(int, char *); +extern void sabre_init(struct device_node *, const char *); +extern void psycho_init(struct device_node *, const char *); +extern void schizo_init(struct device_node *, const char *); +extern void schizo_plus_init(struct device_node *, const char *); +extern void tomatillo_init(struct device_node *, const char *); +extern void sun4v_pci_init(struct device_node *, const char *); static struct { char *model_name; - void (*init)(int, char *); + void (*init)(struct device_node *, const char *); } pci_controller_table[] __initdata = { { "SUNW,sabre", sabre_init }, { "pci108e,a000", sabre_init }, @@ -204,7 +205,7 @@ static struct { #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ sizeof(pci_controller_table[0])) -static int __init pci_controller_init(char *model_name, int namelen, int node) +static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp) { int i; @@ -212,18 +213,15 @@ static int __init pci_controller_init(char *model_name, int namelen, int node) if (!strncmp(model_name, pci_controller_table[i].model_name, namelen)) { - pci_controller_table[i].init(node, model_name); + pci_controller_table[i].init(dp, model_name); return 1; } } - printk("PCI: Warning unknown controller, model name [%s]\n", - model_name); - printk("PCI: Ignoring controller...\n"); return 0; } -static int __init pci_is_controller(char *model_name, int namelen, int node) +static int __init pci_is_controller(const char *model_name, int namelen, struct device_node *dp) { int i; @@ -237,36 +235,35 @@ static int __init pci_is_controller(char *model_name, int namelen, int node) return 0; } -static int __init pci_controller_scan(int (*handler)(char *, int, int)) +static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *)) { - char namebuf[64]; - int node; + struct device_node *dp; int count = 0; - node = prom_getchild(prom_root_node); - while ((node = prom_searchsiblings(node, "pci")) != 0) { + for_each_node_by_name(dp, "pci") { + struct property *prop; int len; - if ((len = prom_getproperty(node, "model", namebuf, sizeof(namebuf))) > 0 || - (len = prom_getproperty(node, "compatible", namebuf, sizeof(namebuf))) > 0) { + prop = of_find_property(dp, "model", &len); + if (!prop) + prop = of_find_property(dp, "compatible", &len); + + if (prop) { + const char *model = prop->value; int item_len = 0; /* Our value may be a multi-valued string in the * case of some compatible properties. For sanity, - * only try the first one. */ - - while (namebuf[item_len] && len) { + * only try the first one. + */ + while (model[item_len] && len) { len--; item_len++; } - if (handler(namebuf, item_len, node)) + if (handler(model, item_len, dp)) count++; } - - node = prom_getsibling(node); - if (!node) - break; } return count; diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 33dedb1aacd..fc71b28795a 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -664,7 +664,7 @@ static unsigned int __init pci_intmap_match_to_root(struct pci_pbm_info *pbm, } pdev = pbus; - if (cnode == pbm->prom_node) + if (cnode == pbm->prom_node->node) break; } @@ -680,7 +680,7 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt int i, cnode, plen; cnode = pci_intmap_match_to_root(pbm, pdev, interrupt); - if (cnode == pbm->prom_node) + if (cnode == pbm->prom_node->node) goto success; plen = prom_getproperty(cnode, "reg", (char *) reg, sizeof(reg)); @@ -691,10 +691,10 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt goto fail; } - hi = reg[0].phys_hi & pbm->pbm_intmask.phys_hi; - mid = reg[0].phys_mid & pbm->pbm_intmask.phys_mid; - lo = reg[0].phys_lo & pbm->pbm_intmask.phys_lo; - irq = *interrupt & pbm->pbm_intmask.interrupt; + hi = reg[0].phys_hi & pbm->pbm_intmask->phys_hi; + mid = reg[0].phys_mid & pbm->pbm_intmask->phys_mid; + lo = reg[0].phys_lo & pbm->pbm_intmask->phys_lo; + irq = *interrupt & pbm->pbm_intmask->interrupt; for (i = 0; i < pbm->num_pbm_intmap; i++) { struct linux_prom_pci_intmap *intmap; @@ -714,7 +714,8 @@ fail: return 0; success: - printk("PCI-IRQ: Routing bus[%2x] slot[%2x] to INO[%02x]\n", + printk("%s: Routing bus[%2x] slot[%2x] to INO[%02x]\n", + pbm->name, pdev->bus->number, PCI_SLOT(pdev->devfn), *interrupt); return 1; diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 24db22aa972..40c2b681998 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "pci_impl.h" #include "iommu_common.h" @@ -1103,7 +1104,7 @@ static void pbm_scan_bus(struct pci_controller_info *p, pci_fixup_host_bridge_self(pbm->pci_bus); pbm->pci_bus->self->sysdata = cookie; - pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node->node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); pci_fixup_irq(pbm, pbm->pci_bus); @@ -1291,11 +1292,12 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p, #define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL static void psycho_pbm_init(struct pci_controller_info *p, - int prom_node, int is_pbm_a) + struct device_node *dp, int is_pbm_a) { - unsigned int busrange[2]; + unsigned int *busrange; + struct property *prop; struct pci_pbm_info *pbm; - int err; + int len; if (is_pbm_a) { pbm = &p->pbm_A; @@ -1310,10 +1312,14 @@ static void psycho_pbm_init(struct pci_controller_info *p, } pbm->chip_type = PBM_CHIP_TYPE_PSYCHO; - pbm->chip_version = - prom_getintdefault(prom_node, "version#", 0); - pbm->chip_revision = - prom_getintdefault(prom_node, "module-revision#", 0); + pbm->chip_version = 0; + prop = of_find_property(dp, "version#", NULL); + if (prop) + pbm->chip_version = *(int *) prop->value; + pbm->chip_revision = 0; + prop = of_find_property(dp, "module-revision#", NULL); + if (prop) + pbm->chip_revision = *(int *) prop->value; pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE; pbm->io_space.flags = IORESOURCE_IO; @@ -1322,45 +1328,36 @@ static void psycho_pbm_init(struct pci_controller_info *p, pbm_register_toplevel_resources(p, pbm); pbm->parent = p; - pbm->prom_node = prom_node; - prom_getstring(prom_node, "name", - pbm->prom_name, - sizeof(pbm->prom_name)); - - err = prom_getproperty(prom_node, "ranges", - (char *)pbm->pbm_ranges, - sizeof(pbm->pbm_ranges)); - if (err != -1) + pbm->prom_node = dp; + pbm->name = dp->full_name; + + printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n", + pbm->name, + pbm->chip_version, pbm->chip_revision); + + prop = of_find_property(dp, "ranges", &len); + if (prop) { + pbm->pbm_ranges = prop->value; pbm->num_pbm_ranges = - (err / sizeof(struct linux_prom_pci_ranges)); - else + (len / sizeof(struct linux_prom_pci_ranges)); + } else { pbm->num_pbm_ranges = 0; + } - err = prom_getproperty(prom_node, "interrupt-map", - (char *)pbm->pbm_intmap, - sizeof(pbm->pbm_intmap)); - if (err != -1) { - pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); - err = prom_getproperty(prom_node, "interrupt-map-mask", - (char *)&pbm->pbm_intmask, - sizeof(pbm->pbm_intmask)); - if (err == -1) { - prom_printf("PSYCHO-PBM: Fatal error, no " - "interrupt-map-mask.\n"); - prom_halt(); - } + prop = of_find_property(dp, "interrupt-map", &len); + if (prop) { + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); + + prop = of_find_property(dp, "interrupt-map-mask", NULL); + pbm->pbm_intmask = prop->value; } else { pbm->num_pbm_intmap = 0; - memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); } - err = prom_getproperty(prom_node, "bus-range", - (char *)&busrange[0], - sizeof(busrange)); - if (err == 0 || err == -1) { - prom_printf("PSYCHO-PBM: Fatal error, no bus-range.\n"); - prom_halt(); - } + prop = of_find_property(dp, "bus-range", NULL); + busrange = prop->value; pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; @@ -1369,20 +1366,24 @@ static void psycho_pbm_init(struct pci_controller_info *p, #define PSYCHO_CONFIGSPACE 0x001000000UL -void psycho_init(int node, char *model_name) +void psycho_init(struct device_node *dp, char *model_name) { - struct linux_prom64_registers pr_regs[3]; + struct linux_prom64_registers *pr_regs; struct pci_controller_info *p; struct pci_iommu *iommu; + struct property *prop; u32 upa_portid; - int is_pbm_a, err; + int is_pbm_a; - upa_portid = prom_getintdefault(node, "upa-portid", 0xff); + upa_portid = 0xff; + prop = of_find_property(dp, "upa-portid", NULL); + if (prop) + upa_portid = *(u32 *) prop->value; for(p = pci_controller_root; p; p = p->next) { if (p->pbm_A.portid == upa_portid) { - is_pbm_a = (p->pbm_A.prom_node == 0); - psycho_pbm_init(p, node, is_pbm_a); + is_pbm_a = (p->pbm_A.prom_node == NULL); + psycho_pbm_init(p, dp, is_pbm_a); return; } } @@ -1412,23 +1413,14 @@ void psycho_init(int node, char *model_name) p->resource_adjust = psycho_resource_adjust; p->pci_ops = &psycho_ops; - err = prom_getproperty(node, "reg", - (char *)&pr_regs[0], - sizeof(pr_regs)); - if (err == 0 || err == -1) { - prom_printf("PSYCHO: Fatal error, no reg property.\n"); - prom_halt(); - } + prop = of_find_property(dp, "reg", NULL); + pr_regs = prop->value; p->pbm_A.controller_regs = pr_regs[2].phys_addr; p->pbm_B.controller_regs = pr_regs[2].phys_addr; - printk("PCI: Found PSYCHO, control regs at %016lx\n", - p->pbm_A.controller_regs); p->pbm_A.config_space = p->pbm_B.config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE); - printk("PSYCHO: Shared PCI config space at %016lx\n", - p->pbm_A.config_space); /* * Psycho's PCI MEM space is mapped to a 2GB aligned area, so @@ -1441,5 +1433,5 @@ void psycho_init(int node, char *model_name) psycho_iommu_init(p); is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); - psycho_pbm_init(p, node, is_pbm_a); + psycho_pbm_init(p, dp, is_pbm_a); } diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index b7d997b55f0..91d1aa44efc 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "pci_impl.h" #include "iommu_common.h" @@ -1160,7 +1161,7 @@ static void sabre_scan_bus(struct pci_controller_info *p) pbus->sysdata = pbm; pbm->pci_bus = pbus; - pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node); + pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node->node); pci_record_assignments(pbm, pbus); pci_assign_unassigned(pbm, pbus); pci_fixup_irq(pbm, pbus); @@ -1173,7 +1174,7 @@ static void sabre_scan_bus(struct pci_controller_info *p) pbm = &p->pbm_A; sabre_bus->sysdata = pbm; pbm->pci_bus = sabre_bus; - pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node); + pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node->node); pci_record_assignments(pbm, sabre_bus); pci_assign_unassigned(pbm, sabre_bus); pci_fixup_irq(pbm, sabre_bus); @@ -1306,34 +1307,36 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p, &pbm->mem_space); } -static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dma_begin) +static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin) { struct pci_pbm_info *pbm; - char namebuf[128]; - u32 busrange[2]; - int node, simbas_found; + struct device_node *node; + struct property *prop; + u32 *busrange; + int len, simbas_found; simbas_found = 0; - node = prom_getchild(sabre_node); - while ((node = prom_searchsiblings(node, "pci")) != 0) { - int err; - - err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); - if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err)) + node = dp->child; + while (node != NULL) { + if (strcmp(node->name, "pci")) goto next_pci; - err = prom_getproperty(node, "bus-range", - (char *)&busrange[0], sizeof(busrange)); - if (err == 0 || err == -1) { - prom_printf("APB: Error, cannot get PCI bus-range.\n"); - prom_halt(); - } + prop = of_find_property(node, "model", NULL); + if (!prop || strncmp(prop->value, "SUNW,simba", prop->length)) + goto next_pci; simbas_found++; + + prop = of_find_property(node, "bus-range", NULL); + busrange = prop->value; if (busrange[0] == 1) pbm = &p->pbm_B; else pbm = &p->pbm_A; + + pbm->name = node->full_name; + printk("%s: SABRE PCI Bus Module\n", pbm->name); + pbm->chip_type = PBM_CHIP_TYPE_SABRE; pbm->parent = p; pbm->prom_node = node; @@ -1341,83 +1344,68 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; - prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name)); - err = prom_getproperty(node, "ranges", - (char *)pbm->pbm_ranges, - sizeof(pbm->pbm_ranges)); - if (err != -1) + prop = of_find_property(node, "ranges", &len); + if (prop) { + pbm->pbm_ranges = prop->value; pbm->num_pbm_ranges = - (err / sizeof(struct linux_prom_pci_ranges)); - else + (len / sizeof(struct linux_prom_pci_ranges)); + } else { pbm->num_pbm_ranges = 0; + } - err = prom_getproperty(node, "interrupt-map", - (char *)pbm->pbm_intmap, - sizeof(pbm->pbm_intmap)); - if (err != -1) { - pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); - err = prom_getproperty(node, "interrupt-map-mask", - (char *)&pbm->pbm_intmask, - sizeof(pbm->pbm_intmask)); - if (err == -1) { - prom_printf("APB: Fatal error, no interrupt-map-mask.\n"); - prom_halt(); - } + prop = of_find_property(node, "interrupt-map", &len); + if (prop) { + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); + + prop = of_find_property(node, "interrupt-map-mask", + NULL); + pbm->pbm_intmask = prop->value; } else { pbm->num_pbm_intmap = 0; - memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); } pbm_register_toplevel_resources(p, pbm); next_pci: - node = prom_getsibling(node); - if (!node) - break; + node = node->sibling; } if (simbas_found == 0) { - int err; - /* No APBs underneath, probably this is a hummingbird * system. */ pbm = &p->pbm_A; pbm->parent = p; - pbm->prom_node = sabre_node; + pbm->prom_node = dp; pbm->pci_first_busno = p->pci_first_busno; pbm->pci_last_busno = p->pci_last_busno; - prom_getstring(sabre_node, "name", pbm->prom_name, sizeof(pbm->prom_name)); - err = prom_getproperty(sabre_node, "ranges", - (char *) pbm->pbm_ranges, - sizeof(pbm->pbm_ranges)); - if (err != -1) + prop = of_find_property(dp, "ranges", &len); + if (prop) { + pbm->pbm_ranges = prop->value; pbm->num_pbm_ranges = - (err / sizeof(struct linux_prom_pci_ranges)); - else + (len / sizeof(struct linux_prom_pci_ranges)); + } else { pbm->num_pbm_ranges = 0; + } - err = prom_getproperty(sabre_node, "interrupt-map", - (char *) pbm->pbm_intmap, - sizeof(pbm->pbm_intmap)); - - if (err != -1) { - pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); - err = prom_getproperty(sabre_node, "interrupt-map-mask", - (char *)&pbm->pbm_intmask, - sizeof(pbm->pbm_intmask)); - if (err == -1) { - prom_printf("Hummingbird: Fatal error, no interrupt-map-mask.\n"); - prom_halt(); - } + prop = of_find_property(dp, "interrupt-map", &len); + if (prop) { + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); + + prop = of_find_property(dp, "interrupt-map-mask", + NULL); + pbm->pbm_intmask = prop->value; } else { pbm->num_pbm_intmap = 0; - memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); } + pbm->name = dp->full_name; + printk("%s: SABRE PCI Bus Module\n", pbm->name); - sprintf(pbm->name, "SABRE%d PBM%c", p->index, - (pbm == &p->pbm_A ? 'A' : 'B')); pbm->io_space.name = pbm->mem_space.name = pbm->name; /* Hack up top-level resources. */ @@ -1443,14 +1431,15 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm } } -void sabre_init(int pnode, char *model_name) +void sabre_init(struct device_node *dp, char *model_name) { - struct linux_prom64_registers pr_regs[2]; + struct linux_prom64_registers *pr_regs; struct pci_controller_info *p; struct pci_iommu *iommu; - int tsbsize, err; - u32 busrange[2]; - u32 vdma[2]; + struct property *prop; + int tsbsize; + u32 *busrange; + u32 *vdma; u32 upa_portid, dma_mask; u64 clear_irq; @@ -1458,13 +1447,15 @@ void sabre_init(int pnode, char *model_name) if (!strcmp(model_name, "pci108e,a001")) hummingbird_p = 1; else if (!strcmp(model_name, "SUNW,sabre")) { - char compat[64]; + prop = of_find_property(dp, "compatible", NULL); + if (prop) { + const char *compat = prop->value; - if (prom_getproperty(pnode, "compatible", - compat, sizeof(compat)) > 0 && - !strcmp(compat, "pci108e,a001")) { - hummingbird_p = 1; - } else { + if (!strcmp(compat, "pci108e,a001")) + hummingbird_p = 1; + } + if (!hummingbird_p) { + char compat[64]; int cpu_node; /* Of course, Sun has to encode things a thousand @@ -1491,7 +1482,10 @@ void sabre_init(int pnode, char *model_name) } p->pbm_A.iommu = p->pbm_B.iommu = iommu; - upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); + upa_portid = 0xff; + prop = of_find_property(dp, "upa-portid", NULL); + if (prop) + upa_portid = *(u32 *) prop->value; p->next = pci_controller_root; pci_controller_root = p; @@ -1509,13 +1503,9 @@ void sabre_init(int pnode, char *model_name) /* * Map in SABRE register set and report the presence of this SABRE. */ - err = prom_getproperty(pnode, "reg", - (char *)&pr_regs[0], sizeof(pr_regs)); - if(err == 0 || err == -1) { - prom_printf("SABRE: Error, cannot get U2P registers " - "from PROM.\n"); - prom_halt(); - } + + prop = of_find_property(dp, "reg", NULL); + pr_regs = prop->value; /* * First REG in property is base of entire SABRE register space. @@ -1523,9 +1513,6 @@ void sabre_init(int pnode, char *model_name) p->pbm_A.controller_regs = pr_regs[0].phys_addr; p->pbm_B.controller_regs = pr_regs[0].phys_addr; - printk("PCI: Found SABRE, main regs at %016lx\n", - p->pbm_A.controller_regs); - /* Clear interrupts */ /* PCI first */ @@ -1544,16 +1531,9 @@ void sabre_init(int pnode, char *model_name) /* Now map in PCI config space for entire SABRE. */ p->pbm_A.config_space = p->pbm_B.config_space = (p->pbm_A.controller_regs + SABRE_CONFIGSPACE); - printk("SABRE: Shared PCI config space at %016lx\n", - p->pbm_A.config_space); - - err = prom_getproperty(pnode, "virtual-dma", - (char *)&vdma[0], sizeof(vdma)); - if(err == 0 || err == -1) { - prom_printf("SABRE: Error, cannot get virtual-dma property " - "from PROM.\n"); - prom_halt(); - } + + prop = of_find_property(dp, "virtual-dma", NULL); + vdma = prop->value; dma_mask = vdma[0]; switch(vdma[1]) { @@ -1577,21 +1557,13 @@ void sabre_init(int pnode, char *model_name) sabre_iommu_init(p, tsbsize, vdma[0], dma_mask); - printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); - - err = prom_getproperty(pnode, "bus-range", - (char *)&busrange[0], sizeof(busrange)); - if(err == 0 || err == -1) { - prom_printf("SABRE: Error, cannot get PCI bus-range " - " from PROM.\n"); - prom_halt(); - } - + prop = of_find_property(dp, "bus-range", NULL); + busrange = prop->value; p->pci_first_busno = busrange[0]; p->pci_last_busno = busrange[1]; /* * Look for APB underneath. */ - sabre_pbm_init(p, pnode, vdma[0]); + sabre_pbm_init(p, dp, vdma[0]); } diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index cc662e915d3..d2682008684 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "pci_impl.h" #include "iommu_common.h" @@ -1437,7 +1438,7 @@ static void pbm_scan_bus(struct pci_controller_info *p, pci_fixup_host_bridge_self(pbm->pci_bus); pbm->pci_bus->self->sysdata = cookie; - pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node->node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); pci_fixup_irq(pbm, pbm->pci_bus); @@ -1456,10 +1457,12 @@ static void __schizo_scan_bus(struct pci_controller_info *p, pbm_config_busmastering(&p->pbm_B); p->pbm_B.is_66mhz_capable = - prom_getbool(p->pbm_B.prom_node, "66mhz-capable"); + (of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL) + != NULL); pbm_config_busmastering(&p->pbm_A); p->pbm_A.is_66mhz_capable = - prom_getbool(p->pbm_A.prom_node, "66mhz-capable"); + (of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL) + != NULL); pbm_scan_bus(p, &p->pbm_B); pbm_scan_bus(p, &p->pbm_A); @@ -1661,13 +1664,18 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) { struct pci_iommu *iommu = pbm->iommu; unsigned long i, tagbase, database; + struct property *prop; u32 vdma[2], dma_mask; u64 control; - int err, tsbsize; + int tsbsize; - err = prom_getproperty(pbm->prom_node, "virtual-dma", - (char *)&vdma[0], sizeof(vdma)); - if (err == 0 || err == -1) { + prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); + if (prop) { + u32 *val = prop->value; + + vdma[0] = val[0]; + vdma[1] = val[1]; + } else { /* No property, use default values. */ vdma[0] = 0xc0000000; vdma[1] = 0x40000000; @@ -1778,6 +1786,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) { + struct property *prop; u64 tmp; schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5); @@ -1791,7 +1800,8 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) pbm->chip_version >= 0x2) tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT; - if (!prom_getbool(pbm->prom_node, "no-bus-parking")) + prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL); + if (!prop) tmp |= SCHIZO_PCICTRL_PARK; else tmp &= ~SCHIZO_PCICTRL_PARK; @@ -1831,16 +1841,17 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) } static void schizo_pbm_init(struct pci_controller_info *p, - int prom_node, u32 portid, + struct device_node *dp, u32 portid, int chip_type) { - struct linux_prom64_registers pr_regs[4]; - unsigned int busrange[2]; + struct linux_prom64_registers *regs; + struct property *prop; + unsigned int *busrange; struct pci_pbm_info *pbm; const char *chipset_name; - u32 ino_bitmap[2]; + u32 *ino_bitmap; int is_pbm_a; - int err; + int len; switch (chip_type) { case PBM_CHIP_TYPE_TOMATILLO: @@ -1868,16 +1879,10 @@ static void schizo_pbm_init(struct pci_controller_info *p, * 3) PBM PCI config space * 4) Ichip regs */ - err = prom_getproperty(prom_node, "reg", - (char *)&pr_regs[0], - sizeof(pr_regs)); - if (err == 0 || err == -1) { - prom_printf("%s: Fatal error, no reg property.\n", - chipset_name); - prom_halt(); - } + prop = of_find_property(dp, "reg", NULL); + regs = prop->value; - is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000); + is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000); if (is_pbm_a) pbm = &p->pbm_A; @@ -1886,92 +1891,62 @@ static void schizo_pbm_init(struct pci_controller_info *p, pbm->portid = portid; pbm->parent = p; - pbm->prom_node = prom_node; + pbm->prom_node = dp; pbm->pci_first_slot = 1; pbm->chip_type = chip_type; - pbm->chip_version = - prom_getintdefault(prom_node, "version#", 0); - pbm->chip_revision = - prom_getintdefault(prom_node, "module-revision#", 0); - - pbm->pbm_regs = pr_regs[0].phys_addr; - pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL; + pbm->chip_version = 0; + prop = of_find_property(dp, "version#", NULL); + if (prop) + pbm->chip_version = *(int *) prop->value; + pbm->chip_revision = 0; + prop = of_find_property(dp, "module-revision#", NULL); + if (prop) + pbm->chip_revision = *(int *) prop->value; + + pbm->pbm_regs = regs[0].phys_addr; + pbm->controller_regs = regs[1].phys_addr - 0x10000UL; if (chip_type == PBM_CHIP_TYPE_TOMATILLO) - pbm->sync_reg = pr_regs[3].phys_addr + 0x1a18UL; + pbm->sync_reg = regs[3].phys_addr + 0x1a18UL; - sprintf(pbm->name, - (chip_type == PBM_CHIP_TYPE_TOMATILLO ? - "TOMATILLO%d PBM%c" : - "SCHIZO%d PBM%c"), - p->index, - (pbm == &p->pbm_A ? 'A' : 'B')); + pbm->name = dp->full_name; - printk("%s: ver[%x:%x], portid %x, " - "cregs[%lx] pregs[%lx]\n", + printk("%s: %s PCI Bus Module ver[%x:%x]\n", pbm->name, - pbm->chip_version, pbm->chip_revision, - pbm->portid, - pbm->controller_regs, - pbm->pbm_regs); + (chip_type == PBM_CHIP_TYPE_TOMATILLO ? + "TOMATILLO" : "SCHIZO"), + pbm->chip_version, pbm->chip_revision); schizo_pbm_hw_init(pbm); - prom_getstring(prom_node, "name", - pbm->prom_name, - sizeof(pbm->prom_name)); - - err = prom_getproperty(prom_node, "ranges", - (char *) pbm->pbm_ranges, - sizeof(pbm->pbm_ranges)); - if (err == 0 || err == -1) { - prom_printf("%s: Fatal error, no ranges property.\n", - pbm->name); - prom_halt(); - } - + prop = of_find_property(dp, "ranges", &len); + pbm->pbm_ranges = prop->value; pbm->num_pbm_ranges = - (err / sizeof(struct linux_prom_pci_ranges)); + (len / sizeof(struct linux_prom_pci_ranges)); schizo_determine_mem_io_space(pbm); pbm_register_toplevel_resources(p, pbm); - err = prom_getproperty(prom_node, "interrupt-map", - (char *)pbm->pbm_intmap, - sizeof(pbm->pbm_intmap)); - if (err != -1) { - pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); - err = prom_getproperty(prom_node, "interrupt-map-mask", - (char *)&pbm->pbm_intmask, - sizeof(pbm->pbm_intmask)); - if (err == -1) { - prom_printf("%s: Fatal error, no " - "interrupt-map-mask.\n", pbm->name); - prom_halt(); - } + prop = of_find_property(dp, "interrupt-map", &len); + if (prop) { + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); + + prop = of_find_property(dp, "interrupt-map-mask", NULL); + pbm->pbm_intmask = prop->value; } else { pbm->num_pbm_intmap = 0; - memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); } - err = prom_getproperty(prom_node, "ino-bitmap", - (char *) &ino_bitmap[0], - sizeof(ino_bitmap)); - if (err == 0 || err == -1) { - prom_printf("%s: Fatal error, no ino-bitmap.\n", pbm->name); - prom_halt(); - } + prop = of_find_property(dp, "ino-bitmap", NULL); + ino_bitmap = prop->value; pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) | ((u64)ino_bitmap[0] << 0UL)); - err = prom_getproperty(prom_node, "bus-range", - (char *)&busrange[0], - sizeof(busrange)); - if (err == 0 || err == -1) { - prom_printf("%s: Fatal error, no bus-range.\n", pbm->name); - prom_halt(); - } + prop = of_find_property(dp, "bus-range", NULL); + busrange = prop->value; pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; @@ -1989,16 +1964,20 @@ static inline int portid_compare(u32 x, u32 y, int chip_type) return (x == y); } -static void __schizo_init(int node, char *model_name, int chip_type) +static void __schizo_init(struct device_node *dp, char *model_name, int chip_type) { struct pci_controller_info *p; struct pci_iommu *iommu; + struct property *prop; int is_pbm_a; u32 portid; - portid = prom_getintdefault(node, "portid", 0xff); + portid = 0xff; + prop = of_find_property(dp, "portid", NULL); + if (prop) + portid = *(u32 *) prop->value; - for(p = pci_controller_root; p; p = p->next) { + for (p = pci_controller_root; p; p = p->next) { struct pci_pbm_info *pbm; if (p->pbm_A.prom_node && p->pbm_B.prom_node) @@ -2009,8 +1988,8 @@ static void __schizo_init(int node, char *model_name, int chip_type) &p->pbm_B); if (portid_compare(pbm->portid, portid, chip_type)) { - is_pbm_a = (p->pbm_A.prom_node == 0); - schizo_pbm_init(p, node, portid, chip_type); + is_pbm_a = (p->pbm_A.prom_node == NULL); + schizo_pbm_init(p, dp, portid, chip_type); return; } } @@ -2051,20 +2030,20 @@ static void __schizo_init(int node, char *model_name, int chip_type) /* Like PSYCHO we have a 2GB aligned area for memory space. */ pci_memspace_mask = 0x7fffffffUL; - schizo_pbm_init(p, node, portid, chip_type); + schizo_pbm_init(p, dp, portid, chip_type); } -void schizo_init(int node, char *model_name) +void schizo_init(struct device_node *dp, char *model_name) { - __schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO); + __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO); } -void schizo_plus_init(int node, char *model_name) +void schizo_plus_init(struct device_node *dp, char *model_name) { - __schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS); + __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS); } -void tomatillo_init(int node, char *model_name) +void tomatillo_init(struct device_node *dp, char *model_name) { - __schizo_init(node, model_name, PBM_CHIP_TYPE_TOMATILLO); + __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO); } diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 5419480edf4..b63b2834133 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "pci_impl.h" #include "iommu_common.h" @@ -646,35 +647,37 @@ static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, u /* Recursively descend into the OBP device tree, rooted at toplevel_node, * looking for a PCI device matching bus and devfn. */ -static int obp_find(struct linux_prom_pci_registers *pregs, int toplevel_node, unsigned int bus, unsigned int devfn) +static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn) { - toplevel_node = prom_getchild(toplevel_node); + toplevel_node = toplevel_node->child; - while (toplevel_node != 0) { - int ret = obp_find(pregs, toplevel_node, bus, devfn); + while (toplevel_node != NULL) { + struct linux_prom_pci_registers *regs; + struct property *prop; + int ret; + ret = obp_find(toplevel_node, bus, devfn); if (ret != 0) return ret; - ret = prom_getproperty(toplevel_node, "reg", (char *) pregs, - sizeof(*pregs) * PROMREG_MAX); - if (ret == 0 || ret == -1) + prop = of_find_property(toplevel_node, "reg", NULL); + if (!prop) goto next_sibling; - if (((pregs[0].phys_hi >> 16) & 0xff) == bus && - ((pregs[0].phys_hi >> 8) & 0xff) == devfn) + regs = prop->value; + if (((regs->phys_hi >> 16) & 0xff) == bus && + ((regs->phys_hi >> 8) & 0xff) == devfn) break; next_sibling: - toplevel_node = prom_getsibling(toplevel_node); + toplevel_node = toplevel_node->sibling; } - return toplevel_node; + return toplevel_node != NULL; } static int pdev_htab_populate(struct pci_pbm_info *pbm) { - struct linux_prom_pci_registers pr[PROMREG_MAX]; u32 devhandle = pbm->devhandle; unsigned int bus; @@ -685,7 +688,7 @@ static int pdev_htab_populate(struct pci_pbm_info *pbm) unsigned int device = PCI_SLOT(devfn); unsigned int func = PCI_FUNC(devfn); - if (obp_find(pr, pbm->prom_node, bus, devfn)) { + if (obp_find(pbm->prom_node, bus, devfn)) { int err = pdev_htab_add(devhandle, bus, device, func); if (err) @@ -812,7 +815,7 @@ static void pbm_scan_bus(struct pci_controller_info *p, pbm->pci_bus->self->sysdata = cookie; #endif pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, - pbm->prom_node); + pbm->prom_node->node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); pci_fixup_irq(pbm, pbm->pci_bus); @@ -822,15 +825,18 @@ static void pbm_scan_bus(struct pci_controller_info *p, static void pci_sun4v_scan_bus(struct pci_controller_info *p) { - if (p->pbm_A.prom_node) { - p->pbm_A.is_66mhz_capable = - prom_getbool(p->pbm_A.prom_node, "66mhz-capable"); + struct property *prop; + struct device_node *dp; + + if ((dp = p->pbm_A.prom_node) != NULL) { + prop = of_find_property(dp, "66mhz-capable", NULL); + p->pbm_A.is_66mhz_capable = (prop != NULL); pbm_scan_bus(p, &p->pbm_A); } - if (p->pbm_B.prom_node) { - p->pbm_B.is_66mhz_capable = - prom_getbool(p->pbm_B.prom_node, "66mhz-capable"); + if ((dp = p->pbm_B.prom_node) != NULL) { + prop = of_find_property(dp, "66mhz-capable", NULL); + p->pbm_B.is_66mhz_capable = (prop != NULL); pbm_scan_bus(p, &p->pbm_B); } @@ -993,13 +999,18 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) { struct pci_iommu *iommu = pbm->iommu; + struct property *prop; unsigned long num_tsb_entries, sz; u32 vdma[2], dma_mask, dma_offset; - int err, tsbsize; + int tsbsize; + + prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); + if (prop) { + u32 *val = prop->value; - err = prom_getproperty(pbm->prom_node, "virtual-dma", - (char *)&vdma[0], sizeof(vdma)); - if (err == 0 || err == -1) { + vdma[0] = val[0]; + vdma[1] = val[1]; + } else { /* No property, use default values. */ vdma[0] = 0x80000000; vdma[1] = 0x80000000; @@ -1058,27 +1069,23 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm) { - unsigned int busrange[2]; - int prom_node = pbm->prom_node; - int err; - - err = prom_getproperty(prom_node, "bus-range", - (char *)&busrange[0], - sizeof(busrange)); - if (err == 0 || err == -1) { - prom_printf("%s: Fatal error, no bus-range.\n", pbm->name); - prom_halt(); - } + struct property *prop; + unsigned int *busrange; + + prop = of_find_property(pbm->prom_node, "bus-range", NULL); + + busrange = prop->value; pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; } -static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 devhandle) +static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle) { struct pci_pbm_info *pbm; - int err, i; + struct property *prop; + int len, i; if (devhandle & 0x40) pbm = &p->pbm_B; @@ -1086,32 +1093,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 pbm = &p->pbm_A; pbm->parent = p; - pbm->prom_node = prom_node; + pbm->prom_node = dp; pbm->pci_first_slot = 1; pbm->devhandle = devhandle; - sprintf(pbm->name, "SUN4V-PCI%d PBM%c", - p->index, (pbm == &p->pbm_A ? 'A' : 'B')); - - printk("%s: devhandle[%x] prom_node[%x:%x]\n", - pbm->name, pbm->devhandle, - pbm->prom_node, prom_getchild(pbm->prom_node)); + pbm->name = dp->full_name; - prom_getstring(prom_node, "name", - pbm->prom_name, sizeof(pbm->prom_name)); - - err = prom_getproperty(prom_node, "ranges", - (char *) pbm->pbm_ranges, - sizeof(pbm->pbm_ranges)); - if (err == 0 || err == -1) { - prom_printf("%s: Fatal error, no ranges property.\n", - pbm->name); - prom_halt(); - } + printk("%s: SUN4V PCI Bus Module\n", pbm->name); + prop = of_find_property(dp, "ranges", &len); + pbm->pbm_ranges = prop->value; pbm->num_pbm_ranges = - (err / sizeof(struct linux_prom_pci_ranges)); + (len / sizeof(struct linux_prom_pci_ranges)); /* Mask out the top 8 bits of the ranges, leaving the real * physical address. @@ -1122,24 +1116,13 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 pci_sun4v_determine_mem_io_space(pbm); pbm_register_toplevel_resources(p, pbm); - err = prom_getproperty(prom_node, "interrupt-map", - (char *)pbm->pbm_intmap, - sizeof(pbm->pbm_intmap)); - if (err == 0 || err == -1) { - prom_printf("%s: Fatal error, no interrupt-map property.\n", - pbm->name); - prom_halt(); - } + prop = of_find_property(dp, "interrupt-map", &len); + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); - pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); - err = prom_getproperty(prom_node, "interrupt-map-mask", - (char *)&pbm->pbm_intmask, - sizeof(pbm->pbm_intmask)); - if (err == 0 || err == -1) { - prom_printf("%s: Fatal error, no interrupt-map-mask.\n", - pbm->name); - prom_halt(); - } + prop = of_find_property(dp, "interrupt-map-mask", NULL); + pbm->pbm_intmask = prop->value; pci_sun4v_get_bus_range(pbm); pci_sun4v_iommu_init(pbm); @@ -1147,16 +1130,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 pdev_htab_populate(pbm); } -void sun4v_pci_init(int node, char *model_name) +void sun4v_pci_init(struct device_node *dp, char *model_name) { struct pci_controller_info *p; struct pci_iommu *iommu; - struct linux_prom64_registers regs; + struct property *prop; + struct linux_prom64_registers *regs; u32 devhandle; int i; - prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); - devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff; + prop = of_find_property(dp, "reg", NULL); + regs = prop->value; + + devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff; for (p = pci_controller_root; p; p = p->next) { struct pci_pbm_info *pbm; @@ -1169,7 +1155,7 @@ void sun4v_pci_init(int node, char *model_name) &p->pbm_B); if (pbm->devhandle == (devhandle ^ 0x40)) { - pci_sun4v_pbm_init(p, node, devhandle); + pci_sun4v_pbm_init(p, dp, devhandle); return; } } @@ -1220,7 +1206,7 @@ void sun4v_pci_init(int node, char *model_name) */ pci_memspace_mask = 0x7fffffffUL; - pci_sun4v_pbm_init(p, node, devhandle); + pci_sun4v_pbm_init(p, dp, devhandle); return; fatal_memory_error: diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 1396f110939..142cc4028bb 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -15,6 +15,7 @@ #include #include #include +#include #include /* The abstraction used here is that there are PCI controllers, @@ -153,16 +154,15 @@ struct pci_pbm_info { int chip_revision; /* Name used for top-level resources. */ - char name[64]; + char *name; /* OBP specific information. */ - int prom_node; - char prom_name[64]; - struct linux_prom_pci_ranges pbm_ranges[PROM_PCIRNG_MAX]; + struct device_node *prom_node; + struct linux_prom_pci_ranges *pbm_ranges; int num_pbm_ranges; - struct linux_prom_pci_intmap pbm_intmap[PROM_PCIIMAP_MAX]; + struct linux_prom_pci_intmap *pbm_intmap; int num_pbm_intmap; - struct linux_prom_pci_intmask pbm_intmask; + struct linux_prom_pci_intmask *pbm_intmask; u64 ino_bitmap; /* PBM I/O and Memory space resources. */ -- cgit v1.2.3-70-g09d2 From 6760d28bc691bb255c501c9b680f2fc1162258b2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 21 Jun 2006 22:56:20 -0700 Subject: [SPARC64]: Convert sun4v virtual-device layer to in-kernel PROM device tree. Signed-off-by: David S. Miller --- arch/sparc64/kernel/devices.c | 104 ++++++++++++++---------------------------- drivers/serial/sunhv.c | 35 +++++++------- include/asm-sparc64/vdev.h | 5 +- 3 files changed, 56 insertions(+), 88 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 0dd95ae50e1..136f872a8a5 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -33,7 +33,7 @@ extern void cpu_probe(void); extern void central_probe(void); u32 sun4v_vdev_devhandle; -int sun4v_vdev_root; +struct device_node *sun4v_vdev_root; struct vdev_intmap { unsigned int phys; @@ -50,102 +50,68 @@ struct vdev_intmask { static struct vdev_intmap *vdev_intmap; static int vdev_num_intmap; -static struct vdev_intmask vdev_intmask; +static struct vdev_intmask *vdev_intmask; static void __init sun4v_virtual_device_probe(void) { - struct linux_prom64_registers regs; - struct vdev_intmap *ip; - int node, sz, err; + struct linux_prom64_registers *regs; + struct property *prop; + struct device_node *dp; + int sz; if (tlb_type != hypervisor) return; - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "virtual-devices"); - if (!node) { + dp = of_find_node_by_name(NULL, "virtual-devices"); + if (!dp) { prom_printf("SUN4V: Fatal error, no virtual-devices node.\n"); prom_halt(); } - sun4v_vdev_root = node; + sun4v_vdev_root = dp; - prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); - sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff; + prop = of_find_property(dp, "reg", NULL); + regs = prop->value; + sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff; - sz = prom_getproplen(node, "interrupt-map"); - if (sz <= 0) { - prom_printf("SUN4V: Error, no vdev interrupt-map.\n"); - prom_halt(); - } - - if ((sz % sizeof(*ip)) != 0) { - prom_printf("SUN4V: Bogus interrupt-map property size %d\n", - sz); - prom_halt(); - } - - vdev_intmap = ip = alloc_bootmem_low_pages(sz); - if (!vdev_intmap) { - prom_printf("SUN4V: Error, cannot allocate vdev_intmap.\n"); - prom_halt(); - } - - err = prom_getproperty(node, "interrupt-map", (char *) ip, sz); - if (err == -1) { - prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n"); - prom_halt(); - } - if (err != sz) { - prom_printf("SUN4V: Inconsistent interrupt-map size, " - "proplen(%d) vs getprop(%d).\n", sz,err); - prom_halt(); - } - - vdev_num_intmap = err / sizeof(*ip); + prop = of_find_property(dp, "interrupt-map", &sz); + vdev_intmap = prop->value; + vdev_num_intmap = sz / sizeof(struct vdev_intmap); - err = prom_getproperty(node, "interrupt-map-mask", - (char *) &vdev_intmask, - sizeof(vdev_intmask)); - if (err <= 0) { - prom_printf("SUN4V: Fatal error, no vdev " - "interrupt-map-mask.\n"); - prom_halt(); - } - if (err % sizeof(vdev_intmask)) { - prom_printf("SUN4V: Bogus interrupt-map-mask " - "property size %d\n", err); - prom_halt(); - } + prop = of_find_property(dp, "interrupt-map-mask", NULL); + vdev_intmask = prop->value; - printk("SUN4V: virtual-devices devhandle[%x]\n", - sun4v_vdev_devhandle); + printk("%s: Virtual Device Bus devhandle[%x]\n", + dp->full_name, sun4v_vdev_devhandle); } -unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) +unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node) { + struct property *prop; unsigned int irq, reg; - int err, i; + int i; - err = prom_getproperty(dev_node, "interrupts", - (char *) &irq, sizeof(irq)); - if (err <= 0) { + prop = of_find_property(dev_node, "interrupts", NULL); + if (!prop) { printk("VDEV: Cannot get \"interrupts\" " - "property for OBP node %x\n", dev_node); + "property for OBP node %s\n", + dev_node->full_name); return 0; } + irq = *(unsigned int *) prop->value; - err = prom_getproperty(dev_node, "reg", - (char *) ®, sizeof(reg)); - if (err <= 0) { + prop = of_find_property(dev_node, "reg", NULL); + if (!prop) { printk("VDEV: Cannot get \"reg\" " - "property for OBP node %x\n", dev_node); + "property for OBP node %s\n", + dev_node->full_name); return 0; } + reg = *(unsigned int *) prop->value; for (i = 0; i < vdev_num_intmap; i++) { - if (vdev_intmap[i].phys == (reg & vdev_intmask.phys) && - vdev_intmap[i].irq == (irq & vdev_intmask.interrupt)) { + if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) && + vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) { irq = vdev_intmap[i].cinterrupt; break; } @@ -153,7 +119,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) if (i == vdev_num_intmap) { printk("VDEV: No matching interrupt map entry " - "for OBP node %x\n", dev_node); + "for OBP node %s\n", dev_node->full_name); return 0; } diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index f137804b313..ba22e256c6f 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -427,31 +427,32 @@ static int __init hv_console_compatible(char *buf, int len) static unsigned int __init get_interrupt(void) { - const char *cons_str = "console"; - const char *compat_str = "compatible"; - int node = prom_getchild(sun4v_vdev_root); - char buf[64]; - int err, len; - - node = prom_searchsiblings(node, cons_str); - if (!node) - return 0; + struct device_node *dev_node; - len = prom_getproplen(node, compat_str); - if (len == 0 || len == -1) - return 0; + dev_node = sun4v_vdev_root->child; + while (dev_node != NULL) { + struct property *prop; - err = prom_getproperty(node, compat_str, buf, 64); - if (err == -1) - return 0; + if (strcmp(dev_node->name, "console")) + goto next_sibling; + + prop = of_find_property(dev_node, "compatible", NULL); + if (!prop) + goto next_sibling; - if (!hv_console_compatible(buf, len)) + if (hv_console_compatible(prop->value, prop->length)) + break; + + next_sibling: + dev_node = dev_node->sibling; + } + if (!dev_node) return 0; /* Ok, the this is the OBP node for the sun4v hypervisor * console device. Decode the interrupt. */ - return sun4v_vdev_device_interrupt(node); + return sun4v_vdev_device_interrupt(dev_node); } static int __init sunhv_init(void) diff --git a/include/asm-sparc64/vdev.h b/include/asm-sparc64/vdev.h index 996e6be7b97..25637c57675 100644 --- a/include/asm-sparc64/vdev.h +++ b/include/asm-sparc64/vdev.h @@ -7,10 +7,11 @@ #define _SPARC64_VDEV_H #include +#include extern u32 sun4v_vdev_devhandle; -extern int sun4v_vdev_root; +extern struct device_node *sun4v_vdev_root; -extern unsigned int sun4v_vdev_device_interrupt(unsigned int); +extern unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node); #endif /* !(_SPARC64_VDEV_H) */ -- cgit v1.2.3-70-g09d2 From 6d307724cb6a6b8466cad4fdf13d8a409bc2433f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 21 Jun 2006 23:07:29 -0700 Subject: [SPARC64]: Add of_getintprop_default(). This encodes a common idiomatic coding pattern used when dealing with integer properties. Signed-off-by: David S. Miller --- arch/sparc64/kernel/prom.c | 12 ++++++++++++ include/asm-sparc64/prom.h | 3 +++ 2 files changed, 15 insertions(+) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index fd46e94ce06..0a32b1064df 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -104,6 +104,18 @@ struct property *of_find_property(struct device_node *np, const char *name, return pp; } +int of_getintprop_default(struct device_node *np, const char *name, int def) +{ + struct property *prop; + int len; + + prop = of_find_property(np, name, &len); + if (!prop || len != 4) + return def; + + return *(int *) prop->value; +} + static unsigned int prom_early_allocated; static void * __init prom_early_alloc(unsigned long size) diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index eb75d3cbcf4..d0187b3a0ec 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -82,6 +82,9 @@ extern struct device_node *of_get_next_child(const struct device_node *node, extern struct property *of_find_property(struct device_node *np, const char *name, int *lenp); +extern int of_getintprop_default(struct device_node *np, + const char *name, + int def); extern void prom_build_devicetree(void); -- cgit v1.2.3-70-g09d2 From 07f8e5f358a0b7240f1dad6b3819f2fd1103f159 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 21 Jun 2006 23:34:02 -0700 Subject: [SPARC64]: Convert cpu_find_by_*() interface to in-kernel PROM device tree. Signed-off-by: David S. Miller --- arch/sparc64/kernel/devices.c | 118 +++++++++++++++++++--------------------- arch/sparc64/kernel/pci_sabre.c | 9 +-- arch/sparc64/kernel/smp.c | 41 +++++++------- arch/sparc64/kernel/time.c | 16 +++--- arch/sparc64/kernel/traps.c | 18 +++--- include/asm-sparc64/oplib.h | 5 +- 6 files changed, 104 insertions(+), 103 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 136f872a8a5..389301c95cb 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -133,38 +133,44 @@ static const char *cpu_mid_prop(void) return "portid"; } -static int get_cpu_mid(int prom_node) +static int get_cpu_mid(struct device_node *dp) { + struct property *prop; + if (tlb_type == hypervisor) { - struct linux_prom64_registers reg; + struct linux_prom64_registers *reg; + int len; - if (prom_getproplen(prom_node, "cpuid") == 4) - return prom_getintdefault(prom_node, "cpuid", 0); + prop = of_find_property(dp, "cpuid", &len); + if (prop && len == 4) + return *(int *) prop->value; - prom_getproperty(prom_node, "reg", (char *) ®, sizeof(reg)); - return (reg.phys_addr >> 32) & 0x0fffffffUL; + prop = of_find_property(dp, "reg", NULL); + reg = prop->value; + return (reg[0].phys_addr >> 32) & 0x0fffffffUL; } else { const char *prop_name = cpu_mid_prop(); - return prom_getintdefault(prom_node, prop_name, 0); + prop = of_find_property(dp, prop_name, NULL); + if (prop) + return *(int *) prop->value; + return 0; } } -static int check_cpu_node(int nd, int *cur_inst, - int (*compare)(int, int, void *), void *compare_arg, - int *prom_node, int *mid) +static int check_cpu_node(struct device_node *dp, int *cur_inst, + int (*compare)(struct device_node *, int, void *), + void *compare_arg, + struct device_node **dev_node, int *mid) { - char node_str[128]; - - prom_getstring(nd, "device_type", node_str, sizeof(node_str)); - if (strcmp(node_str, "cpu")) + if (strcmp(dp->type, "cpu")) return -ENODEV; - if (!compare(nd, *cur_inst, compare_arg)) { - if (prom_node) - *prom_node = nd; + if (!compare(dp, *cur_inst, compare_arg)) { + if (dev_node) + *dev_node = dp; if (mid) - *mid = get_cpu_mid(nd); + *mid = get_cpu_mid(dp); return 0; } @@ -173,25 +179,18 @@ static int check_cpu_node(int nd, int *cur_inst, return -ENODEV; } -static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg, - int *prom_node, int *mid) +static int __cpu_find_by(int (*compare)(struct device_node *, int, void *), + void *compare_arg, + struct device_node **dev_node, int *mid) { - int nd, cur_inst, err; + struct device_node *dp; + int cur_inst; - nd = prom_root_node; cur_inst = 0; - - err = check_cpu_node(nd, &cur_inst, - compare, compare_arg, - prom_node, mid); - if (err == 0) - return 0; - - nd = prom_getchild(nd); - while ((nd = prom_getsibling(nd)) != 0) { - err = check_cpu_node(nd, &cur_inst, - compare, compare_arg, - prom_node, mid); + for_each_node_by_type(dp, "cpu") { + int err = check_cpu_node(dp, &cur_inst, + compare, compare_arg, + dev_node, mid); if (err == 0) return 0; } @@ -199,7 +198,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg, return -ENODEV; } -static int cpu_instance_compare(int nd, int instance, void *_arg) +static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg) { int desired_instance = (int) (long) _arg; @@ -208,27 +207,27 @@ static int cpu_instance_compare(int nd, int instance, void *_arg) return -ENODEV; } -int cpu_find_by_instance(int instance, int *prom_node, int *mid) +int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid) { return __cpu_find_by(cpu_instance_compare, (void *)(long)instance, - prom_node, mid); + dev_node, mid); } -static int cpu_mid_compare(int nd, int instance, void *_arg) +static int cpu_mid_compare(struct device_node *dp, int instance, void *_arg) { int desired_mid = (int) (long) _arg; int this_mid; - this_mid = get_cpu_mid(nd); + this_mid = get_cpu_mid(dp); if (this_mid == desired_mid) return 0; return -ENODEV; } -int cpu_find_by_mid(int mid, int *prom_node) +int cpu_find_by_mid(int mid, struct device_node **dev_node) { return __cpu_find_by(cpu_mid_compare, (void *)(long)mid, - prom_node, NULL); + dev_node, NULL); } void __init device_scan(void) @@ -240,50 +239,47 @@ void __init device_scan(void) #ifndef CONFIG_SMP { - int err, cpu_node, def; + struct device_node *dp; + int err, def; - err = cpu_find_by_instance(0, &cpu_node, NULL); + err = cpu_find_by_instance(0, &dp, NULL); if (err) { prom_printf("No cpu nodes, cannot continue\n"); prom_halt(); } - cpu_data(0).clock_tick = prom_getintdefault(cpu_node, - "clock-frequency", - 0); + cpu_data(0).clock_tick = + of_getintprop_default(dp, "clock-frequency", 0); def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024)); - cpu_data(0).dcache_size = prom_getintdefault(cpu_node, - "dcache-size", - def); + cpu_data(0).dcache_size = of_getintprop_default(dp, + "dcache-size", + def); def = 32; cpu_data(0).dcache_line_size = - prom_getintdefault(cpu_node, "dcache-line-size", - def); + of_getintprop_default(dp, "dcache-line-size", def); def = 16 * 1024; - cpu_data(0).icache_size = prom_getintdefault(cpu_node, - "icache-size", - def); + cpu_data(0).icache_size = of_getintprop_default(dp, + "icache-size", + def); def = 32; cpu_data(0).icache_line_size = - prom_getintdefault(cpu_node, "icache-line-size", - def); + of_getintprop_default(dp, "icache-line-size", def); def = ((tlb_type == hypervisor) ? (3 * 1024 * 1024) : (4 * 1024 * 1024)); - cpu_data(0).ecache_size = prom_getintdefault(cpu_node, - "ecache-size", - def); + cpu_data(0).ecache_size = of_getintprop_default(dp, + "ecache-size", + def); def = 64; cpu_data(0).ecache_line_size = - prom_getintdefault(cpu_node, "ecache-line-size", - def); + of_getintprop_default(dp, "ecache-line-size", def); printk("CPU[0]: Caches " "D[sz(%d):line_sz(%d)] " "I[sz(%d):line_sz(%d)] " diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 91d1aa44efc..4ce7b4620c0 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1455,16 +1455,13 @@ void sabre_init(struct device_node *dp, char *model_name) hummingbird_p = 1; } if (!hummingbird_p) { - char compat[64]; - int cpu_node; + struct device_node *dp; /* Of course, Sun has to encode things a thousand * different ways, inconsistently. */ - cpu_find_by_instance(0, &cpu_node, NULL); - if (prom_getproperty(cpu_node, "name", - compat, sizeof(compat)) > 0 && - !strcmp(compat, "SUNW,UltraSPARC-IIe")) + cpu_find_by_instance(0, &dp, NULL); + if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe")) hummingbird_p = 1; } } diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index f03d52d0b88..f62bf3a2de1 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -39,6 +39,7 @@ #include #include #include +#include extern void calibrate_delay(void); @@ -76,41 +77,42 @@ void smp_bogo(struct seq_file *m) void __init smp_store_cpu_info(int id) { - int cpu_node, def; + struct device_node *dp; + int def; /* multiplier and counter set by smp_setup_percpu_timer() */ cpu_data(id).udelay_val = loops_per_jiffy; - cpu_find_by_mid(id, &cpu_node); - cpu_data(id).clock_tick = prom_getintdefault(cpu_node, - "clock-frequency", 0); + cpu_find_by_mid(id, &dp); + cpu_data(id).clock_tick = + of_getintprop_default(dp, "clock-frequency", 0); def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024)); - cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size", - def); + cpu_data(id).dcache_size = + of_getintprop_default(dp, "dcache-size", def); def = 32; cpu_data(id).dcache_line_size = - prom_getintdefault(cpu_node, "dcache-line-size", def); + of_getintprop_default(dp, "dcache-line-size", def); def = 16 * 1024; - cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size", - def); + cpu_data(id).icache_size = + of_getintprop_default(dp, "icache-size", def); def = 32; cpu_data(id).icache_line_size = - prom_getintdefault(cpu_node, "icache-line-size", def); + of_getintprop_default(dp, "icache-line-size", def); def = ((tlb_type == hypervisor) ? (3 * 1024 * 1024) : (4 * 1024 * 1024)); - cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size", - def); + cpu_data(id).ecache_size = + of_getintprop_default(dp, "ecache-size", def); def = 64; cpu_data(id).ecache_line_size = - prom_getintdefault(cpu_node, "ecache-line-size", def); + of_getintprop_default(dp, "ecache-line-size", def); printk("CPU[%d]: Caches " "D[sz(%d):line_sz(%d)] " @@ -342,10 +344,10 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu) prom_startcpu_cpuid(cpu, entry, cookie); } else { - int cpu_node; + struct device_node *dp; - cpu_find_by_mid(cpu, &cpu_node); - prom_startcpu(cpu_node, entry, cookie); + cpu_find_by_mid(cpu, &dp); + prom_startcpu(dp->node, entry, cookie); } for (timeout = 0; timeout < 5000000; timeout++) { @@ -1289,7 +1291,8 @@ int setup_profiling_timer(unsigned int multiplier) static void __init smp_tune_scheduling(void) { - int instance, node; + struct device_node *dp; + int instance; unsigned int def, smallest = ~0U; def = ((tlb_type == hypervisor) ? @@ -1297,10 +1300,10 @@ static void __init smp_tune_scheduling(void) (4 * 1024 * 1024)); instance = 0; - while (!cpu_find_by_instance(instance, &node, NULL)) { + while (!cpu_find_by_instance(instance, &dp, NULL)) { unsigned int val; - val = prom_getintdefault(node, "ecache-size", def); + val = of_getintprop_default(dp, "ecache-size", def); if (val < smallest) smallest = val; diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 0f00a99927e..aa5438a4fd5 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -48,6 +48,7 @@ #include #include #include +#include DEFINE_SPINLOCK(mostek_lock); DEFINE_SPINLOCK(rtc_lock); @@ -983,12 +984,14 @@ try_isa_clock: /* This is gets the master TICK_INT timer going. */ static unsigned long sparc64_init_timers(void) { + struct device_node *dp; + struct property *prop; unsigned long clock; - int node; #ifdef CONFIG_SMP extern void smp_tick_init(void); #endif + dp = of_find_node_by_path("/"); if (tlb_type == spitfire) { unsigned long ver, manuf, impl; @@ -999,18 +1002,17 @@ static unsigned long sparc64_init_timers(void) if (manuf == 0x17 && impl == 0x13) { /* Hummingbird, aka Ultra-IIe */ tick_ops = &hbtick_operations; - node = prom_root_node; - clock = prom_getint(node, "stick-frequency"); + prop = of_find_property(dp, "stick-frequency", NULL); } else { tick_ops = &tick_operations; - cpu_find_by_instance(0, &node, NULL); - clock = prom_getint(node, "clock-frequency"); + cpu_find_by_instance(0, &dp, NULL); + prop = of_find_property(dp, "clock-frequency", NULL); } } else { tick_ops = &stick_operations; - node = prom_root_node; - clock = prom_getint(node, "stick-frequency"); + prop = of_find_property(dp, "stick-frequency", NULL); } + clock = *(unsigned int *) prop->value; timer_tick_offset = clock / HZ; #ifdef CONFIG_SMP diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 5059cbd4fee..1ff34b019f3 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -42,6 +42,7 @@ #ifdef CONFIG_KMOD #include #endif +#include ATOMIC_NOTIFIER_HEAD(sparc64die_chain); @@ -807,7 +808,8 @@ extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector void __init cheetah_ecache_flush_init(void) { unsigned long largest_size, smallest_linesize, order, ver; - int node, i, instance; + struct device_node *dp; + int i, instance, sz; /* Scan all cpu device tree nodes, note two values: * 1) largest E-cache size @@ -817,14 +819,14 @@ void __init cheetah_ecache_flush_init(void) smallest_linesize = ~0UL; instance = 0; - while (!cpu_find_by_instance(instance, &node, NULL)) { + while (!cpu_find_by_instance(instance, &dp, NULL)) { unsigned long val; - val = prom_getintdefault(node, "ecache-size", - (2 * 1024 * 1024)); + val = of_getintprop_default(dp, "ecache-size", + (2 * 1024 * 1024)); if (val > largest_size) largest_size = val; - val = prom_getintdefault(node, "ecache-line-size", 64); + val = of_getintprop_default(dp, "ecache-line-size", 64); if (val < smallest_linesize) smallest_linesize = val; instance++; @@ -849,16 +851,16 @@ void __init cheetah_ecache_flush_init(void) } /* Now allocate error trap reporting scoreboard. */ - node = NR_CPUS * (2 * sizeof(struct cheetah_err_info)); + sz = NR_CPUS * (2 * sizeof(struct cheetah_err_info)); for (order = 0; order < MAX_ORDER; order++) { - if ((PAGE_SIZE << order) >= node) + if ((PAGE_SIZE << order) >= sz) break; } cheetah_error_log = (struct cheetah_err_info *) __get_free_pages(GFP_KERNEL, order); if (!cheetah_error_log) { prom_printf("cheetah_ecache_flush_init: Failed to allocate " - "error logging scoreboard (%d bytes).\n", node); + "error logging scoreboard (%d bytes).\n", sz); prom_halt(); } memset(cheetah_error_log, 0, PAGE_SIZE << order); diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h index dea3e73f095..a68b0bb0595 100644 --- a/include/asm-sparc64/oplib.h +++ b/include/asm-sparc64/oplib.h @@ -323,8 +323,9 @@ extern int prom_pathtoinode(const char *path); extern int prom_inst2pkg(int); /* CPU probing helpers. */ -int cpu_find_by_instance(int instance, int *prom_node, int *mid); -int cpu_find_by_mid(int mid, int *prom_node); +struct device_node; +int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid); +int cpu_find_by_mid(int mid, struct device_node **prom_node); /* Client interface level routines. */ extern void prom_set_trap_table(unsigned long tba); -- cgit v1.2.3-70-g09d2 From c2a5a46be4a1c682e18e29e67785126b7610b14d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Jun 2006 00:01:56 -0700 Subject: [SPARC64]: Fix for Niagara memory corruption. On some sun4v systems, after netboot the ethernet controller and it's DMA mappings can be left active. The net result is that the kernel can end up using memory the ethernet controller will continue to DMA into, resulting in corruption. To deal with this, we are more careful about importing IOMMU translations which OBP has left in the IO-TLB. If the mapping maps into an area the firmware claimed was free and available memory for the kernel to use, we demap instead of import that IOMMU entry. This is going to cause the network chip to take a PCI master abort on the next DMA it attempts, if it has been left going like this. All tests show that this is handled properly by the PCI layer and the e1000 drivers. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_sun4v.c | 15 ++++++++++----- arch/sparc64/mm/init.c | 28 +++++++++++++++++++++++++++- include/asm-sparc64/pgtable.h | 2 ++ 3 files changed, 39 insertions(+), 6 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index b63b2834133..b275c7df018 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -988,8 +988,13 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, HV_PCI_TSBID(0, i), &io_attrs, &ra); if (ret == HV_EOK) { - cnt++; - __set_bit(i, arena->map); + if (page_in_phys_avail(ra)) { + pci_sun4v_iommu_demap(devhandle, + HV_PCI_TSBID(0, i), 1); + } else { + cnt++; + __set_bit(i, arena->map); + } } } @@ -1062,9 +1067,9 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) iommu->arena.limit = num_tsb_entries; sz = probe_existing_entries(pbm, iommu); - - printk("%s: TSB entries [%lu], existing mapings [%lu]\n", - pbm->name, num_tsb_entries, sz); + if (sz) + printk("%s: Imported %lu TSB entries from OBP\n", + pbm->name, sz); } static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 9d2b0da590a..51399341474 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1396,7 +1396,7 @@ static void __init taint_real_pages(void) while (old_start < old_end) { int n; - for (n = 0; pavail_rescan_ents; n++) { + for (n = 0; n < pavail_rescan_ents; n++) { unsigned long new_start, new_end; new_start = pavail_rescan[n].phys_addr; @@ -1418,6 +1418,32 @@ static void __init taint_real_pages(void) } } +int __init page_in_phys_avail(unsigned long paddr) +{ + int i; + + paddr &= PAGE_MASK; + + for (i = 0; i < pavail_rescan_ents; i++) { + unsigned long start, end; + + start = pavail_rescan[i].phys_addr; + end = start + pavail_rescan[i].reg_size; + + if (paddr >= start && paddr < end) + return 1; + } + if (paddr >= kern_base && paddr < (kern_base + kern_size)) + return 1; +#ifdef CONFIG_BLK_DEV_INITRD + if (paddr >= __pa(initrd_start) && + paddr < __pa(PAGE_ALIGN(initrd_end))) + return 1; +#endif + + return 0; +} + void __init mem_init(void) { unsigned long codepages, datapages, initpages; diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index 4e218814bb3..03f5bc9b6be 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -756,6 +756,8 @@ extern unsigned long *sparc64_valid_addr_bitmap; #define kern_addr_valid(addr) \ (test_bit(__pa((unsigned long)(addr))>>22, sparc64_valid_addr_bitmap)) +extern int page_in_phys_avail(unsigned long paddr); + extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot); -- cgit v1.2.3-70-g09d2 From de8d28b16f5614aeb12bb69c8f9a38578b8d3ada Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Jun 2006 16:18:54 -0700 Subject: [SPARC64]: Convert sparc64 PCI layer to in-kernel device tree. One thing this change pointed out was that we really should pull the "get 'local-mac-address' property" logic into a helper function all the network drivers can call. Signed-off-by: David S. Miller --- arch/sparc64/kernel/ebus.c | 6 +- arch/sparc64/kernel/isa.c | 4 +- arch/sparc64/kernel/pci_common.c | 196 ++++++++++++++++++++------------------- arch/sparc64/kernel/pci_impl.h | 3 +- arch/sparc64/kernel/pci_psycho.c | 2 +- arch/sparc64/kernel/pci_sabre.c | 4 +- arch/sparc64/kernel/pci_schizo.c | 2 +- arch/sparc64/kernel/pci_sun4v.c | 3 +- arch/sparc64/kernel/prom.c | 25 +++++ drivers/net/sungem.c | 19 ++-- drivers/net/sunhme.c | 18 ++-- drivers/net/tg3.c | 10 +- drivers/net/tulip/tulip_core.c | 12 ++- drivers/sbus/char/openprom.c | 4 +- drivers/video/aty/atyfb_base.c | 2 +- include/asm-sparc64/pbm.h | 3 +- include/asm-sparc64/prom.h | 3 + 17 files changed, 182 insertions(+), 134 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index c69504aa638..3125a5b4977 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -553,7 +553,7 @@ void __init ebus_init(void) } cookie = pdev->sysdata; - ebusnd = cookie->prom_node; + ebusnd = cookie->prom_node->node; ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); ebus->next = NULL; @@ -578,7 +578,7 @@ void __init ebus_init(void) } ebus->is_rio = is_rio; cookie = pdev->sysdata; - ebusnd = cookie->prom_node; + ebusnd = cookie->prom_node->node; continue; } printk("ebus%d:", num_ebus); @@ -622,7 +622,7 @@ void __init ebus_init(void) break; cookie = pdev->sysdata; - ebusnd = cookie->prom_node; + ebusnd = cookie->prom_node->node; ebus->next = ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index 30862abee61..ae02c3820ea 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -291,8 +291,8 @@ void __init isa_init(void) isa_br->parent = pbm; isa_br->self = pdev; isa_br->index = index++; - isa_br->prom_node = pdev_cookie->prom_node; - strncpy(isa_br->prom_name, pdev_cookie->prom_name, + isa_br->prom_node = pdev_cookie->prom_node->node; + strncpy(isa_br->prom_name, pdev_cookie->prom_node->name, sizeof(isa_br->prom_name)); prop_len = prom_getproperty(isa_br->prom_node, diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 2319d732b13..b06a2955bf5 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -9,6 +9,9 @@ #include #include +#include + +#include "pci_impl.h" /* Pass "pci=irq_verbose" on the kernel command line to enable this. */ int pci_irq_verbose; @@ -31,16 +34,14 @@ void __init pci_fixup_host_bridge_self(struct pci_bus *pbus) prom_halt(); } -/* Find the OBP PROM device tree node for a PCI device. - * Return zero if not found. - */ -static int __init find_device_prom_node(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - int bus_prom_node, - struct linux_prom_pci_registers *pregs, - int *nregs) +/* Find the OBP PROM device tree node for a PCI device. */ +static struct device_node * __init +find_device_prom_node(struct pci_pbm_info *pbm, struct pci_dev *pdev, + struct device_node *bus_node, + struct linux_prom_pci_registers **pregs, + int *nregs) { - int node; + struct device_node *dp; *nregs = 0; @@ -57,24 +58,30 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm, pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO || pdev->device == PCI_DEVICE_ID_SUN_SABRE || pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) - return bus_prom_node; - - node = prom_getchild(bus_prom_node); - while (node != 0) { - int err = prom_getproperty(node, "reg", - (char *)pregs, - sizeof(*pregs) * PROMREG_MAX); - if (err == 0 || err == -1) + return bus_node; + + dp = bus_node->child; + while (dp) { + struct linux_prom_pci_registers *regs; + struct property *prop; + int len; + + prop = of_find_property(dp, "reg", &len); + if (!prop) goto do_next_sibling; - if (((pregs[0].phys_hi >> 8) & 0xff) == pdev->devfn) { - *nregs = err / sizeof(*pregs); - return node; + + regs = prop->value; + if (((regs[0].phys_hi >> 8) & 0xff) == pdev->devfn) { + *pregs = regs; + *nregs = len / sizeof(struct linux_prom_pci_registers); + return dp; } do_next_sibling: - node = prom_getsibling(node); + dp = dp->sibling; } - return 0; + + return NULL; } /* Older versions of OBP on PCI systems encode 64-bit MEM @@ -131,15 +138,17 @@ static void __init fixup_obp_assignments(struct pci_dev *pdev, */ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, struct pci_dev *pdev, - int bus_prom_node) + struct device_node *bus_node) { - struct linux_prom_pci_registers pregs[PROMREG_MAX]; + struct linux_prom_pci_registers *pregs = NULL; struct pcidev_cookie *pcp; - int device_prom_node, nregs, err; + struct device_node *dp; + struct property *prop; + int nregs, len; - device_prom_node = find_device_prom_node(pbm, pdev, bus_prom_node, - pregs, &nregs); - if (device_prom_node == 0) { + dp = find_device_prom_node(pbm, pdev, bus_node, + &pregs, &nregs); + if (!dp) { /* If it is not in the OBP device tree then * there must be a damn good reason for it. * @@ -153,45 +162,43 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, return; } - pcp = kmalloc(sizeof(*pcp), GFP_ATOMIC); + pcp = kzalloc(sizeof(*pcp), GFP_ATOMIC); if (pcp == NULL) { prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n"); prom_halt(); } pcp->pbm = pbm; - pcp->prom_node = device_prom_node; - memcpy(pcp->prom_regs, pregs, sizeof(pcp->prom_regs)); + pcp->prom_node = dp; + memcpy(pcp->prom_regs, pregs, + nregs * sizeof(struct linux_prom_pci_registers)); pcp->num_prom_regs = nregs; - err = prom_getproperty(device_prom_node, "name", - pcp->prom_name, sizeof(pcp->prom_name)); - if (err > 0) - pcp->prom_name[err] = 0; - else - pcp->prom_name[0] = 0; - - err = prom_getproperty(device_prom_node, - "assigned-addresses", - (char *)pcp->prom_assignments, - sizeof(pcp->prom_assignments)); - if (err == 0 || err == -1) + + /* We can't have the pcidev_cookie assignments be just + * direct pointers into the property value, since they + * are potentially modified by the probing process. + */ + prop = of_find_property(dp, "assigned-addresses", &len); + if (!prop) { pcp->num_prom_assignments = 0; - else + } else { + memcpy(pcp->prom_assignments, prop->value, len); pcp->num_prom_assignments = - (err / sizeof(pcp->prom_assignments[0])); + (len / sizeof(pcp->prom_assignments[0])); + } - if (strcmp(pcp->prom_name, "ebus") == 0) { - struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX]; + if (strcmp(dp->name, "ebus") == 0) { + struct linux_prom_ebus_ranges *erng; int iter; /* EBUS is special... */ - err = prom_getproperty(device_prom_node, "ranges", - (char *)&erng[0], sizeof(erng)); - if (err == 0 || err == -1) { + prop = of_find_property(dp, "ranges", &len); + if (!prop) { prom_printf("EBUS: Fatal error, no range property\n"); prom_halt(); } - err = (err / sizeof(erng[0])); - for(iter = 0; iter < err; iter++) { + erng = prop->value; + len = (len / sizeof(erng[0])); + for (iter = 0; iter < len; iter++) { struct linux_prom_ebus_ranges *ep = &erng[iter]; struct linux_prom_pci_registers *ap; @@ -203,7 +210,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, ap->size_hi = 0; ap->size_lo = ep->size; } - pcp->num_prom_assignments = err; + pcp->num_prom_assignments = len; } fixup_obp_assignments(pdev, pcp); @@ -213,7 +220,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus, struct pci_pbm_info *pbm, - int prom_node) + struct device_node *dp) { struct pci_dev *pdev, *pdev_next; struct pci_bus *this_pbus, *pbus_next; @@ -221,7 +228,7 @@ void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus, /* This must be _safe because the cookie fillin routine can delete devices from the tree. */ list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list) - pdev_cookie_fillin(pbm, pdev, prom_node); + pdev_cookie_fillin(pbm, pdev, dp); list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) { struct pcidev_cookie *pcp = this_pbus->self->sysdata; @@ -244,7 +251,6 @@ static void __init bad_assignment(struct pci_dev *pdev, if (res) prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n", res->start, res->end, res->flags); - prom_printf("Please email this information to davem@redhat.com\n"); if (do_prom_halt) prom_halt(); } @@ -276,8 +282,7 @@ __init get_root_resource(struct linux_prom_pci_registers *ap, return &pbm->mem_space; default: - printk("PCI: What is resource space %x? " - "Tell davem@redhat.com about it!\n", space); + printk("PCI: What is resource space %x?\n", space); return NULL; }; } @@ -572,50 +577,51 @@ static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm, struct pci_dev *pbus, struct pci_dev *pdev, unsigned int interrupt, - unsigned int *cnode) + struct device_node **cnode) { - struct linux_prom_pci_intmap imap[PROM_PCIIMAP_MAX]; - struct linux_prom_pci_intmask imask; + struct linux_prom_pci_intmap *imap; + struct linux_prom_pci_intmask *imask; struct pcidev_cookie *pbus_pcp = pbus->sysdata; struct pcidev_cookie *pdev_pcp = pdev->sysdata; struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs; + struct property *prop; int plen, num_imap, i; unsigned int hi, mid, lo, irq, orig_interrupt; *cnode = pbus_pcp->prom_node; - plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map", - (char *) &imap[0], sizeof(imap)); - if (plen <= 0 || + prop = of_find_property(pbus_pcp->prom_node, "interrupt-map", &plen); + if (!prop || (plen % sizeof(struct linux_prom_pci_intmap)) != 0) { printk("%s: Device %s interrupt-map has bad len %d\n", pbm->name, pci_name(pbus), plen); goto no_intmap; } + imap = prop->value; num_imap = plen / sizeof(struct linux_prom_pci_intmap); - plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map-mask", - (char *) &imask, sizeof(imask)); - if (plen <= 0 || + prop = of_find_property(pbus_pcp->prom_node, "interrupt-map-mask", &plen); + if (!prop || (plen % sizeof(struct linux_prom_pci_intmask)) != 0) { printk("%s: Device %s interrupt-map-mask has bad len %d\n", pbm->name, pci_name(pbus), plen); goto no_intmap; } + imask = prop->value; orig_interrupt = interrupt; - hi = pregs->phys_hi & imask.phys_hi; - mid = pregs->phys_mid & imask.phys_mid; - lo = pregs->phys_lo & imask.phys_lo; - irq = interrupt & imask.interrupt; + hi = pregs->phys_hi & imask->phys_hi; + mid = pregs->phys_mid & imask->phys_mid; + lo = pregs->phys_lo & imask->phys_lo; + irq = interrupt & imask->interrupt; for (i = 0; i < num_imap; i++) { if (imap[i].phys_hi == hi && imap[i].phys_mid == mid && imap[i].phys_lo == lo && imap[i].interrupt == irq) { - *cnode = imap[i].cnode; + *cnode = of_find_node_by_phandle(imap[i].cnode); interrupt = imap[i].cinterrupt; } } @@ -638,21 +644,22 @@ no_intmap: * all interrupt translations are complete, else we should use that node's * "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt. */ -static unsigned int __init pci_intmap_match_to_root(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int *interrupt) +static struct device_node * __init +pci_intmap_match_to_root(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + unsigned int *interrupt) { struct pci_dev *toplevel_pdev = pdev; struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata; - unsigned int cnode = toplevel_pcp->prom_node; + struct device_node *cnode = toplevel_pcp->prom_node; while (pdev->bus->number != pbm->pci_first_busno) { struct pci_dev *pbus = pdev->bus->self; struct pcidev_cookie *pcp = pbus->sysdata; - int plen; + struct property *prop; - plen = prom_getproplen(pcp->prom_node, "interrupt-map"); - if (plen <= 0) { + prop = of_find_property(pcp->prom_node, "interrupt-map", NULL); + if (!prop) { *interrupt = pci_slot_swivel(pbm, toplevel_pdev, pdev, *interrupt); cnode = pcp->prom_node; @@ -669,7 +676,7 @@ static unsigned int __init pci_intmap_match_to_root(struct pci_pbm_info *pbm, } pdev = pbus; - if (cnode == pbm->prom_node->node) + if (cnode == pbm->prom_node) break; } @@ -680,21 +687,24 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt { struct pcidev_cookie *dev_pcp = pdev->sysdata; struct pci_pbm_info *pbm = dev_pcp->pbm; - struct linux_prom_pci_registers reg[PROMREG_MAX]; + struct linux_prom_pci_registers *reg; + struct device_node *cnode; + struct property *prop; unsigned int hi, mid, lo, irq; - int i, cnode, plen; + int i, plen; cnode = pci_intmap_match_to_root(pbm, pdev, interrupt); - if (cnode == pbm->prom_node->node) + if (cnode == pbm->prom_node) goto success; - plen = prom_getproperty(cnode, "reg", (char *) reg, sizeof(reg)); - if (plen <= 0 || + prop = of_find_property(cnode, "reg", &plen); + if (!prop || (plen % sizeof(struct linux_prom_pci_registers)) != 0) { - printk("%s: OBP node %x reg property has bad len %d\n", - pbm->name, cnode, plen); + printk("%s: OBP node %s reg property has bad len %d\n", + pbm->name, cnode->full_name, plen); goto fail; } + reg = prop->value; hi = reg[0].phys_hi & pbm->pbm_intmask->phys_hi; mid = reg[0].phys_mid & pbm->pbm_intmask->phys_mid; @@ -734,8 +744,8 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev) struct pci_controller_info *p = pbm->parent; unsigned int portid = pbm->portid; unsigned int prom_irq; - int prom_node = pcp->prom_node; - int err; + struct device_node *dp = pcp->prom_node; + struct property *prop; /* If this is an empty EBUS device, sometimes OBP fails to * give it a valid fully specified interrupts property. @@ -746,17 +756,17 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev) */ if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_EBUS && - !prom_getchild(prom_node)) { + !dp->child) { pdev->irq = 0; return; } - err = prom_getproperty(prom_node, "interrupts", - (char *)&prom_irq, sizeof(prom_irq)); - if (err == 0 || err == -1) { + prop = of_find_property(dp, "interrupts", NULL); + if (!prop) { pdev->irq = 0; return; } + prom_irq = *(unsigned int *) prop->value; if (tlb_type != hypervisor) { /* Fully specified already? */ diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index 6c320596254..971e2bea30b 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -10,6 +10,7 @@ #include #include #include +#include extern struct pci_controller_info *pci_controller_root; @@ -19,7 +20,7 @@ extern int pci_num_controllers; extern void pci_fixup_host_bridge_self(struct pci_bus *pbus); extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus, struct pci_pbm_info *pbm, - int prom_node); + struct device_node *prom_node); extern void pci_record_assignments(struct pci_pbm_info *pbm, struct pci_bus *pbus); extern void pci_assign_unassigned(struct pci_pbm_info *pbm, diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 40c2b681998..5b2261ebda6 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1104,7 +1104,7 @@ static void pbm_scan_bus(struct pci_controller_info *p, pci_fixup_host_bridge_self(pbm->pci_bus); pbm->pci_bus->self->sysdata = cookie; - pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node->node); + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); pci_fixup_irq(pbm, pbm->pci_bus); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 4ce7b4620c0..26f194ce440 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1161,7 +1161,7 @@ static void sabre_scan_bus(struct pci_controller_info *p) pbus->sysdata = pbm; pbm->pci_bus = pbus; - pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node->node); + pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node); pci_record_assignments(pbm, pbus); pci_assign_unassigned(pbm, pbus); pci_fixup_irq(pbm, pbus); @@ -1174,7 +1174,7 @@ static void sabre_scan_bus(struct pci_controller_info *p) pbm = &p->pbm_A; sabre_bus->sysdata = pbm; pbm->pci_bus = sabre_bus; - pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node->node); + pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node); pci_record_assignments(pbm, sabre_bus); pci_assign_unassigned(pbm, sabre_bus); pci_fixup_irq(pbm, sabre_bus); diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index d2682008684..f16449ccd7b 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1438,7 +1438,7 @@ static void pbm_scan_bus(struct pci_controller_info *p, pci_fixup_host_bridge_self(pbm->pci_bus); pbm->pci_bus->self->sysdata = cookie; - pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node->node); + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); pci_fixup_irq(pbm, pbm->pci_bus); diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index b275c7df018..b69e2270a72 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -814,8 +814,7 @@ static void pbm_scan_bus(struct pci_controller_info *p, pci_fixup_host_bridge_self(pbm->pci_bus); pbm->pci_bus->self->sysdata = cookie; #endif - pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, - pbm->prom_node->node); + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); pci_fixup_irq(pbm, pbm->pci_bus); diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 0a32b1064df..fb112c3c048 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,17 @@ struct device_node *of_find_node_by_path(const char *path) return np; } +struct device_node *of_find_node_by_phandle(phandle handle) +{ + struct device_node *np; + + for (np = allnodes; np != 0; np = np->allnext) + if (np->node == handle) + break; + + return np; +} + struct device_node *of_find_node_by_name(struct device_node *from, const char *name) { @@ -103,6 +115,18 @@ struct property *of_find_property(struct device_node *np, const char *name, } return pp; } +EXPORT_SYMBOL(of_find_property); + +/* + * Find a property with a given name for a given node + * and return the value. + */ +void *of_get_property(struct device_node *np, const char *name, int *lenp) +{ + struct property *pp = of_find_property(np,name,lenp); + return pp ? pp->value : NULL; +} +EXPORT_SYMBOL(of_get_property); int of_getintprop_default(struct device_node *np, const char *name, int def) { @@ -115,6 +139,7 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) return *(int *) prop->value; } +EXPORT_SYMBOL(of_getintprop_default); static unsigned int prom_early_allocated; diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 38cd30cb7c7..5248670d29f 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2880,17 +2880,20 @@ static int __devinit gem_get_device_address(struct gem *gp) #if defined(__sparc__) struct pci_dev *pdev = gp->pdev; struct pcidev_cookie *pcp = pdev->sysdata; - int node = -1; + int use_idprom = 1; if (pcp != NULL) { - node = pcp->prom_node; - if (prom_getproplen(node, "local-mac-address") == 6) - prom_getproperty(node, "local-mac-address", - dev->dev_addr, 6); - else - node = -1; + unsigned char *addr; + int len; + + addr = of_get_property(pcp->prom_node, "local-mac-address", + &len); + if (addr && len == 6) { + use_idprom = 0; + memcpy(dev->dev_addr, addr, 6); + } } - if (node == -1) + if (use_idprom) memcpy(dev->dev_addr, idprom->id_ethaddr, 6); #elif defined(CONFIG_PPC_PMAC) unsigned char *addr; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index bd5d2668a36..b0d452733c9 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -3013,7 +3013,6 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) struct quattro *qp = NULL; #ifdef __sparc__ struct pcidev_cookie *pcp; - int node; #endif struct happy_meal *hp; struct net_device *dev; @@ -3026,13 +3025,12 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) /* Now make sure pci_dev cookie is there. */ #ifdef __sparc__ pcp = pdev->sysdata; - if (pcp == NULL || pcp->prom_node == -1) { + if (pcp == NULL) { printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n"); return -ENODEV; } - node = pcp->prom_node; - prom_getstring(node, "name", prom_name, sizeof(prom_name)); + strcpy(prom_name, pcp->prom_node->name); #else if (is_quattro_p(pdev)) strcpy(prom_name, "SUNW,qfe"); @@ -3104,10 +3102,14 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) macaddr[5]++; } else { #ifdef __sparc__ + unsigned char *addr; + int len; + if (qfe_slot != -1 && - prom_getproplen(node, "local-mac-address") == 6) { - prom_getproperty(node, "local-mac-address", - dev->dev_addr, 6); + (addr = of_get_property(pcp->prom_node, + "local-mac-address", &len)) != NULL + && len == 6) { + memcpy(dev->dev_addr, addr, 6); } else { memcpy(dev->dev_addr, idprom->id_ethaddr, 6); } @@ -3124,7 +3126,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) hp->tcvregs = (hpreg_base + 0x7000UL); #ifdef __sparc__ - hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff); + hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff); if (hp->hm_revision == 0xff) { unsigned char prev; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e3e380f90f8..35f93163875 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10549,11 +10549,13 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp) struct pcidev_cookie *pcp = pdev->sysdata; if (pcp != NULL) { - int node = pcp->prom_node; + unsigned char *addr; + int len; - if (prom_getproplen(node, "local-mac-address") == 6) { - prom_getproperty(node, "local-mac-address", - dev->dev_addr, 6); + addr = of_get_property(pcp->prom_node, "local-mac-address", + &len); + if (addr && len == 6) { + memcpy(dev->dev_addr, addr, 6); memcpy(dev->perm_addr, dev->dev_addr, 6); return 0; } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index cabdf894e21..e0de66739a4 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1550,10 +1550,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; #if defined(__sparc__) - if ((pcp != NULL) && prom_getproplen(pcp->prom_node, - "local-mac-address") == 6) { - prom_getproperty(pcp->prom_node, "local-mac-address", - dev->dev_addr, 6); + if (pcp) { + unsigned char *addr; + int len; + + addr = of_get_property(pcp->prom_node, + "local-mac-address", &len); + if (addr && len == 6) + memcpy(dev->dev_addr, addr, 6); } #endif #if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */ diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 239e108b8ed..cf5b476b549 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -243,8 +243,8 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, ((int *) opp->oprom_array)[1]); pcp = pdev->sysdata; - if (pcp != NULL && pcp->prom_node != -1 && pcp->prom_node) { - node = pcp->prom_node; + if (pcp != NULL) { + node = pcp->prom_node->node; data->current_node = node; *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index eb6aa42be60..c054bb28b1c 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2966,7 +2966,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, } pcp = pdev->sysdata; - if (node == pcp->prom_node) { + if (node == pcp->prom_node->node) { struct fb_var_screeninfo *var = &default_var; unsigned int N, P, Q, M, T, R; u32 v_total, h_total; diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 142cc4028bb..cebe80b1da6 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -227,8 +227,7 @@ struct pci_controller_info { */ struct pcidev_cookie { struct pci_pbm_info *pbm; - char prom_name[64]; - int prom_node; + struct device_node *prom_node; struct linux_prom_pci_registers prom_regs[PROMREG_MAX]; int num_prom_regs; struct linux_prom_pci_registers prom_assignments[PROMREG_MAX]; diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index d0187b3a0ec..062ae6e1212 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -76,12 +76,15 @@ extern struct device_node *of_find_node_by_type(struct device_node *from, for (dn = of_find_node_by_type(NULL, type); dn; \ dn = of_find_node_by_type(dn, type)) extern struct device_node *of_find_node_by_path(const char *path); +extern struct device_node *of_find_node_by_phandle(phandle handle); extern struct device_node *of_get_parent(const struct device_node *node); extern struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev); extern struct property *of_find_property(struct device_node *np, const char *name, int *lenp); +extern void *of_get_property(struct device_node *node, const char *name, + int *lenp); extern int of_getintprop_default(struct device_node *np, const char *name, int def); -- cgit v1.2.3-70-g09d2 From 690c8fd31f1e35985d0f35772fde514da59ec9d1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Jun 2006 19:12:03 -0700 Subject: [SPARC64]: Use in-kernel PROM tree for EBUS and ISA. Signed-off-by: David S. Miller --- arch/sparc64/kernel/auxio.c | 2 +- arch/sparc64/kernel/ebus.c | 141 +++++++------- arch/sparc64/kernel/isa.c | 144 ++++++-------- arch/sparc64/kernel/power.c | 20 +- arch/sparc64/kernel/prom.c | 1 + arch/sparc64/kernel/time.c | 368 +++++++++++++++++++----------------- drivers/char/rtc.c | 4 +- drivers/input/misc/sparcspkr.c | 4 +- drivers/input/serio/i8042-sparcio.h | 10 +- drivers/sbus/char/bbc_envctrl.c | 4 +- drivers/sbus/char/bbc_i2c.c | 4 +- drivers/sbus/char/display7seg.c | 2 +- drivers/sbus/char/envctrl.c | 71 ++++--- drivers/sbus/char/flash.c | 16 +- drivers/serial/sunsab.c | 12 +- drivers/serial/sunsu.c | 4 +- include/asm-sparc64/ebus.h | 10 +- include/asm-sparc64/floppy.h | 27 ++- include/asm-sparc64/isa.h | 8 +- include/asm-sparc64/parport.h | 25 ++- sound/sparc/cs4231.c | 13 +- 21 files changed, 440 insertions(+), 450 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c index 8852c20c8d9..db36b66a4e3 100644 --- a/arch/sparc64/kernel/auxio.c +++ b/arch/sparc64/kernel/auxio.c @@ -136,7 +136,7 @@ found_sdev: for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "auxio")) + if (!strcmp(edev->prom_node->name, "auxio")) goto ebus_done; } } diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 3125a5b4977..919a91d9e5d 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -285,36 +285,38 @@ static inline void *ebus_alloc(size_t size) static void __init ebus_ranges_init(struct linux_ebus *ebus) { - int success; + struct linux_prom_ebus_ranges *rngs; + int len; ebus->num_ebus_ranges = 0; - success = prom_getproperty(ebus->prom_node, "ranges", - (char *)ebus->ebus_ranges, - sizeof(ebus->ebus_ranges)); - if (success != -1) - ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); + rngs = of_get_property(ebus->prom_node, "ranges", &len); + if (rngs) { + memcpy(ebus->ebus_ranges, rngs, len); + ebus->num_ebus_ranges = + (len / sizeof(struct linux_prom_ebus_ranges)); + } } static void __init ebus_intmap_init(struct linux_ebus *ebus) { - int success; + struct linux_prom_ebus_intmap *imap; + struct linux_prom_ebus_intmask *imask; + int len; ebus->num_ebus_intmap = 0; - success = prom_getproperty(ebus->prom_node, "interrupt-map", - (char *)ebus->ebus_intmap, - sizeof(ebus->ebus_intmap)); - if (success == -1) + imap = of_get_property(ebus->prom_node, "interrupt-map", &len); + if (!imap) return; - ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap)); + memcpy(ebus->ebus_intmap, imap, len); + ebus->num_ebus_intmap = (len / sizeof(struct linux_prom_ebus_intmap)); - success = prom_getproperty(ebus->prom_node, "interrupt-map-mask", - (char *)&ebus->ebus_intmask, - sizeof(ebus->ebus_intmask)); - if (success == -1) { - prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); + imask = of_get_property(ebus->prom_node, "interrupt-map-mask", &len); + if (!imask) { + prom_printf("EBUS: can't get interrupt-map-mask\n"); prom_halt(); } + memcpy(&ebus->ebus_intmask, imask, sizeof(ebus->ebus_intmask)); } int __init ebus_intmap_match(struct linux_ebus *ebus, @@ -341,19 +343,23 @@ int __init ebus_intmap_match(struct linux_ebus *ebus, return -1; } -void __init fill_ebus_child(int node, struct linux_prom_registers *preg, - struct linux_ebus_child *dev, int non_standard_regs) +void __init fill_ebus_child(struct device_node *dp, + struct linux_prom_registers *preg, + struct linux_ebus_child *dev, + int non_standard_regs) { - int regs[PROMREG_MAX]; - int irqs[PROMREG_MAX]; + int *regs; + int *irqs; int i, len; - dev->prom_node = node; - prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name)); - printk(" (%s)", dev->prom_name); + dev->prom_node = dp; + printk(" (%s)", dp->name); - len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); - dev->num_addrs = len / sizeof(regs[0]); + regs = of_get_property(dp, "reg", &len); + if (!regs) + dev->num_addrs = 0; + else + dev->num_addrs = len / sizeof(regs[0]); if (non_standard_regs) { /* This is to handle reg properties which are not @@ -370,21 +376,21 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg, int rnum = regs[i]; if (rnum >= dev->parent->num_addrs) { prom_printf("UGH: property for %s was %d, need < %d\n", - dev->prom_name, len, dev->parent->num_addrs); - panic(__FUNCTION__); + dp->name, len, dev->parent->num_addrs); + prom_halt(); } dev->resource[i].start = dev->parent->resource[i].start; dev->resource[i].end = dev->parent->resource[i].end; dev->resource[i].flags = IORESOURCE_MEM; - dev->resource[i].name = dev->prom_name; + dev->resource[i].name = dp->name; } } for (i = 0; i < PROMINTR_MAX; i++) dev->irqs[i] = PCI_IRQ_NONE; - len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); - if ((len == -1) || (len == 0)) { + irqs = of_get_property(dp, "interrupts", &len); + if (!irqs) { dev->num_irqs = 0; /* * Oh, well, some PROMs don't export interrupts @@ -392,8 +398,8 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg, * * Be smart about PS/2 keyboard and mouse. */ - if (!strcmp(dev->parent->prom_name, "8042")) { - if (!strcmp(dev->prom_name, "kb_ps2")) { + if (!strcmp(dev->parent->prom_node->name, "8042")) { + if (!strcmp(dev->prom_node->name, "kb_ps2")) { dev->num_irqs = 1; dev->irqs[0] = dev->parent->irqs[0]; } else { @@ -423,32 +429,32 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg, static int __init child_regs_nonstandard(struct linux_ebus_device *dev) { - if (!strcmp(dev->prom_name, "i2c") || - !strcmp(dev->prom_name, "SUNW,lombus")) + if (!strcmp(dev->prom_node->name, "i2c") || + !strcmp(dev->prom_node->name, "SUNW,lombus")) return 1; return 0; } -void __init fill_ebus_device(int node, struct linux_ebus_device *dev) +void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) { - struct linux_prom_registers regs[PROMREG_MAX]; + struct linux_prom_registers *regs; struct linux_ebus_child *child; - int irqs[PROMINTR_MAX]; + int *irqs; int i, n, len; - dev->prom_node = node; - prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name)); - printk(" [%s", dev->prom_name); + dev->prom_node = dp; - len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); - if (len == -1) { + printk(" [%s", dp->name); + + regs = of_get_property(dp, "reg", &len); + if (!regs) { dev->num_addrs = 0; goto probe_interrupts; } if (len % sizeof(struct linux_prom_registers)) { prom_printf("UGH: proplen for %s was %d, need multiple of %d\n", - dev->prom_name, len, + dev->prom_node->name, len, (int)sizeof(struct linux_prom_registers)); prom_halt(); } @@ -466,7 +472,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev) dev->resource[i].end = (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL); dev->resource[i].flags = IORESOURCE_MEM; - dev->resource[i].name = dev->prom_name; + dev->resource[i].name = dev->prom_node->name; request_resource(&dev->bus->self->resource[n], &dev->resource[i]); } @@ -475,8 +481,8 @@ probe_interrupts: for (i = 0; i < PROMINTR_MAX; i++) dev->irqs[i] = PCI_IRQ_NONE; - len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); - if ((len == -1) || (len == 0)) { + irqs = of_get_property(dp, "interrupts", &len); + if (!irqs) { dev->num_irqs = 0; } else { dev->num_irqs = len / sizeof(irqs[0]); @@ -497,7 +503,8 @@ probe_interrupts: } } - if ((node = prom_getchild(node))) { + dp = dp->child; + if (dp) { printk(" ->"); dev->children = ebus_alloc(sizeof(struct linux_ebus_child)); @@ -505,18 +512,18 @@ probe_interrupts: child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(node, ®s[0], - child, child_regs_nonstandard(dev)); + fill_ebus_child(dp, regs, child, + child_regs_nonstandard(dev)); - while ((node = prom_getsibling(node)) != 0) { + while ((dp = dp->sibling) != NULL) { child->next = ebus_alloc(sizeof(struct linux_ebus_child)); child = child->next; child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(node, ®s[0], - child, child_regs_nonstandard(dev)); + fill_ebus_child(dp, regs, child, + child_regs_nonstandard(dev)); } } printk("]"); @@ -543,7 +550,8 @@ void __init ebus_init(void) struct linux_ebus *ebus; struct pci_dev *pdev; struct pcidev_cookie *cookie; - int nd, ebusnd, is_rio; + struct device_node *dp; + int is_rio; int num_ebus = 0; pdev = find_next_ebus(NULL, &is_rio); @@ -553,20 +561,22 @@ void __init ebus_init(void) } cookie = pdev->sysdata; - ebusnd = cookie->prom_node->node; + dp = cookie->prom_node; ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); ebus->next = NULL; ebus->is_rio = is_rio; - while (ebusnd) { + while (dp) { + struct device_node *child; + /* SUNW,pci-qfe uses four empty ebuses on it. I think we should not consider them here, as they have half of the properties this code expects and once we do PCI hot-plug, we'd have to tweak with the ebus_chain in the runtime after initialization. -jj */ - if (!prom_getchild (ebusnd)) { + if (!dp->child) { pdev = find_next_ebus(pdev, &is_rio); if (!pdev) { if (ebus == ebus_chain) { @@ -578,22 +588,21 @@ void __init ebus_init(void) } ebus->is_rio = is_rio; cookie = pdev->sysdata; - ebusnd = cookie->prom_node->node; + dp = cookie->prom_node; continue; } printk("ebus%d:", num_ebus); - prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name)); ebus->index = num_ebus; - ebus->prom_node = ebusnd; + ebus->prom_node = dp; ebus->self = pdev; ebus->parent = pbm = cookie->pbm; ebus_ranges_init(ebus); ebus_intmap_init(ebus); - nd = prom_getchild(ebusnd); - if (!nd) + child = dp->child; + if (!child) goto next_ebus; ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device)); @@ -602,16 +611,16 @@ void __init ebus_init(void) dev->next = NULL; dev->children = NULL; dev->bus = ebus; - fill_ebus_device(nd, dev); + fill_ebus_device(child, dev); - while ((nd = prom_getsibling(nd)) != 0) { + while ((child = child->sibling) != NULL) { dev->next = ebus_alloc(sizeof(struct linux_ebus_device)); dev = dev->next; dev->next = NULL; dev->children = NULL; dev->bus = ebus; - fill_ebus_device(nd, dev); + fill_ebus_device(child, dev); } next_ebus: @@ -622,7 +631,7 @@ void __init ebus_init(void) break; cookie = pdev->sysdata; - ebusnd = cookie->prom_node->node; + dp = cookie->prom_node; ebus->next = ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index ae02c3820ea..8c8c5a491ad 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -15,23 +15,19 @@ static void __init fatal_err(const char *reason) static void __init report_dev(struct sparc_isa_device *isa_dev, int child) { if (child) - printk(" (%s)", isa_dev->prom_name); + printk(" (%s)", isa_dev->prom_node->name); else - printk(" [%s", isa_dev->prom_name); + printk(" [%s", isa_dev->prom_node->name); } -static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev, - struct linux_prom_registers *pregs, - int pregs_size) +static struct linux_prom_registers * __init +isa_dev_get_resource(struct sparc_isa_device *isa_dev) { + struct linux_prom_registers *pregs; unsigned long base, len; int prop_len; - prop_len = prom_getproperty(isa_dev->prom_node, "reg", - (char *) pregs, pregs_size); - - if (prop_len <= 0) - return; + pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len); /* Only the first one is interesting. */ len = pregs[0].reg_size; @@ -42,10 +38,12 @@ static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev, isa_dev->resource.start = base; isa_dev->resource.end = (base + len - 1UL); isa_dev->resource.flags = IORESOURCE_IO; - isa_dev->resource.name = isa_dev->prom_name; + isa_dev->resource.name = isa_dev->prom_node->name; request_resource(&isa_dev->bus->parent->io_space, &isa_dev->resource); + + return pregs; } /* I can't believe they didn't put a real INO in the isa device @@ -98,8 +96,8 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev, { int irq_prop; - irq_prop = prom_getintdefault(isa_dev->prom_node, - "interrupts", -1); + irq_prop = of_getintprop_default(isa_dev->prom_node, + "interrupts", -1); if (irq_prop <= 0) { goto no_irq; } else { @@ -141,16 +139,15 @@ no_irq: static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) { - int node = prom_getchild(parent_isa_dev->prom_node); + struct device_node *dp = parent_isa_dev->prom_node->child; - if (node == 0) + if (!dp) return; printk(" ->"); - while (node != 0) { - struct linux_prom_registers regs[PROMREG_MAX]; + while (dp) { + struct linux_prom_registers *regs; struct sparc_isa_device *isa_dev; - int prop_len; isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL); if (!isa_dev) { @@ -165,40 +162,24 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) parent_isa_dev->child = isa_dev; isa_dev->bus = parent_isa_dev->bus; - isa_dev->prom_node = node; - prop_len = prom_getproperty(node, "name", - (char *) isa_dev->prom_name, - sizeof(isa_dev->prom_name)); - if (prop_len <= 0) { - fatal_err("cannot get child isa_dev OBP node name"); - prom_halt(); - } - - prop_len = prom_getproperty(node, "compatible", - (char *) isa_dev->compatible, - sizeof(isa_dev->compatible)); + isa_dev->prom_node = dp; - /* Not having this is OK. */ - if (prop_len <= 0) - isa_dev->compatible[0] = '\0'; - - isa_dev_get_resource(isa_dev, regs, sizeof(regs)); + regs = isa_dev_get_resource(isa_dev); isa_dev_get_irq(isa_dev, regs); report_dev(isa_dev, 1); - node = prom_getsibling(node); + dp = dp->sibling; } } static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) { - int node = prom_getchild(isa_br->prom_node); + struct device_node *dp = isa_br->prom_node->child; - while (node != 0) { - struct linux_prom_registers regs[PROMREG_MAX]; + while (dp) { + struct linux_prom_registers *regs; struct sparc_isa_device *isa_dev; - int prop_len; isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL); if (!isa_dev) { @@ -222,24 +203,9 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) } isa_dev->bus = isa_br; - isa_dev->prom_node = node; - prop_len = prom_getproperty(node, "name", - (char *) isa_dev->prom_name, - sizeof(isa_dev->prom_name)); - if (prop_len <= 0) { - fatal_err("cannot get isa_dev OBP node name"); - prom_halt(); - } - - prop_len = prom_getproperty(node, "compatible", - (char *) isa_dev->compatible, - sizeof(isa_dev->compatible)); - - /* Not having this is OK. */ - if (prop_len <= 0) - isa_dev->compatible[0] = '\0'; + isa_dev->prom_node = dp; - isa_dev_get_resource(isa_dev, regs, sizeof(regs)); + regs = isa_dev_get_resource(isa_dev); isa_dev_get_irq(isa_dev, regs); report_dev(isa_dev, 0); @@ -248,10 +214,40 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) printk("]"); - node = prom_getsibling(node); + dp = dp->sibling; } } +static void __init get_bridge_props(struct sparc_isa_bridge *isa_br) +{ + struct device_node *dp = isa_br->prom_node; + void *pval; + int len; + + pval = of_get_property(dp, "ranges", &len); + if (pval) { + memcpy(isa_br->isa_ranges, pval, len); + isa_br->num_isa_ranges = + len / sizeof(struct linux_prom_isa_ranges); + } else { + isa_br->num_isa_ranges = 0; + } + + pval = of_get_property(dp, "interrupt-map", &len); + if (pval) { + memcpy(isa_br->isa_intmap, pval, len); + isa_br->num_isa_intmap = + (len / sizeof(struct linux_prom_isa_intmap)); + } else { + isa_br->num_isa_intmap = 0; + } + + pval = of_get_property(dp, "interrupt-map-mask", &len); + if (pval) + memcpy(&isa_br->isa_intmask, pval, + sizeof(isa_br->isa_intmask)); +} + void __init isa_init(void) { struct pci_dev *pdev; @@ -266,7 +262,6 @@ void __init isa_init(void) struct pcidev_cookie *pdev_cookie; struct pci_pbm_info *pbm; struct sparc_isa_bridge *isa_br; - int prop_len; pdev_cookie = pdev->sysdata; if (!pdev_cookie) { @@ -291,34 +286,9 @@ void __init isa_init(void) isa_br->parent = pbm; isa_br->self = pdev; isa_br->index = index++; - isa_br->prom_node = pdev_cookie->prom_node->node; - strncpy(isa_br->prom_name, pdev_cookie->prom_node->name, - sizeof(isa_br->prom_name)); - - prop_len = prom_getproperty(isa_br->prom_node, - "ranges", - (char *) isa_br->isa_ranges, - sizeof(isa_br->isa_ranges)); - if (prop_len <= 0) - isa_br->num_isa_ranges = 0; - else - isa_br->num_isa_ranges = - (prop_len / sizeof(struct linux_prom_isa_ranges)); - - prop_len = prom_getproperty(isa_br->prom_node, - "interrupt-map", - (char *) isa_br->isa_intmap, - sizeof(isa_br->isa_intmap)); - if (prop_len <= 0) - isa_br->num_isa_intmap = 0; - else - isa_br->num_isa_intmap = - (prop_len / sizeof(struct linux_prom_isa_intmap)); - - prop_len = prom_getproperty(isa_br->prom_node, - "interrupt-map-mask", - (char *) &(isa_br->isa_intmask), - sizeof(isa_br->isa_intmask)); + isa_br->prom_node = pdev_cookie->prom_node; + + get_bridge_props(isa_br); printk("isa%d:", isa_br->index); diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 30bcaf58e3a..75159a7843f 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -105,24 +105,24 @@ again: return 0; } -static int __init has_button_interrupt(unsigned int irq, int prom_node) +static int __init has_button_interrupt(unsigned int irq, struct device_node *dp) { if (irq == PCI_IRQ_NONE) return 0; - if (!prom_node_has_property(prom_node, "button")) + if (!of_find_property(dp, "button", NULL)) return 0; return 1; } -static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, int *prom_node_p) +static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, struct device_node **prom_node_p) { struct linux_ebus *ebus; struct linux_ebus_device *edev; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "power")) { + if (!strcmp(edev->prom_node->name, "power")) { *resp = &edev->resource[0]; *irq_p = edev->irqs[0]; *prom_node_p = edev->prom_node; @@ -133,14 +133,14 @@ static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, return -ENODEV; } -static int __init power_probe_isa(struct resource **resp, unsigned int *irq_p, int *prom_node_p) +static int __init power_probe_isa(struct resource **resp, unsigned int *irq_p, struct device_node **prom_node_p) { struct sparc_isa_bridge *isa_bus; struct sparc_isa_device *isa_dev; for_each_isa(isa_bus) { for_each_isadev(isa_dev, isa_bus) { - if (!strcmp(isa_dev->prom_name, "power")) { + if (!strcmp(isa_dev->prom_node->name, "power")) { *resp = &isa_dev->resource; *irq_p = isa_dev->irq; *prom_node_p = isa_dev->prom_node; @@ -155,17 +155,17 @@ void __init power_init(void) { struct resource *res = NULL; unsigned int irq; - int prom_node; + struct device_node *dp; static int invoked; if (invoked) return; invoked = 1; - if (!power_probe_ebus(&res, &irq, &prom_node)) + if (!power_probe_ebus(&res, &irq, &dp)) goto found; - if (!power_probe_isa(&res, &irq, &prom_node)) + if (!power_probe_isa(&res, &irq, &dp)) goto found; return; @@ -174,7 +174,7 @@ found: power_reg = ioremap(res->start, 0x4); printk("power: Control reg at %p ... ", power_reg); poweroff_method = machine_halt; /* able to use the standard halt */ - if (has_button_interrupt(irq, prom_node)) { + if (has_button_interrupt(irq, dp)) { if (kernel_thread(powerd, NULL, CLONE_FS) < 0) { printk("Failed to start power daemon.\n"); return; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index fb112c3c048..7809100034b 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -63,6 +63,7 @@ struct device_node *of_find_node_by_path(const char *path) return np; } +EXPORT_SYMBOL(of_find_node_by_path); struct device_node *of_find_node_by_phandle(phandle handle) { diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index aa5438a4fd5..d072b8632cc 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -756,24 +756,200 @@ retry: return -EOPNOTSUPP; } -void __init clock_probe(void) +static int __init clock_model_matches(char *model) +{ + if (strcmp(model, "mk48t02") && + strcmp(model, "mk48t08") && + strcmp(model, "mk48t59") && + strcmp(model, "m5819") && + strcmp(model, "m5819p") && + strcmp(model, "m5823") && + strcmp(model, "ds1287")) + return 0; + + return 1; +} + +static void __init __clock_assign_common(void __iomem *addr, char *model) +{ + if (model[5] == '0' && model[6] == '2') { + mstk48t02_regs = addr; + } else if(model[5] == '0' && model[6] == '8') { + mstk48t08_regs = addr; + mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; + } else { + mstk48t59_regs = addr; + mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; + } +} + +static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg, + char *model) +{ + unsigned long addr; + + addr = ((unsigned long) clk_reg[0].phys_addr | + (((unsigned long) clk_reg[0].which_io) << 32UL)); + + __clock_assign_common((void __iomem *) addr, model); +} + +static int __init clock_probe_central(void) { struct linux_prom_registers clk_reg[2]; - char model[128]; - int node, busnd = -1, err; - unsigned long flags; - struct linux_central *cbus; + char model[64]; + int node; + + if (!central_bus) + return 0; + + /* Get Central FHC's prom node. */ + node = central_bus->child->prom_node; + + /* Then get the first child device below it. */ + node = prom_getchild(node); + + while (node) { + prom_getstring(node, "model", model, sizeof(model)); + if (!clock_model_matches(model)) + goto next_sibling; + + prom_getproperty(node, "reg", (char *)clk_reg, + sizeof(clk_reg)); + + apply_fhc_ranges(central_bus->child, clk_reg, 1); + apply_central_ranges(central_bus, clk_reg, 1); + + clock_assign_clk_reg(clk_reg, model); + return 1; + + next_sibling: + node = prom_getsibling(node); + } + + return 0; +} + #ifdef CONFIG_PCI - struct linux_ebus *ebus = NULL; - struct sparc_isa_bridge *isa_br = NULL; +static void __init clock_isa_ebus_assign_regs(struct resource *res, char *model) +{ + if (!strcmp(model, "ds1287") || + !strcmp(model, "m5819") || + !strcmp(model, "m5819p") || + !strcmp(model, "m5823")) { + ds1287_regs = res->start; + } else { + mstk48t59_regs = (void __iomem *) res->start; + mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; + } +} + +static int __init clock_probe_one_ebus_dev(struct linux_ebus_device *edev) +{ + struct device_node *dp = edev->prom_node; + char *model; + + model = of_get_property(dp, "model", NULL); + if (!clock_model_matches(model)) + return 0; + + clock_isa_ebus_assign_regs(&edev->resource[0], model); + + return 1; +} + +static int __init clock_probe_ebus(void) +{ + struct linux_ebus *ebus; + + for_each_ebus(ebus) { + struct linux_ebus_device *edev; + + for_each_ebusdev(edev, ebus) { + if (clock_probe_one_ebus_dev(edev)) + return 1; + } + } + + return 0; +} + +static int __init clock_probe_one_isa_dev(struct sparc_isa_device *idev) +{ + struct device_node *dp = idev->prom_node; + char *model; + + model = of_get_property(dp, "model", NULL); + if (!clock_model_matches(model)) + return 0; + + clock_isa_ebus_assign_regs(&idev->resource, model); + + return 1; +} + +static int __init clock_probe_isa(void) +{ + struct sparc_isa_bridge *isa_br; + + for_each_isa(isa_br) { + struct sparc_isa_device *isa_dev; + + for_each_isadev(isa_dev, isa_br) { + if (clock_probe_one_isa_dev(isa_dev)) + return 1; + } + } + + return 0; +} +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_SBUS +static int __init clock_probe_one_sbus_dev(struct sbus_bus *sbus, struct sbus_dev *sdev) +{ + struct resource *res; + char model[64]; + void __iomem *addr; + + prom_getstring(sdev->prom_node, "model", model, sizeof(model)); + if (!clock_model_matches(model)) + return 0; + + res = &sdev->resource[0]; + addr = sbus_ioremap(res, 0, 0x800UL, "eeprom"); + + __clock_assign_common(addr, model); + + return 1; +} + +static int __init clock_probe_sbus(void) +{ + struct sbus_bus *sbus; + + for_each_sbus(sbus) { + struct sbus_dev *sdev; + + for_each_sbusdev(sdev, sbus) { + if (clock_probe_one_sbus_dev(sbus, sdev)) + return 1; + } + } + + return 0; +} #endif + +void __init clock_probe(void) +{ static int invoked; + unsigned long flags; if (invoked) return; invoked = 1; - if (this_is_starfire) { xtime.tv_sec = starfire_get_time(); xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); @@ -789,183 +965,27 @@ void __init clock_probe(void) return; } - local_irq_save(flags); - - cbus = central_bus; - if (cbus != NULL) - busnd = central_bus->child->prom_node; - /* Check FHC Central then EBUSs then ISA bridges then SBUSs. * That way we handle the presence of multiple properly. * * As a special case, machines with Central must provide the * timer chip there. */ + if (!clock_probe_central() && #ifdef CONFIG_PCI - if (ebus_chain != NULL) { - ebus = ebus_chain; - if (busnd == -1) - busnd = ebus->prom_node; - } - if (isa_chain != NULL) { - isa_br = isa_chain; - if (busnd == -1) - busnd = isa_br->prom_node; - } -#endif - if (sbus_root != NULL && busnd == -1) - busnd = sbus_root->prom_node; - - if (busnd == -1) { - prom_printf("clock_probe: problem, cannot find bus to search.\n"); - prom_halt(); - } - - node = prom_getchild(busnd); - - while (1) { - if (!node) - model[0] = 0; - else - prom_getstring(node, "model", model, sizeof(model)); - if (strcmp(model, "mk48t02") && - strcmp(model, "mk48t08") && - strcmp(model, "mk48t59") && - strcmp(model, "m5819") && - strcmp(model, "m5819p") && - strcmp(model, "m5823") && - strcmp(model, "ds1287")) { - if (cbus != NULL) { - prom_printf("clock_probe: Central bus lacks timer chip.\n"); - prom_halt(); - } - - if (node != 0) - node = prom_getsibling(node); -#ifdef CONFIG_PCI - while ((node == 0) && ebus != NULL) { - ebus = ebus->next; - if (ebus != NULL) { - busnd = ebus->prom_node; - node = prom_getchild(busnd); - } - } - while ((node == 0) && isa_br != NULL) { - isa_br = isa_br->next; - if (isa_br != NULL) { - busnd = isa_br->prom_node; - node = prom_getchild(busnd); - } - } + !clock_probe_ebus() && + !clock_probe_isa() && #endif - if (node == 0) { - prom_printf("clock_probe: Cannot find timer chip\n"); - prom_halt(); - } - continue; - } - - err = prom_getproperty(node, "reg", (char *)clk_reg, - sizeof(clk_reg)); - if(err == -1) { - prom_printf("clock_probe: Cannot get Mostek reg property\n"); - prom_halt(); - } - - if (cbus != NULL) { - apply_fhc_ranges(central_bus->child, clk_reg, 1); - apply_central_ranges(central_bus, clk_reg, 1); - } -#ifdef CONFIG_PCI - else if (ebus != NULL) { - struct linux_ebus_device *edev; - - for_each_ebusdev(edev, ebus) - if (edev->prom_node == node) - break; - if (edev == NULL) { - if (isa_chain != NULL) - goto try_isa_clock; - prom_printf("%s: Mostek not probed by EBUS\n", - __FUNCTION__); - prom_halt(); - } - - if (!strcmp(model, "ds1287") || - !strcmp(model, "m5819") || - !strcmp(model, "m5819p") || - !strcmp(model, "m5823")) { - ds1287_regs = edev->resource[0].start; - } else { - mstk48t59_regs = (void __iomem *) - edev->resource[0].start; - mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; - } - break; - } - else if (isa_br != NULL) { - struct sparc_isa_device *isadev; - -try_isa_clock: - for_each_isadev(isadev, isa_br) - if (isadev->prom_node == node) - break; - if (isadev == NULL) { - prom_printf("%s: Mostek not probed by ISA\n"); - prom_halt(); - } - if (!strcmp(model, "ds1287") || - !strcmp(model, "m5819") || - !strcmp(model, "m5819p") || - !strcmp(model, "m5823")) { - ds1287_regs = isadev->resource.start; - } else { - mstk48t59_regs = (void __iomem *) - isadev->resource.start; - mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; - } - break; - } +#ifdef CONFIG_SBUS + !clock_probe_sbus() #endif - else { - if (sbus_root->num_sbus_ranges) { - int nranges = sbus_root->num_sbus_ranges; - int rngc; - - for (rngc = 0; rngc < nranges; rngc++) - if (clk_reg[0].which_io == - sbus_root->sbus_ranges[rngc].ot_child_space) - break; - if (rngc == nranges) { - prom_printf("clock_probe: Cannot find ranges for " - "clock regs.\n"); - prom_halt(); - } - clk_reg[0].which_io = - sbus_root->sbus_ranges[rngc].ot_parent_space; - clk_reg[0].phys_addr += - sbus_root->sbus_ranges[rngc].ot_parent_base; - } - } - - if(model[5] == '0' && model[6] == '2') { - mstk48t02_regs = (void __iomem *) - (((u64)clk_reg[0].phys_addr) | - (((u64)clk_reg[0].which_io)<<32UL)); - } else if(model[5] == '0' && model[6] == '8') { - mstk48t08_regs = (void __iomem *) - (((u64)clk_reg[0].phys_addr) | - (((u64)clk_reg[0].which_io)<<32UL)); - mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; - } else { - mstk48t59_regs = (void __iomem *) - (((u64)clk_reg[0].phys_addr) | - (((u64)clk_reg[0].which_io)<<32UL)); - mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; - } - break; + ) { + printk(KERN_WARNING "No clock chip found.\n"); + return; } + local_irq_save(flags); + if (mstk48t02_regs != NULL) { /* Report a low battery voltage condition. */ if (has_low_battery()) diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index f6686fcce80..0897b0c8d52 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -928,7 +928,7 @@ static int __init rtc_init(void) #ifdef __sparc__ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if(strcmp(edev->prom_name, "rtc") == 0) { + if(strcmp(edev->prom_node->name, "rtc") == 0) { rtc_port = edev->resource[0].start; rtc_irq = edev->irqs[0]; goto found; @@ -938,7 +938,7 @@ static int __init rtc_init(void) #ifdef __sparc_v9__ for_each_isa(isa_br) { for_each_isadev(isa_dev, isa_br) { - if (strcmp(isa_dev->prom_name, "rtc") == 0) { + if (strcmp(isa_dev->prom_node->name, "rtc") == 0) { rtc_port = isa_dev->resource.start; rtc_irq = isa_dev->irq; goto found; diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index f0fd2c4740f..ed95dc9420d 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -199,7 +199,7 @@ static int __init sparcspkr_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "beep")) { + if (!strcmp(edev->prom_node->name, "beep")) { beep_name = "Sparc EBUS Speaker"; beep_event = ebus_spkr_event; beep_iobase = edev->resource[0].start; @@ -213,7 +213,7 @@ static int __init sparcspkr_init(void) /* A hack, the beep device's base lives in * the DMA isa node. */ - if (!strcmp(isa_dev->prom_name, "dma")) { + if (!strcmp(isa_dev->prom_node->name, "dma")) { beep_name = "Sparc ISA Speaker"; beep_event = isa_spkr_event, beep_iobase = isa_dev->resource.start; diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index ed9446f6d7e..6d66351805a 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -74,7 +74,7 @@ static int __init i8042_platform_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "8042")) + if (!strcmp(edev->prom_node->name, "8042")) goto edev_found; } } @@ -82,14 +82,14 @@ static int __init i8042_platform_init(void) edev_found: for_each_edevchild(edev, child) { - if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) || - !strcmp(child->prom_name, OBP_PS2KBD_NAME2)) { + if (!strcmp(child->prom_node->name, OBP_PS2KBD_NAME1) || + !strcmp(child->prom_node->name, OBP_PS2KBD_NAME2)) { i8042_kbd_irq = child->irqs[0]; kbd_iobase = ioremap(child->resource[0].start, 8); } - if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) || - !strcmp(child->prom_name, OBP_PS2MS_NAME2)) + if (!strcmp(child->prom_node->name, OBP_PS2MS_NAME1) || + !strcmp(child->prom_node->name, OBP_PS2MS_NAME2)) i8042_aux_irq = child->irqs[0]; } if (i8042_kbd_irq == -1 || diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index d89f83f769f..1cc706e1111 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -575,9 +575,9 @@ int bbc_envctrl_init(void) int devidx = 0; while ((echild = bbc_i2c_getdev(devidx++)) != NULL) { - if (!strcmp(echild->prom_name, "temperature")) + if (!strcmp(echild->prom_node->name, "temperature")) attach_one_temp(echild, temp_index++); - if (!strcmp(echild->prom_name, "fan-control")) + if (!strcmp(echild->prom_node->name, "fan-control")) attach_one_fan(echild, fan_index++); } if (temp_index != 0 && fan_index != 0) { diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 3e156e005f2..73634371393 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -423,7 +423,7 @@ static int __init bbc_present(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "bbc")) + if (!strcmp(edev->prom_node->name, "bbc")) return 1; } } @@ -446,7 +446,7 @@ static int __init bbc_i2c_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "i2c")) { + if (!strcmp(edev->prom_node->name, "i2c")) { if (!attach_one_i2c(edev, index)) index++; } diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index c3a51d1fae5..d92bc8827a9 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -184,7 +184,7 @@ static int __init d7s_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, D7S_OBPNAME)) + if (!strcmp(edev->prom_node->name, D7S_OBPNAME)) goto ebus_done; } } diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 19e8eddf887..cf97e9efe9b 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -768,16 +768,14 @@ static void envctrl_set_mon(struct i2c_child_t *pchild, * decoding tables, monitor type, optional properties. * Return: None. */ -static void envctrl_init_adc(struct i2c_child_t *pchild, int node) +static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp) { - char chnls_desc[CHANNEL_DESC_SZ]; int i = 0, len; - char *pos = chnls_desc; + char *pos; + unsigned int *pval; /* Firmware describe channels into a stream separated by a '\0'. */ - len = prom_getproperty(node, "channels-description", chnls_desc, - CHANNEL_DESC_SZ); - chnls_desc[CHANNEL_DESC_SZ - 1] = '\0'; + pos = of_get_property(dp, "channels-description", &len); while (len > 0) { int l = strlen(pos) + 1; @@ -787,10 +785,13 @@ static void envctrl_init_adc(struct i2c_child_t *pchild, int node) } /* Get optional properties. */ - len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature, - sizeof(warning_temperature)); - len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature, - sizeof(shutdown_temperature)); + pval = of_get_property(dp, "warning-temp", NULL); + if (pval) + warning_temperature = *pval; + + pval = of_get_property(dp, "shutdown-temp", NULL); + if (pval) + shutdown_temperature = *pval; } /* Function Description: Initialize child device monitoring fan status. @@ -864,21 +865,18 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild) static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, struct i2c_child_t *pchild) { - int node, len, i, tbls_size = 0; - - node = edev_child->prom_node; + int len, i, tbls_size = 0; + struct device_node *dp = edev_child->prom_node; + void *pval; /* Get device address. */ - len = prom_getproperty(node, "reg", - (char *) &(pchild->addr), - sizeof(pchild->addr)); + pval = of_get_property(dp, "reg", &len); + memcpy(&pchild->addr, pval, len); /* Get tables property. Read firmware temperature tables. */ - len = prom_getproperty(node, "translation", - (char *) pchild->tblprop_array, - (PCF8584_MAX_CHANNELS * - sizeof(struct pcf8584_tblprop))); - if (len > 0) { + pval = of_get_property(dp, "translation", &len); + if (pval && len > 0) { + memcpy(pchild->tblprop_array, pval, len); pchild->total_tbls = len / sizeof(struct pcf8584_tblprop); for (i = 0; i < pchild->total_tbls; i++) { if ((pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset) > tbls_size) { @@ -891,12 +889,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, printk("envctrl: Failed to allocate table.\n"); return; } - len = prom_getproperty(node, "tables", - (char *) pchild->tables, tbls_size); - if (len <= 0) { + pval = of_get_property(dp, "tables", &len); + if (!pval || len <= 0) { printk("envctrl: Failed to get table.\n"); return; } + memcpy(pchild->tables, pval, len); } /* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04) @@ -907,12 +905,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, * 'NULL' monitor type. */ if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) { + struct device_node *root_node; int len; - char prop[56]; - len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); - if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len))) - { + root_node = of_find_node_by_path("/"); + if (!strcmp(root_node->name, "SUNW,UltraSPARC-IIi-cEngine")) { for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) { pchild->mon_type[len] = ENVCTRL_NOMON; } @@ -921,16 +918,14 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, } /* Get the monitor channels. */ - len = prom_getproperty(node, "channels-in-use", - (char *) pchild->chnl_array, - (PCF8584_MAX_CHANNELS * - sizeof(struct pcf8584_channel))); + pval = of_get_property(dp, "channels-in-use", &len); + memcpy(pchild->chnl_array, pval, len); pchild->total_chnls = len / sizeof(struct pcf8584_channel); for (i = 0; i < pchild->total_chnls; i++) { switch (pchild->chnl_array[i].type) { case PCF8584_TEMP_TYPE: - envctrl_init_adc(pchild, node); + envctrl_init_adc(pchild, dp); break; case PCF8584_GLOBALADDR_TYPE: @@ -945,7 +940,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, case PCF8584_VOLTAGE_TYPE: if (pchild->i2ctype == I2C_ADC) { - envctrl_init_adc(pchild,node); + envctrl_init_adc(pchild,dp); } else { envctrl_init_voltage_status(pchild); } @@ -1046,7 +1041,7 @@ static int __init envctrl_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "bbc")) { + if (!strcmp(edev->prom_node->name, "bbc")) { /* If we find a boot-bus controller node, * then this envctrl driver is not for us. */ @@ -1060,14 +1055,14 @@ static int __init envctrl_init(void) */ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "i2c")) { + if (!strcmp(edev->prom_node->name, "i2c")) { i2c = ioremap(edev->resource[0].start, 0x2); for_each_edevchild(edev, edev_child) { - if (!strcmp("gpio", edev_child->prom_name)) { + if (!strcmp("gpio", edev_child->prom_node->name)) { i2c_childlist[i].i2ctype = I2C_GPIO; envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); } - if (!strcmp("adc", edev_child->prom_name)) { + if (!strcmp("adc", edev_child->prom_node->name)) { i2c_childlist[i].i2ctype = I2C_ADC; envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); } diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 2beb3dded08..5ae684c011f 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -192,9 +192,11 @@ static int __init flash_init(void) } if (!sdev) { #ifdef CONFIG_PCI + struct linux_prom_registers *ebus_regs; + for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "flashprom")) + if (!strcmp(edev->prom_node->name, "flashprom")) goto ebus_done; } } @@ -202,23 +204,23 @@ static int __init flash_init(void) if (!edev) return -ENODEV; - len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs)); - if ((len % sizeof(regs[0])) != 0) { + ebus_regs = of_get_property(edev->prom_node, "reg", &len); + if (!ebus_regs || (len % sizeof(regs[0])) != 0) { printk("flash: Strange reg property size %d\n", len); return -ENODEV; } - nregs = len / sizeof(regs[0]); + nregs = len / sizeof(ebus_regs[0]); flash.read_base = edev->resource[0].start; - flash.read_size = regs[0].reg_size; + flash.read_size = ebus_regs[0].reg_size; if (nregs == 1) { flash.write_base = edev->resource[0].start; - flash.write_size = regs[0].reg_size; + flash.write_size = ebus_regs[0].reg_size; } else if (nregs == 2) { flash.write_base = edev->resource[1].start; - flash.write_size = regs[1].reg_size; + flash.write_size = ebus_regs[1].reg_size; } else { printk("flash: Strange number of regs %d\n", nregs); return -ENODEV; diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index bfbe9dc90cc..e4c0fd2d6a9 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -984,19 +984,19 @@ static void __init for_each_sab_edev(void (*callback)(struct linux_ebus_device * for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "se")) { + if (!strcmp(edev->prom_node->name, "se")) { callback(edev, arg); continue; - } else if (!strcmp(edev->prom_name, "serial")) { - char compat[32]; + } else if (!strcmp(edev->prom_node->name, "serial")) { + char *compat; int clen; /* On RIO this can be an SE, check it. We could * just check ebus->is_rio, but this is more portable. */ - clen = prom_getproperty(edev->prom_node, "compatible", - compat, sizeof(compat)); - if (clen > 0) { + compat = of_get_property(edev->prom_node, + "compatible", &clen); + if (compat && clen > 0) { if (strncmp(compat, "sab82532", 8) == 0) { callback(edev, arg); continue; diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 4cdb610cdd3..0268b307c01 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1053,7 +1053,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) */ for_each_ebus(ebus) { for_each_ebusdev(dev, ebus) { - if (dev->prom_node == up->port_node) { + if (dev->prom_node->node == up->port_node) { /* * The EBus is broken on sparc; it delivers * virtual addresses in resources. Oh well... @@ -1073,7 +1073,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) #ifdef CONFIG_SPARC64 for_each_isa(isa_br) { for_each_isadev(isa_dev, isa_br) { - if (isa_dev->prom_node == up->port_node) { + if (isa_dev->prom_node->node == up->port_node) { /* Same on sparc64. Cool architecure... */ up->port.membase = (char *) isa_dev->resource.start; up->port.mapbase = isa_dev->resource.start; diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h index 7a408a030f5..876912f4d83 100644 --- a/include/asm-sparc64/ebus.h +++ b/include/asm-sparc64/ebus.h @@ -10,13 +10,13 @@ #include #include +#include struct linux_ebus_child { struct linux_ebus_child *next; struct linux_ebus_device *parent; struct linux_ebus *bus; - int prom_node; - char prom_name[64]; + struct device_node *prom_node; struct resource resource[PROMREG_MAX]; int num_addrs; unsigned int irqs[PROMINTR_MAX]; @@ -27,8 +27,7 @@ struct linux_ebus_device { struct linux_ebus_device *next; struct linux_ebus_child *children; struct linux_ebus *bus; - int prom_node; - char prom_name[64]; + struct device_node *prom_node; struct resource resource[PROMREG_MAX]; int num_addrs; unsigned int irqs[PROMINTR_MAX]; @@ -42,8 +41,7 @@ struct linux_ebus { struct pci_dev *self; int index; int is_rio; - int prom_node; - char prom_name[64]; + struct device_node *prom_node; struct linux_prom_ebus_ranges ebus_ranges[PROMREG_MAX]; int num_ebus_ranges; struct linux_prom_ebus_intmap ebus_intmap[PROMREG_MAX]; diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index 07ccd6f04b5..f8d57bb5570 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -498,15 +498,14 @@ static int sun_pci_fd_test_drive(unsigned long port, int drive) #ifdef CONFIG_PCI static int __init ebus_fdthree_p(struct linux_ebus_device *edev) { - if (!strcmp(edev->prom_name, "fdthree")) + if (!strcmp(edev->prom_node->name, "fdthree")) return 1; - if (!strcmp(edev->prom_name, "floppy")) { - char compat[16]; - prom_getstring(edev->prom_node, - "compatible", - compat, sizeof(compat)); - compat[15] = '\0'; - if (!strcmp(compat, "fdthree")) + if (!strcmp(edev->prom_node->name, "floppy")) { + char *compat; + + compat = of_get_property(edev->prom_node, + "compatible", NULL); + if (compat && !strcmp(compat, "fdthree")) return 1; } return 0; @@ -524,12 +523,12 @@ static unsigned long __init isa_floppy_init(void) for_each_isa(isa_br) { for_each_isadev(isa_dev, isa_br) { - if (!strcmp(isa_dev->prom_name, "dma")) { + if (!strcmp(isa_dev->prom_node->name, "dma")) { struct sparc_isa_device *child = isa_dev->child; while (child) { - if (!strcmp(child->prom_name, + if (!strcmp(child->prom_node->name, "floppy")) { isa_dev = child; goto isa_done; @@ -614,6 +613,7 @@ static unsigned long __init sun_floppy_init(void) struct linux_ebus_device *edev = NULL; unsigned long config = 0; void __iomem *auxio_reg; + char *state_prop; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { @@ -630,9 +630,8 @@ static unsigned long __init sun_floppy_init(void) #endif } - prom_getproperty(edev->prom_node, "status", - state, sizeof(state)); - if (!strncmp(state, "disabled", 8)) + state_prop = of_get_property(edev->prom_node, "status", NULL); + if (state_prop && !strncmp(state_prop, "disabled", 8)) return 0; FLOPPY_IRQ = edev->irqs[0]; @@ -703,7 +702,7 @@ static unsigned long __init sun_floppy_init(void) */ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "ecpp")) { + if (!strcmp(edev->prom_node->name, "ecpp")) { config = edev->resource[1].start; goto config_done; } diff --git a/include/asm-sparc64/isa.h b/include/asm-sparc64/isa.h index 4601bbfc3e7..e110435b14e 100644 --- a/include/asm-sparc64/isa.h +++ b/include/asm-sparc64/isa.h @@ -9,6 +9,7 @@ #include #include +#include struct sparc_isa_bridge; @@ -16,9 +17,7 @@ struct sparc_isa_device { struct sparc_isa_device *next; struct sparc_isa_device *child; struct sparc_isa_bridge *bus; - int prom_node; - char prom_name[64]; - char compatible[64]; + struct device_node *prom_node; struct resource resource; unsigned int irq; }; @@ -29,8 +28,7 @@ struct sparc_isa_bridge { struct pci_pbm_info *parent; struct pci_dev *self; int index; - int prom_node; - char prom_name[64]; + struct device_node *prom_node; #define linux_prom_isa_ranges linux_prom_ebus_ranges struct linux_prom_isa_ranges isa_ranges[PROMREG_MAX]; int num_isa_ranges; diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h index 56b5197d789..d3895873e4c 100644 --- a/include/asm-sparc64/parport.h +++ b/include/asm-sparc64/parport.h @@ -67,18 +67,17 @@ static __inline__ unsigned int get_dma_residue(unsigned int dmanr) static int ebus_ecpp_p(struct linux_ebus_device *edev) { - if (!strcmp(edev->prom_name, "ecpp")) + if (!strcmp(edev->prom_node->name, "ecpp")) return 1; - if (!strcmp(edev->prom_name, "parallel")) { - char compat[19]; - prom_getstring(edev->prom_node, - "compatible", - compat, sizeof(compat)); - compat[18] = '\0'; - if (!strcmp(compat, "ecpp")) - return 1; - if (!strcmp(compat, "ns87317-ecpp") && - !strcmp(compat + 13, "ecpp")) + if (!strcmp(edev->prom_node->name, "parallel")) { + char *compat; + + compat = of_get_property(edev->prom_node, + "compatible", NULL); + if (compat && + (!strcmp(compat, "ecpp") || + !strcmp(compat, "ns87317-ecpp") || + !strcmp(compat + 13, "ecpp"))) return 1; } return 0; @@ -94,12 +93,12 @@ static int parport_isa_probe(int count) struct sparc_isa_device *child; unsigned long base; - if (strcmp(isa_dev->prom_name, "dma")) + if (strcmp(isa_dev->prom_node->name, "dma")) continue; child = isa_dev->child; while (child) { - if (!strcmp(child->prom_name, "parallel")) + if (!strcmp(child->prom_node->name, "parallel")) break; child = child->next; } diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index b3efc9aa291..da54d04a3e3 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -2284,15 +2284,14 @@ static int __init cs4231_init(void) for_each_ebusdev(edev, ebus) { int match = 0; - if (!strcmp(edev->prom_name, "SUNW,CS4231")) { + if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) { match = 1; - } else if (!strcmp(edev->prom_name, "audio")) { - char compat[16]; + } else if (!strcmp(edev->prom_node->name, "audio")) { + char *compat; - prom_getstring(edev->prom_node, "compatible", - compat, sizeof(compat)); - compat[15] = '\0'; - if (!strcmp(compat, "SUNW,CS4231")) + compat = of_get_property(edev->prom_node, + "compatible", NULL); + if (compat && !strcmp(compat, "SUNW,CS4231")) match = 1; } -- cgit v1.2.3-70-g09d2 From 9c10a58ed634d98114c5717e2da761d8a63f2cd4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Jun 2006 19:31:11 -0700 Subject: [SPARC64]: Kill ebus/isa range and interrupt mapping struct members. Unused outside of initial bus probe scan. Signed-off-by: David S. Miller --- arch/sparc64/kernel/ebus.c | 65 ++++++++++++-------------------------------- arch/sparc64/kernel/isa.c | 68 ++++++++++++++++------------------------------ include/asm-sparc64/ebus.h | 5 ---- include/asm-sparc64/isa.h | 8 ------ 4 files changed, 41 insertions(+), 105 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 919a91d9e5d..33d79e10c65 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -283,60 +283,32 @@ static inline void *ebus_alloc(size_t size) return mem; } -static void __init ebus_ranges_init(struct linux_ebus *ebus) -{ - struct linux_prom_ebus_ranges *rngs; - int len; - - ebus->num_ebus_ranges = 0; - rngs = of_get_property(ebus->prom_node, "ranges", &len); - if (rngs) { - memcpy(ebus->ebus_ranges, rngs, len); - ebus->num_ebus_ranges = - (len / sizeof(struct linux_prom_ebus_ranges)); - } -} - -static void __init ebus_intmap_init(struct linux_ebus *ebus) +int __init ebus_intmap_match(struct linux_ebus *ebus, + struct linux_prom_registers *reg, + int *interrupt) { struct linux_prom_ebus_intmap *imap; struct linux_prom_ebus_intmask *imask; - int len; + unsigned int hi, lo, irq; + int i, len, n_imap; - ebus->num_ebus_intmap = 0; imap = of_get_property(ebus->prom_node, "interrupt-map", &len); if (!imap) - return; - - memcpy(ebus->ebus_intmap, imap, len); - ebus->num_ebus_intmap = (len / sizeof(struct linux_prom_ebus_intmap)); - - imask = of_get_property(ebus->prom_node, "interrupt-map-mask", &len); - if (!imask) { - prom_printf("EBUS: can't get interrupt-map-mask\n"); - prom_halt(); - } - memcpy(&ebus->ebus_intmask, imask, sizeof(ebus->ebus_intmask)); -} - -int __init ebus_intmap_match(struct linux_ebus *ebus, - struct linux_prom_registers *reg, - int *interrupt) -{ - unsigned int hi, lo, irq; - int i; + return 0; + n_imap = len / sizeof(imap[0]); - if (!ebus->num_ebus_intmap) + imask = of_get_property(ebus->prom_node, "interrupt-map-mask", NULL); + if (!imask) return 0; - hi = reg->which_io & ebus->ebus_intmask.phys_hi; - lo = reg->phys_addr & ebus->ebus_intmask.phys_lo; - irq = *interrupt & ebus->ebus_intmask.interrupt; - for (i = 0; i < ebus->num_ebus_intmap; i++) { - if ((ebus->ebus_intmap[i].phys_hi == hi) && - (ebus->ebus_intmap[i].phys_lo == lo) && - (ebus->ebus_intmap[i].interrupt == irq)) { - *interrupt = ebus->ebus_intmap[i].cinterrupt; + hi = reg->which_io & imask->phys_hi; + lo = reg->phys_addr & imask->phys_lo; + irq = *interrupt & imask->interrupt; + for (i = 0; i < n_imap; i++) { + if ((imap[i].phys_hi == hi) && + (imap[i].phys_lo == lo) && + (imap[i].interrupt == irq)) { + *interrupt = imap[i].cinterrupt; return 0; } } @@ -598,9 +570,6 @@ void __init ebus_init(void) ebus->self = pdev; ebus->parent = pbm = cookie->pbm; - ebus_ranges_init(ebus); - ebus_intmap_init(ebus); - child = dp->child; if (!child) goto next_ebus; diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index 8c8c5a491ad..2693f2de549 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -72,19 +72,30 @@ static struct { static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev, struct sparc_isa_bridge *isa_br, int *interrupt, - struct linux_prom_registers *pregs) + struct linux_prom_registers *reg) { + struct linux_prom_ebus_intmap *imap; + struct linux_prom_ebus_intmap *imask; unsigned int hi, lo, irq; - int i; - - hi = pregs->which_io & isa_br->isa_intmask.phys_hi; - lo = pregs->phys_addr & isa_br->isa_intmask.phys_lo; - irq = *interrupt & isa_br->isa_intmask.interrupt; - for (i = 0; i < isa_br->num_isa_intmap; i++) { - if ((isa_br->isa_intmap[i].phys_hi == hi) && - (isa_br->isa_intmap[i].phys_lo == lo) && - (isa_br->isa_intmap[i].interrupt == irq)) { - *interrupt = isa_br->isa_intmap[i].cinterrupt; + int i, len, n_imap; + + imap = of_get_property(isa_br->prom_node, "interrupt-map", &len); + if (!imap) + return 0; + n_imap = len / sizeof(imap[0]); + + imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL); + if (!imask) + return 0; + + hi = reg->which_io & imask->phys_hi; + lo = reg->phys_addr & imask->phys_lo; + irq = *interrupt & imask->interrupt; + for (i = 0; i < n_imap; i++) { + if ((imap[i].phys_hi == hi) && + (imap[i].phys_lo == lo) && + (imap[i].interrupt == irq)) { + *interrupt = imap[i].cinterrupt; return 0; } } @@ -105,7 +116,8 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev, struct pci_pbm_info *pbm; int i; - if (isa_dev->bus->num_isa_intmap) { + if (of_find_property(isa_dev->bus->prom_node, + "interrupt-map", NULL)) { if (!isa_dev_get_irq_using_imap(isa_dev, isa_dev->bus, &irq_prop, @@ -218,36 +230,6 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) } } -static void __init get_bridge_props(struct sparc_isa_bridge *isa_br) -{ - struct device_node *dp = isa_br->prom_node; - void *pval; - int len; - - pval = of_get_property(dp, "ranges", &len); - if (pval) { - memcpy(isa_br->isa_ranges, pval, len); - isa_br->num_isa_ranges = - len / sizeof(struct linux_prom_isa_ranges); - } else { - isa_br->num_isa_ranges = 0; - } - - pval = of_get_property(dp, "interrupt-map", &len); - if (pval) { - memcpy(isa_br->isa_intmap, pval, len); - isa_br->num_isa_intmap = - (len / sizeof(struct linux_prom_isa_intmap)); - } else { - isa_br->num_isa_intmap = 0; - } - - pval = of_get_property(dp, "interrupt-map-mask", &len); - if (pval) - memcpy(&isa_br->isa_intmask, pval, - sizeof(isa_br->isa_intmask)); -} - void __init isa_init(void) { struct pci_dev *pdev; @@ -288,8 +270,6 @@ void __init isa_init(void) isa_br->index = index++; isa_br->prom_node = pdev_cookie->prom_node; - get_bridge_props(isa_br); - printk("isa%d:", isa_br->index); isa_fill_devices(isa_br); diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h index 876912f4d83..545882bd356 100644 --- a/include/asm-sparc64/ebus.h +++ b/include/asm-sparc64/ebus.h @@ -42,11 +42,6 @@ struct linux_ebus { int index; int is_rio; struct device_node *prom_node; - struct linux_prom_ebus_ranges ebus_ranges[PROMREG_MAX]; - int num_ebus_ranges; - struct linux_prom_ebus_intmap ebus_intmap[PROMREG_MAX]; - int num_ebus_intmap; - struct linux_prom_ebus_intmask ebus_intmask; }; struct ebus_dma_info { diff --git a/include/asm-sparc64/isa.h b/include/asm-sparc64/isa.h index e110435b14e..2e7fb18ec1b 100644 --- a/include/asm-sparc64/isa.h +++ b/include/asm-sparc64/isa.h @@ -29,14 +29,6 @@ struct sparc_isa_bridge { struct pci_dev *self; int index; struct device_node *prom_node; -#define linux_prom_isa_ranges linux_prom_ebus_ranges - struct linux_prom_isa_ranges isa_ranges[PROMREG_MAX]; - int num_isa_ranges; -#define linux_prom_isa_intmap linux_prom_ebus_intmap - struct linux_prom_isa_intmap isa_intmap[PROMREG_MAX]; - int num_isa_intmap; -#define linux_prom_isa_intmask linux_prom_ebus_intmask - struct linux_prom_isa_intmap isa_intmask; }; extern struct sparc_isa_bridge *isa_chain; -- cgit v1.2.3-70-g09d2 From cecc4e9222c4e2bca59834750e493eea6be97613 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Jun 2006 19:53:24 -0700 Subject: [SPARC64]: Convert central bus layer to in-kernel PROM device tree. Signed-off-by: David S. Miller --- arch/sparc64/kernel/central.c | 127 +++++++++++++++++++++--------------------- arch/sparc64/kernel/time.c | 22 ++++---- drivers/serial/sunzilog.c | 2 +- include/asm-sparc64/fhc.h | 7 +-- 4 files changed, 78 insertions(+), 80 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c index 3d184a78496..b66336db00e 100644 --- a/arch/sparc64/kernel/central.c +++ b/arch/sparc64/kernel/central.c @@ -29,28 +29,34 @@ static void central_probe_failure(int line) prom_halt(); } -static void central_ranges_init(int cnode, struct linux_central *central) +static void central_ranges_init(struct linux_central *central) { - int success; + struct device_node *dp = central->prom_node; + void *pval; + int len; central->num_central_ranges = 0; - success = prom_getproperty(central->prom_node, "ranges", - (char *) central->central_ranges, - sizeof (central->central_ranges)); - if (success != -1) - central->num_central_ranges = (success/sizeof(struct linux_prom_ranges)); + pval = of_get_property(dp, "ranges", &len); + if (pval) { + memcpy(central->central_ranges, pval, len); + central->num_central_ranges = + (len / sizeof(struct linux_prom_ranges)); + } } -static void fhc_ranges_init(int fnode, struct linux_fhc *fhc) +static void fhc_ranges_init(struct linux_fhc *fhc) { - int success; + struct device_node *dp = fhc->prom_node; + void *pval; + int len; fhc->num_fhc_ranges = 0; - success = prom_getproperty(fhc->prom_node, "ranges", - (char *) fhc->fhc_ranges, - sizeof (fhc->fhc_ranges)); - if (success != -1) - fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges)); + pval = of_get_property(dp, "ranges", &len); + if (pval) { + memcpy(fhc->fhc_ranges, pval, len); + fhc->num_fhc_ranges = + (len / sizeof(struct linux_prom_ranges)); + } } /* Range application routines are exported to various drivers, @@ -112,15 +118,10 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r) static void probe_other_fhcs(void) { - struct linux_prom64_registers fpregs[6]; - char namebuf[128]; - int node; + struct device_node *dp; + struct linux_prom64_registers *fpregs; - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "fhc"); - if (node == 0) - central_probe_failure(__LINE__); - while (node) { + for_each_node_by_name(dp, "fhc") { struct linux_fhc *fhc; int board; u32 tmp; @@ -137,14 +138,12 @@ static void probe_other_fhcs(void) /* Toplevel FHCs have no parent. */ fhc->parent = NULL; - fhc->prom_node = node; - prom_getstring(node, "name", namebuf, sizeof(namebuf)); - strcpy(fhc->prom_name, namebuf); - fhc_ranges_init(node, fhc); + fhc->prom_node = dp; + fhc_ranges_init(fhc); /* Non-central FHC's have 64-bit OBP format registers. */ - if (prom_getproperty(node, "reg", - (char *)&fpregs[0], sizeof(fpregs)) == -1) + fpregs = of_get_property(dp, "reg", NULL); + if (!fpregs) central_probe_failure(__LINE__); /* Only central FHC needs special ranges applied. */ @@ -155,7 +154,7 @@ static void probe_other_fhcs(void) fhc->fhc_regs.uregs = fpregs[4].phys_addr; fhc->fhc_regs.tregs = fpregs[5].phys_addr; - board = prom_getintdefault(node, "board#", -1); + board = of_getintprop_default(dp, "board#", -1); fhc->board = board; tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL); @@ -179,33 +178,33 @@ static void probe_other_fhcs(void) tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); tmp |= FHC_CONTROL_IXIST; upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); - - /* Look for the next FHC. */ - node = prom_getsibling(node); - if (node == 0) - break; - node = prom_searchsiblings(node, "fhc"); - if (node == 0) - break; } } static void probe_clock_board(struct linux_central *central, struct linux_fhc *fhc, - int cnode, int fnode) + struct device_node *fp) { - struct linux_prom_registers cregs[3]; - int clknode, nslots, tmp, nregs; + struct device_node *dp; + struct linux_prom_registers cregs[3], *pr; + int nslots, tmp, nregs; - clknode = prom_searchsiblings(prom_getchild(fnode), "clock-board"); - if (clknode == 0 || clknode == -1) + dp = fp->child; + while (dp) { + if (!strcmp(dp->name, "clock-board")) + break; + dp = dp->sibling; + } + if (!dp) central_probe_failure(__LINE__); - nregs = prom_getproperty(clknode, "reg", (char *)&cregs[0], sizeof(cregs)); - if (nregs == -1) + pr = of_get_property(dp, "reg", &nregs); + if (!pr) central_probe_failure(__LINE__); + memcpy(cregs, pr, nregs); nregs /= sizeof(struct linux_prom_registers); + apply_fhc_ranges(fhc, &cregs[0], nregs); apply_central_ranges(central, &cregs[0], nregs); central->cfreg = prom_reg_to_paddr(&cregs[0]); @@ -296,13 +295,13 @@ static void init_all_fhc_hw(void) void central_probe(void) { - struct linux_prom_registers fpregs[6]; + struct linux_prom_registers fpregs[6], *pr; struct linux_fhc *fhc; - char namebuf[128]; - int cnode, fnode, err; + struct device_node *dp, *fp; + int err; - cnode = prom_finddevice("/central"); - if (cnode == 0 || cnode == -1) { + dp = of_find_node_by_name(NULL, "central"); + if (!dp) { if (this_is_starfire) starfire_cpu_setup(); return; @@ -321,31 +320,31 @@ void central_probe(void) /* First init central. */ central_bus->child = fhc; - central_bus->prom_node = cnode; - - prom_getstring(cnode, "name", namebuf, sizeof(namebuf)); - strcpy(central_bus->prom_name, namebuf); - - central_ranges_init(cnode, central_bus); + central_bus->prom_node = dp; + central_ranges_init(central_bus); /* And then central's FHC. */ fhc->next = fhc_list; fhc_list = fhc; fhc->parent = central_bus; - fnode = prom_searchsiblings(prom_getchild(cnode), "fhc"); - if (fnode == 0 || fnode == -1) + fp = dp->child; + while (fp) { + if (!strcmp(fp->name, "fhc")) + break; + fp = fp->sibling; + } + if (!fp) central_probe_failure(__LINE__); - fhc->prom_node = fnode; - prom_getstring(fnode, "name", namebuf, sizeof(namebuf)); - strcpy(fhc->prom_name, namebuf); - - fhc_ranges_init(fnode, fhc); + fhc->prom_node = fp; + fhc_ranges_init(fhc); /* Now, map in FHC register set. */ - if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1) + pr = of_get_property(fp, "reg", NULL); + if (!pr) central_probe_failure(__LINE__); + memcpy(fpregs, pr, sizeof(fpregs)); apply_central_ranges(central_bus, &fpregs[0], 6); @@ -366,7 +365,7 @@ void central_probe(void) fhc->jtag_master = 0; /* Attach the clock board registers for CENTRAL. */ - probe_clock_board(central_bus, fhc, cnode, fnode); + probe_clock_board(central_bus, fhc, fp); err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID); printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n", diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index d072b8632cc..348b8203556 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -796,26 +796,26 @@ static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg, static int __init clock_probe_central(void) { - struct linux_prom_registers clk_reg[2]; - char model[64]; - int node; + struct linux_prom_registers clk_reg[2], *pr; + struct device_node *dp; + char *model; if (!central_bus) return 0; /* Get Central FHC's prom node. */ - node = central_bus->child->prom_node; + dp = central_bus->child->prom_node; /* Then get the first child device below it. */ - node = prom_getchild(node); + dp = dp->child; - while (node) { - prom_getstring(node, "model", model, sizeof(model)); - if (!clock_model_matches(model)) + while (dp) { + model = of_get_property(dp, "model", NULL); + if (!model || !clock_model_matches(model)) goto next_sibling; - prom_getproperty(node, "reg", (char *)clk_reg, - sizeof(clk_reg)); + pr = of_get_property(dp, "reg", NULL); + memcpy(clk_reg, pr, sizeof(clk_reg)); apply_fhc_ranges(central_bus->child, clk_reg, 1); apply_central_ranges(central_bus, clk_reg, 1); @@ -824,7 +824,7 @@ static int __init clock_probe_central(void) return 1; next_sibling: - node = prom_getsibling(node); + dp = dp->sibling; } return 0; diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 5b6569728a9..76c9bac9271 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1106,7 +1106,7 @@ static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode) + FHC_UREGS_ICLR; imap = central_bus->child->fhc_regs.uregs + FHC_UREGS_IMAP; - zilog_irq = build_irq(12, 0, iclr, imap); + zilog_irq = build_irq(0, iclr, imap); } else { err = prom_getproperty(zsnode, "interrupts", (char *) &sun4u_ino, diff --git a/include/asm-sparc64/fhc.h b/include/asm-sparc64/fhc.h index f29eaa25405..9e7f1b0d78b 100644 --- a/include/asm-sparc64/fhc.h +++ b/include/asm-sparc64/fhc.h @@ -10,6 +10,7 @@ #include #include +#include #include struct linux_fhc; @@ -34,8 +35,7 @@ struct linux_central { unsigned long clkregs; unsigned long clkver; int slots; - int prom_node; - char prom_name[64]; + struct device_node *prom_node; struct linux_prom_ranges central_ranges[PROMREG_MAX]; int num_central_ranges; @@ -112,8 +112,7 @@ struct linux_fhc { struct fhc_regs fhc_regs; int board; int jtag_master; - int prom_node; - char prom_name[64]; + struct device_node *prom_node; struct linux_prom_ranges fhc_ranges[PROMREG_MAX]; int num_fhc_ranges; -- cgit v1.2.3-70-g09d2 From 8cd24ed4f8031636fb5dacb04adee9e02556ecd5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Jun 2006 22:08:58 -0700 Subject: [SPARC64]: Expand of_*() interfaces some more. Import some more stuff from powerpc. Add of_device_is_compatible(), and of_find_compatible_node(). Export some more of the other routines to modules. Signed-off-by: David S. Miller --- arch/sparc64/kernel/prom.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/asm-sparc64/prom.h | 3 +++ 2 files changed, 46 insertions(+) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 7809100034b..e9d703eea80 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -27,6 +27,26 @@ static struct device_node *allnodes; +int of_device_is_compatible(struct device_node *device, const char *compat) +{ + const char* cp; + int cplen, l; + + cp = (char *) of_get_property(device, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strncmp(cp, compat, strlen(compat)) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} +EXPORT_SYMBOL(of_device_is_compatible); + struct device_node *of_get_parent(const struct device_node *node) { struct device_node *np; @@ -38,6 +58,7 @@ struct device_node *of_get_parent(const struct device_node *node) return np; } +EXPORT_SYMBOL(of_get_parent); struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev) @@ -51,6 +72,7 @@ struct device_node *of_get_next_child(const struct device_node *node, return next; } +EXPORT_SYMBOL(of_get_next_child); struct device_node *of_find_node_by_path(const char *path) { @@ -75,6 +97,7 @@ struct device_node *of_find_node_by_phandle(phandle handle) return np; } +EXPORT_SYMBOL(of_find_node_by_phandle); struct device_node *of_find_node_by_name(struct device_node *from, const char *name) @@ -88,6 +111,7 @@ struct device_node *of_find_node_by_name(struct device_node *from, return np; } +EXPORT_SYMBOL(of_find_node_by_name); struct device_node *of_find_node_by_type(struct device_node *from, const char *type) @@ -101,6 +125,25 @@ struct device_node *of_find_node_by_type(struct device_node *from, return np; } +EXPORT_SYMBOL(of_find_node_by_type); + +struct device_node *of_find_compatible_node(struct device_node *from, + const char *type, const char *compatible) +{ + struct device_node *np; + + np = from ? from->allnext : allnodes; + for (; np != 0; np = np->allnext) { + if (type != NULL + && !(np->type != 0 && strcmp(np->type, type) == 0)) + continue; + if (of_device_is_compatible(np, compatible)) + break; + } + + return np; +} +EXPORT_SYMBOL(of_find_compatible_node); struct property *of_find_property(struct device_node *np, const char *name, int *lenp) diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 062ae6e1212..6d1556c0c26 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -75,6 +75,8 @@ extern struct device_node *of_find_node_by_type(struct device_node *from, #define for_each_node_by_type(dn, type) \ for (dn = of_find_node_by_type(NULL, type); dn; \ dn = of_find_node_by_type(dn, type)) +extern struct device_node *of_find_compatible_node(struct device_node *from, + const char *type, const char *compat); extern struct device_node *of_find_node_by_path(const char *path); extern struct device_node *of_find_node_by_phandle(phandle handle); extern struct device_node *of_get_parent(const struct device_node *node); @@ -83,6 +85,7 @@ extern struct device_node *of_get_next_child(const struct device_node *node, extern struct property *of_find_property(struct device_node *np, const char *name, int *lenp); +extern int of_device_is_compatible(struct device_node *device, const char *); extern void *of_get_property(struct device_node *node, const char *name, int *lenp); extern int of_getintprop_default(struct device_node *np, -- cgit v1.2.3-70-g09d2 From a2bd4fd17926d715a470fbe0ebe05128ba410984 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 23 Jun 2006 01:44:10 -0700 Subject: [SPARC64]: Add of_device layer and make ebus/isa use it. Sparcspkr and power drivers are converted, to make sure it works. Eventually the SBUS device layer will use this as a sub-class. I really cannot cut loose on that bit until sparc32 is given the same infrastructure. Signed-off-by: David S. Miller --- arch/sparc64/kernel/Makefile | 2 +- arch/sparc64/kernel/ebus.c | 21 +++ arch/sparc64/kernel/isa.c | 37 +++++- arch/sparc64/kernel/of_device.c | 279 ++++++++++++++++++++++++++++++++++++++++ arch/sparc64/kernel/power.c | 109 ++++++++-------- drivers/input/misc/Kconfig | 2 +- drivers/input/misc/sparcspkr.c | 218 +++++++++++++++++-------------- include/asm-sparc64/ebus.h | 5 + include/asm-sparc64/isa.h | 5 + include/asm-sparc64/of_device.h | 64 +++++++++ 10 files changed, 585 insertions(+), 157 deletions(-) create mode 100644 arch/sparc64/kernel/of_device.c create mode 100644 include/asm-sparc64/of_device.h (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 7f00189ed29..86c9fe3f3e4 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := process.o setup.o cpu.o idprom.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ - visemul.o prom.o + visemul.o prom.o of_device.o obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ pci_psycho.o pci_sabre.o pci_schizo.o \ diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 33d79e10c65..b390a2f3a15 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -475,6 +475,16 @@ probe_interrupts: } } + dev->ofdev.node = dp; + dev->ofdev.dev.parent = &dev->bus->ofdev.dev; + dev->ofdev.dev.bus = &ebus_bus_type; + strcpy(dev->ofdev.dev.bus_id, dp->path_component_name); + + /* Register with core */ + if (of_device_register(&dev->ofdev) != 0) + printk(KERN_DEBUG "ebus: device registration error for %s!\n", + dev->ofdev.dev.bus_id); + dp = dp->child; if (dp) { printk(" ->"); @@ -570,6 +580,17 @@ void __init ebus_init(void) ebus->self = pdev; ebus->parent = pbm = cookie->pbm; + ebus->ofdev.node = dp; + ebus->ofdev.dev.parent = &pdev->dev; + ebus->ofdev.dev.bus = &ebus_bus_type; + strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name); + + /* Register with core */ + if (of_device_register(&ebus->ofdev) != 0) + printk(KERN_DEBUG "ebus: device registration error for %s!\n", + ebus->ofdev.dev.bus_id); + + child = dp->child; if (!child) goto next_ebus; diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index 2693f2de549..6f16dee280a 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -195,12 +195,25 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL); if (!isa_dev) { - fatal_err("cannot allocate isa_dev"); - prom_halt(); + printk(KERN_DEBUG "ISA: cannot allocate isa_dev"); + return; } memset(isa_dev, 0, sizeof(*isa_dev)); + isa_dev->ofdev.node = dp; + isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev; + isa_dev->ofdev.dev.bus = &isa_bus_type; + strcpy(isa_dev->ofdev.dev.bus_id, dp->path_component_name); + + /* Register with core */ + if (of_device_register(&isa_dev->ofdev) != 0) { + printk(KERN_DEBUG "isa: device registration error for %s!\n", + isa_dev->ofdev.dev.bus_id); + kfree(isa_dev); + goto next_sibling; + } + /* Link it in. */ isa_dev->next = NULL; if (isa_br->devices == NULL) { @@ -226,6 +239,7 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) printk("]"); + next_sibling: dp = dp->sibling; } } @@ -244,6 +258,7 @@ void __init isa_init(void) struct pcidev_cookie *pdev_cookie; struct pci_pbm_info *pbm; struct sparc_isa_bridge *isa_br; + struct device_node *dp; pdev_cookie = pdev->sysdata; if (!pdev_cookie) { @@ -252,15 +267,29 @@ void __init isa_init(void) continue; } pbm = pdev_cookie->pbm; + dp = pdev_cookie->prom_node; isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL); if (!isa_br) { - fatal_err("cannot allocate sparc_isa_bridge"); - prom_halt(); + printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge"); + return; } memset(isa_br, 0, sizeof(*isa_br)); + isa_br->ofdev.node = dp; + isa_br->ofdev.dev.parent = &pdev->dev; + isa_br->ofdev.dev.bus = &isa_bus_type; + strcpy(isa_br->ofdev.dev.bus_id, dp->path_component_name); + + /* Register with core */ + if (of_device_register(&isa_br->ofdev) != 0) { + printk(KERN_DEBUG "isa: device registration error for %s!\n", + isa_br->ofdev.dev.bus_id); + kfree(isa_br); + return; + } + /* Link it in. */ isa_br->next = isa_chain; isa_chain = isa_br; diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c new file mode 100644 index 00000000000..566aa343aa6 --- /dev/null +++ b/arch/sparc64/kernel/of_device.c @@ -0,0 +1,279 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * of_match_device - Tell if an of_device structure has a matching + * of_match structure + * @ids: array of of device match structures to search in + * @dev: the of device structure to match against + * + * Used by a driver to check whether an of_device present in the + * system is in its list of supported devices. + */ +const struct of_device_id *of_match_device(const struct of_device_id *matches, + const struct of_device *dev) +{ + if (!dev->node) + return NULL; + while (matches->name[0] || matches->type[0] || matches->compatible[0]) { + int match = 1; + if (matches->name[0]) + match &= dev->node->name + && !strcmp(matches->name, dev->node->name); + if (matches->type[0]) + match &= dev->node->type + && !strcmp(matches->type, dev->node->type); + if (matches->compatible[0]) + match &= of_device_is_compatible(dev->node, + matches->compatible); + if (match) + return matches; + matches++; + } + return NULL; +} + +static int of_platform_bus_match(struct device *dev, struct device_driver *drv) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * of_drv = to_of_platform_driver(drv); + const struct of_device_id * matches = of_drv->match_table; + + if (!matches) + return 0; + + return of_match_device(matches, of_dev) != NULL; +} + +struct of_device *of_dev_get(struct of_device *dev) +{ + struct device *tmp; + + if (!dev) + return NULL; + tmp = get_device(&dev->dev); + if (tmp) + return to_of_device(tmp); + else + return NULL; +} + +void of_dev_put(struct of_device *dev) +{ + if (dev) + put_device(&dev->dev); +} + + +static int of_device_probe(struct device *dev) +{ + int error = -ENODEV; + struct of_platform_driver *drv; + struct of_device *of_dev; + const struct of_device_id *match; + + drv = to_of_platform_driver(dev->driver); + of_dev = to_of_device(dev); + + if (!drv->probe) + return error; + + of_dev_get(of_dev); + + match = of_match_device(drv->match_table, of_dev); + if (match) + error = drv->probe(of_dev, match); + if (error) + of_dev_put(of_dev); + + return error; +} + +static int of_device_remove(struct device *dev) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(dev->driver); + + if (dev->driver && drv->remove) + drv->remove(of_dev); + return 0; +} + +static int of_device_suspend(struct device *dev, pm_message_t state) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(dev->driver); + int error = 0; + + if (dev->driver && drv->suspend) + error = drv->suspend(of_dev, state); + return error; +} + +static int of_device_resume(struct device * dev) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(dev->driver); + int error = 0; + + if (dev->driver && drv->resume) + error = drv->resume(of_dev); + return error; +} + +#ifdef CONFIG_PCI +struct bus_type isa_bus_type = { + .name = "isa", + .match = of_platform_bus_match, + .probe = of_device_probe, + .remove = of_device_remove, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; + +struct bus_type ebus_bus_type = { + .name = "ebus", + .match = of_platform_bus_match, + .probe = of_device_probe, + .remove = of_device_remove, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; +#endif + +#ifdef CONFIG_SBUS +struct bus_type sbus_bus_type = { + .name = "sbus", + .match = of_platform_bus_match, + .probe = of_device_probe, + .remove = of_device_remove, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; +#endif + +static int __init of_bus_driver_init(void) +{ + int err = 0; + +#ifdef CONFIG_PCI + if (!err) + err = bus_register(&isa_bus_type); + if (!err) + err = bus_register(&ebus_bus_type); +#endif +#ifdef CONFIG_SBUS + if (!err) + err = bus_register(&sbus_bus_type); +#endif + return 0; +} + +postcore_initcall(of_bus_driver_init); + +int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) +{ + /* initialize common driver fields */ + drv->driver.name = drv->name; + drv->driver.bus = bus; + + /* register with core */ + return driver_register(&drv->driver); +} + +void of_unregister_driver(struct of_platform_driver *drv) +{ + driver_unregister(&drv->driver); +} + + +static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct of_device *ofdev; + + ofdev = to_of_device(dev); + return sprintf(buf, "%s", ofdev->node->full_name); +} + +static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); + +/** + * of_release_dev - free an of device structure when all users of it are finished. + * @dev: device that's been disconnected + * + * Will be called only by the device core when all users of this of device are + * done. + */ +void of_release_dev(struct device *dev) +{ + struct of_device *ofdev; + + ofdev = to_of_device(dev); + + kfree(ofdev); +} + +int of_device_register(struct of_device *ofdev) +{ + int rc; + + BUG_ON(ofdev->node == NULL); + + rc = device_register(&ofdev->dev); + if (rc) + return rc; + + device_create_file(&ofdev->dev, &dev_attr_devspec); + + return 0; +} + +void of_device_unregister(struct of_device *ofdev) +{ + device_remove_file(&ofdev->dev, &dev_attr_devspec); + device_unregister(&ofdev->dev); +} + +struct of_device* of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent, + struct bus_type *bus) +{ + struct of_device *dev; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + memset(dev, 0, sizeof(*dev)); + + dev->dev.parent = parent; + dev->dev.bus = bus; + dev->dev.release = of_release_dev; + + strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); + + if (of_device_register(dev) != 0) { + kfree(dev); + return NULL; + } + + return dev; +} + +EXPORT_SYMBOL(of_match_device); +EXPORT_SYMBOL(of_register_driver); +EXPORT_SYMBOL(of_unregister_driver); +EXPORT_SYMBOL(of_device_register); +EXPORT_SYMBOL(of_device_unregister); +EXPORT_SYMBOL(of_dev_get); +EXPORT_SYMBOL(of_dev_put); +EXPORT_SYMBOL(of_platform_device_create); +EXPORT_SYMBOL(of_release_dev); diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 75159a7843f..9496c773401 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -115,66 +115,15 @@ static int __init has_button_interrupt(unsigned int irq, struct device_node *dp) return 1; } -static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, struct device_node **prom_node_p) +static void __devinit power_probe_common(struct of_device *dev, struct resource *res, unsigned int irq) { - struct linux_ebus *ebus; - struct linux_ebus_device *edev; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "power")) { - *resp = &edev->resource[0]; - *irq_p = edev->irqs[0]; - *prom_node_p = edev->prom_node; - return 0; - } - } - } - return -ENODEV; -} - -static int __init power_probe_isa(struct resource **resp, unsigned int *irq_p, struct device_node **prom_node_p) -{ - struct sparc_isa_bridge *isa_bus; - struct sparc_isa_device *isa_dev; - - for_each_isa(isa_bus) { - for_each_isadev(isa_dev, isa_bus) { - if (!strcmp(isa_dev->prom_node->name, "power")) { - *resp = &isa_dev->resource; - *irq_p = isa_dev->irq; - *prom_node_p = isa_dev->prom_node; - return 0; - } - } - } - return -ENODEV; -} - -void __init power_init(void) -{ - struct resource *res = NULL; - unsigned int irq; - struct device_node *dp; - static int invoked; - - if (invoked) - return; - invoked = 1; - - if (!power_probe_ebus(&res, &irq, &dp)) - goto found; - - if (!power_probe_isa(&res, &irq, &dp)) - goto found; - - return; - -found: power_reg = ioremap(res->start, 0x4); + printk("power: Control reg at %p ... ", power_reg); + poweroff_method = machine_halt; /* able to use the standard halt */ - if (has_button_interrupt(irq, dp)) { + + if (has_button_interrupt(irq, dev->node)) { if (kernel_thread(powerd, NULL, CLONE_FS) < 0) { printk("Failed to start power daemon.\n"); return; @@ -188,4 +137,52 @@ found: printk("not using powerd.\n"); } } + +static struct of_device_id power_match[] = { + { + .name = "power", + }, + {}, +}; + +static int __devinit ebus_power_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct linux_ebus_device *edev = to_ebus_device(&dev->dev); + struct resource *res = &edev->resource[0]; + unsigned int irq = edev->irqs[0]; + + power_probe_common(dev, res,irq); + + return 0; +} + +static struct of_platform_driver ebus_power_driver = { + .name = "power", + .match_table = power_match, + .probe = ebus_power_probe, +}; + +static int __devinit isa_power_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct sparc_isa_device *idev = to_isa_device(&dev->dev); + struct resource *res = &idev->resource; + unsigned int irq = idev->irq; + + power_probe_common(dev, res,irq); + + return 0; +} + +static struct of_platform_driver isa_power_driver = { + .name = "power", + .match_table = power_match, + .probe = isa_power_probe, +}; + +void __init power_init(void) +{ + of_register_driver(&ebus_power_driver, &ebus_bus_type); + of_register_driver(&isa_power_driver, &isa_bus_type); + return; +} #endif /* CONFIG_PCI */ diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 4bad588d0e5..a6dfc745573 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -26,7 +26,7 @@ config INPUT_PCSPKR config INPUT_SPARCSPKR tristate "SPARC Speaker support" - depends on PCI && SPARC + depends on PCI && SPARC64 help Say Y here if you want the standard Speaker on Sparc PCI systems to be used for bells and whistles. diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index ed95dc9420d..42c11fbf3c7 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -2,7 +2,7 @@ * Driver for PC-speaker like devices found on various Sparc systems. * * Copyright (c) 2002 Vojtech Pavlik - * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net) */ #include #include @@ -13,21 +13,23 @@ #include #include -#ifdef CONFIG_SPARC64 #include -#endif -MODULE_AUTHOR("David S. Miller "); +MODULE_AUTHOR("David S. Miller "); MODULE_DESCRIPTION("Sparc Speaker beeper driver"); MODULE_LICENSE("GPL"); -const char *beep_name; -static unsigned long beep_iobase; -static int (*beep_event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); -static DEFINE_SPINLOCK(beep_lock); +struct sparcspkr_state { + const char *name; + unsigned long iobase; + int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); + spinlock_t lock; + struct input_dev *input_dev; +}; static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { + struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev); unsigned int count = 0; unsigned long flags; @@ -43,24 +45,24 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in if (value > 20 && value < 32767) count = 1193182 / value; - spin_lock_irqsave(&beep_lock, flags); + spin_lock_irqsave(&state->lock, flags); /* EBUS speaker only has on/off state, the frequency does not * appear to be programmable. */ - if (beep_iobase & 0x2UL) - outb(!!count, beep_iobase); + if (state->iobase & 0x2UL) + outb(!!count, state->iobase); else - outl(!!count, beep_iobase); + outl(!!count, state->iobase); - spin_unlock_irqrestore(&beep_lock, flags); + spin_unlock_irqrestore(&state->lock, flags); return 0; } -#ifdef CONFIG_SPARC64 static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { + struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev); unsigned int count = 0; unsigned long flags; @@ -76,29 +78,29 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int if (value > 20 && value < 32767) count = 1193182 / value; - spin_lock_irqsave(&beep_lock, flags); + spin_lock_irqsave(&state->lock, flags); if (count) { /* enable counter 2 */ - outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61); + outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61); /* set command for counter 2, 2 byte write */ - outb(0xB6, beep_iobase + 0x43); + outb(0xB6, state->iobase + 0x43); /* select desired HZ */ - outb(count & 0xff, beep_iobase + 0x42); - outb((count >> 8) & 0xff, beep_iobase + 0x42); + outb(count & 0xff, state->iobase + 0x42); + outb((count >> 8) & 0xff, state->iobase + 0x42); } else { /* disable counter 2 */ - outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61); + outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61); } - spin_unlock_irqrestore(&beep_lock, flags); + spin_unlock_irqrestore(&state->lock, flags); return 0; } -#endif -static int __devinit sparcspkr_probe(struct platform_device *dev) +static int __devinit sparcspkr_probe(struct device *dev) { + struct sparcspkr_state *state = dev_get_drvdata(dev); struct input_dev *input_dev; int error; @@ -106,18 +108,18 @@ static int __devinit sparcspkr_probe(struct platform_device *dev) if (!input_dev) return -ENOMEM; - input_dev->name = beep_name; + input_dev->name = state->name; input_dev->phys = "sparc/input0"; input_dev->id.bustype = BUS_ISA; input_dev->id.vendor = 0x001f; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->cdev.dev = &dev->dev; + input_dev->cdev.dev = dev; input_dev->evbit[0] = BIT(EV_SND); input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - input_dev->event = beep_event; + input_dev->event = state->event; error = input_register_device(input_dev); if (error) { @@ -125,111 +127,137 @@ static int __devinit sparcspkr_probe(struct platform_device *dev) return error; } - platform_set_drvdata(dev, input_dev); + state->input_dev = input_dev; return 0; } -static int __devexit sparcspkr_remove(struct platform_device *dev) +static int __devexit sparcspkr_remove(struct of_device *dev) { - struct input_dev *input_dev = platform_get_drvdata(dev); + struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); + struct input_dev *input_dev = state->input_dev; - input_unregister_device(input_dev); - platform_set_drvdata(dev, NULL); /* turn off the speaker */ - beep_event(NULL, EV_SND, SND_BELL, 0); + state->event(input_dev, EV_SND, SND_BELL, 0); + + input_unregister_device(input_dev); + + dev_set_drvdata(&dev->dev, NULL); + kfree(state); return 0; } -static void sparcspkr_shutdown(struct platform_device *dev) +static int sparcspkr_shutdown(struct of_device *dev) { + struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); + struct input_dev *input_dev = state->input_dev; + /* turn off the speaker */ - beep_event(NULL, EV_SND, SND_BELL, 0); + state->event(input_dev, EV_SND, SND_BELL, 0); + + return 0; +} + +static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct linux_ebus_device *edev = to_ebus_device(&dev->dev); + struct sparcspkr_state *state; + int err; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->name = "Sparc EBUS Speaker"; + state->iobase = edev->resource[0].start; + state->event = ebus_spkr_event; + spin_lock_init(&state->lock); + + dev_set_drvdata(&dev->dev, state); + + err = sparcspkr_probe(&dev->dev); + if (err) { + dev_set_drvdata(&dev->dev, NULL); + kfree(state); + } + + return 0; } -static struct platform_driver sparcspkr_platform_driver = { - .driver = { - .name = "sparcspkr", - .owner = THIS_MODULE, +static struct of_device_id ebus_beep_match[] = { + { + .name = "beep", }, - .probe = sparcspkr_probe, - .remove = __devexit_p(sparcspkr_remove), - .shutdown = sparcspkr_shutdown, + {}, }; -static struct platform_device *sparcspkr_platform_device; +static struct of_platform_driver ebus_beep_driver = { + .name = "beep", + .match_table = ebus_beep_match, + .probe = ebus_beep_probe, + .remove = sparcspkr_remove, + .shutdown = sparcspkr_shutdown, +}; -static int __init sparcspkr_drv_init(void) +static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match) { - int error; + struct sparc_isa_device *idev = to_isa_device(&dev->dev); + struct sparcspkr_state *state; + int err; - error = platform_driver_register(&sparcspkr_platform_driver); - if (error) - return error; + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; - sparcspkr_platform_device = platform_device_alloc("sparcspkr", -1); - if (!sparcspkr_platform_device) { - error = -ENOMEM; - goto err_unregister_driver; - } + state->name = "Sparc ISA Speaker"; + state->iobase = idev->resource.start; + state->event = isa_spkr_event; + spin_lock_init(&state->lock); + + dev_set_drvdata(&dev->dev, state); - error = platform_device_add(sparcspkr_platform_device); - if (error) - goto err_free_device; + err = sparcspkr_probe(&dev->dev); + if (err) { + dev_set_drvdata(&dev->dev, NULL); + kfree(state); + } return 0; +} - err_free_device: - platform_device_put(sparcspkr_platform_device); - err_unregister_driver: - platform_driver_unregister(&sparcspkr_platform_driver); +static struct of_device_id isa_beep_match[] = { + { + .name = "dma", + }, + {}, +}; - return error; -} +static struct of_platform_driver isa_beep_driver = { + .name = "beep", + .match_table = isa_beep_match, + .probe = isa_beep_probe, + .remove = sparcspkr_remove, + .shutdown = sparcspkr_shutdown, +}; static int __init sparcspkr_init(void) { - struct linux_ebus *ebus; - struct linux_ebus_device *edev; -#ifdef CONFIG_SPARC64 - struct sparc_isa_bridge *isa_br; - struct sparc_isa_device *isa_dev; -#endif - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "beep")) { - beep_name = "Sparc EBUS Speaker"; - beep_event = ebus_spkr_event; - beep_iobase = edev->resource[0].start; - return sparcspkr_drv_init(); - } - } - } -#ifdef CONFIG_SPARC64 - for_each_isa(isa_br) { - for_each_isadev(isa_dev, isa_br) { - /* A hack, the beep device's base lives in - * the DMA isa node. - */ - if (!strcmp(isa_dev->prom_node->name, "dma")) { - beep_name = "Sparc ISA Speaker"; - beep_event = isa_spkr_event, - beep_iobase = isa_dev->resource.start; - return sparcspkr_drv_init(); - } - } + int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type); + + if (!err) { + err = of_register_driver(&isa_beep_driver, &isa_bus_type); + if (err) + of_unregister_driver(&ebus_beep_driver); } -#endif - return -ENODEV; + return err; } static void __exit sparcspkr_exit(void) { - platform_device_unregister(sparcspkr_platform_device); - platform_driver_unregister(&sparcspkr_platform_driver); + of_unregister_driver(&ebus_beep_driver); + of_unregister_driver(&isa_beep_driver); } module_init(sparcspkr_init); diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h index 545882bd356..a4afe9d5703 100644 --- a/include/asm-sparc64/ebus.h +++ b/include/asm-sparc64/ebus.h @@ -11,6 +11,7 @@ #include #include #include +#include struct linux_ebus_child { struct linux_ebus_child *next; @@ -24,6 +25,7 @@ struct linux_ebus_child { }; struct linux_ebus_device { + struct of_device ofdev; struct linux_ebus_device *next; struct linux_ebus_child *children; struct linux_ebus *bus; @@ -33,8 +35,10 @@ struct linux_ebus_device { unsigned int irqs[PROMINTR_MAX]; int num_irqs; }; +#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev) struct linux_ebus { + struct of_device ofdev; struct linux_ebus *next; struct linux_ebus_device *devices; struct pci_pbm_info *parent; @@ -43,6 +47,7 @@ struct linux_ebus { int is_rio; struct device_node *prom_node; }; +#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev) struct ebus_dma_info { spinlock_t lock; diff --git a/include/asm-sparc64/isa.h b/include/asm-sparc64/isa.h index 2e7fb18ec1b..d9728b9031f 100644 --- a/include/asm-sparc64/isa.h +++ b/include/asm-sparc64/isa.h @@ -10,10 +10,12 @@ #include #include #include +#include struct sparc_isa_bridge; struct sparc_isa_device { + struct of_device ofdev; struct sparc_isa_device *next; struct sparc_isa_device *child; struct sparc_isa_bridge *bus; @@ -21,8 +23,10 @@ struct sparc_isa_device { struct resource resource; unsigned int irq; }; +#define to_isa_device(d) container_of(d, struct sparc_isa_device, ofdev.dev) struct sparc_isa_bridge { + struct of_device ofdev; struct sparc_isa_bridge *next; struct sparc_isa_device *devices; struct pci_pbm_info *parent; @@ -30,6 +34,7 @@ struct sparc_isa_bridge { int index; struct device_node *prom_node; }; +#define to_isa_bridge(d) container_of(d, struct sparc_isa_bridge, ofdev.dev) extern struct sparc_isa_bridge *isa_chain; diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h new file mode 100644 index 00000000000..ceea825899c --- /dev/null +++ b/include/asm-sparc64/of_device.h @@ -0,0 +1,64 @@ +#ifndef _ASM_SPARC64_OF_DEVICE_H +#define _ASM_SPARC64_OF_DEVICE_H +#ifdef __KERNEL__ + +#include +#include +#include + +extern struct bus_type isa_bus_type; +extern struct bus_type ebus_bus_type; +extern struct bus_type sbus_bus_type; + +/* + * The of_device is a kind of "base class" that is a superset of + * struct device for use by devices attached to an OF node and + * probed using OF properties. + */ +struct of_device +{ + struct device_node *node; /* OF device node */ + struct device dev; /* Generic device interface */ +}; +#define to_of_device(d) container_of(d, struct of_device, dev) + +extern const struct of_device_id *of_match_device( + const struct of_device_id *matches, const struct of_device *dev); + +extern struct of_device *of_dev_get(struct of_device *dev); +extern void of_dev_put(struct of_device *dev); + +/* + * An of_platform_driver driver is attached to a basic of_device on + * the ISA, EBUS, and SBUS busses on sparc64. + */ +struct of_platform_driver +{ + char *name; + struct of_device_id *match_table; + struct module *owner; + + int (*probe)(struct of_device* dev, const struct of_device_id *match); + int (*remove)(struct of_device* dev); + + int (*suspend)(struct of_device* dev, pm_message_t state); + int (*resume)(struct of_device* dev); + int (*shutdown)(struct of_device* dev); + + struct device_driver driver; +}; +#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver) + +extern int of_register_driver(struct of_platform_driver *drv, + struct bus_type *bus); +extern void of_unregister_driver(struct of_platform_driver *drv); +extern int of_device_register(struct of_device *ofdev); +extern void of_device_unregister(struct of_device *ofdev); +extern struct of_device *of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent, + struct bus_type *bus); +extern void of_release_dev(struct device *dev); + +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_OF_DEVICE_H */ -- cgit v1.2.3-70-g09d2 From fd5314311634245172d40ccb418d89dac91d6ad6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 23 Jun 2006 15:55:17 -0700 Subject: [SPARC]: Port of_device layer and make ebus use it. Signed-off-by: David S. Miller --- arch/sparc/kernel/Makefile | 2 +- arch/sparc/kernel/ebus.c | 21 ++++ arch/sparc/kernel/of_device.c | 268 ++++++++++++++++++++++++++++++++++++++++ include/asm-sparc/ebus.h | 5 + include/asm-sparc/of_device.h | 63 ++++++++++ include/asm-sparc64/of_device.h | 2 +- 6 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 arch/sparc/kernel/of_device.c create mode 100644 include/asm-sparc/of_device.h (limited to 'include/asm-sparc64') diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 93e41d0dd8d..6616ee05c31 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \ sys_sparc.o sunos_asm.o systbls.o \ time.o windows.o cpu.o devices.o sclow.o \ tadpole.o tick14.o ptrace.o sys_solaris.o \ - unaligned.o muldiv.o semaphore.o prom.o + unaligned.o muldiv.o semaphore.o prom.o of_device.o obj-$(CONFIG_PCI) += pcic.o obj-$(CONFIG_SUN4) += sun4setup.o diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c index 9d461da7639..a7a4892956c 100644 --- a/arch/sparc/kernel/ebus.c +++ b/arch/sparc/kernel/ebus.c @@ -235,6 +235,16 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d } } + dev->ofdev.node = dp; + dev->ofdev.dev.parent = &dev->bus->ofdev.dev; + dev->ofdev.dev.bus = &ebus_bus_type; + strcpy(dev->ofdev.dev.bus_id, dp->path_component_name); + + /* Register with core */ + if (of_device_register(&dev->ofdev) != 0) + printk(KERN_DEBUG "ebus: device registration error for %s!\n", + dev->ofdev.dev.bus_id); + if ((dp = dp->child) != NULL) { dev->children = (struct linux_ebus_child *) ebus_alloc(sizeof(struct linux_ebus_child)); @@ -321,6 +331,17 @@ void __init ebus_init(void) *base++ = addr; } + ebus->ofdev.node = dp; + ebus->ofdev.dev.parent = &pdev->dev; + ebus->ofdev.dev.bus = &ebus_bus_type; + strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name); + + /* Register with core */ + if (of_device_register(&ebus->ofdev) != 0) + printk(KERN_DEBUG "ebus: device registration error for %s!\n", + ebus->ofdev.dev.bus_id); + + nd = dp->child; if (!nd) goto next_ebus; diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c new file mode 100644 index 00000000000..001b8673b4b --- /dev/null +++ b/arch/sparc/kernel/of_device.c @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * of_match_device - Tell if an of_device structure has a matching + * of_match structure + * @ids: array of of device match structures to search in + * @dev: the of device structure to match against + * + * Used by a driver to check whether an of_device present in the + * system is in its list of supported devices. + */ +const struct of_device_id *of_match_device(const struct of_device_id *matches, + const struct of_device *dev) +{ + if (!dev->node) + return NULL; + while (matches->name[0] || matches->type[0] || matches->compatible[0]) { + int match = 1; + if (matches->name[0]) + match &= dev->node->name + && !strcmp(matches->name, dev->node->name); + if (matches->type[0]) + match &= dev->node->type + && !strcmp(matches->type, dev->node->type); + if (matches->compatible[0]) + match &= of_device_is_compatible(dev->node, + matches->compatible); + if (match) + return matches; + matches++; + } + return NULL; +} + +static int of_platform_bus_match(struct device *dev, struct device_driver *drv) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * of_drv = to_of_platform_driver(drv); + const struct of_device_id * matches = of_drv->match_table; + + if (!matches) + return 0; + + return of_match_device(matches, of_dev) != NULL; +} + +struct of_device *of_dev_get(struct of_device *dev) +{ + struct device *tmp; + + if (!dev) + return NULL; + tmp = get_device(&dev->dev); + if (tmp) + return to_of_device(tmp); + else + return NULL; +} + +void of_dev_put(struct of_device *dev) +{ + if (dev) + put_device(&dev->dev); +} + + +static int of_device_probe(struct device *dev) +{ + int error = -ENODEV; + struct of_platform_driver *drv; + struct of_device *of_dev; + const struct of_device_id *match; + + drv = to_of_platform_driver(dev->driver); + of_dev = to_of_device(dev); + + if (!drv->probe) + return error; + + of_dev_get(of_dev); + + match = of_match_device(drv->match_table, of_dev); + if (match) + error = drv->probe(of_dev, match); + if (error) + of_dev_put(of_dev); + + return error; +} + +static int of_device_remove(struct device *dev) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(dev->driver); + + if (dev->driver && drv->remove) + drv->remove(of_dev); + return 0; +} + +static int of_device_suspend(struct device *dev, pm_message_t state) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(dev->driver); + int error = 0; + + if (dev->driver && drv->suspend) + error = drv->suspend(of_dev, state); + return error; +} + +static int of_device_resume(struct device * dev) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(dev->driver); + int error = 0; + + if (dev->driver && drv->resume) + error = drv->resume(of_dev); + return error; +} + +#ifdef CONFIG_PCI +struct bus_type ebus_bus_type = { + .name = "ebus", + .match = of_platform_bus_match, + .probe = of_device_probe, + .remove = of_device_remove, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; +#endif + +#ifdef CONFIG_SBUS +struct bus_type sbus_bus_type = { + .name = "sbus", + .match = of_platform_bus_match, + .probe = of_device_probe, + .remove = of_device_remove, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; +#endif + +static int __init of_bus_driver_init(void) +{ + int err = 0; + +#ifdef CONFIG_PCI + if (!err) + err = bus_register(&ebus_bus_type); +#endif +#ifdef CONFIG_SBUS + if (!err) + err = bus_register(&sbus_bus_type); +#endif + return 0; +} + +postcore_initcall(of_bus_driver_init); + +int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) +{ + /* initialize common driver fields */ + drv->driver.name = drv->name; + drv->driver.bus = bus; + + /* register with core */ + return driver_register(&drv->driver); +} + +void of_unregister_driver(struct of_platform_driver *drv) +{ + driver_unregister(&drv->driver); +} + + +static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct of_device *ofdev; + + ofdev = to_of_device(dev); + return sprintf(buf, "%s", ofdev->node->full_name); +} + +static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); + +/** + * of_release_dev - free an of device structure when all users of it are finished. + * @dev: device that's been disconnected + * + * Will be called only by the device core when all users of this of device are + * done. + */ +void of_release_dev(struct device *dev) +{ + struct of_device *ofdev; + + ofdev = to_of_device(dev); + + kfree(ofdev); +} + +int of_device_register(struct of_device *ofdev) +{ + int rc; + + BUG_ON(ofdev->node == NULL); + + rc = device_register(&ofdev->dev); + if (rc) + return rc; + + device_create_file(&ofdev->dev, &dev_attr_devspec); + + return 0; +} + +void of_device_unregister(struct of_device *ofdev) +{ + device_remove_file(&ofdev->dev, &dev_attr_devspec); + device_unregister(&ofdev->dev); +} + +struct of_device* of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent, + struct bus_type *bus) +{ + struct of_device *dev; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + memset(dev, 0, sizeof(*dev)); + + dev->dev.parent = parent; + dev->dev.bus = bus; + dev->dev.release = of_release_dev; + + strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); + + if (of_device_register(dev) != 0) { + kfree(dev); + return NULL; + } + + return dev; +} + +EXPORT_SYMBOL(of_match_device); +EXPORT_SYMBOL(of_register_driver); +EXPORT_SYMBOL(of_unregister_driver); +EXPORT_SYMBOL(of_device_register); +EXPORT_SYMBOL(of_device_unregister); +EXPORT_SYMBOL(of_dev_get); +EXPORT_SYMBOL(of_dev_put); +EXPORT_SYMBOL(of_platform_device_create); +EXPORT_SYMBOL(of_release_dev); diff --git a/include/asm-sparc/ebus.h b/include/asm-sparc/ebus.h index 0dc3c01b4b1..54652887c12 100644 --- a/include/asm-sparc/ebus.h +++ b/include/asm-sparc/ebus.h @@ -14,6 +14,7 @@ #endif #include #include +#include struct linux_ebus_child { struct linux_ebus_child *next; @@ -27,6 +28,7 @@ struct linux_ebus_child { }; struct linux_ebus_device { + struct of_device ofdev; struct linux_ebus_device *next; struct linux_ebus_child *children; struct linux_ebus *bus; @@ -36,14 +38,17 @@ struct linux_ebus_device { unsigned int irqs[PROMINTR_MAX]; int num_irqs; }; +#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev) struct linux_ebus { + struct of_device ofdev; struct linux_ebus *next; struct linux_ebus_device *devices; struct linux_pbm_info *parent; struct pci_dev *self; struct device_node *prom_node; }; +#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev) struct linux_ebus_dma { unsigned int dcsr; diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h new file mode 100644 index 00000000000..4816d102f91 --- /dev/null +++ b/include/asm-sparc/of_device.h @@ -0,0 +1,63 @@ +#ifndef _ASM_SPARC_OF_DEVICE_H +#define _ASM_SPARC_OF_DEVICE_H +#ifdef __KERNEL__ + +#include +#include +#include + +extern struct bus_type ebus_bus_type; +extern struct bus_type sbus_bus_type; + +/* + * The of_device is a kind of "base class" that is a superset of + * struct device for use by devices attached to an OF node and + * probed using OF properties. + */ +struct of_device +{ + struct device_node *node; /* OF device node */ + struct device dev; /* Generic device interface */ +}; +#define to_of_device(d) container_of(d, struct of_device, dev) + +extern const struct of_device_id *of_match_device( + const struct of_device_id *matches, const struct of_device *dev); + +extern struct of_device *of_dev_get(struct of_device *dev); +extern void of_dev_put(struct of_device *dev); + +/* + * An of_platform_driver driver is attached to a basic of_device on + * the ISA, EBUS, and SBUS busses on sparc64. + */ +struct of_platform_driver +{ + char *name; + struct of_device_id *match_table; + struct module *owner; + + int (*probe)(struct of_device* dev, const struct of_device_id *match); + int (*remove)(struct of_device* dev); + + int (*suspend)(struct of_device* dev, pm_message_t state); + int (*resume)(struct of_device* dev); + int (*shutdown)(struct of_device* dev); + + struct device_driver driver; +}; +#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver) + +extern int of_register_driver(struct of_platform_driver *drv, + struct bus_type *bus); +extern void of_unregister_driver(struct of_platform_driver *drv); +extern int of_device_register(struct of_device *ofdev); +extern void of_device_unregister(struct of_device *ofdev); +extern struct of_device *of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent, + struct bus_type *bus); +extern void of_release_dev(struct device *dev); + +#endif /* __KERNEL__ */ +#endif /* _ASM_SPARC_OF_DEVICE_H */ diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h index ceea825899c..024088ef9d2 100644 --- a/include/asm-sparc64/of_device.h +++ b/include/asm-sparc64/of_device.h @@ -61,4 +61,4 @@ extern struct of_device *of_platform_device_create(struct device_node *np, extern void of_release_dev(struct device *dev); #endif /* __KERNEL__ */ -#endif /* _ASM_POWERPC_OF_DEVICE_H */ +#endif /* _ASM_SPARC64_OF_DEVICE_H */ -- cgit v1.2.3-70-g09d2 From 576c352e89e57cfa6c9f493e549d10d86f60a0cf Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 23 Jun 2006 15:55:45 -0700 Subject: [SBUS]: Rewrite and plug into of_device framework. I severely apologize, I was still learning how to program in C when I wrote this stuff 10 years ago... Signed-off-by: David S. Miller --- arch/sparc/kernel/ioport.c | 85 +++++++++ arch/sparc64/kernel/sbus.c | 31 +++- drivers/sbus/sbus.c | 449 ++++++++++++++------------------------------- include/asm-sparc/sbus.h | 27 ++- include/asm-sparc64/sbus.h | 28 ++- 5 files changed, 293 insertions(+), 327 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 00cf4118291..ae4c667c906 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -458,6 +460,89 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, { printk("sbus_dma_sync_sg_for_device: not implemented yet\n"); } + +/* Support code for sbus_init(). */ +/* + * XXX This functions appears to be a distorted version of + * prom_sbus_ranges_init(), with all sun4d stuff cut away. + * Ask DaveM what is going on here, how is sun4d supposed to work... XXX + */ +/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */ +void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus) +{ + int parent_node = pn->node; + + if (sparc_cpu_model == sun4d) { + struct linux_prom_ranges iounit_ranges[PROMREG_MAX]; + int num_iounit_ranges, len; + + len = prom_getproperty(parent_node, "ranges", + (char *) iounit_ranges, + sizeof (iounit_ranges)); + if (len != -1) { + num_iounit_ranges = + (len / sizeof(struct linux_prom_ranges)); + prom_adjust_ranges(sbus->sbus_ranges, + sbus->num_sbus_ranges, + iounit_ranges, num_iounit_ranges); + } + } +} + +void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp) +{ + struct device_node *parent = dp->parent; + + if (sparc_cpu_model != sun4d && + parent != NULL && + !strcmp(parent->name, "iommu")) { + extern void iommu_init(int iommu_node, struct sbus_bus *sbus); + + iommu_init(parent->node, sbus); + } + + if (sparc_cpu_model == sun4d) { + extern void iounit_init(int sbi_node, int iounit_node, + struct sbus_bus *sbus); + + iounit_init(dp->node, parent->node, sbus); + } +} + +void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp) +{ + if (sparc_cpu_model == sun4d) { + struct device_node *parent = dp->parent; + + sbus->devid = of_getintprop_default(parent, "device-id", 0); + sbus->board = of_getintprop_default(parent, "board#", 0); + } +} + +int __init sbus_arch_preinit(void) +{ + extern void register_proc_sparc_ioport(void); + + register_proc_sparc_ioport(); + +#ifdef CONFIG_SUN4 + { + extern void sun4_dvma_init(void); + sun4_dvma_init(); + } + return 1; +#else + return 0; +#endif +} + +void __init sbus_arch_postinit(void) +{ + if (sparc_cpu_model == sun4d) { + extern void sun4d_init_sbi_irq(void); + sun4d_init_sbi_irq(); + } +} #endif /* CONFIG_SBUS */ #ifdef CONFIG_PCI diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index a72bba39880..d3da23cdc26 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -1099,7 +1099,7 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus) } /* Boot time initialization. */ -void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) +static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) { struct linux_prom64_registers *pr; struct device_node *dp; @@ -1247,3 +1247,32 @@ void sbus_fill_device_irq(struct sbus_dev *sdev) sdev->irqs[0] = sbus_build_irq(sdev->bus, pri); } } + +void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus) +{ +} + +void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp) +{ + sbus_iommu_init(dp->node, sbus); +} + +void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp) +{ +} + +int __init sbus_arch_preinit(void) +{ + return 0; +} + +void __init sbus_arch_postinit(void) +{ + extern void firetruck_init(void); + extern void auxio_probe(void); + extern void clock_probe(void); + + firetruck_init(); + auxio_probe(); + clock_probe(); +} diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 6e9b2608202..387a6aa8c02 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -13,32 +13,29 @@ #include #include #include +#include +#include #include #include struct sbus_bus *sbus_root; -#ifdef CONFIG_PCI -extern int pcic_present(void); -#endif - -static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) +static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) { - unsigned long address, base; + unsigned long base; + void *pval; int len; - sdev->prom_node = prom_node; - prom_getstring(prom_node, "name", - sdev->prom_name, sizeof(sdev->prom_name)); - address = prom_getint(prom_node, "address"); - len = prom_getproperty(prom_node, "reg", - (char *) sdev->reg_addrs, - sizeof(sdev->reg_addrs)); + sdev->prom_node = dp->node; + strcpy(sdev->prom_name, dp->name); + + pval = of_get_property(dp, "reg", &len); sdev->num_registers = 0; - if (len != -1) { + if (pval) { + memcpy(sdev->reg_addrs, pval, len); + sdev->num_registers = len / sizeof(struct linux_prom_registers); - sdev->ranges_applied = 0; base = (unsigned long) sdev->reg_addrs[0].phys_addr; @@ -49,97 +46,43 @@ static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) sdev->slot = sdev->reg_addrs[0].which_io; } - len = prom_getproperty(prom_node, "ranges", - (char *)sdev->device_ranges, - sizeof(sdev->device_ranges)); + pval = of_get_property(dp, "ranges", &len); sdev->num_device_ranges = 0; - if (len != -1) + if (pval) { + memcpy(sdev->device_ranges, pval, len); sdev->num_device_ranges = len / sizeof(struct linux_prom_ranges); + } sbus_fill_device_irq(sdev); -} -/* This routine gets called from whoever needs the sbus first, to scan - * the SBus device tree. Currently it just prints out the devices - * found on the bus and builds trees of SBUS structs and attached - * devices. - */ - -extern void iommu_init(int iommu_node, struct sbus_bus *sbus); -extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus); -void sun4_init(void); -#ifdef CONFIG_SUN_AUXIO -extern void auxio_probe(void); -#endif - -static void __init sbus_do_child_siblings(int start_node, - struct sbus_dev *child, - struct sbus_dev *parent, - struct sbus_bus *sbus) -{ - struct sbus_dev *this_dev = child; - int this_node = start_node; - - /* Child already filled in, just need to traverse siblings. */ - child->child = NULL; - child->parent = parent; - while((this_node = prom_getsibling(this_node)) != 0) { - this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); - this_dev = this_dev->next; - this_dev->next = NULL; - this_dev->parent = parent; - - this_dev->bus = sbus; - fill_sbus_device(this_node, this_dev); - - if(prom_getchild(this_node)) { - this_dev->child = kmalloc(sizeof(struct sbus_dev), - GFP_ATOMIC); - this_dev->child->bus = sbus; - this_dev->child->next = NULL; - fill_sbus_device(prom_getchild(this_node), this_dev->child); - sbus_do_child_siblings(prom_getchild(this_node), - this_dev->child, this_dev, sbus); - } else { - this_dev->child = NULL; - } - } + sdev->ofdev.node = dp; + if (sdev->parent) + sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev; + else + sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev; + sdev->ofdev.dev.bus = &sbus_bus_type; + strcpy(sdev->ofdev.dev.bus_id, dp->path_component_name); + + if (of_device_register(&sdev->ofdev) != 0) + printk(KERN_DEBUG "sbus: device registration error for %s!\n", + sdev->ofdev.dev.bus_id); } -/* - * XXX This functions appears to be a distorted version of - * prom_sbus_ranges_init(), with all sun4d stuff cut away. - * Ask DaveM what is going on here, how is sun4d supposed to work... XXX - */ -/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */ - -static void __init sbus_bus_ranges_init(int parent_node, struct sbus_bus *sbus) +static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) { + void *pval; int len; - len = prom_getproperty(sbus->prom_node, "ranges", - (char *) sbus->sbus_ranges, - sizeof(sbus->sbus_ranges)); - if (len == -1 || len == 0) { - sbus->num_sbus_ranges = 0; - return; - } - sbus->num_sbus_ranges = len / sizeof(struct linux_prom_ranges); -#ifdef CONFIG_SPARC32 - if (sparc_cpu_model == sun4d) { - struct linux_prom_ranges iounit_ranges[PROMREG_MAX]; - int num_iounit_ranges; - - len = prom_getproperty(parent_node, "ranges", - (char *) iounit_ranges, - sizeof (iounit_ranges)); - if (len != -1) { - num_iounit_ranges = (len/sizeof(struct linux_prom_ranges)); - prom_adjust_ranges (sbus->sbus_ranges, sbus->num_sbus_ranges, iounit_ranges, num_iounit_ranges); - } + pval = of_get_property(dp, "ranges", &len); + sbus->num_sbus_ranges = 0; + if (pval) { + memcpy(sbus->sbus_ranges, pval, len); + sbus->num_sbus_ranges = + len / sizeof(struct linux_prom_ranges); + + sbus_arch_bus_ranges_init(dp->parent, sbus); } -#endif } static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges, @@ -217,241 +160,127 @@ static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev) } } -extern void register_proc_sparc_ioport(void); -extern void firetruck_init(void); +/* We preserve the "probe order" of these bus and device lists to give + * the same ordering as the old code. + */ +static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root) +{ + while (*root) + root = &(*root)->next; + *root = sbus; + sbus->next = NULL; +} -#ifdef CONFIG_SUN4 -extern void sun4_dvma_init(void); -#endif +static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root) +{ + while (*root) + root = &(*root)->next; + *root = sdev; + sdev->next = NULL; +} -static int __init sbus_init(void) +static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus) { - int nd, this_sbus, sbus_devs, topnd, iommund; - unsigned int sbus_clock; - struct sbus_bus *sbus; - struct sbus_dev *this_dev; - int num_sbus = 0; /* How many did we find? */ + dp = dp->child; + while (dp) { + struct sbus_dev *sdev; -#ifdef CONFIG_SPARC32 - register_proc_sparc_ioport(); -#endif + sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); + if (sdev) { + sdev_insert(sdev, &parent->child); -#ifdef CONFIG_SUN4 - sun4_dvma_init(); - return 0; -#endif - - topnd = prom_getchild(prom_root_node); - - /* Finding the first sbus is a special case... */ - iommund = 0; - if(sparc_cpu_model == sun4u) { - nd = prom_searchsiblings(topnd, "sbus"); - if(nd == 0) { -#ifdef CONFIG_PCI - if (!pcic_present()) { - prom_printf("Neither SBUS nor PCI found.\n"); - prom_halt(); - } else { -#ifdef CONFIG_SPARC64 - firetruck_init(); -#endif - } - return 0; -#else - prom_printf("YEEE, UltraSparc sbus not found\n"); - prom_halt(); -#endif - } - } else if(sparc_cpu_model == sun4d) { - if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 || - (nd = prom_getchild(iommund)) == 0 || - (nd = prom_searchsiblings(nd, "sbi")) == 0) { - panic("sbi not found"); - } - } else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) { - if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 || - (nd = prom_getchild(iommund)) == 0 || - (nd = prom_searchsiblings(nd, "sbus")) == 0) { -#ifdef CONFIG_PCI - if (!pcic_present()) { - prom_printf("Neither SBUS nor PCI found.\n"); - prom_halt(); - } - return 0; -#else - /* No reason to run further - the data access trap will occur. */ - panic("sbus not found"); -#endif + sdev->bus = sbus; + sdev->parent = parent; + + fill_sbus_device(dp, sdev); + + walk_children(dp, sdev, sbus); } + dp = dp->sibling; } +} - /* Ok, we've found the first one, allocate first SBus struct - * and place in chain. - */ - sbus = sbus_root = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC); - sbus->next = NULL; - sbus->prom_node = nd; - this_sbus = nd; +static void __init build_one_sbus(struct device_node *dp, int num_sbus) +{ + struct sbus_bus *sbus; + unsigned int sbus_clock; + struct device_node *dev_dp; - if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d) - iommu_init(iommund, sbus); + sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC); + if (!sbus) + return; - /* Loop until we find no more SBUS's */ - while(this_sbus) { -#ifdef CONFIG_SPARC64 - /* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */ - if(sparc_cpu_model == sun4u) { - extern void sbus_iommu_init(int prom_node, struct sbus_bus *sbus); + sbus_insert(sbus, &sbus_root); + sbus->prom_node = dp->node; - sbus_iommu_init(this_sbus, sbus); - } -#endif /* CONFIG_SPARC64 */ - -#ifdef CONFIG_SPARC32 - if (sparc_cpu_model == sun4d) - iounit_init(this_sbus, iommund, sbus); -#endif /* CONFIG_SPARC32 */ - printk("sbus%d: ", num_sbus); - sbus_clock = prom_getint(this_sbus, "clock-frequency"); - if(sbus_clock == -1) - sbus_clock = (25*1000*1000); - printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), - (int) (((sbus_clock/1000)%1000 != 0) ? - (((sbus_clock/1000)%1000) + 1000) : 0)); - - prom_getstring(this_sbus, "name", - sbus->prom_name, sizeof(sbus->prom_name)); - sbus->clock_freq = sbus_clock; -#ifdef CONFIG_SPARC32 - if (sparc_cpu_model == sun4d) { - sbus->devid = prom_getint(iommund, "device-id"); - sbus->board = prom_getint(iommund, "board#"); - } -#endif - - sbus_bus_ranges_init(iommund, sbus); - - sbus_devs = prom_getchild(this_sbus); - if (!sbus_devs) { - sbus->devices = NULL; - goto next_bus; - } + sbus_setup_iommu(sbus, dp); - sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); - - this_dev = sbus->devices; - this_dev->next = NULL; - - this_dev->bus = sbus; - this_dev->parent = NULL; - fill_sbus_device(sbus_devs, this_dev); - - /* Should we traverse for children? */ - if(prom_getchild(sbus_devs)) { - /* Allocate device node */ - this_dev->child = kmalloc(sizeof(struct sbus_dev), - GFP_ATOMIC); - /* Fill it */ - this_dev->child->bus = sbus; - this_dev->child->next = NULL; - fill_sbus_device(prom_getchild(sbus_devs), - this_dev->child); - sbus_do_child_siblings(prom_getchild(sbus_devs), - this_dev->child, - this_dev, - sbus); - } else { - this_dev->child = NULL; - } + printk("sbus%d: ", num_sbus); - while((sbus_devs = prom_getsibling(sbus_devs)) != 0) { - /* Allocate device node */ - this_dev->next = kmalloc(sizeof(struct sbus_dev), - GFP_ATOMIC); - this_dev = this_dev->next; - this_dev->next = NULL; - - /* Fill it */ - this_dev->bus = sbus; - this_dev->parent = NULL; - fill_sbus_device(sbus_devs, this_dev); - - /* Is there a child node hanging off of us? */ - if(prom_getchild(sbus_devs)) { - /* Get new device struct */ - this_dev->child = kmalloc(sizeof(struct sbus_dev), - GFP_ATOMIC); - /* Fill it */ - this_dev->child->bus = sbus; - this_dev->child->next = NULL; - fill_sbus_device(prom_getchild(sbus_devs), - this_dev->child); - sbus_do_child_siblings(prom_getchild(sbus_devs), - this_dev->child, - this_dev, - sbus); - } else { - this_dev->child = NULL; - } + sbus_clock = of_getintprop_default(dp, "clock-frequency", + (25*1000*1000)); + sbus->clock_freq = sbus_clock; + + printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), + (int) (((sbus_clock/1000)%1000 != 0) ? + (((sbus_clock/1000)%1000) + 1000) : 0)); + + strcpy(sbus->prom_name, dp->name); + + sbus_setup_arch_props(sbus, dp); + + sbus_bus_ranges_init(dp, sbus); + + sbus->ofdev.node = dp; + sbus->ofdev.dev.parent = NULL; + sbus->ofdev.dev.bus = &sbus_bus_type; + strcpy(sbus->ofdev.dev.bus_id, dp->path_component_name); + + if (of_device_register(&sbus->ofdev) != 0) + printk(KERN_DEBUG "sbus: device registration error for %s!\n", + sbus->ofdev.dev.bus_id); + + dev_dp = dp->child; + while (dev_dp) { + struct sbus_dev *sdev; + + sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); + if (sdev) { + sdev_insert(sdev, &sbus->devices); + + sdev->bus = sbus; + sdev->parent = NULL; + fill_sbus_device(dev_dp, sdev); + + walk_children(dev_dp, sdev, sbus); } + dev_dp = dev_dp->sibling; + } + + sbus_fixup_all_regs(sbus->devices); + + dvma_init(sbus); +} + +static int __init sbus_init(void) +{ + struct device_node *dp; + const char *sbus_name = "sbus"; + int num_sbus = 0; - /* Walk all devices and apply parent ranges. */ - sbus_fixup_all_regs(sbus->devices); + if (sbus_arch_preinit()) + return 0; - dvma_init(sbus); - next_bus: + if (sparc_cpu_model == sun4d) + sbus_name = "sbi"; + + for_each_node_by_name(dp, sbus_name) { + build_one_sbus(dp, num_sbus); num_sbus++; - if(sparc_cpu_model == sun4u) { - this_sbus = prom_getsibling(this_sbus); - if(!this_sbus) - break; - this_sbus = prom_searchsiblings(this_sbus, "sbus"); - } else if(sparc_cpu_model == sun4d) { - iommund = prom_getsibling(iommund); - if(!iommund) - break; - iommund = prom_searchsiblings(iommund, "io-unit"); - if(!iommund) - break; - this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi"); - } else { - this_sbus = prom_getsibling(this_sbus); - if(!this_sbus) - break; - this_sbus = prom_searchsiblings(this_sbus, "sbus"); - } - if(this_sbus) { - sbus->next = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC); - sbus = sbus->next; - sbus->next = NULL; - sbus->prom_node = this_sbus; - } else { - break; - } - } /* while(this_sbus) */ - if (sparc_cpu_model == sun4d) { - extern void sun4d_init_sbi_irq(void); - sun4d_init_sbi_irq(); - } - -#ifdef CONFIG_SPARC64 - if (sparc_cpu_model == sun4u) { - firetruck_init(); } -#endif -#ifdef CONFIG_SUN_AUXIO - if (sparc_cpu_model == sun4u) - auxio_probe (); -#endif -#ifdef CONFIG_SPARC64 - if (sparc_cpu_model == sun4u) { - extern void clock_probe(void); - - clock_probe(); - } -#endif + + sbus_arch_postinit(); return 0; } diff --git a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h index 76654fa2309..d036e4419d7 100644 --- a/include/asm-sparc/sbus.h +++ b/include/asm-sparc/sbus.h @@ -11,7 +11,8 @@ #include #include -/* #include */ /* Unused since we use opaque iommu (|io-unit) */ +#include +#include #include /* We scan which devices are on the SBus using the PROM node device @@ -42,18 +43,19 @@ struct sbus_bus; /* Linux SBUS device tables */ struct sbus_dev { - struct sbus_bus *bus; /* Back ptr to sbus */ - struct sbus_dev *next; /* next device on this SBus or null */ - struct sbus_dev *child; /* For ledma and espdma on sun4m */ - struct sbus_dev *parent; /* Parent device if not toplevel */ - int prom_node; /* PROM device tree node for this device */ - char prom_name[64]; /* PROM device name */ + struct of_device ofdev; + struct sbus_bus *bus; + struct sbus_dev *next; + struct sbus_dev *child; + struct sbus_dev *parent; + int prom_node; + char prom_name[64]; int slot; struct resource resource[PROMREG_MAX]; struct linux_prom_registers reg_addrs[PROMREG_MAX]; - int num_registers, ranges_applied; + int num_registers; struct linux_prom_ranges device_ranges[PROMREG_MAX]; int num_device_ranges; @@ -61,9 +63,11 @@ struct sbus_dev { unsigned int irqs[4]; int num_irqs; }; +#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev) /* This struct describes the SBus(s) found on this machine. */ struct sbus_bus { + struct of_device ofdev; void *iommu; /* Opaque IOMMU cookie */ struct sbus_dev *devices; /* Link to devices on this SBus */ struct sbus_bus *next; /* next SBus, if more than one SBus */ @@ -77,6 +81,7 @@ struct sbus_bus { int devid; int board; }; +#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev) extern struct sbus_bus *sbus_root; @@ -140,4 +145,10 @@ extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int) #define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint) +extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *); +extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *); +extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *); +extern int sbus_arch_preinit(void); +extern void sbus_arch_postinit(void); + #endif /* !(_SPARC_SBUS_H) */ diff --git a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h index ca2054da243..56ee985e460 100644 --- a/include/asm-sparc64/sbus.h +++ b/include/asm-sparc64/sbus.h @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include @@ -42,18 +44,19 @@ struct sbus_bus; /* Linux SBUS device tables */ struct sbus_dev { - struct sbus_bus *bus; /* Our toplevel parent SBUS */ - struct sbus_dev *next; /* Chain of siblings */ - struct sbus_dev *child; /* Chain of children */ - struct sbus_dev *parent;/* Parent device if not toplevel*/ - int prom_node; /* OBP node of this device */ - char prom_name[64]; /* OBP device name property */ - int slot; /* SBUS slot number */ + struct of_device ofdev; + struct sbus_bus *bus; + struct sbus_dev *next; + struct sbus_dev *child; + struct sbus_dev *parent; + int prom_node; + char prom_name[64]; + int slot; struct resource resource[PROMREG_MAX]; struct linux_prom_registers reg_addrs[PROMREG_MAX]; - int num_registers, ranges_applied; + int num_registers; struct linux_prom_ranges device_ranges[PROMREG_MAX]; int num_device_ranges; @@ -61,9 +64,11 @@ struct sbus_dev { unsigned int irqs[4]; int num_irqs; }; +#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev) /* This struct describes the SBus(s) found on this machine. */ struct sbus_bus { + struct of_device ofdev; void *iommu; /* Opaque IOMMU cookie */ struct sbus_dev *devices; /* Tree of SBUS devices */ struct sbus_bus *next; /* Next SBUS in system */ @@ -77,6 +82,7 @@ struct sbus_bus { int portid; void *starfire_cookie; }; +#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev) extern struct sbus_bus *sbus_root; @@ -120,4 +126,10 @@ extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, in #define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int); +extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *); +extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *); +extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *); +extern int sbus_arch_preinit(void); +extern void sbus_arch_postinit(void); + #endif /* !(_SPARC64_SBUS_H) */ -- cgit v1.2.3-70-g09d2 From bfe5d834195b3089b8846577311340376cc0f450 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 25 Jun 2006 05:47:14 -0700 Subject: [PATCH] Define __raw_get_cpu_var and use it There are several instances of per_cpu(foo, raw_smp_processor_id()), which is semantically equivalent to __get_cpu_var(foo) but without the warning that smp_processor_id() can give if CONFIG_DEBUG_PREEMPT is enabled. For those architectures with optimized per-cpu implementations, namely ia64, powerpc, s390, sparc64 and x86_64, per_cpu() turns into more and slower code than __get_cpu_var(), so it would be preferable to use __get_cpu_var on those platforms. This defines a __raw_get_cpu_var(x) macro which turns into per_cpu(x, raw_smp_processor_id()) on architectures that use the generic per-cpu implementation, and turns into __get_cpu_var(x) on the architectures that have an optimized per-cpu implementation. Signed-off-by: Paul Mackerras Acked-by: David S. Miller Acked-by: Ingo Molnar Acked-by: Martin Schwidefsky Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-generic/percpu.h | 2 ++ include/asm-ia64/percpu.h | 2 ++ include/asm-powerpc/percpu.h | 2 ++ include/asm-s390/percpu.h | 2 ++ include/asm-sparc64/percpu.h | 2 ++ include/asm-x86_64/percpu.h | 2 ++ kernel/hrtimer.c | 4 ++-- kernel/sched.c | 4 ++-- kernel/softlockup.c | 2 +- kernel/timer.c | 2 +- net/ipv4/route.c | 2 +- 11 files changed, 19 insertions(+), 7 deletions(-) (limited to 'include/asm-sparc64') diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index c0caf433a7d..c7452115746 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -14,6 +14,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS]; /* var is in discarded region: offset to particular copy we want */ #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) #define __get_cpu_var(var) per_cpu(var, smp_processor_id()) +#define __raw_get_cpu_var(var) per_cpu(var, raw_smp_processor_id()) /* A macro to avoid #include hell... */ #define percpu_modcopy(pcpudst, src, size) \ @@ -30,6 +31,7 @@ do { \ #define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var)) #define __get_cpu_var(var) per_cpu__##var +#define __raw_get_cpu_var(var) per_cpu__##var #endif /* SMP */ diff --git a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h index ae357d504fb..24d898b650c 100644 --- a/include/asm-ia64/percpu.h +++ b/include/asm-ia64/percpu.h @@ -42,6 +42,7 @@ DECLARE_PER_CPU(unsigned long, local_per_cpu_offset); #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset))) +#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset))) extern void percpu_modcopy(void *pcpudst, const void *src, unsigned long size); extern void setup_per_cpu_areas (void); @@ -51,6 +52,7 @@ extern void *per_cpu_init(void); #define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var)) #define __get_cpu_var(var) per_cpu__##var +#define __raw_get_cpu_var(var) per_cpu__##var #define per_cpu_init() (__phys_per_cpu_start) #endif /* SMP */ diff --git a/include/asm-powerpc/percpu.h b/include/asm-powerpc/percpu.h index 184a7a4d2fd..faa1fc70305 100644 --- a/include/asm-powerpc/percpu.h +++ b/include/asm-powerpc/percpu.h @@ -22,6 +22,7 @@ /* var is in discarded region: offset to particular copy we want */ #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu))) #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset())) +#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset())) /* A macro to avoid #include hell... */ #define percpu_modcopy(pcpudst, src, size) \ @@ -41,6 +42,7 @@ extern void setup_per_cpu_areas(void); #define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var)) #define __get_cpu_var(var) per_cpu__##var +#define __raw_get_cpu_var(var) per_cpu__##var #endif /* SMP */ diff --git a/include/asm-s390/percpu.h b/include/asm-s390/percpu.h index 436d216601e..d9a8cca9b65 100644 --- a/include/asm-s390/percpu.h +++ b/include/asm-s390/percpu.h @@ -40,6 +40,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS]; __typeof__(type) per_cpu__##name #define __get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset) +#define __raw_get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset) #define per_cpu(var,cpu) __reloc_hide(var,__per_cpu_offset[cpu]) /* A macro to avoid #include hell... */ @@ -57,6 +58,7 @@ do { \ __typeof__(type) per_cpu__##name #define __get_cpu_var(var) __reloc_hide(var,0) +#define __raw_get_cpu_var(var) __reloc_hide(var,0) #define per_cpu(var,cpu) __reloc_hide(var,0) #endif /* SMP */ diff --git a/include/asm-sparc64/percpu.h b/include/asm-sparc64/percpu.h index baef13b5895..a6ece06b83d 100644 --- a/include/asm-sparc64/percpu.h +++ b/include/asm-sparc64/percpu.h @@ -21,6 +21,7 @@ register unsigned long __local_per_cpu_offset asm("g5"); /* var is in discarded region: offset to particular copy we want */ #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu))) #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset)) +#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset)) /* A macro to avoid #include hell... */ #define percpu_modcopy(pcpudst, src, size) \ @@ -37,6 +38,7 @@ do { \ #define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var)) #define __get_cpu_var(var) per_cpu__##var +#define __raw_get_cpu_var(var) per_cpu__##var #endif /* SMP */ diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h index 7f33aaf9f7b..549eb929b2c 100644 --- a/include/asm-x86_64/percpu.h +++ b/include/asm-x86_64/percpu.h @@ -21,6 +21,7 @@ /* var is in discarded region: offset to particular copy we want */ #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu))) #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset())) +#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset())) /* A macro to avoid #include hell... */ #define percpu_modcopy(pcpudst, src, size) \ @@ -40,6 +41,7 @@ extern void setup_per_cpu_areas(void); #define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var)) #define __get_cpu_var(var) per_cpu__##var +#define __raw_get_cpu_var(var) per_cpu__##var #endif /* SMP */ diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 18324305724..9587aac72f4 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -576,7 +576,7 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, memset(timer, 0, sizeof(struct hrtimer)); - bases = per_cpu(hrtimer_bases, raw_smp_processor_id()); + bases = __raw_get_cpu_var(hrtimer_bases); if (clock_id == CLOCK_REALTIME && mode != HRTIMER_ABS) clock_id = CLOCK_MONOTONIC; @@ -599,7 +599,7 @@ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp) { struct hrtimer_base *bases; - bases = per_cpu(hrtimer_bases, raw_smp_processor_id()); + bases = __raw_get_cpu_var(hrtimer_bases); *tp = ktime_to_timespec(bases[which_clock].resolution); return 0; diff --git a/kernel/sched.c b/kernel/sched.c index 5dbc4269447..f8d540b324c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4152,7 +4152,7 @@ EXPORT_SYMBOL(yield); */ void __sched io_schedule(void) { - struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id()); + struct runqueue *rq = &__raw_get_cpu_var(runqueues); atomic_inc(&rq->nr_iowait); schedule(); @@ -4163,7 +4163,7 @@ EXPORT_SYMBOL(io_schedule); long __sched io_schedule_timeout(long timeout) { - struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id()); + struct runqueue *rq = &__raw_get_cpu_var(runqueues); long ret; atomic_inc(&rq->nr_iowait); diff --git a/kernel/softlockup.c b/kernel/softlockup.c index 14c7faf0290..2c1be1163ed 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c @@ -36,7 +36,7 @@ static struct notifier_block panic_block = { void touch_softlockup_watchdog(void) { - per_cpu(touch_timestamp, raw_smp_processor_id()) = jiffies; + __raw_get_cpu_var(touch_timestamp) = jiffies; } EXPORT_SYMBOL(touch_softlockup_watchdog); diff --git a/kernel/timer.c b/kernel/timer.c index f35b3939e93..eb97371b87d 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -146,7 +146,7 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer) void fastcall init_timer(struct timer_list *timer) { timer->entry.next = NULL; - timer->base = per_cpu(tvec_bases, raw_smp_processor_id()); + timer->base = __raw_get_cpu_var(tvec_bases); } EXPORT_SYMBOL(init_timer); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cc9423de731..60b11aece5c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -244,7 +244,7 @@ static unsigned int rt_hash_rnd; static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); #define RT_CACHE_STAT_INC(field) \ - (per_cpu(rt_cache_stat, raw_smp_processor_id()).field++) + (__raw_get_cpu_var(rt_cache_stat).field++) static int rt_intern_hash(unsigned hash, struct rtable *rth, struct rtable **res); -- cgit v1.2.3-70-g09d2 From 350559961593a9680244b22b32733a49e21f25d6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 25 Jun 2006 01:32:25 -0700 Subject: [SPARC64]: Allow floppy driver to build modular. Signed-off-by: David S. Miller --- arch/sparc64/kernel/irq.c | 61 -------------------------------------------- include/asm-sparc64/floppy.h | 50 +++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 62 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 31e0fbb0d82..cc89b06d017 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -563,67 +563,6 @@ void handler_irq(int irq, struct pt_regs *regs) irq_exit(); } -#ifdef CONFIG_BLK_DEV_FD -extern irqreturn_t floppy_interrupt(int, void *, struct pt_regs *); - -/* XXX No easy way to include asm/floppy.h XXX */ -extern unsigned char *pdma_vaddr; -extern unsigned long pdma_size; -extern volatile int doing_pdma; -extern unsigned long fdc_status; - -irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) -{ - if (likely(doing_pdma)) { - void __iomem *stat = (void __iomem *) fdc_status; - unsigned char *vaddr = pdma_vaddr; - unsigned long size = pdma_size; - u8 val; - - while (size) { - val = readb(stat); - if (unlikely(!(val & 0x80))) { - pdma_vaddr = vaddr; - pdma_size = size; - return IRQ_HANDLED; - } - if (unlikely(!(val & 0x20))) { - pdma_vaddr = vaddr; - pdma_size = size; - doing_pdma = 0; - goto main_interrupt; - } - if (val & 0x40) { - /* read */ - *vaddr++ = readb(stat + 1); - } else { - unsigned char data = *vaddr++; - - /* write */ - writeb(data, stat + 1); - } - size--; - } - - pdma_vaddr = vaddr; - pdma_size = size; - - /* Send Terminal Count pulse to floppy controller. */ - val = readb(auxio_register); - val |= AUXIO_AUX1_FTCNT; - writeb(val, auxio_register); - val &= ~AUXIO_AUX1_FTCNT; - writeb(val, auxio_register); - - doing_pdma = 0; - } - -main_interrupt: - return floppy_interrupt(irq, dev_cookie, regs); -} -EXPORT_SYMBOL(sparc_floppy_irq); -#endif - struct sun5_timer { u64 count0; u64 limit0; diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index f8d57bb5570..b591d0e8d8f 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -208,7 +208,55 @@ static void sun_fd_enable_dma(void) pdma_areasize = pdma_size; } -extern irqreturn_t sparc_floppy_irq(int, void *, struct pt_regs *); +irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) +{ + if (likely(doing_pdma)) { + void __iomem *stat = (void __iomem *) fdc_status; + unsigned char *vaddr = pdma_vaddr; + unsigned long size = pdma_size; + u8 val; + + while (size) { + val = readb(stat); + if (unlikely(!(val & 0x80))) { + pdma_vaddr = vaddr; + pdma_size = size; + return IRQ_HANDLED; + } + if (unlikely(!(val & 0x20))) { + pdma_vaddr = vaddr; + pdma_size = size; + doing_pdma = 0; + goto main_interrupt; + } + if (val & 0x40) { + /* read */ + *vaddr++ = readb(stat + 1); + } else { + unsigned char data = *vaddr++; + + /* write */ + writeb(data, stat + 1); + } + size--; + } + + pdma_vaddr = vaddr; + pdma_size = size; + + /* Send Terminal Count pulse to floppy controller. */ + val = readb(auxio_register); + val |= AUXIO_AUX1_FTCNT; + writeb(val, auxio_register); + val &= ~AUXIO_AUX1_FTCNT; + writeb(val, auxio_register); + + doing_pdma = 0; + } + +main_interrupt: + return floppy_interrupt(irq, dev_cookie, regs); +} static int sun_fd_request_irq(void) { -- cgit v1.2.3-70-g09d2 From 36321426e320c2c6bc2f8a1587d6f4d695fca84c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 25 Jun 2006 02:07:52 -0700 Subject: [SPARC64]: Add missing interfaces to dma-mapping.h Signed-off-by: David S. Miller --- include/asm-sparc64/dma-mapping.h | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'include/asm-sparc64') diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h index 3c2b5bc8650..0f5b89c9323 100644 --- a/include/asm-sparc64/dma-mapping.h +++ b/include/asm-sparc64/dma-mapping.h @@ -162,4 +162,47 @@ static inline void dma_free_coherent(struct device *dev, size_t size, #endif /* PCI */ + +/* Now for the API extensions over the pci_ one */ + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(d) (1) + +static inline int +dma_get_cache_alignment(void) +{ + /* no easy way to get cache size on all processors, so return + * the maximum possible, to be safe */ + return (1 << INTERNODE_CACHE_SHIFT); +} + +static inline void +dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + /* just sync everything, that's all the pci API can do */ + dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction); +} + +static inline void +dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + /* just sync everything, that's all the pci API can do */ + dma_sync_single_for_device(dev, dma_handle, offset+size, direction); +} + +static inline void +dma_cache_sync(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + /* could define this in terms of the dma_cache ... operations, + * but if you get this on a platform, you should convert the platform + * to using the generic device DMA API */ + BUG(); +} + #endif /* _ASM_SPARC64_DMA_MAPPING_H */ -- cgit v1.2.3-70-g09d2 From fb7cd9d9acfb52dc1b9fbd5079445e4732667bbc Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 25 Jun 2006 23:18:36 -0700 Subject: [SPARC]: Add of_set_property() interface. Signed-off-by: David S. Miller --- arch/sparc/kernel/prom.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ arch/sparc64/kernel/prom.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ include/asm-sparc/prom.h | 8 +++++++ include/asm-sparc64/prom.h | 8 +++++++ 4 files changed, 122 insertions(+) (limited to 'include/asm-sparc64') diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 63b2b9bd778..f3f53f2e0e1 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -27,6 +27,11 @@ static struct device_node *allnodes; +/* use when traversing tree through the allnext, child, sibling, + * or parent members of struct device_node. + */ +static DEFINE_RWLOCK(devtree_lock); + int of_device_is_compatible(struct device_node *device, const char *compat) { const char* cp; @@ -185,6 +190,54 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); +int of_set_property(struct device_node *dp, const char *name, void *val, int len) +{ + struct property **prevp; + void *new_val; + int err; + + new_val = kmalloc(len, GFP_KERNEL); + if (!new_val) + return -ENOMEM; + + memcpy(new_val, val, len); + + err = -ENODEV; + + write_lock(&devtree_lock); + prevp = &dp->properties; + while (*prevp) { + struct property *prop = *prevp; + + if (!strcmp(prop->name, name)) { + void *old_val = prop->value; + int ret; + + ret = prom_setprop(dp->node, name, val, len); + err = -EINVAL; + if (ret >= 0) { + prop->value = new_val; + prop->length = len; + + if (OF_IS_DYNAMIC(prop)) + kfree(old_val); + + OF_MARK_DYNAMIC(prop); + + err = 0; + } + break; + } + prevp = &(*prevp)->next; + } + write_unlock(&devtree_lock); + + /* XXX Upate procfs if necessary... */ + + return err; +} +EXPORT_SYMBOL(of_set_property); + static unsigned int prom_early_allocated; static void * __init prom_early_alloc(unsigned long size) diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index e9d703eea80..c62fd3e7a0f 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -27,6 +27,11 @@ static struct device_node *allnodes; +/* use when traversing tree through the allnext, child, sibling, + * or parent members of struct device_node. + */ +static DEFINE_RWLOCK(devtree_lock); + int of_device_is_compatible(struct device_node *device, const char *compat) { const char* cp; @@ -185,6 +190,54 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); +int of_set_property(struct device_node *dp, const char *name, void *val, int len) +{ + struct property **prevp; + void *new_val; + int err; + + new_val = kmalloc(len, GFP_KERNEL); + if (!new_val) + return -ENOMEM; + + memcpy(new_val, val, len); + + err = -ENODEV; + + write_lock(&devtree_lock); + prevp = &dp->properties; + while (*prevp) { + struct property *prop = *prevp; + + if (!strcmp(prop->name, name)) { + void *old_val = prop->value; + int ret; + + ret = prom_setprop(dp->node, name, val, len); + err = -EINVAL; + if (ret >= 0) { + prop->value = new_val; + prop->length = len; + + if (OF_IS_DYNAMIC(prop)) + kfree(old_val); + + OF_MARK_DYNAMIC(prop); + + err = 0; + } + break; + } + prevp = &(*prevp)->next; + } + write_unlock(&devtree_lock); + + /* XXX Upate procfs if necessary... */ + + return err; +} +EXPORT_SYMBOL(of_set_property); + static unsigned int prom_early_allocated; static void * __init prom_early_alloc(unsigned long size) diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index c5e3d26eabd..e9b8047470f 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -35,6 +35,7 @@ struct property { int length; void *value; struct property *next; + unsigned long _flags; }; struct device_node { @@ -60,6 +61,12 @@ struct device_node { void *data; }; +/* flag descriptions */ +#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ + +#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) +#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) + static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; @@ -88,6 +95,7 @@ extern struct property *of_find_property(struct device_node *np, extern int of_device_is_compatible(struct device_node *device, const char *); extern void *of_get_property(struct device_node *node, const char *name, int *lenp); +extern int of_set_property(struct device_node *node, const char *name, void *val, int len); extern int of_getintprop_default(struct device_node *np, const char *name, int def); diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 6d1556c0c26..c8022a33738 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -35,6 +35,7 @@ struct property { int length; void *value; struct property *next; + unsigned long _flags; }; struct device_node { @@ -60,6 +61,12 @@ struct device_node { void *data; }; +/* flag descriptions */ +#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ + +#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) +#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) + static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; @@ -88,6 +95,7 @@ extern struct property *of_find_property(struct device_node *np, extern int of_device_is_compatible(struct device_node *device, const char *); extern void *of_get_property(struct device_node *node, const char *name, int *lenp); +extern int of_set_property(struct device_node *node, const char *name, void *val, int len); extern int of_getintprop_default(struct device_node *np, const char *name, int def); -- cgit v1.2.3-70-g09d2 From 87b385da1f5a5f4a12a28e00fe597bcde8d6fea3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 25 Jun 2006 23:18:57 -0700 Subject: [SPARC]: Add unique device_node IDs and a ".node" property. Signed-off-by: David S. Miller --- arch/sparc/kernel/prom.c | 53 +++++++++++++++++++++++++++++---------------- arch/sparc64/kernel/prom.c | 54 ++++++++++++++++++++++++++++++---------------- include/asm-sparc/prom.h | 2 ++ include/asm-sparc64/prom.h | 2 ++ 4 files changed, 75 insertions(+), 36 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index f3f53f2e0e1..946ce6d1581 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -407,7 +407,9 @@ static char * __init build_full_name(struct device_node *dp) return n; } -static struct property * __init build_one_prop(phandle node, char *prev) +static unsigned int unique_id; + +static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len) { static struct property *tmp = NULL; struct property *p; @@ -417,25 +419,34 @@ static struct property * __init build_one_prop(phandle node, char *prev) p = tmp; memset(p, 0, sizeof(*p) + 32); tmp = NULL; - } else + } else { p = prom_early_alloc(sizeof(struct property) + 32); + p->unique_id = unique_id++; + } p->name = (char *) (p + 1); - if (prev == NULL) { - prom_firstprop(node, p->name); + if (special_name) { + p->length = special_len; + p->value = prom_early_alloc(special_len); + memcpy(p->value, special_val, special_len); } else { - prom_nextprop(node, prev, p->name); - } - if (strlen(p->name) == 0) { - tmp = p; - return NULL; - } - p->length = prom_getproplen(node, p->name); - if (p->length <= 0) { - p->length = 0; - } else { - p->value = prom_early_alloc(p->length); - len = prom_getproperty(node, p->name, p->value, p->length); + if (prev == NULL) { + prom_firstprop(node, p->name); + } else { + prom_nextprop(node, prev, p->name); + } + if (strlen(p->name) == 0) { + tmp = p; + return NULL; + } + p->length = prom_getproplen(node, p->name); + if (p->length <= 0) { + p->length = 0; + } else { + p->value = prom_early_alloc(p->length + 1); + prom_getproperty(node, p->name, p->value, p->length); + ((unsigned char *)p->value)[p->length] = '\0'; + } } return p; } @@ -444,9 +455,14 @@ static struct property * __init build_prop_list(phandle node) { struct property *head, *tail; - head = tail = build_one_prop(node, NULL); + head = tail = build_one_prop(node, NULL, + ".node", &node, sizeof(node)); + + tail->next = build_one_prop(node, NULL, NULL, NULL, 0); + tail = tail->next; while(tail) { - tail->next = build_one_prop(node, tail->name); + tail->next = build_one_prop(node, tail->name, + NULL, NULL, 0); tail = tail->next; } @@ -475,6 +491,7 @@ static struct device_node * __init create_node(phandle node) return NULL; dp = prom_early_alloc(sizeof(*dp)); + dp->unique_id = unique_id++; kref_init(&dp->kref); diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index c62fd3e7a0f..8e87e7ea032 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -584,7 +584,9 @@ static char * __init build_full_name(struct device_node *dp) return n; } -static struct property * __init build_one_prop(phandle node, char *prev) +static unsigned int unique_id; + +static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len) { static struct property *tmp = NULL; struct property *p; @@ -593,25 +595,35 @@ static struct property * __init build_one_prop(phandle node, char *prev) p = tmp; memset(p, 0, sizeof(*p) + 32); tmp = NULL; - } else + } else { p = prom_early_alloc(sizeof(struct property) + 32); + p->unique_id = unique_id++; + } p->name = (char *) (p + 1); - if (prev == NULL) { - prom_firstprop(node, p->name); + if (special_name) { + strcpy(p->name, special_name); + p->length = special_len; + p->value = prom_early_alloc(special_len); + memcpy(p->value, special_val, special_len); } else { - prom_nextprop(node, prev, p->name); - } - if (strlen(p->name) == 0) { - tmp = p; - return NULL; - } - p->length = prom_getproplen(node, p->name); - if (p->length <= 0) { - p->length = 0; - } else { - p->value = prom_early_alloc(p->length); - prom_getproperty(node, p->name, p->value, p->length); + if (prev == NULL) { + prom_firstprop(node, p->name); + } else { + prom_nextprop(node, prev, p->name); + } + if (strlen(p->name) == 0) { + tmp = p; + return NULL; + } + p->length = prom_getproplen(node, p->name); + if (p->length <= 0) { + p->length = 0; + } else { + p->value = prom_early_alloc(p->length + 1); + prom_getproperty(node, p->name, p->value, p->length); + ((unsigned char *)p->value)[p->length] = '\0'; + } } return p; } @@ -620,9 +632,14 @@ static struct property * __init build_prop_list(phandle node) { struct property *head, *tail; - head = tail = build_one_prop(node, NULL); + head = tail = build_one_prop(node, NULL, + ".node", &node, sizeof(node)); + + tail->next = build_one_prop(node, NULL, NULL, NULL, 0); + tail = tail->next; while(tail) { - tail->next = build_one_prop(node, tail->name); + tail->next = build_one_prop(node, tail->name, + NULL, NULL, 0); tail = tail->next; } @@ -651,6 +668,7 @@ static struct device_node * __init create_node(phandle node) return NULL; dp = prom_early_alloc(sizeof(*dp)); + dp->unique_id = unique_id++; kref_init(&dp->kref); diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index e9b8047470f..f9cf44c0716 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -36,6 +36,7 @@ struct property { void *value; struct property *next; unsigned long _flags; + unsigned int unique_id; }; struct device_node { @@ -59,6 +60,7 @@ struct device_node { struct kref kref; unsigned long _flags; void *data; + unsigned int unique_id; }; /* flag descriptions */ diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index c8022a33738..265614d497c 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -36,6 +36,7 @@ struct property { void *value; struct property *next; unsigned long _flags; + unsigned int unique_id; }; struct device_node { @@ -59,6 +60,7 @@ struct device_node { struct kref kref; unsigned long _flags; void *data; + unsigned int unique_id; }; /* flag descriptions */ -- cgit v1.2.3-70-g09d2 From d98f8f05188b45168db43df8ddc9feeb0b1cd512 Mon Sep 17 00:00:00 2001 From: Anil S Keshavamurthy Date: Mon, 26 Jun 2006 00:25:27 -0700 Subject: [PATCH] Notify page fault call chain for sparc64 Overloading of page fault notification with the notify_die() has performance issues(since the only interested components for page fault is kprobes and/or kdb) and hence this patch introduces the new notifier call chain exclusively for page fault notifications their by avoiding notifying unnecessary components in the do_page_fault() code path. Signed-off-by: Anil S Keshavamurthy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/sparc64/mm/fault.c | 36 +++++++++++++++++++++++++++++++++++- include/asm-sparc64/kdebug.h | 2 ++ 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 6e002aacb96..1605967cce9 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -31,6 +31,40 @@ #include #include +#ifdef CONFIG_KPROBES +ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); + +/* Hook to register for page fault notifications */ +int register_page_fault_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); +} + +int unregister_page_fault_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); +} + +static inline int notify_page_fault(enum die_val val, const char *str, + struct pt_regs *regs, long err, int trap, int sig) +{ + struct die_args args = { + .regs = regs, + .str = str, + .err = err, + .trapnr = trap, + .signr = sig + }; + return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); +} +#else +static inline int notify_page_fault(enum die_val val, const char *str, + struct pt_regs *regs, long err, int trap, int sig) +{ + return NOTIFY_DONE; +} +#endif + /* * To debug kernel to catch accesses to certain virtual/physical addresses. * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints. @@ -263,7 +297,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) fault_code = get_thread_fault_code(); - if (notify_die(DIE_PAGE_FAULT, "page_fault", regs, + if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs, fault_code, 0, SIGSEGV) == NOTIFY_STOP) return; diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h index 4040d127ac3..11251bdd00c 100644 --- a/include/asm-sparc64/kdebug.h +++ b/include/asm-sparc64/kdebug.h @@ -17,6 +17,8 @@ struct die_args { extern int register_die_notifier(struct notifier_block *); extern int unregister_die_notifier(struct notifier_block *); +extern int register_page_fault_notifier(struct notifier_block *); +extern int unregister_page_fault_notifier(struct notifier_block *); extern struct atomic_notifier_head sparc64die_chain; extern void bad_trap(struct pt_regs *, long); -- cgit v1.2.3-70-g09d2 From e6f47f978bcd5413fff610613b18e9e0eab9bc1b Mon Sep 17 00:00:00 2001 From: Anil S Keshavamurthy Date: Mon, 26 Jun 2006 00:25:29 -0700 Subject: [PATCH] Notify page fault call chain With this patch Kprobes now registers for page fault notifications only when their is an active probe registered. Once all the active probes are unregistered their is no need to be notified of page faults and kprobes unregisters itself from the page fault notifications. Hence we will have ZERO side effects when no probes are active. Signed-off-by: Anil S Keshavamurthy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-i386/kprobes.h | 1 + include/asm-ia64/kprobes.h | 1 + include/asm-powerpc/kprobes.h | 2 ++ include/asm-sparc64/kprobes.h | 1 + include/asm-x86_64/kprobes.h | 1 + kernel/kprobes.c | 30 +++++++++++++++++++++++------- 6 files changed, 29 insertions(+), 7 deletions(-) (limited to 'include/asm-sparc64') diff --git a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h index 57d157c5cf8..0730a20f6db 100644 --- a/include/asm-i386/kprobes.h +++ b/include/asm-i386/kprobes.h @@ -44,6 +44,7 @@ typedef u8 kprobe_opcode_t; #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry #define ARCH_SUPPORTS_KRETPROBES +#define ARCH_INACTIVE_KPROBE_COUNT 0 void arch_remove_kprobe(struct kprobe *p); void kretprobe_trampoline(void); diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h index 8c0fc227f0f..2418a787c40 100644 --- a/include/asm-ia64/kprobes.h +++ b/include/asm-ia64/kprobes.h @@ -82,6 +82,7 @@ struct kprobe_ctlblk { #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry #define ARCH_SUPPORTS_KRETPROBES +#define ARCH_INACTIVE_KPROBE_COUNT 1 #define SLOT0_OPCODE_SHIFT (37) #define SLOT1_p1_OPCODE_SHIFT (37 - (64-46)) diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h index f466bc804f4..2d0af52c823 100644 --- a/include/asm-powerpc/kprobes.h +++ b/include/asm-powerpc/kprobes.h @@ -50,6 +50,8 @@ typedef unsigned int kprobe_opcode_t; IS_TWI(instr) || IS_TDI(instr)) #define ARCH_SUPPORTS_KRETPROBES +#define ARCH_INACTIVE_KPROBE_COUNT 1 + void kretprobe_trampoline(void); extern void arch_remove_kprobe(struct kprobe *p); diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h index e9bb26f770e..15065af566c 100644 --- a/include/asm-sparc64/kprobes.h +++ b/include/asm-sparc64/kprobes.h @@ -12,6 +12,7 @@ typedef u32 kprobe_opcode_t; #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry #define arch_remove_kprobe(p) do {} while (0) +#define ARCH_INACTIVE_KPROBE_COUNT 0 /* Architecture specific copy of original instruction*/ struct arch_specific_insn { diff --git a/include/asm-x86_64/kprobes.h b/include/asm-x86_64/kprobes.h index 98a1e95ddb9..d36febd9bb1 100644 --- a/include/asm-x86_64/kprobes.h +++ b/include/asm-x86_64/kprobes.h @@ -43,6 +43,7 @@ typedef u8 kprobe_opcode_t; #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry #define ARCH_SUPPORTS_KRETPROBES +#define ARCH_INACTIVE_KPROBE_COUNT 1 void kretprobe_trampoline(void); extern void arch_remove_kprobe(struct kprobe *p); diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 507f26e7ae7..64aab081153 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -47,11 +47,17 @@ static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; +static atomic_t kprobe_count; DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */ DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */ static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; +static struct notifier_block kprobe_page_fault_nb = { + .notifier_call = kprobe_exceptions_notify, + .priority = 0x7fffffff /* we need to notified first */ +}; + #ifdef __ARCH_WANT_KPROBES_INSN_SLOT /* * kprobe->ainsn.insn points to the copy of the instruction to be @@ -465,6 +471,8 @@ static int __kprobes __register_kprobe(struct kprobe *p, old_p = get_kprobe(p->addr); if (old_p) { ret = register_aggr_kprobe(old_p, p); + if (!ret) + atomic_inc(&kprobe_count); goto out; } @@ -475,6 +483,10 @@ static int __kprobes __register_kprobe(struct kprobe *p, hlist_add_head_rcu(&p->hlist, &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); + if (atomic_add_return(1, &kprobe_count) == \ + (ARCH_INACTIVE_KPROBE_COUNT + 1)) + register_page_fault_notifier(&kprobe_page_fault_nb); + arch_arm_kprobe(p); out: @@ -553,6 +565,16 @@ valid_p: } mutex_unlock(&kprobe_mutex); } + + /* Call unregister_page_fault_notifier() + * if no probes are active + */ + mutex_lock(&kprobe_mutex); + if (atomic_add_return(-1, &kprobe_count) == \ + ARCH_INACTIVE_KPROBE_COUNT) + unregister_page_fault_notifier(&kprobe_page_fault_nb); + mutex_unlock(&kprobe_mutex); + return; } static struct notifier_block kprobe_exceptions_nb = { @@ -560,10 +582,6 @@ static struct notifier_block kprobe_exceptions_nb = { .priority = 0x7fffffff /* we need to be notified first */ }; -static struct notifier_block kprobe_page_fault_nb = { - .notifier_call = kprobe_exceptions_notify, - .priority = 0x7fffffff /* we need to notified first */ -}; int __kprobes register_jprobe(struct jprobe *jp) { @@ -673,14 +691,12 @@ static int __init init_kprobes(void) INIT_HLIST_HEAD(&kprobe_table[i]); INIT_HLIST_HEAD(&kretprobe_inst_table[i]); } + atomic_set(&kprobe_count, 0); err = arch_init_kprobes(); if (!err) err = register_die_notifier(&kprobe_exceptions_nb); - if (!err) - err = register_page_fault_notifier(&kprobe_page_fault_nb); - return err; } -- cgit v1.2.3-70-g09d2 From 5c45bf279d378d436ce45825c0f136696c7b6109 Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" Date: Tue, 27 Jun 2006 02:54:42 -0700 Subject: [PATCH] sched: mc/smt power savings sched policy sysfs entries 'sched_mc_power_savings' and 'sched_smt_power_savings' in /sys/devices/system/cpu/ control the MC/SMT power savings policy for the scheduler. Based on the values (1-enable, 0-disable) for these controls, sched groups cpu power will be determined for different domains. When power savings policy is enabled and under light load conditions, scheduler will minimize the physical packages/cpu cores carrying the load and thus conserving power(with a perf impact based on the workload characteristics... see OLS 2005 CMP kernel scheduler paper for more details..) Signed-off-by: Suresh Siddha Cc: Ingo Molnar Cc: Nick Piggin Cc: Con Kolivas Cc: "Chen, Kenneth W" Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/smpboot.c | 8 +- arch/x86_64/kernel/smpboot.c | 8 +- drivers/base/cpu.c | 10 +- include/asm-i386/topology.h | 5 + include/asm-ia64/topology.h | 1 + include/asm-powerpc/topology.h | 5 + include/asm-sparc64/topology.h | 3 + include/asm-x86_64/topology.h | 2 + include/linux/sched.h | 10 ++ include/linux/topology.h | 3 +- kernel/sched.c | 240 ++++++++++++++++++++++++++++++++++++----- 11 files changed, 262 insertions(+), 33 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index ab5275beddf..89e7315e539 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -448,10 +448,12 @@ cpumask_t cpu_coregroup_map(int cpu) struct cpuinfo_x86 *c = cpu_data + cpu; /* * For perf, we return last level cache shared map. - * TBD: when power saving sched policy is added, we will return - * cpu_core_map when power saving policy is enabled + * And for power savings, we return cpu_core_map */ - return c->llc_shared_map; + if (sched_mc_power_savings || sched_smt_power_savings) + return cpu_core_map[cpu]; + else + return c->llc_shared_map; } /* representing cpus for which sibling maps can be computed */ diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 4e9755179ec..540c0ccbccc 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -455,10 +455,12 @@ cpumask_t cpu_coregroup_map(int cpu) struct cpuinfo_x86 *c = cpu_data + cpu; /* * For perf, we return last level cache shared map. - * TBD: when power saving sched policy is added, we will return - * cpu_core_map when power saving policy is enabled + * And for power savings, we return cpu_core_map */ - return c->llc_shared_map; + if (sched_mc_power_savings || sched_smt_power_savings) + return cpu_core_map[cpu]; + else + return c->llc_shared_map; } /* representing cpus for which sibling maps can be computed */ diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 3972d8ac978..4bef76a2f3f 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -143,5 +143,13 @@ EXPORT_SYMBOL_GPL(get_cpu_sysdev); int __init cpu_dev_init(void) { - return sysdev_class_register(&cpu_sysdev_class); + int err; + + err = sysdev_class_register(&cpu_sysdev_class); +#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) + if (!err) + err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class); +#endif + + return err; } diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h index aa4185ee81f..6adbd9b1ae8 100644 --- a/include/asm-i386/topology.h +++ b/include/asm-i386/topology.h @@ -112,4 +112,9 @@ extern unsigned long node_remap_size[]; extern cpumask_t cpu_coregroup_map(int cpu); +#ifdef CONFIG_SMP +#define mc_capable() (boot_cpu_data.x86_max_cores > 1) +#define smt_capable() (smp_num_siblings > 1) +#endif + #endif /* _ASM_I386_TOPOLOGY_H */ diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h index 616b5ed2aa7..937c2125752 100644 --- a/include/asm-ia64/topology.h +++ b/include/asm-ia64/topology.h @@ -112,6 +112,7 @@ void build_cpu_to_node_map(void); #define topology_core_id(cpu) (cpu_data(cpu)->core_id) #define topology_core_siblings(cpu) (cpu_core_map[cpu]) #define topology_thread_siblings(cpu) (cpu_sibling_map[cpu]) +#define smt_capable() (smp_num_siblings > 1) #endif #include diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h index 92f3e5507d2..bbc3844b086 100644 --- a/include/asm-powerpc/topology.h +++ b/include/asm-powerpc/topology.h @@ -93,5 +93,10 @@ static inline void sysfs_remove_device_from_node(struct sys_device *dev, #endif /* CONFIG_NUMA */ +#ifdef CONFIG_SMP +#include +#define smt_capable() (cpu_has_feature(CPU_FTR_SMT)) +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_TOPOLOGY_H */ diff --git a/include/asm-sparc64/topology.h b/include/asm-sparc64/topology.h index 0e234e201bd..98a6c613589 100644 --- a/include/asm-sparc64/topology.h +++ b/include/asm-sparc64/topology.h @@ -1,6 +1,9 @@ #ifndef _ASM_SPARC64_TOPOLOGY_H #define _ASM_SPARC64_TOPOLOGY_H +#include +#define smt_capable() (tlb_type == hypervisor) + #include #endif /* _ASM_SPARC64_TOPOLOGY_H */ diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h index c4e46e7fa7b..6e7a2e976b0 100644 --- a/include/asm-x86_64/topology.h +++ b/include/asm-x86_64/topology.h @@ -59,6 +59,8 @@ extern int __node_distance(int, int); #define topology_core_id(cpu) (cpu_data[cpu].cpu_core_id) #define topology_core_siblings(cpu) (cpu_core_map[cpu]) #define topology_thread_siblings(cpu) (cpu_sibling_map[cpu]) +#define mc_capable() (boot_cpu_data.x86_max_cores > 1) +#define smt_capable() (smp_num_siblings > 1) #endif #include diff --git a/include/linux/sched.h b/include/linux/sched.h index ab8ffc54423..0bc81a151e5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -570,6 +570,11 @@ enum idle_type #define SD_WAKE_AFFINE 32 /* Wake task to waking CPU */ #define SD_WAKE_BALANCE 64 /* Perform balancing at task wakeup */ #define SD_SHARE_CPUPOWER 128 /* Domain members share cpu power */ +#define SD_POWERSAVINGS_BALANCE 256 /* Balance for power savings */ + +#define BALANCE_FOR_POWER ((sched_mc_power_savings || sched_smt_power_savings) \ + ? SD_POWERSAVINGS_BALANCE : 0) + struct sched_group { struct sched_group *next; /* Must be a circular list */ @@ -1412,6 +1417,11 @@ static inline void arch_pick_mmap_layout(struct mm_struct *mm) extern long sched_setaffinity(pid_t pid, cpumask_t new_mask); extern long sched_getaffinity(pid_t pid, cpumask_t *mask); +#include +extern int sched_mc_power_savings, sched_smt_power_savings; +extern struct sysdev_attribute attr_sched_mc_power_savings, attr_sched_smt_power_savings; +extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls); + extern void normalize_rt_tasks(void); #ifdef CONFIG_PM diff --git a/include/linux/topology.h b/include/linux/topology.h index a305ae2e44b..ec1eca85290 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -134,7 +134,8 @@ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_NEWIDLE \ | SD_BALANCE_EXEC \ - | SD_WAKE_AFFINE, \ + | SD_WAKE_AFFINE \ + | BALANCE_FOR_POWER, \ .last_balance = jiffies, \ .balance_interval = 1, \ .nr_balance_failed = 0, \ diff --git a/kernel/sched.c b/kernel/sched.c index 122b75584a1..54fa282657c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1162,6 +1162,11 @@ static int sched_balance_self(int cpu, int flag) struct sched_domain *tmp, *sd = NULL; for_each_domain(cpu, tmp) { + /* + * If power savings logic is enabled for a domain, stop there. + */ + if (tmp->flags & SD_POWERSAVINGS_BALANCE) + break; if (tmp->flags & flag) sd = tmp; } @@ -2082,6 +2087,12 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, unsigned long busiest_load_per_task, busiest_nr_running; unsigned long this_load_per_task, this_nr_running; int load_idx; +#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) + int power_savings_balance = 1; + unsigned long leader_nr_running = 0, min_load_per_task = 0; + unsigned long min_nr_running = ULONG_MAX; + struct sched_group *group_min = NULL, *group_leader = NULL; +#endif max_load = this_load = total_load = total_pwr = 0; busiest_load_per_task = busiest_nr_running = 0; @@ -2094,7 +2105,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, load_idx = sd->idle_idx; do { - unsigned long load; + unsigned long load, group_capacity; int local_group; int i; unsigned long sum_nr_running, sum_weighted_load; @@ -2127,18 +2138,76 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, /* Adjust by relative CPU power of the group */ avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power; + group_capacity = group->cpu_power / SCHED_LOAD_SCALE; + if (local_group) { this_load = avg_load; this = group; this_nr_running = sum_nr_running; this_load_per_task = sum_weighted_load; } else if (avg_load > max_load && - sum_nr_running > group->cpu_power / SCHED_LOAD_SCALE) { + sum_nr_running > group_capacity) { max_load = avg_load; busiest = group; busiest_nr_running = sum_nr_running; busiest_load_per_task = sum_weighted_load; } + +#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) + /* + * Busy processors will not participate in power savings + * balance. + */ + if (idle == NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE)) + goto group_next; + + /* + * If the local group is idle or completely loaded + * no need to do power savings balance at this domain + */ + if (local_group && (this_nr_running >= group_capacity || + !this_nr_running)) + power_savings_balance = 0; + + /* + * If a group is already running at full capacity or idle, + * don't include that group in power savings calculations + */ + if (!power_savings_balance || sum_nr_running >= group_capacity + || !sum_nr_running) + goto group_next; + + /* + * Calculate the group which has the least non-idle load. + * This is the group from where we need to pick up the load + * for saving power + */ + if ((sum_nr_running < min_nr_running) || + (sum_nr_running == min_nr_running && + first_cpu(group->cpumask) < + first_cpu(group_min->cpumask))) { + group_min = group; + min_nr_running = sum_nr_running; + min_load_per_task = sum_weighted_load / + sum_nr_running; + } + + /* + * Calculate the group which is almost near its + * capacity but still has some space to pick up some load + * from other group and save more power + */ + if (sum_nr_running <= group_capacity - 1) + if (sum_nr_running > leader_nr_running || + (sum_nr_running == leader_nr_running && + first_cpu(group->cpumask) > + first_cpu(group_leader->cpumask))) { + group_leader = group; + leader_nr_running = sum_nr_running; + } + +group_next: +#endif group = group->next; } while (group != sd->groups); @@ -2247,7 +2316,16 @@ small_imbalance: return busiest; out_balanced: +#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) + if (idle == NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE)) + goto ret; + if (this == group_leader && group_leader != group_min) { + *imbalance = min_load_per_task; + return group_min; + } +ret: +#endif *imbalance = 0; return NULL; } @@ -2300,7 +2378,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, int active_balance = 0; int sd_idle = 0; - if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER) + if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER && + !sched_smt_power_savings) sd_idle = 1; schedstat_inc(sd, lb_cnt[idle]); @@ -2389,7 +2468,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, sd->balance_interval *= 2; } - if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER) + if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER && + !sched_smt_power_savings) return -1; return nr_moved; @@ -2404,7 +2484,7 @@ out_one_pinned: (sd->balance_interval < sd->max_interval)) sd->balance_interval *= 2; - if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER) + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings) return -1; return 0; } @@ -2425,7 +2505,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq, int nr_moved = 0; int sd_idle = 0; - if (sd->flags & SD_SHARE_CPUPOWER) + if (sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings) sd_idle = 1; schedstat_inc(sd, lb_cnt[NEWLY_IDLE]); @@ -2466,7 +2546,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq, out_balanced: schedstat_inc(sd, lb_balanced[NEWLY_IDLE]); - if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER) + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings) return -1; sd->nr_balance_failed = 0; return 0; @@ -5732,6 +5812,7 @@ static cpumask_t sched_domain_node_span(int node) } #endif +int sched_smt_power_savings = 0, sched_mc_power_savings = 0; /* * At the moment, CONFIG_SCHED_SMT is never defined, but leave it in so we * can switch it on easily if needed. @@ -6113,37 +6194,72 @@ static int build_sched_domains(const cpumask_t *cpu_map) #endif /* Calculate CPU power for physical packages and nodes */ +#ifdef CONFIG_SCHED_SMT for_each_cpu_mask(i, *cpu_map) { - int power; struct sched_domain *sd; -#ifdef CONFIG_SCHED_SMT sd = &per_cpu(cpu_domains, i); - power = SCHED_LOAD_SCALE; - sd->groups->cpu_power = power; + sd->groups->cpu_power = SCHED_LOAD_SCALE; + } #endif #ifdef CONFIG_SCHED_MC + for_each_cpu_mask(i, *cpu_map) { + int power; + struct sched_domain *sd; sd = &per_cpu(core_domains, i); - power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1) + if (sched_smt_power_savings) + power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask); + else + power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1) * SCHED_LOAD_SCALE / 10; sd->groups->cpu_power = power; + } +#endif + for_each_cpu_mask(i, *cpu_map) { + struct sched_domain *sd; +#ifdef CONFIG_SCHED_MC sd = &per_cpu(phys_domains, i); + if (i != first_cpu(sd->groups->cpumask)) + continue; - /* - * This has to be < 2 * SCHED_LOAD_SCALE - * Lets keep it SCHED_LOAD_SCALE, so that - * while calculating NUMA group's cpu_power - * we can simply do - * numa_group->cpu_power += phys_group->cpu_power; - * - * See "only add power once for each physical pkg" - * comment below - */ - sd->groups->cpu_power = SCHED_LOAD_SCALE; + sd->groups->cpu_power = 0; + if (sched_mc_power_savings || sched_smt_power_savings) { + int j; + + for_each_cpu_mask(j, sd->groups->cpumask) { + struct sched_domain *sd1; + sd1 = &per_cpu(core_domains, j); + /* + * for each core we will add once + * to the group in physical domain + */ + if (j != first_cpu(sd1->groups->cpumask)) + continue; + + if (sched_smt_power_savings) + sd->groups->cpu_power += sd1->groups->cpu_power; + else + sd->groups->cpu_power += SCHED_LOAD_SCALE; + } + } else + /* + * This has to be < 2 * SCHED_LOAD_SCALE + * Lets keep it SCHED_LOAD_SCALE, so that + * while calculating NUMA group's cpu_power + * we can simply do + * numa_group->cpu_power += phys_group->cpu_power; + * + * See "only add power once for each physical pkg" + * comment below + */ + sd->groups->cpu_power = SCHED_LOAD_SCALE; #else + int power; sd = &per_cpu(phys_domains, i); - power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE * - (cpus_weight(sd->groups->cpumask)-1) / 10; + if (sched_smt_power_savings) + power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask); + else + power = SCHED_LOAD_SCALE; sd->groups->cpu_power = power; #endif } @@ -6244,6 +6360,80 @@ int partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2) return err; } +#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) +int arch_reinit_sched_domains(void) +{ + int err; + + lock_cpu_hotplug(); + detach_destroy_domains(&cpu_online_map); + err = arch_init_sched_domains(&cpu_online_map); + unlock_cpu_hotplug(); + + return err; +} + +static ssize_t sched_power_savings_store(const char *buf, size_t count, int smt) +{ + int ret; + + if (buf[0] != '0' && buf[0] != '1') + return -EINVAL; + + if (smt) + sched_smt_power_savings = (buf[0] == '1'); + else + sched_mc_power_savings = (buf[0] == '1'); + + ret = arch_reinit_sched_domains(); + + return ret ? ret : count; +} + +int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls) +{ + int err = 0; +#ifdef CONFIG_SCHED_SMT + if (smt_capable()) + err = sysfs_create_file(&cls->kset.kobj, + &attr_sched_smt_power_savings.attr); +#endif +#ifdef CONFIG_SCHED_MC + if (!err && mc_capable()) + err = sysfs_create_file(&cls->kset.kobj, + &attr_sched_mc_power_savings.attr); +#endif + return err; +} +#endif + +#ifdef CONFIG_SCHED_MC +static ssize_t sched_mc_power_savings_show(struct sys_device *dev, char *page) +{ + return sprintf(page, "%u\n", sched_mc_power_savings); +} +static ssize_t sched_mc_power_savings_store(struct sys_device *dev, const char *buf, size_t count) +{ + return sched_power_savings_store(buf, count, 0); +} +SYSDEV_ATTR(sched_mc_power_savings, 0644, sched_mc_power_savings_show, + sched_mc_power_savings_store); +#endif + +#ifdef CONFIG_SCHED_SMT +static ssize_t sched_smt_power_savings_show(struct sys_device *dev, char *page) +{ + return sprintf(page, "%u\n", sched_smt_power_savings); +} +static ssize_t sched_smt_power_savings_store(struct sys_device *dev, const char *buf, size_t count) +{ + return sched_power_savings_store(buf, count, 1); +} +SYSDEV_ATTR(sched_smt_power_savings, 0644, sched_smt_power_savings_show, + sched_smt_power_savings_store); +#endif + + #ifdef CONFIG_HOTPLUG_CPU /* * Force a reinitialization of the sched domains hierarchy. The domains -- cgit v1.2.3-70-g09d2 From 286bbe87c143ca7ecee5bb499cd78048c5a05d49 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Jun 2006 14:27:13 -0700 Subject: [SPARC64]: Kill starfire_cookie from SBUS/PCI. Totally unused. We need to traverse the list of global IRQ translaters, so storing it in the per-bus structures was useless. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_psycho.c | 4 +--- arch/sparc64/kernel/sbus.c | 4 +--- arch/sparc64/kernel/starfire.c | 4 +--- include/asm-sparc64/pbm.h | 2 -- include/asm-sparc64/sbus.h | 1 - include/asm-sparc64/starfire.h | 2 +- 6 files changed, 4 insertions(+), 13 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 5b2261ebda6..1cb63346f09 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1171,9 +1171,7 @@ static void psycho_iommu_init(struct pci_controller_info *p) /* If necessary, hook us up for starfire IRQ translations. */ if (this_is_starfire) - p->starfire_cookie = starfire_hookup(p->pbm_A.portid); - else - p->starfire_cookie = NULL; + starfire_hookup(p->pbm_A.portid); } #define PSYCHO_IRQ_RETRY 0x1a00UL diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index ac05e0f692e..945222e6698 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -1221,9 +1221,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) /* Now some Xfire specific grot... */ if (this_is_starfire) - sbus->starfire_cookie = starfire_hookup(sbus->portid); - else - sbus->starfire_cookie = NULL; + starfire_hookup(sbus->portid); sysio_register_error_handlers(sbus); } diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c index ae859d40771..b930fee7708 100644 --- a/arch/sparc64/kernel/starfire.c +++ b/arch/sparc64/kernel/starfire.c @@ -54,7 +54,7 @@ struct starfire_irqinfo { static struct starfire_irqinfo *sflist = NULL; /* Beam me up Scott(McNeil)y... */ -void *starfire_hookup(int upaid) +void starfire_hookup(int upaid) { struct starfire_irqinfo *p; unsigned long treg_base, hwmid, i; @@ -81,8 +81,6 @@ void *starfire_hookup(int upaid) p->upaid = upaid; p->next = sflist; sflist = p; - - return (void *) p; } unsigned int starfire_translate(unsigned long imap, diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index cebe80b1da6..83b3c26cd06 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -217,8 +217,6 @@ struct pci_controller_info { struct pci_ops *pci_ops; unsigned int pci_first_busno; unsigned int pci_last_busno; - - void *starfire_cookie; }; /* PCI devices which are not bridges have this placed in their pci_dev diff --git a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h index 56ee985e460..7efd49d31bb 100644 --- a/include/asm-sparc64/sbus.h +++ b/include/asm-sparc64/sbus.h @@ -80,7 +80,6 @@ struct sbus_bus { int num_sbus_ranges; int portid; - void *starfire_cookie; }; #define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev) diff --git a/include/asm-sparc64/starfire.h b/include/asm-sparc64/starfire.h index b606cb2b32a..48b50b5e35b 100644 --- a/include/asm-sparc64/starfire.h +++ b/include/asm-sparc64/starfire.h @@ -14,7 +14,7 @@ extern int this_is_starfire; extern void check_if_starfire(void); extern void starfire_cpu_setup(void); extern int starfire_hard_smp_processor_id(void); -extern void *starfire_hookup(int); +extern void starfire_hookup(int); extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid); #endif -- cgit v1.2.3-70-g09d2 From 3ae9a3489a4e2ba665a344a9250c2af05b7b0c59 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Jun 2006 14:34:12 -0700 Subject: [SPARC]: Add of_n_{addr,size}_cells(). Signed-off-by: David S. Miller --- arch/sparc/kernel/prom.c | 30 ++++++++++++++++++++++++++++++ arch/sparc64/kernel/prom.c | 30 ++++++++++++++++++++++++++++++ include/asm-sparc/prom.h | 2 ++ include/asm-sparc64/prom.h | 2 ++ 4 files changed, 64 insertions(+) (limited to 'include/asm-sparc64') diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 946ce6d1581..4b06dcb00eb 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -190,6 +190,36 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); +int of_n_addr_cells(struct device_node *np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#address-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #address-cells property for the root node, default to 2 */ + return 2; +} +EXPORT_SYMBOL(of_n_addr_cells); + +int of_n_size_cells(struct device_node *np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#size-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #size-cells property for the root node, default to 1 */ + return 1; +} +EXPORT_SYMBOL(of_n_size_cells); + int of_set_property(struct device_node *dp, const char *name, void *val, int len) { struct property **prevp; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 8e87e7ea032..6aa856a1815 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -190,6 +190,36 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); +int of_n_addr_cells(struct device_node *np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#address-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #address-cells property for the root node, default to 2 */ + return 2; +} +EXPORT_SYMBOL(of_n_addr_cells); + +int of_n_size_cells(struct device_node *np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#size-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #size-cells property for the root node, default to 1 */ + return 1; +} +EXPORT_SYMBOL(of_n_size_cells); + int of_set_property(struct device_node *dp, const char *name, void *val, int len) { struct property **prevp; diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index f9cf44c0716..7032d02d319 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -101,6 +101,8 @@ extern int of_set_property(struct device_node *node, const char *name, void *val extern int of_getintprop_default(struct device_node *np, const char *name, int def); +extern int of_n_addr_cells(struct device_node *np); +extern int of_n_size_cells(struct device_node *np); extern void prom_build_devicetree(void); diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 265614d497c..4cecfe6d135 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -101,6 +101,8 @@ extern int of_set_property(struct device_node *node, const char *name, void *val extern int of_getintprop_default(struct device_node *np, const char *name, int def); +extern int of_n_addr_cells(struct device_node *np); +extern int of_n_size_cells(struct device_node *np); extern void prom_build_devicetree(void); -- cgit v1.2.3-70-g09d2 From cf44bbc26cf1361b692ab68c884f6a0df7da2fdb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Jun 2006 14:34:50 -0700 Subject: [SPARC]: Beginnings of generic of_device framework. The idea is to fully construct the device register and interrupt values into these of_device objects, and convert all of SBUS, EBUS, ISA drivers to use this new stuff. Much ideas and code taken from Ben H.'s powerpc work. Signed-off-by: David S. Miller --- arch/sparc/kernel/of_device.c | 422 +++++++++++++++++++++++++++++++++- arch/sparc64/kernel/of_device.c | 490 +++++++++++++++++++++++++++++++++++++++- include/asm-sparc/of_device.h | 14 +- include/asm-sparc/prom.h | 2 + include/asm-sparc64/of_device.h | 14 +- include/asm-sparc64/prom.h | 2 + 6 files changed, 936 insertions(+), 8 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index 80a80947878..13a70bd8781 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c @@ -153,10 +153,424 @@ struct bus_type sbus_bus_type = { EXPORT_SYMBOL(sbus_bus_type); #endif +struct bus_type of_bus_type = { + .name = "of", + .match = of_platform_bus_match, + .probe = of_device_probe, + .remove = of_device_remove, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; +EXPORT_SYMBOL(of_bus_type); + +static inline u64 of_read_addr(u32 *cell, int size) +{ + u64 r = 0; + while (size--) + r = (r << 32) | *(cell++); + return r; +} + +static void __init get_cells(struct device_node *dp, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = of_n_addr_cells(dp); + if (sizec) + *sizec = of_n_size_cells(dp); +} + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 + +struct of_bus { + const char *name; + const char *addr_prop_name; + int (*match)(struct device_node *parent); + void (*count_cells)(struct device_node *child, + int *addrc, int *sizec); + u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); + int (*translate)(u32 *addr, u64 offset, int na); + unsigned int (*get_flags)(u32 *addr); +}; + +/* + * Default translator (generic bus) + */ + +static void of_bus_default_count_cells(struct device_node *dev, + int *addrc, int *sizec) +{ + get_cells(dev, addrc, sizec); +} + +static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = of_read_addr(range, na); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr, na); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_default_translate(u32 *addr, u64 offset, int na) +{ + u64 a = of_read_addr(addr, na); + memset(addr, 0, na * 4); + a += offset; + if (na > 1) + addr[na - 2] = a >> 32; + addr[na - 1] = a & 0xffffffffu; + + return 0; +} + +static unsigned int of_bus_default_get_flags(u32 *addr) +{ + return IORESOURCE_MEM; +} + + +/* + * PCI bus specific translator + */ + +static int of_bus_pci_match(struct device_node *np) +{ + return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); +} + +static void of_bus_pci_count_cells(struct device_node *np, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 3; + if (sizec) + *sizec = 2; +} + +static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & 0x03000000) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_addr(range + 1, na - 1); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr + 1, na - 1); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_pci_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +static unsigned int of_bus_pci_get_flags(u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + switch((w >> 24) & 0x03) { + case 0x01: + flags |= IORESOURCE_IO; + case 0x02: /* 32 bits */ + case 0x03: /* 64 bits */ + flags |= IORESOURCE_MEM; + } + if (w & 0x40000000) + flags |= IORESOURCE_PREFETCH; + return flags; +} + +/* + * SBUS bus specific translator + */ + +static int of_bus_sbus_match(struct device_node *np) +{ + return !strcmp(np->name, "sbus") || + !strcmp(np->name, "sbi"); +} + +static void of_bus_sbus_count_cells(struct device_node *child, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + return of_bus_default_map(addr, range, na, ns, pna); +} + +static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr, offset, na); +} + +static unsigned int of_bus_sbus_get_flags(u32 *addr) +{ + return IORESOURCE_MEM; +} + + +/* + * Array of bus specific translators + */ + +static struct of_bus of_busses[] = { + /* PCI */ + { + .name = "pci", + .addr_prop_name = "assigned-addresses", + .match = of_bus_pci_match, + .count_cells = of_bus_pci_count_cells, + .map = of_bus_pci_map, + .translate = of_bus_pci_translate, + .get_flags = of_bus_pci_get_flags, + }, + /* SBUS */ + { + .name = "sbus", + .addr_prop_name = "reg", + .match = of_bus_sbus_match, + .count_cells = of_bus_sbus_count_cells, + .map = of_bus_sbus_map, + .translate = of_bus_sbus_translate, + .get_flags = of_bus_sbus_get_flags, + }, + /* Default */ + { + .name = "default", + .addr_prop_name = "reg", + .match = NULL, + .count_cells = of_bus_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + .get_flags = of_bus_default_get_flags, + }, +}; + +static struct of_bus *of_match_bus(struct device_node *np) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(of_busses); i ++) + if (!of_busses[i].match || of_busses[i].match(np)) + return &of_busses[i]; + BUG(); + return NULL; +} + +static int __init build_one_resource(struct device_node *parent, + struct of_bus *bus, + struct of_bus *pbus, + u32 *addr, + int na, int ns, int pna) +{ + u32 *ranges; + unsigned int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + ranges = of_get_property(parent, "ranges", &rlen); + if (ranges == NULL || rlen == 0) { + offset = of_read_addr(addr, na); + memset(addr, 0, pna * 4); + goto finish; + } + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map(addr, ranges, na, ns, pna); + if (offset != OF_BAD_ADDR) + break; + } + if (offset == OF_BAD_ADDR) + return 1; + + memcpy(addr, ranges + na, 4 * pna); + +finish: + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +static void __init build_device_resources(struct of_device *op, + struct device *parent) +{ + struct of_device *p_op; + struct of_bus *bus; + int na, ns; + int index, num_reg; + void *preg; + + if (!parent) + return; + + p_op = to_of_device(parent); + bus = of_match_bus(p_op->node); + bus->count_cells(op->node, &na, &ns); + + preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); + if (!preg || num_reg == 0) + return; + + /* Convert to num-cells. */ + num_reg /= 4; + + /* Conver to num-entries. */ + num_reg /= na + ns; + + for (index = 0; index < num_reg; index++) { + struct resource *r = &op->resource[index]; + u32 addr[OF_MAX_ADDR_CELLS]; + u32 *reg = (preg + (index * ((na + ns) * 4))); + struct device_node *dp = op->node; + struct device_node *pp = p_op->node; + struct of_bus *pbus; + u64 size, result = OF_BAD_ADDR; + unsigned long flags; + int dna, dns; + int pna, pns; + + size = of_read_addr(reg + na, ns); + flags = bus->get_flags(reg); + + memcpy(addr, reg, na * 4); + + /* If the immediate parent has no ranges property to apply, + * just use a 1<->1 mapping. + */ + if (of_find_property(pp, "ranges", NULL) == NULL) { + result = of_read_addr(addr, na); + goto build_res; + } + + dna = na; + dns = ns; + + while (1) { + dp = pp; + pp = dp->parent; + if (!pp) { + result = of_read_addr(addr, dna); + break; + } + + pbus = of_match_bus(pp); + pbus->count_cells(dp, &pna, &pns); + + if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) + break; + + dna = pna; + dns = pns; + bus = pbus; + } + + build_res: + memset(r, 0, sizeof(*r)); + if (result != OF_BAD_ADDR) { + r->start = result; + r->end = result + size - 1; + r->flags = flags; + } else { + r->start = ~0UL; + r->end = ~0UL; + } + r->name = op->node->name; + } +} + +static struct of_device * __init scan_one_device(struct device_node *dp, + struct device *parent) +{ + struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); + unsigned int *irq; + int len; + + if (!op) + return NULL; + + op->node = dp; + + op->clock_freq = of_getintprop_default(dp, "clock-frequency", + (25*1000*1000)); + op->portid = of_getintprop_default(dp, "upa-portid", -1); + if (op->portid == -1) + op->portid = of_getintprop_default(dp, "portid", -1); + + irq = of_get_property(dp, "interrupts", &len); + if (irq) + op->irq = *irq; + else + op->irq = 0xffffffff; + + build_device_resources(op, parent); + + op->dev.parent = parent; + op->dev.bus = &of_bus_type; + if (!parent) + strcpy(op->dev.bus_id, "root"); + else + strcpy(op->dev.bus_id, dp->path_component_name); + + if (of_device_register(op)) { + printk("%s: Could not register of device.\n", + dp->full_name); + kfree(op); + op = NULL; + } + + return op; +} + +static void __init scan_tree(struct device_node *dp, struct device *parent) +{ + while (dp) { + struct of_device *op = scan_one_device(dp, parent); + + if (op) + scan_tree(dp->child, &op->dev); + + dp = dp->sibling; + } +} + +static void __init scan_of_devices(void) +{ + struct device_node *root = of_find_node_by_path("/"); + struct of_device *parent; + + parent = scan_one_device(root, NULL); + if (!parent) + return; + + scan_tree(root->child, &parent->dev); +} + static int __init of_bus_driver_init(void) { - int err = 0; + int err; + err = bus_register(&of_bus_type); #ifdef CONFIG_PCI if (!err) err = bus_register(&ebus_bus_type); @@ -165,7 +579,11 @@ static int __init of_bus_driver_init(void) if (!err) err = bus_register(&sbus_bus_type); #endif - return 0; + + if (!err) + scan_of_devices(); + + return err; } postcore_initcall(of_bus_driver_init); diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 768475bbce8..00502dc280e 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -163,10 +163,492 @@ struct bus_type sbus_bus_type = { EXPORT_SYMBOL(sbus_bus_type); #endif +struct bus_type of_bus_type = { + .name = "of", + .match = of_platform_bus_match, + .probe = of_device_probe, + .remove = of_device_remove, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; +EXPORT_SYMBOL(of_bus_type); + +static inline u64 of_read_addr(u32 *cell, int size) +{ + u64 r = 0; + while (size--) + r = (r << 32) | *(cell++); + return r; +} + +static void __init get_cells(struct device_node *dp, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = of_n_addr_cells(dp); + if (sizec) + *sizec = of_n_size_cells(dp); +} + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 + +struct of_bus { + const char *name; + const char *addr_prop_name; + int (*match)(struct device_node *parent); + void (*count_cells)(struct device_node *child, + int *addrc, int *sizec); + u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); + int (*translate)(u32 *addr, u64 offset, int na); + unsigned int (*get_flags)(u32 *addr); +}; + +/* + * Default translator (generic bus) + */ + +static void of_bus_default_count_cells(struct device_node *dev, + int *addrc, int *sizec) +{ + get_cells(dev, addrc, sizec); +} + +static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = of_read_addr(range, na); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr, na); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_default_translate(u32 *addr, u64 offset, int na) +{ + u64 a = of_read_addr(addr, na); + memset(addr, 0, na * 4); + a += offset; + if (na > 1) + addr[na - 2] = a >> 32; + addr[na - 1] = a & 0xffffffffu; + + return 0; +} + +static unsigned int of_bus_default_get_flags(u32 *addr) +{ + return IORESOURCE_MEM; +} + + +/* + * PCI bus specific translator + */ + +static int of_bus_pci_match(struct device_node *np) +{ + return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); +} + +static void of_bus_pci_count_cells(struct device_node *np, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 3; + if (sizec) + *sizec = 2; +} + +static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & 0x03000000) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_addr(range + 1, na - 1); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr + 1, na - 1); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_pci_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +static unsigned int of_bus_pci_get_flags(u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + switch((w >> 24) & 0x03) { + case 0x01: + flags |= IORESOURCE_IO; + case 0x02: /* 32 bits */ + case 0x03: /* 64 bits */ + flags |= IORESOURCE_MEM; + } + if (w & 0x40000000) + flags |= IORESOURCE_PREFETCH; + return flags; +} + +/* + * ISA bus specific translator + */ + +static int of_bus_isa_match(struct device_node *np) +{ + return !strcmp(np->name, "isa"); +} + +static void of_bus_isa_count_cells(struct device_node *child, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & 0x00000001) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_addr(range + 1, na - 1); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr + 1, na - 1); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_isa_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +static unsigned int of_bus_isa_get_flags(u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + if (w & 1) + flags |= IORESOURCE_IO; + else + flags |= IORESOURCE_MEM; + return flags; +} + +/* + * SBUS bus specific translator + */ + +static int of_bus_sbus_match(struct device_node *np) +{ + return !strcmp(np->name, "sbus") || + !strcmp(np->name, "sbi"); +} + +static void of_bus_sbus_count_cells(struct device_node *child, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + return of_bus_default_map(addr, range, na, ns, pna); +} + +static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr, offset, na); +} + +static unsigned int of_bus_sbus_get_flags(u32 *addr) +{ + return IORESOURCE_MEM; +} + + +/* + * Array of bus specific translators + */ + +static struct of_bus of_busses[] = { + /* PCI */ + { + .name = "pci", + .addr_prop_name = "assigned-addresses", + .match = of_bus_pci_match, + .count_cells = of_bus_pci_count_cells, + .map = of_bus_pci_map, + .translate = of_bus_pci_translate, + .get_flags = of_bus_pci_get_flags, + }, + /* ISA */ + { + .name = "isa", + .addr_prop_name = "reg", + .match = of_bus_isa_match, + .count_cells = of_bus_isa_count_cells, + .map = of_bus_isa_map, + .translate = of_bus_isa_translate, + .get_flags = of_bus_isa_get_flags, + }, + /* SBUS */ + { + .name = "sbus", + .addr_prop_name = "reg", + .match = of_bus_sbus_match, + .count_cells = of_bus_sbus_count_cells, + .map = of_bus_sbus_map, + .translate = of_bus_sbus_translate, + .get_flags = of_bus_sbus_get_flags, + }, + /* Default */ + { + .name = "default", + .addr_prop_name = "reg", + .match = NULL, + .count_cells = of_bus_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + .get_flags = of_bus_default_get_flags, + }, +}; + +static struct of_bus *of_match_bus(struct device_node *np) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(of_busses); i ++) + if (!of_busses[i].match || of_busses[i].match(np)) + return &of_busses[i]; + BUG(); + return NULL; +} + +static int __init build_one_resource(struct device_node *parent, + struct of_bus *bus, + struct of_bus *pbus, + u32 *addr, + int na, int ns, int pna) +{ + u32 *ranges; + unsigned int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + ranges = of_get_property(parent, "ranges", &rlen); + if (ranges == NULL || rlen == 0) { + offset = of_read_addr(addr, na); + memset(addr, 0, pna * 4); + goto finish; + } + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map(addr, ranges, na, ns, pna); + if (offset != OF_BAD_ADDR) + break; + } + if (offset == OF_BAD_ADDR) + return 1; + + memcpy(addr, ranges + na, 4 * pna); + +finish: + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +static void __init build_device_resources(struct of_device *op, + struct device *parent) +{ + struct of_device *p_op; + struct of_bus *bus; + int na, ns; + int index, num_reg; + void *preg; + + if (!parent) + return; + + p_op = to_of_device(parent); + bus = of_match_bus(p_op->node); + bus->count_cells(op->node, &na, &ns); + + preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); + if (!preg || num_reg == 0) + return; + + /* Convert to num-cells. */ + num_reg /= 4; + + /* Conver to num-entries. */ + num_reg /= na + ns; + + for (index = 0; index < num_reg; index++) { + struct resource *r = &op->resource[index]; + u32 addr[OF_MAX_ADDR_CELLS]; + u32 *reg = (preg + (index * ((na + ns) * 4))); + struct device_node *dp = op->node; + struct device_node *pp = p_op->node; + struct of_bus *pbus; + u64 size, result = OF_BAD_ADDR; + unsigned long flags; + int dna, dns; + int pna, pns; + + size = of_read_addr(reg + na, ns); + flags = bus->get_flags(reg); + + memcpy(addr, reg, na * 4); + + /* If the immediate parent has no ranges property to apply, + * just use a 1<->1 mapping. Unless it is the 'dma' child + * of an isa bus, which must be passed up towards the root. + * + * Also, don't try to translate PMU bus device registers. + */ + if ((of_find_property(pp, "ranges", NULL) == NULL && + strcmp(pp->name, "dma") != 0) || + !strcmp(pp->name, "pmu")) { + result = of_read_addr(addr, na); + goto build_res; + } + + dna = na; + dns = ns; + + while (1) { + dp = pp; + pp = dp->parent; + if (!pp) { + result = of_read_addr(addr, dna); + break; + } + + pbus = of_match_bus(pp); + pbus->count_cells(dp, &pna, &pns); + + if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) + break; + + dna = pna; + dns = pns; + bus = pbus; + } + + build_res: + memset(r, 0, sizeof(*r)); + if (result != OF_BAD_ADDR) { + r->start = result; + r->end = result + size - 1; + r->flags = flags; + } else { + r->start = ~0UL; + r->end = ~0UL; + } + r->name = op->node->name; + } +} + +static struct of_device * __init scan_one_device(struct device_node *dp, + struct device *parent) +{ + struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); + unsigned int *irq; + int len; + + if (!op) + return NULL; + + op->node = dp; + + op->clock_freq = of_getintprop_default(dp, "clock-frequency", + (25*1000*1000)); + op->portid = of_getintprop_default(dp, "upa-portid", -1); + if (op->portid == -1) + op->portid = of_getintprop_default(dp, "portid", -1); + + irq = of_get_property(dp, "interrupts", &len); + if (irq) + op->irq = *irq; + else + op->irq = 0xffffffff; + + build_device_resources(op, parent); + + op->dev.parent = parent; + op->dev.bus = &of_bus_type; + if (!parent) + strcpy(op->dev.bus_id, "root"); + else + strcpy(op->dev.bus_id, dp->path_component_name); + + if (of_device_register(op)) { + printk("%s: Could not register of device.\n", + dp->full_name); + kfree(op); + op = NULL; + } + + return op; +} + +static void __init scan_tree(struct device_node *dp, struct device *parent) +{ + while (dp) { + struct of_device *op = scan_one_device(dp, parent); + + if (op) + scan_tree(dp->child, &op->dev); + + dp = dp->sibling; + } +} + +static void __init scan_of_devices(void) +{ + struct device_node *root = of_find_node_by_path("/"); + struct of_device *parent; + + parent = scan_one_device(root, NULL); + if (!parent) + return; + + scan_tree(root->child, &parent->dev); +} + static int __init of_bus_driver_init(void) { - int err = 0; + int err; + err = bus_register(&of_bus_type); #ifdef CONFIG_PCI if (!err) err = bus_register(&isa_bus_type); @@ -177,7 +659,11 @@ static int __init of_bus_driver_init(void) if (!err) err = bus_register(&sbus_bus_type); #endif - return 0; + + if (!err) + scan_of_devices(); + + return err; } postcore_initcall(of_bus_driver_init); diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h index 4816d102f91..1b43ee5eb5e 100644 --- a/include/asm-sparc/of_device.h +++ b/include/asm-sparc/of_device.h @@ -4,10 +4,12 @@ #include #include +#include #include extern struct bus_type ebus_bus_type; extern struct bus_type sbus_bus_type; +extern struct bus_type of_bus_type; /* * The of_device is a kind of "base class" that is a superset of @@ -16,8 +18,16 @@ extern struct bus_type sbus_bus_type; */ struct of_device { - struct device_node *node; /* OF device node */ - struct device dev; /* Generic device interface */ + struct device_node *node; + struct device dev; + struct resource resource[PROMREG_MAX]; + unsigned int irq; + + void *sysdata; + + int slot; + int portid; + int clock_freq; }; #define to_of_device(d) container_of(d, struct of_device, dev) diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index 7032d02d319..b4a061c5241 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -69,6 +69,8 @@ struct device_node { #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) +#define OF_BAD_ADDR ((u64)-1) + static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h index 024088ef9d2..27bc08671d6 100644 --- a/include/asm-sparc64/of_device.h +++ b/include/asm-sparc64/of_device.h @@ -4,11 +4,13 @@ #include #include +#include #include extern struct bus_type isa_bus_type; extern struct bus_type ebus_bus_type; extern struct bus_type sbus_bus_type; +extern struct bus_type of_bus_type; /* * The of_device is a kind of "base class" that is a superset of @@ -17,8 +19,16 @@ extern struct bus_type sbus_bus_type; */ struct of_device { - struct device_node *node; /* OF device node */ - struct device dev; /* Generic device interface */ + struct device_node *node; + struct device dev; + struct resource resource[PROMREG_MAX]; + unsigned int irq; + + void *sysdata; + + int slot; + int portid; + int clock_freq; }; #define to_of_device(d) container_of(d, struct of_device, dev) diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 4cecfe6d135..d2849312dea 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -69,6 +69,8 @@ struct device_node { #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) +#define OF_BAD_ADDR ((u64)-1) + static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; -- cgit v1.2.3-70-g09d2 From 3ca9fab410fbef6fc3a13284f5c26faccade21d1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Jun 2006 14:35:33 -0700 Subject: [SPARC]: Add of_io{remap,unmap}(). Signed-off-by: David S. Miller --- arch/sparc/kernel/ioport.c | 17 +++++++++++++++++ arch/sparc64/kernel/of_device.c | 17 +++++++++++++++++ include/asm-sparc/of_device.h | 3 +++ include/asm-sparc64/of_device.h | 3 +++ 4 files changed, 40 insertions(+) (limited to 'include/asm-sparc64') diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 79d177149fd..8654b446ac9 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -26,6 +26,7 @@ */ #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -143,6 +145,21 @@ void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset, phyres->start + offset, size, name); } +void __iomem *of_ioremap(struct resource *res, unsigned long offset, + unsigned long size, char *name) +{ + return _sparc_alloc_io(res->flags & 0xF, + res->start + offset, + size, name); +} +EXPORT_SYMBOL(of_ioremap); + +void of_iounmap(void __iomem *base, unsigned long size) +{ + iounmap(base); +} +EXPORT_SYMBOL(of_iounmap); + /* */ void sbus_iounmap(volatile void __iomem *addr, unsigned long size) diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 00502dc280e..9812cfa6dd3 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -129,6 +129,23 @@ static int of_device_resume(struct device * dev) return error; } +void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name) +{ + unsigned long ret = res->start + offset; + + if (!request_region(ret, size, name)) + ret = 0; + + return (void __iomem *) ret; +} +EXPORT_SYMBOL(of_ioremap); + +void of_iounmap(void __iomem *base, unsigned long size) +{ + release_region((unsigned long) base, size); +} +EXPORT_SYMBOL(of_iounmap); + #ifdef CONFIG_PCI struct bus_type isa_bus_type = { .name = "isa", diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h index 1b43ee5eb5e..b5ca3145d48 100644 --- a/include/asm-sparc/of_device.h +++ b/include/asm-sparc/of_device.h @@ -31,6 +31,9 @@ struct of_device }; #define to_of_device(d) container_of(d, struct of_device, dev) +extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); +extern void of_iounmap(void __iomem *base, unsigned long size); + extern const struct of_device_id *of_match_device( const struct of_device_id *matches, const struct of_device *dev); diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h index 27bc08671d6..37c5856fae1 100644 --- a/include/asm-sparc64/of_device.h +++ b/include/asm-sparc64/of_device.h @@ -32,6 +32,9 @@ struct of_device }; #define to_of_device(d) container_of(d, struct of_device, dev) +extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); +extern void of_iounmap(void __iomem *base, unsigned long size); + extern const struct of_device_id *of_match_device( const struct of_device_id *matches, const struct of_device *dev); -- cgit v1.2.3-70-g09d2 From 946ea09962a56674fe564b41c3007933bb41a068 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Jun 2006 14:37:09 -0700 Subject: [SPARC]: Kill interrupt stuff and linux_phandle from device_node. Signed-off-by: David S. Miller --- include/asm-sparc/prom.h | 8 -------- include/asm-sparc64/prom.h | 8 -------- 2 files changed, 16 deletions(-) (limited to 'include/asm-sparc64') diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index b4a061c5241..86c13dccea3 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -25,11 +25,6 @@ typedef u32 phandle; typedef u32 ihandle; -struct interrupt_info { - int line; - int sense; /* +ve/-ve logic, edge or level, etc. */ -}; - struct property { char *name; int length; @@ -43,9 +38,6 @@ struct device_node { char *name; char *type; phandle node; - phandle linux_phandle; - int n_intrs; - struct interrupt_info *intrs; char *path_component_name; char *full_name; diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index d2849312dea..aad16c2aa5e 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -25,11 +25,6 @@ typedef u32 phandle; typedef u32 ihandle; -struct interrupt_info { - int line; - int sense; /* +ve/-ve logic, edge or level, etc. */ -}; - struct property { char *name; int length; @@ -43,9 +38,6 @@ struct device_node { char *name; char *type; phandle node; - phandle linux_phandle; - int n_intrs; - struct interrupt_info *intrs; char *path_component_name; char *full_name; -- cgit v1.2.3-70-g09d2 From 2b1e59787198e75fb2ffb3bb4fb247da1c55ac12 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Jun 2006 15:07:37 -0700 Subject: [SPARC64]: of_device layer IRQ resolution Do IRQ determination generically by parsing the PROM properties, and using IRQ controller drivers for final resolution. One immediate positive effect is that all of the IRQ frobbing in the EBUS, ISA, and PCI controller layers has been eliminated. We just look up the of_device and use the properly computed value. The PCI controller irq_build() routines are gone and no longer used. Unfortunately sbus_build_irq() has to remain as there is a direct reference to this in the sunzilog driver. That can be killed off once the sparc32 side of this is written and the sunzilog driver is transformed into an "of" bus driver. Signed-off-by: David S. Miller --- arch/sparc64/kernel/ebus.c | 150 ++------ arch/sparc64/kernel/isa.c | 101 +----- arch/sparc64/kernel/of_device.c | 194 +++++++++- arch/sparc64/kernel/pci.c | 6 - arch/sparc64/kernel/pci_common.c | 291 +-------------- arch/sparc64/kernel/pci_psycho.c | 161 ++------- arch/sparc64/kernel/pci_sabre.c | 158 ++------ arch/sparc64/kernel/pci_schizo.c | 311 ++++------------ arch/sparc64/kernel/pci_sun4v.c | 10 - arch/sparc64/kernel/prom.c | 757 ++++++++++++++++++++++++++++++++++++++- include/asm-sparc64/of_device.h | 5 +- include/asm-sparc64/pbm.h | 3 +- include/asm-sparc64/prom.h | 8 + 13 files changed, 1105 insertions(+), 1050 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 98e0a8cbeec..aac014d15ad 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -279,45 +281,12 @@ static inline void *ebus_alloc(size_t size) return mem; } -int __init ebus_intmap_match(struct linux_ebus *ebus, - struct linux_prom_registers *reg, - int *interrupt) -{ - struct linux_prom_ebus_intmap *imap; - struct linux_prom_ebus_intmask *imask; - unsigned int hi, lo, irq; - int i, len, n_imap; - - imap = of_get_property(ebus->prom_node, "interrupt-map", &len); - if (!imap) - return 0; - n_imap = len / sizeof(imap[0]); - - imask = of_get_property(ebus->prom_node, "interrupt-map-mask", NULL); - if (!imask) - return 0; - - hi = reg->which_io & imask->phys_hi; - lo = reg->phys_addr & imask->phys_lo; - irq = *interrupt & imask->interrupt; - for (i = 0; i < n_imap; i++) { - if ((imap[i].phys_hi == hi) && - (imap[i].phys_lo == lo) && - (imap[i].interrupt == irq)) { - *interrupt = imap[i].cinterrupt; - return 0; - } - } - return -1; -} - -void __init fill_ebus_child(struct device_node *dp, - struct linux_prom_registers *preg, - struct linux_ebus_child *dev, - int non_standard_regs) +static void __init fill_ebus_child(struct device_node *dp, + struct linux_ebus_child *dev, + int non_standard_regs) { + struct of_device *op; int *regs; - int *irqs; int i, len; dev->prom_node = dp; @@ -354,12 +323,16 @@ void __init fill_ebus_child(struct device_node *dp, } } - for (i = 0; i < PROMINTR_MAX; i++) - dev->irqs[i] = PCI_IRQ_NONE; - - irqs = of_get_property(dp, "interrupts", &len); - if (!irqs) { + op = of_find_device_by_node(dp); + if (!op) { dev->num_irqs = 0; + } else { + dev->num_irqs = op->num_irqs; + for (i = 0; i < dev->num_irqs; i++) + dev->irqs[i] = op->irqs[i]; + } + + if (!dev->num_irqs) { /* * Oh, well, some PROMs don't export interrupts * property to children of EBus devices... @@ -375,23 +348,6 @@ void __init fill_ebus_child(struct device_node *dp, dev->irqs[0] = dev->parent->irqs[1]; } } - } else { - dev->num_irqs = len / sizeof(irqs[0]); - for (i = 0; i < dev->num_irqs; i++) { - struct pci_pbm_info *pbm = dev->bus->parent; - struct pci_controller_info *p = pbm->parent; - - if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) { - dev->irqs[i] = p->irq_build(pbm, - dev->bus->self, - irqs[i]); - } else { - /* If we get a bogus interrupt property, just - * record the raw value instead of punting. - */ - dev->irqs[i] = irqs[i]; - } - } } } @@ -403,72 +359,32 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev) return 0; } -void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) +static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) { - struct linux_prom_registers *regs; struct linux_ebus_child *child; - int *irqs; - int i, n, len; + struct of_device *op; + int i, len; dev->prom_node = dp; printk(" [%s", dp->name); - regs = of_get_property(dp, "reg", &len); - if (!regs) { + op = of_find_device_by_node(dp); + if (!op) { dev->num_addrs = 0; - goto probe_interrupts; - } - - if (len % sizeof(struct linux_prom_registers)) { - prom_printf("UGH: proplen for %s was %d, need multiple of %d\n", - dev->prom_node->name, len, - (int)sizeof(struct linux_prom_registers)); - prom_halt(); - } - dev->num_addrs = len / sizeof(struct linux_prom_registers); - - for (i = 0; i < dev->num_addrs; i++) { - /* XXX Learn how to interpret ebus ranges... -DaveM */ - if (regs[i].which_io >= 0x10) - n = (regs[i].which_io - 0x10) >> 2; - else - n = regs[i].which_io; - - dev->resource[i].start = dev->bus->self->resource[n].start; - dev->resource[i].start += (unsigned long)regs[i].phys_addr; - dev->resource[i].end = - (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL); - dev->resource[i].flags = IORESOURCE_MEM; - dev->resource[i].name = dev->prom_node->name; - request_resource(&dev->bus->self->resource[n], - &dev->resource[i]); - } - -probe_interrupts: - for (i = 0; i < PROMINTR_MAX; i++) - dev->irqs[i] = PCI_IRQ_NONE; - - irqs = of_get_property(dp, "interrupts", &len); - if (!irqs) { dev->num_irqs = 0; } else { - dev->num_irqs = len / sizeof(irqs[0]); - for (i = 0; i < dev->num_irqs; i++) { - struct pci_pbm_info *pbm = dev->bus->parent; - struct pci_controller_info *p = pbm->parent; - - if (ebus_intmap_match(dev->bus, ®s[0], &irqs[i]) != -1) { - dev->irqs[i] = p->irq_build(pbm, - dev->bus->self, - irqs[i]); - } else { - /* If we get a bogus interrupt property, just - * record the raw value instead of punting. - */ - dev->irqs[i] = irqs[i]; - } - } + (void) of_get_property(dp, "reg", &len); + dev->num_addrs = len / sizeof(struct linux_prom_registers); + + for (i = 0; i < dev->num_addrs; i++) + memcpy(&dev->resource[i], + &op->resource[i], + sizeof(struct resource)); + + dev->num_irqs = op->num_irqs; + for (i = 0; i < dev->num_irqs; i++) + dev->irqs[i] = op->irqs[i]; } dev->ofdev.node = dp; @@ -490,7 +406,7 @@ probe_interrupts: child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(dp, regs, child, + fill_ebus_child(dp, child, child_regs_nonstandard(dev)); while ((dp = dp->sibling) != NULL) { @@ -500,7 +416,7 @@ probe_interrupts: child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(dp, regs, child, + fill_ebus_child(dp, child, child_regs_nonstandard(dev)); } } diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index 24c0dc34be3..0f3aec72ef5 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include struct sparc_isa_bridge *isa_chain; @@ -46,107 +48,16 @@ isa_dev_get_resource(struct sparc_isa_device *isa_dev) return pregs; } -/* I can't believe they didn't put a real INO in the isa device - * interrupts property. The whole point of the OBP properties - * is to shield the kernel from IRQ routing details. - * - * The P1275 standard for ISA devices seems to also have been - * totally ignored. - * - * On later systems, an interrupt-map and interrupt-map-mask scheme - * akin to EBUS is used. - */ -static struct { - int obp_irq; - int pci_ino; -} grover_irq_table[] = { - { 1, 0x00 }, /* dma, unknown ino at this point */ - { 2, 0x27 }, /* floppy */ - { 3, 0x22 }, /* parallel */ - { 4, 0x2b }, /* serial */ - { 5, 0x25 }, /* acpi power management */ - - { 0, 0x00 } /* end of table */ -}; - -static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev, - struct sparc_isa_bridge *isa_br, - int *interrupt, - struct linux_prom_registers *reg) -{ - struct linux_prom_ebus_intmap *imap; - struct linux_prom_ebus_intmask *imask; - unsigned int hi, lo, irq; - int i, len, n_imap; - - imap = of_get_property(isa_br->prom_node, "interrupt-map", &len); - if (!imap) - return 0; - n_imap = len / sizeof(imap[0]); - - imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL); - if (!imask) - return 0; - - hi = reg->which_io & imask->phys_hi; - lo = reg->phys_addr & imask->phys_lo; - irq = *interrupt & imask->interrupt; - for (i = 0; i < n_imap; i++) { - if ((imap[i].phys_hi == hi) && - (imap[i].phys_lo == lo) && - (imap[i].interrupt == irq)) { - *interrupt = imap[i].cinterrupt; - return 0; - } - } - return -1; -} - static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev, struct linux_prom_registers *pregs) { - int irq_prop; + struct of_device *op = of_find_device_by_node(isa_dev->prom_node); - irq_prop = of_getintprop_default(isa_dev->prom_node, - "interrupts", -1); - if (irq_prop <= 0) { - goto no_irq; + if (!op || !op->num_irqs) { + isa_dev->irq = PCI_IRQ_NONE; } else { - struct pci_controller_info *pcic; - struct pci_pbm_info *pbm; - int i; - - if (of_find_property(isa_dev->bus->prom_node, - "interrupt-map", NULL)) { - if (!isa_dev_get_irq_using_imap(isa_dev, - isa_dev->bus, - &irq_prop, - pregs)) - goto route_irq; - } - - for (i = 0; grover_irq_table[i].obp_irq != 0; i++) { - if (grover_irq_table[i].obp_irq == irq_prop) { - int ino = grover_irq_table[i].pci_ino; - - if (ino == 0) - goto no_irq; - - irq_prop = ino; - goto route_irq; - } - } - goto no_irq; - -route_irq: - pbm = isa_dev->bus->parent; - pcic = pbm->parent; - isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop); - return; + isa_dev->irq = op->irqs[0]; } - -no_irq: - isa_dev->irq = PCI_IRQ_NONE; } static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 9812cfa6dd3..3670dc8a7d5 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -146,6 +146,26 @@ void of_iounmap(void __iomem *base, unsigned long size) } EXPORT_SYMBOL(of_iounmap); +static int node_match(struct device *dev, void *data) +{ + struct of_device *op = to_of_device(dev); + struct device_node *dp = data; + + return (op->node == dp); +} + +struct of_device *of_find_device_by_node(struct device_node *dp) +{ + struct device *dev = bus_find_device(&of_bus_type, NULL, + dp, node_match); + + if (dev) + return to_of_device(dev); + + return NULL; +} +EXPORT_SYMBOL(of_find_device_by_node); + #ifdef CONFIG_PCI struct bus_type isa_bus_type = { .name = "isa", @@ -261,7 +281,6 @@ static unsigned int of_bus_default_get_flags(u32 *addr) return IORESOURCE_MEM; } - /* * PCI bus specific translator */ @@ -594,12 +613,171 @@ static void __init build_device_resources(struct of_device *op, } } +static struct device_node * __init +apply_interrupt_map(struct device_node *dp, struct device_node *pp, + u32 *imap, int imlen, u32 *imask, + unsigned int *irq_p) +{ + struct device_node *cp; + unsigned int irq = *irq_p; + struct of_bus *bus; + phandle handle; + u32 *reg; + int na, num_reg, i; + + bus = of_match_bus(pp); + bus->count_cells(dp, &na, NULL); + + reg = of_get_property(dp, "reg", &num_reg); + if (!reg || !num_reg) + return NULL; + + imlen /= ((na + 3) * 4); + handle = 0; + for (i = 0; i < imlen; i++) { + int j; + + for (j = 0; j < na; j++) { + if ((reg[j] & imask[j]) != imap[j]) + goto next; + } + if (imap[na] == irq) { + handle = imap[na + 1]; + irq = imap[na + 2]; + break; + } + + next: + imap += (na + 3); + } + if (i == imlen) + return NULL; + + *irq_p = irq; + cp = of_find_node_by_phandle(handle); + + return cp; +} + +static unsigned int __init pci_irq_swizzle(struct device_node *dp, + struct device_node *pp, + unsigned int irq) +{ + struct linux_prom_pci_registers *regs; + unsigned int devfn, slot, ret; + + if (irq < 1 || irq > 4) + return irq; + + regs = of_get_property(dp, "reg", NULL); + if (!regs) + return irq; + + devfn = (regs->phys_hi >> 8) & 0xff; + slot = (devfn >> 3) & 0x1f; + + ret = ((irq - 1 + (slot & 3)) & 3) + 1; + + return ret; +} + +static unsigned int __init build_one_device_irq(struct of_device *op, + struct device *parent, + unsigned int irq) +{ + struct device_node *dp = op->node; + struct device_node *pp, *ip; + unsigned int orig_irq = irq; + + if (irq == 0xffffffff) + return irq; + + if (dp->irq_trans) { + irq = dp->irq_trans->irq_build(dp, irq, + dp->irq_trans->data); +#if 1 + printk("%s: direct translate %x --> %x\n", + dp->full_name, orig_irq, irq); +#endif + return irq; + } + + /* Something more complicated. Walk up to the root, applying + * interrupt-map or bus specific translations, until we hit + * an IRQ translator. + * + * If we hit a bus type or situation we cannot handle, we + * stop and assume that the original IRQ number was in a + * format which has special meaning to it's immediate parent. + */ + pp = dp->parent; + ip = NULL; + while (pp) { + void *imap, *imsk; + int imlen; + + imap = of_get_property(pp, "interrupt-map", &imlen); + imsk = of_get_property(pp, "interrupt-map-mask", NULL); + if (imap && imsk) { + struct device_node *iret; + int this_orig_irq = irq; + + iret = apply_interrupt_map(dp, pp, + imap, imlen, imsk, + &irq); +#if 1 + printk("%s: Apply [%s:%x] imap --> [%s:%x]\n", + op->node->full_name, + pp->full_name, this_orig_irq, + (iret ? iret->full_name : "NULL"), irq); +#endif + if (!iret) + break; + + if (iret->irq_trans) { + ip = iret; + break; + } + } else { + if (!strcmp(pp->type, "pci") || + !strcmp(pp->type, "pciex")) { + unsigned int this_orig_irq = irq; + + irq = pci_irq_swizzle(dp, pp, irq); +#if 1 + printk("%s: PCI swizzle [%s] %x --> %x\n", + op->node->full_name, + pp->full_name, this_orig_irq, irq); +#endif + } + + if (pp->irq_trans) { + ip = pp; + break; + } + } + dp = pp; + pp = pp->parent; + } + if (!ip) + return orig_irq; + + irq = ip->irq_trans->irq_build(op->node, irq, + ip->irq_trans->data); +#if 1 + printk("%s: Apply IRQ trans [%s] %x --> %x\n", + op->node->full_name, ip->full_name, orig_irq, irq); +#endif + + return irq; +} + static struct of_device * __init scan_one_device(struct device_node *dp, struct device *parent) { struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); unsigned int *irq; - int len; + int len, i; if (!op) return NULL; @@ -613,12 +791,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp, op->portid = of_getintprop_default(dp, "portid", -1); irq = of_get_property(dp, "interrupts", &len); - if (irq) - op->irq = *irq; - else - op->irq = 0xffffffff; + if (irq) { + memcpy(op->irqs, irq, len); + op->num_irqs = len / 4; + } else { + op->num_irqs = 0; + } build_device_resources(op, parent); + for (i = 0; i < op->num_irqs; i++) + op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]); op->dev.parent = parent; op->dev.bus = &of_bus_type; diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 7b962582860..04ea6c2eb7a 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -404,14 +404,8 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res, } EXPORT_SYMBOL(pcibios_bus_to_resource); -extern int pci_irq_verbose; - char * __init pcibios_setup(char *str) { - if (!strcmp(str, "irq_verbose")) { - pci_irq_verbose = 1; - return NULL; - } return str; } diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index b06a2955bf5..7a59cc72c84 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -10,12 +10,10 @@ #include #include +#include #include "pci_impl.h" -/* Pass "pci=irq_verbose" on the kernel command line to enable this. */ -int pci_irq_verbose; - /* Fix self device of BUS and hook it into BUS->self. * The pci_scan_bus does not do this for the host bridge. */ @@ -169,6 +167,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, } pcp->pbm = pbm; pcp->prom_node = dp; + pcp->op = of_find_device_by_node(dp); memcpy(pcp->prom_regs, pregs, nregs * sizeof(struct linux_prom_pci_registers)); pcp->num_prom_regs = nregs; @@ -549,296 +548,18 @@ void __init pci_assign_unassigned(struct pci_pbm_info *pbm, pci_assign_unassigned(pbm, bus); } -static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm, - struct pci_dev *toplevel_pdev, - struct pci_dev *pdev, - unsigned int interrupt) -{ - unsigned int ret; - - if (unlikely(interrupt < 1 || interrupt > 4)) { - printk("%s: Device %s interrupt value of %u is strange.\n", - pbm->name, pci_name(pdev), interrupt); - return interrupt; - } - - ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1; - - if (pci_irq_verbose) - printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n", - pbm->name, pci_name(toplevel_pdev), pci_name(pdev), - interrupt, PCI_SLOT(pdev->devfn), ret); - - return ret; -} - -static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm, - struct pci_dev *toplevel_pdev, - struct pci_dev *pbus, - struct pci_dev *pdev, - unsigned int interrupt, - struct device_node **cnode) -{ - struct linux_prom_pci_intmap *imap; - struct linux_prom_pci_intmask *imask; - struct pcidev_cookie *pbus_pcp = pbus->sysdata; - struct pcidev_cookie *pdev_pcp = pdev->sysdata; - struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs; - struct property *prop; - int plen, num_imap, i; - unsigned int hi, mid, lo, irq, orig_interrupt; - - *cnode = pbus_pcp->prom_node; - - prop = of_find_property(pbus_pcp->prom_node, "interrupt-map", &plen); - if (!prop || - (plen % sizeof(struct linux_prom_pci_intmap)) != 0) { - printk("%s: Device %s interrupt-map has bad len %d\n", - pbm->name, pci_name(pbus), plen); - goto no_intmap; - } - imap = prop->value; - num_imap = plen / sizeof(struct linux_prom_pci_intmap); - - prop = of_find_property(pbus_pcp->prom_node, "interrupt-map-mask", &plen); - if (!prop || - (plen % sizeof(struct linux_prom_pci_intmask)) != 0) { - printk("%s: Device %s interrupt-map-mask has bad len %d\n", - pbm->name, pci_name(pbus), plen); - goto no_intmap; - } - imask = prop->value; - - orig_interrupt = interrupt; - - hi = pregs->phys_hi & imask->phys_hi; - mid = pregs->phys_mid & imask->phys_mid; - lo = pregs->phys_lo & imask->phys_lo; - irq = interrupt & imask->interrupt; - - for (i = 0; i < num_imap; i++) { - if (imap[i].phys_hi == hi && - imap[i].phys_mid == mid && - imap[i].phys_lo == lo && - imap[i].interrupt == irq) { - *cnode = of_find_node_by_phandle(imap[i].cnode); - interrupt = imap[i].cinterrupt; - } - } - - if (pci_irq_verbose) - printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n", - pbm->name, pci_name(toplevel_pdev), - pci_name(pbus), pci_name(pdev), - orig_interrupt, interrupt); - -no_intmap: - return interrupt; -} - -/* For each PCI bus on the way to the root: - * 1) If it has an interrupt-map property, apply it. - * 2) Else, swivel the interrupt number based upon the PCI device number. - * - * Return the "IRQ controller" node. If this is the PBM's device node, - * all interrupt translations are complete, else we should use that node's - * "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt. - */ -static struct device_node * __init -pci_intmap_match_to_root(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int *interrupt) -{ - struct pci_dev *toplevel_pdev = pdev; - struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata; - struct device_node *cnode = toplevel_pcp->prom_node; - - while (pdev->bus->number != pbm->pci_first_busno) { - struct pci_dev *pbus = pdev->bus->self; - struct pcidev_cookie *pcp = pbus->sysdata; - struct property *prop; - - prop = of_find_property(pcp->prom_node, "interrupt-map", NULL); - if (!prop) { - *interrupt = pci_slot_swivel(pbm, toplevel_pdev, - pdev, *interrupt); - cnode = pcp->prom_node; - } else { - *interrupt = pci_apply_intmap(pbm, toplevel_pdev, - pbus, pdev, - *interrupt, &cnode); - - while (pcp->prom_node != cnode && - pbus->bus->number != pbm->pci_first_busno) { - pbus = pbus->bus->self; - pcp = pbus->sysdata; - } - } - pdev = pbus; - - if (cnode == pbm->prom_node) - break; - } - - return cnode; -} - -static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) -{ - struct pcidev_cookie *dev_pcp = pdev->sysdata; - struct pci_pbm_info *pbm = dev_pcp->pbm; - struct linux_prom_pci_registers *reg; - struct device_node *cnode; - struct property *prop; - unsigned int hi, mid, lo, irq; - int i, plen; - - cnode = pci_intmap_match_to_root(pbm, pdev, interrupt); - if (cnode == pbm->prom_node) - goto success; - - prop = of_find_property(cnode, "reg", &plen); - if (!prop || - (plen % sizeof(struct linux_prom_pci_registers)) != 0) { - printk("%s: OBP node %s reg property has bad len %d\n", - pbm->name, cnode->full_name, plen); - goto fail; - } - reg = prop->value; - - hi = reg[0].phys_hi & pbm->pbm_intmask->phys_hi; - mid = reg[0].phys_mid & pbm->pbm_intmask->phys_mid; - lo = reg[0].phys_lo & pbm->pbm_intmask->phys_lo; - irq = *interrupt & pbm->pbm_intmask->interrupt; - - for (i = 0; i < pbm->num_pbm_intmap; i++) { - struct linux_prom_pci_intmap *intmap; - - intmap = &pbm->pbm_intmap[i]; - - if (intmap->phys_hi == hi && - intmap->phys_mid == mid && - intmap->phys_lo == lo && - intmap->interrupt == irq) { - *interrupt = intmap->cinterrupt; - goto success; - } - } - -fail: - return 0; - -success: - if (pci_irq_verbose) - printk("%s: Routing bus[%2x] slot[%2x] to INO[%02x]\n", - pbm->name, - pdev->bus->number, PCI_SLOT(pdev->devfn), - *interrupt); - return 1; -} - static void __init pdev_fixup_irq(struct pci_dev *pdev) { struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; - struct pci_controller_info *p = pbm->parent; - unsigned int portid = pbm->portid; - unsigned int prom_irq; - struct device_node *dp = pcp->prom_node; - struct property *prop; - - /* If this is an empty EBUS device, sometimes OBP fails to - * give it a valid fully specified interrupts property. - * The EBUS hooked up to SunHME on PCI I/O boards of - * Ex000 systems is one such case. - * - * The interrupt is not important so just ignore it. - */ - if (pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_EBUS && - !dp->child) { - pdev->irq = 0; - return; - } + struct of_device *op = pcp->op; - prop = of_find_property(dp, "interrupts", NULL); - if (!prop) { - pdev->irq = 0; + if (op->irqs[0] == 0xffffffff) { + pdev->irq = PCI_IRQ_NONE; return; } - prom_irq = *(unsigned int *) prop->value; - - if (tlb_type != hypervisor) { - /* Fully specified already? */ - if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) { - pdev->irq = p->irq_build(pbm, pdev, prom_irq); - goto have_irq; - } - - /* An onboard device? (bit 5 set) */ - if ((prom_irq & PCI_IRQ_INO) & 0x20) { - pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq)); - goto have_irq; - } - } - - /* Can we find a matching entry in the interrupt-map? */ - if (pci_intmap_match(pdev, &prom_irq)) { - pdev->irq = p->irq_build(pbm, pdev, (portid << 6) | prom_irq); - goto have_irq; - } - - /* Ok, we have to do it the hard way. */ - { - unsigned int bus, slot, line; - - bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0; - - /* If we have a legal interrupt property, use it as - * the IRQ line. - */ - if (prom_irq > 0 && prom_irq < 5) { - line = ((prom_irq - 1) & 3); - } else { - u8 pci_irq_line; - /* Else just directly consult PCI config space. */ - pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line); - line = ((pci_irq_line - 1) & 3); - } - - /* Now figure out the slot. - * - * Basically, device number zero on the top-level bus is - * always the PCI host controller. Slot 0 is then device 1. - * PBM A supports two external slots (0 and 1), and PBM B - * supports 4 external slots (0, 1, 2, and 3). On-board PCI - * devices are wired to device numbers outside of these - * ranges. -DaveM - */ - if (pdev->bus->number == pbm->pci_first_busno) { - slot = PCI_SLOT(pdev->devfn) - pbm->pci_first_slot; - } else { - struct pci_dev *bus_dev; - - /* Underneath a bridge, use slot number of parent - * bridge which is closest to the PBM. - */ - bus_dev = pdev->bus->self; - while (bus_dev->bus && - bus_dev->bus->number != pbm->pci_first_busno) - bus_dev = bus_dev->bus->self; - - slot = PCI_SLOT(bus_dev->devfn) - pbm->pci_first_slot; - } - slot = slot << 2; - - pdev->irq = p->irq_build(pbm, pdev, - ((portid << 6) & PCI_IRQ_IGN) | - (bus | slot | line)); - } + pdev->irq = op->irqs[0]; -have_irq: pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq & PCI_IRQ_INO); } diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 1cb63346f09..bf7b32b3670 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "pci_impl.h" #include "iommu_common.h" @@ -208,110 +209,6 @@ static struct pci_ops psycho_ops = { .write = psycho_write_pci_cfg, }; -/* PSYCHO interrupt mapping support. */ -#define PSYCHO_IMAP_A_SLOT0 0x0c00UL -#define PSYCHO_IMAP_B_SLOT0 0x0c20UL -static unsigned long psycho_pcislot_imap_offset(unsigned long ino) -{ - unsigned int bus = (ino & 0x10) >> 4; - unsigned int slot = (ino & 0x0c) >> 2; - - if (bus == 0) - return PSYCHO_IMAP_A_SLOT0 + (slot * 8); - else - return PSYCHO_IMAP_B_SLOT0 + (slot * 8); -} - -#define PSYCHO_IMAP_SCSI 0x1000UL -#define PSYCHO_IMAP_ETH 0x1008UL -#define PSYCHO_IMAP_BPP 0x1010UL -#define PSYCHO_IMAP_AU_REC 0x1018UL -#define PSYCHO_IMAP_AU_PLAY 0x1020UL -#define PSYCHO_IMAP_PFAIL 0x1028UL -#define PSYCHO_IMAP_KMS 0x1030UL -#define PSYCHO_IMAP_FLPY 0x1038UL -#define PSYCHO_IMAP_SHW 0x1040UL -#define PSYCHO_IMAP_KBD 0x1048UL -#define PSYCHO_IMAP_MS 0x1050UL -#define PSYCHO_IMAP_SER 0x1058UL -#define PSYCHO_IMAP_TIM0 0x1060UL -#define PSYCHO_IMAP_TIM1 0x1068UL -#define PSYCHO_IMAP_UE 0x1070UL -#define PSYCHO_IMAP_CE 0x1078UL -#define PSYCHO_IMAP_A_ERR 0x1080UL -#define PSYCHO_IMAP_B_ERR 0x1088UL -#define PSYCHO_IMAP_PMGMT 0x1090UL -#define PSYCHO_IMAP_GFX 0x1098UL -#define PSYCHO_IMAP_EUPA 0x10a0UL - -static unsigned long __onboard_imap_off[] = { -/*0x20*/ PSYCHO_IMAP_SCSI, -/*0x21*/ PSYCHO_IMAP_ETH, -/*0x22*/ PSYCHO_IMAP_BPP, -/*0x23*/ PSYCHO_IMAP_AU_REC, -/*0x24*/ PSYCHO_IMAP_AU_PLAY, -/*0x25*/ PSYCHO_IMAP_PFAIL, -/*0x26*/ PSYCHO_IMAP_KMS, -/*0x27*/ PSYCHO_IMAP_FLPY, -/*0x28*/ PSYCHO_IMAP_SHW, -/*0x29*/ PSYCHO_IMAP_KBD, -/*0x2a*/ PSYCHO_IMAP_MS, -/*0x2b*/ PSYCHO_IMAP_SER, -/*0x2c*/ PSYCHO_IMAP_TIM0, -/*0x2d*/ PSYCHO_IMAP_TIM1, -/*0x2e*/ PSYCHO_IMAP_UE, -/*0x2f*/ PSYCHO_IMAP_CE, -/*0x30*/ PSYCHO_IMAP_A_ERR, -/*0x31*/ PSYCHO_IMAP_B_ERR, -/*0x32*/ PSYCHO_IMAP_PMGMT -}; -#define PSYCHO_ONBOARD_IRQ_BASE 0x20 -#define PSYCHO_ONBOARD_IRQ_LAST 0x32 -#define psycho_onboard_imap_offset(__ino) \ - __onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] - -#define PSYCHO_ICLR_A_SLOT0 0x1400UL -#define PSYCHO_ICLR_SCSI 0x1800UL - -#define psycho_iclr_offset(ino) \ - ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ - (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) - -static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int ino) -{ - unsigned long imap, iclr; - unsigned long imap_off, iclr_off; - int inofixup = 0; - - ino &= PCI_IRQ_INO; - if (ino < PSYCHO_ONBOARD_IRQ_BASE) { - /* PCI slot */ - imap_off = psycho_pcislot_imap_offset(ino); - } else { - /* Onboard device */ - if (ino > PSYCHO_ONBOARD_IRQ_LAST) { - prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - } - imap_off = psycho_onboard_imap_offset(ino); - } - - /* Now build the IRQ bucket. */ - imap = pbm->controller_regs + imap_off; - imap += 4; - - iclr_off = psycho_iclr_offset(ino); - iclr = pbm->controller_regs + iclr_off; - iclr += 4; - - if ((ino & 0x20) == 0) - inofixup = ino & 0x03; - - return build_irq(inofixup, iclr, imap); -} - /* PSYCHO error handling support. */ enum psycho_error_type { UE_ERR, CE_ERR, PCI_ERR @@ -944,51 +841,34 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg #define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */ #define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */ #define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */ -#define PSYCHO_UE_INO 0x2e -#define PSYCHO_CE_INO 0x2f -#define PSYCHO_PCIERR_A_INO 0x30 -#define PSYCHO_PCIERR_B_INO 0x31 static void psycho_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ + struct of_device *op = of_find_device_by_node(pbm->prom_node); unsigned long base = p->pbm_A.controller_regs; - unsigned int irq, portid = pbm->portid; u64 tmp; - /* Build IRQs and register handlers. */ - irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_UE_INO); - if (request_irq(irq, psycho_ue_intr, - SA_SHIRQ, "PSYCHO UE", p) < 0) { - prom_printf("PSYCHO%d: Cannot register UE interrupt.\n", - p->index); - prom_halt(); - } + if (!op) + return; - irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_CE_INO); - if (request_irq(irq, psycho_ce_intr, - SA_SHIRQ, "PSYCHO CE", p) < 0) { - prom_printf("PSYCHO%d: Cannot register CE interrupt.\n", - p->index); - prom_halt(); - } + /* Psycho interrupt property order is: + * 0: PCIERR PBM B INO + * 1: UE ERR + * 2: CE ERR + * 3: POWER FAIL + * 4: SPARE HARDWARE + * 5: PCIERR PBM A INO + */ - pbm = &p->pbm_A; - irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO); - if (request_irq(irq, psycho_pcierr_intr, - SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) { - prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n", - p->index); - prom_halt(); - } + if (op->num_irqs < 6) + return; - pbm = &p->pbm_B; - irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO); - if (request_irq(irq, psycho_pcierr_intr, - SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) { - prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n", - p->index); - prom_halt(); - } + request_irq(op->irqs[1], psycho_ue_intr, SA_SHIRQ, "PSYCHO UE", p); + request_irq(op->irqs[2], psycho_ce_intr, SA_SHIRQ, "PSYCHO CE", p); + request_irq(op->irqs[5], psycho_pcierr_intr, SA_SHIRQ, + "PSYCHO PCIERR-A", &p->pbm_A); + request_irq(op->irqs[0], psycho_pcierr_intr, SA_SHIRQ, + "PSYCHO PCIERR-B", &p->pbm_B); /* Enable UE and CE interrupts for controller. */ psycho_write(base + PSYCHO_ECC_CTRL, @@ -1406,7 +1286,6 @@ void psycho_init(struct device_node *dp, char *model_name) p->index = pci_num_controllers++; p->pbms_same_domain = 0; p->scan_bus = psycho_scan_bus; - p->irq_build = psycho_irq_build; p->base_address_update = psycho_base_address_update; p->resource_adjust = psycho_resource_adjust; p->pci_ops = &psycho_ops; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 26f194ce440..5e087b0fb4c 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -485,114 +485,6 @@ static struct pci_ops sabre_ops = { .write = sabre_write_pci_cfg, }; -static unsigned long sabre_pcislot_imap_offset(unsigned long ino) -{ - unsigned int bus = (ino & 0x10) >> 4; - unsigned int slot = (ino & 0x0c) >> 2; - - if (bus == 0) - return SABRE_IMAP_A_SLOT0 + (slot * 8); - else - return SABRE_IMAP_B_SLOT0 + (slot * 8); -} - -static unsigned long __onboard_imap_off[] = { -/*0x20*/ SABRE_IMAP_SCSI, -/*0x21*/ SABRE_IMAP_ETH, -/*0x22*/ SABRE_IMAP_BPP, -/*0x23*/ SABRE_IMAP_AU_REC, -/*0x24*/ SABRE_IMAP_AU_PLAY, -/*0x25*/ SABRE_IMAP_PFAIL, -/*0x26*/ SABRE_IMAP_KMS, -/*0x27*/ SABRE_IMAP_FLPY, -/*0x28*/ SABRE_IMAP_SHW, -/*0x29*/ SABRE_IMAP_KBD, -/*0x2a*/ SABRE_IMAP_MS, -/*0x2b*/ SABRE_IMAP_SER, -/*0x2c*/ 0 /* reserved */, -/*0x2d*/ 0 /* reserved */, -/*0x2e*/ SABRE_IMAP_UE, -/*0x2f*/ SABRE_IMAP_CE, -/*0x30*/ SABRE_IMAP_PCIERR, -}; -#define SABRE_ONBOARD_IRQ_BASE 0x20 -#define SABRE_ONBOARD_IRQ_LAST 0x30 -#define sabre_onboard_imap_offset(__ino) \ - __onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE] - -#define sabre_iclr_offset(ino) \ - ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ - (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) - -/* When a device lives behind a bridge deeper in the PCI bus topology - * than APB, a special sequence must run to make sure all pending DMA - * transfers at the time of IRQ delivery are visible in the coherency - * domain by the cpu. This sequence is to perform a read on the far - * side of the non-APB bridge, then perform a read of Sabre's DMA - * write-sync register. - */ -static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) -{ - struct pci_dev *pdev = _arg1; - unsigned long sync_reg = (unsigned long) _arg2; - u16 _unused; - - pci_read_config_word(pdev, PCI_VENDOR_ID, &_unused); - sabre_read(sync_reg); -} - -static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int ino) -{ - unsigned long imap, iclr; - unsigned long imap_off, iclr_off; - int inofixup = 0; - int virt_irq; - - ino &= PCI_IRQ_INO; - if (ino < SABRE_ONBOARD_IRQ_BASE) { - /* PCI slot */ - imap_off = sabre_pcislot_imap_offset(ino); - } else { - /* onboard device */ - if (ino > SABRE_ONBOARD_IRQ_LAST) { - prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - } - imap_off = sabre_onboard_imap_offset(ino); - } - - /* Now build the IRQ bucket. */ - imap = pbm->controller_regs + imap_off; - imap += 4; - - iclr_off = sabre_iclr_offset(ino); - iclr = pbm->controller_regs + iclr_off; - iclr += 4; - - if ((ino & 0x20) == 0) - inofixup = ino & 0x03; - - virt_irq = build_irq(inofixup, iclr, imap); - - if (pdev) { - struct pcidev_cookie *pcp = pdev->sysdata; - - if (pdev->bus->number != pcp->pbm->pci_first_busno) { - struct pci_controller_info *p = pcp->pbm->parent; - - irq_install_pre_handler(virt_irq, - sabre_wsync_handler, - pdev, - (void *) - p->pbm_A.controller_regs + - SABRE_WRSYNC); - } - } - return virt_irq; -} - /* SABRE error handling support. */ static void sabre_check_iommu_error(struct pci_controller_info *p, unsigned long afsr, @@ -929,17 +821,30 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs return IRQ_HANDLED; } -/* XXX What about PowerFail/PowerManagement??? -DaveM */ -#define SABRE_UE_INO 0x2e -#define SABRE_CE_INO 0x2f -#define SABRE_PCIERR_INO 0x30 static void sabre_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ + struct device_node *dp = pbm->prom_node; + struct of_device *op; unsigned long base = pbm->controller_regs; - unsigned long irq, portid = pbm->portid; u64 tmp; + if (pbm->chip_type == PBM_CHIP_TYPE_SABRE) + dp = dp->parent; + + op = of_find_device_by_node(dp); + if (!op) + return; + + /* Sabre/Hummingbird IRQ property layout is: + * 0: PCI ERR + * 1: UE ERR + * 2: CE ERR + * 3: POWER FAIL + */ + if (op->num_irqs < 4) + return; + /* We clear the error bits in the appropriate AFSR before * registering the handler so that we don't get spurious * interrupts. @@ -948,32 +853,16 @@ static void sabre_register_error_handlers(struct pci_controller_info *p) (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE)); - irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_UE_INO); - if (request_irq(irq, sabre_ue_intr, - SA_SHIRQ, "SABRE UE", p) < 0) { - prom_printf("SABRE%d: Cannot register UE interrupt.\n", - p->index); - prom_halt(); - } + + request_irq(op->irqs[1], sabre_ue_intr, SA_SHIRQ, "SABRE UE", p); sabre_write(base + SABRE_CE_AFSR, (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR)); - irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_CE_INO); - if (request_irq(irq, sabre_ce_intr, - SA_SHIRQ, "SABRE CE", p) < 0) { - prom_printf("SABRE%d: Cannot register CE interrupt.\n", - p->index); - prom_halt(); - } - irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_PCIERR_INO); - if (request_irq(irq, sabre_pcierr_intr, - SA_SHIRQ, "SABRE PCIERR", p) < 0) { - prom_printf("SABRE%d: Cannot register PciERR interrupt.\n", - p->index); - prom_halt(); - } + request_irq(op->irqs[2], sabre_ce_intr, SA_SHIRQ, "SABRE CE", p); + request_irq(op->irqs[0], sabre_pcierr_intr, SA_SHIRQ, + "SABRE PCIERR", p); tmp = sabre_read(base + SABRE_PCICTRL); tmp |= SABRE_PCICTRL_ERREN; @@ -1492,7 +1381,6 @@ void sabre_init(struct device_node *dp, char *model_name) p->index = pci_num_controllers++; p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; - p->irq_build = sabre_irq_build; p->base_address_update = sabre_base_address_update; p->resource_adjust = sabre_resource_adjust; p->pci_ops = &sabre_ops; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index f16449ccd7b..5c6e2a9b91f 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -217,116 +217,6 @@ static struct pci_ops schizo_ops = { .write = schizo_write_pci_cfg, }; -/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the - * imap/iclr registers are per-PBM. - */ -#define SCHIZO_IMAP_BASE 0x1000UL -#define SCHIZO_ICLR_BASE 0x1400UL - -static unsigned long schizo_imap_offset(unsigned long ino) -{ - return SCHIZO_IMAP_BASE + (ino * 8UL); -} - -static unsigned long schizo_iclr_offset(unsigned long ino) -{ - return SCHIZO_ICLR_BASE + (ino * 8UL); -} - -static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) -{ - unsigned long sync_reg = (unsigned long) _arg2; - u64 mask = 1UL << (ino & IMAP_INO); - u64 val; - int limit; - - schizo_write(sync_reg, mask); - - limit = 100000; - val = 0; - while (--limit) { - val = schizo_read(sync_reg); - if (!(val & mask)) - break; - } - if (limit <= 0) { - printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n", - val, mask); - } - - if (_arg1) { - static unsigned char cacheline[64] - __attribute__ ((aligned (64))); - - __asm__ __volatile__("rd %%fprs, %0\n\t" - "or %0, %4, %1\n\t" - "wr %1, 0x0, %%fprs\n\t" - "stda %%f0, [%5] %6\n\t" - "wr %0, 0x0, %%fprs\n\t" - "membar #Sync" - : "=&r" (mask), "=&r" (val) - : "0" (mask), "1" (val), - "i" (FPRS_FEF), "r" (&cacheline[0]), - "i" (ASI_BLK_COMMIT_P)); - } -} - -static unsigned long schizo_ino_to_iclr(struct pci_pbm_info *pbm, - unsigned int ino) -{ - ino &= PCI_IRQ_INO; - return pbm->pbm_regs + schizo_iclr_offset(ino) + 4; -} - -static unsigned long schizo_ino_to_imap(struct pci_pbm_info *pbm, - unsigned int ino) -{ - ino &= PCI_IRQ_INO; - return pbm->pbm_regs + schizo_imap_offset(ino) + 4; -} - -static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int ino) -{ - unsigned long imap, iclr; - int ign_fixup; - int virt_irq; - - ino &= PCI_IRQ_INO; - - /* Now build the IRQ bucket. */ - imap = schizo_ino_to_imap(pbm, ino); - iclr = schizo_ino_to_iclr(pbm, ino); - - /* On Schizo, no inofixup occurs. This is because each - * INO has it's own IMAP register. On Psycho and Sabre - * there is only one IMAP register for each PCI slot even - * though four different INOs can be generated by each - * PCI slot. - * - * But, for JBUS variants (essentially, Tomatillo), we have - * to fixup the lowest bit of the interrupt group number. - */ - ign_fixup = 0; - if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { - if (pbm->portid & 1) - ign_fixup = (1 << 6); - } - - virt_irq = build_irq(ign_fixup, iclr, imap); - - if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { - irq_install_pre_handler(virt_irq, - tomatillo_wsync_handler, - ((pbm->chip_version <= 4) ? - (void *) 1 : (void *) 0), - (void *) pbm->sync_reg); - } - - return virt_irq; -} - /* SCHIZO error handling support. */ enum schizo_error_type { UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR @@ -362,34 +252,6 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino) return &p->pbm_A; } -static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq) -{ - struct pci_pbm_info *pbm; - unsigned long iclr; - - /* Do not clear the interrupt for the other PCI bus. - * - * This "ACK both PBM IRQs" only needs to be performed - * for chip-wide error interrupts. - */ - if ((irq & IMAP_INO) == SCHIZO_PCIERR_A_INO || - (irq & IMAP_INO) == SCHIZO_PCIERR_B_INO) - return; - - pbm = pbm_for_ino(p, irq); - if (pbm == &p->pbm_A) - pbm = &p->pbm_B; - else - pbm = &p->pbm_A; - - schizo_irq_build(pbm, NULL, - (pbm->portid << 6) | (irq & IMAP_INO)); - - iclr = schizo_ino_to_iclr(pbm, - (pbm->portid << 6) | (irq & IMAP_INO)); - upa_writel(ICLR_IDLE, iclr); -} - #define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */ #define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */ #define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */ @@ -720,8 +582,6 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs) /* Interrogate IOMMU for error status. */ schizo_check_iommu_error(p, UE_ERR); - schizo_clear_other_err_intr(p, irq); - return IRQ_HANDLED; } @@ -811,8 +671,6 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs) printk("(none)"); printk("]\n"); - schizo_clear_other_err_intr(p, irq); - return IRQ_HANDLED; } @@ -1033,8 +891,6 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR)) pci_scan_for_parity_error(p, pbm, pbm->pci_bus); - schizo_clear_other_err_intr(p, irq); - return IRQ_HANDLED; } @@ -1090,7 +946,6 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs * printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n", p->index, errlog); - schizo_clear_other_err_intr(p, irq); return IRQ_HANDLED; } @@ -1098,7 +953,6 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs * p->index); schizo_check_iommu_error(p, SAFARI_ERR); - schizo_clear_other_err_intr(p, irq); return IRQ_HANDLED; } @@ -1130,74 +984,47 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs * static void tomatillo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; - unsigned int irq; + struct of_device *op; u64 tmp, err_mask, err_no_mask; - /* Build IRQs and register handlers. */ + /* Tomatillo IRQ property layout is: + * 0: PCIERR + * 1: UE ERR + * 2: CE ERR + * 3: SERR + * 4: POWER FAIL? + */ + pbm = pbm_for_ino(p, SCHIZO_UE_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO); - if (request_irq(irq, schizo_ue_intr, - SA_SHIRQ, "TOMATILLO UE", p) < 0) { - prom_printf("%s: Cannot register UE interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_UE_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[1], schizo_ue_intr, SA_SHIRQ, + "TOMATILLO_UE", p); pbm = pbm_for_ino(p, SCHIZO_CE_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO); - if (request_irq(irq, schizo_ce_intr, - SA_SHIRQ, "TOMATILLO CE", p) < 0) { - prom_printf("%s: Cannot register CE interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_CE_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[2], schizo_ce_intr, SA_SHIRQ, + "TOMATILLO CE", p); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); - irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | - SCHIZO_PCIERR_A_INO)); - if (request_irq(irq, schizo_pcierr_intr, - SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { - prom_printf("%s: Cannot register PBM A PciERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | - SCHIZO_PCIERR_A_INO))); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + "TOMATILLO PCIERR-A", pbm); + pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); - irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | - SCHIZO_PCIERR_B_INO)); - if (request_irq(irq, schizo_pcierr_intr, - SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { - prom_printf("%s: Cannot register PBM B PciERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | - SCHIZO_PCIERR_B_INO))); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + "TOMATILLO PCIERR-B", pbm); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO); - if (request_irq(irq, schizo_safarierr_intr, - SA_SHIRQ, "TOMATILLO SERR", p) < 0) { - prom_printf("%s: Cannot register SafariERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | - SCHIZO_SERR_INO))); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_SERR_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[3], schizo_safarierr_intr, SA_SHIRQ, + "TOMATILLO SERR", p); /* Enable UE and CE interrupts for controller. */ schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, @@ -1265,64 +1092,47 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) static void schizo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; - unsigned int irq; + struct of_device *op; u64 tmp, err_mask, err_no_mask; - /* Build IRQs and register handlers. */ + /* Schizo IRQ property layout is: + * 0: PCIERR + * 1: UE ERR + * 2: CE ERR + * 3: SERR + * 4: POWER FAIL? + */ + pbm = pbm_for_ino(p, SCHIZO_UE_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO); - if (request_irq(irq, schizo_ue_intr, - SA_SHIRQ, "SCHIZO UE", p) < 0) { - prom_printf("%s: Cannot register UE interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[1], schizo_ue_intr, SA_SHIRQ, + "SCHIZO_UE", p); pbm = pbm_for_ino(p, SCHIZO_CE_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO); - if (request_irq(irq, schizo_ce_intr, - SA_SHIRQ, "SCHIZO CE", p) < 0) { - prom_printf("%s: Cannot register CE interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[2], schizo_ce_intr, SA_SHIRQ, + "SCHIZO CE", p); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO); - if (request_irq(irq, schizo_pcierr_intr, - SA_SHIRQ, "SCHIZO PCIERR", pbm) < 0) { - prom_printf("%s: Cannot register PBM A PciERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + "SCHIZO PCIERR-A", pbm); + pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO); - if (request_irq(irq, schizo_pcierr_intr, - SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_B) < 0) { - prom_printf("%s: Cannot register PBM B PciERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + "SCHIZO PCIERR-B", pbm); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO); - if (request_irq(irq, schizo_safarierr_intr, - SA_SHIRQ, "SCHIZO SERR", p) < 0) { - prom_printf("%s: Cannot register SafariERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_SERR_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[3], schizo_safarierr_intr, SA_SHIRQ, + "SCHIZO SERR", p); /* Enable UE and CE interrupts for controller. */ schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, @@ -2022,7 +1832,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ? tomatillo_scan_bus : schizo_scan_bus); - p->irq_build = schizo_irq_build; p->base_address_update = schizo_base_address_update; p->resource_adjust = schizo_resource_adjust; p->pci_ops = &schizo_ops; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index b69e2270a72..03ad4c06758 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -843,15 +843,6 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p) /* XXX register error interrupt handlers XXX */ } -static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int devino) -{ - u32 devhandle = pbm->devhandle; - - return sun4v_build_irq(devhandle, devino); -} - static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) { struct pcidev_cookie *pcp = pdev->sysdata; @@ -1200,7 +1191,6 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) p->pbms_same_domain = 0; p->scan_bus = pci_sun4v_scan_bus; - p->irq_build = pci_sun4v_irq_build; p->base_address_update = pci_sun4v_base_address_update; p->resource_adjust = pci_sun4v_resource_adjust; p->pci_ops = &pci_sun4v_ops; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 6aa856a1815..8a70c52c044 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -15,6 +15,7 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include #include @@ -23,7 +24,11 @@ #include #include +#include #include +#include +#include +#include static struct device_node *allnodes; @@ -283,6 +288,754 @@ static void * __init prom_early_alloc(unsigned long size) return ret; } +#ifdef CONFIG_PCI +/* PSYCHO interrupt mapping support. */ +#define PSYCHO_IMAP_A_SLOT0 0x0c00UL +#define PSYCHO_IMAP_B_SLOT0 0x0c20UL +static unsigned long psycho_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return PSYCHO_IMAP_A_SLOT0 + (slot * 8); + else + return PSYCHO_IMAP_B_SLOT0 + (slot * 8); +} + +#define PSYCHO_IMAP_SCSI 0x1000UL +#define PSYCHO_IMAP_ETH 0x1008UL +#define PSYCHO_IMAP_BPP 0x1010UL +#define PSYCHO_IMAP_AU_REC 0x1018UL +#define PSYCHO_IMAP_AU_PLAY 0x1020UL +#define PSYCHO_IMAP_PFAIL 0x1028UL +#define PSYCHO_IMAP_KMS 0x1030UL +#define PSYCHO_IMAP_FLPY 0x1038UL +#define PSYCHO_IMAP_SHW 0x1040UL +#define PSYCHO_IMAP_KBD 0x1048UL +#define PSYCHO_IMAP_MS 0x1050UL +#define PSYCHO_IMAP_SER 0x1058UL +#define PSYCHO_IMAP_TIM0 0x1060UL +#define PSYCHO_IMAP_TIM1 0x1068UL +#define PSYCHO_IMAP_UE 0x1070UL +#define PSYCHO_IMAP_CE 0x1078UL +#define PSYCHO_IMAP_A_ERR 0x1080UL +#define PSYCHO_IMAP_B_ERR 0x1088UL +#define PSYCHO_IMAP_PMGMT 0x1090UL +#define PSYCHO_IMAP_GFX 0x1098UL +#define PSYCHO_IMAP_EUPA 0x10a0UL + +static unsigned long __psycho_onboard_imap_off[] = { +/*0x20*/ PSYCHO_IMAP_SCSI, +/*0x21*/ PSYCHO_IMAP_ETH, +/*0x22*/ PSYCHO_IMAP_BPP, +/*0x23*/ PSYCHO_IMAP_AU_REC, +/*0x24*/ PSYCHO_IMAP_AU_PLAY, +/*0x25*/ PSYCHO_IMAP_PFAIL, +/*0x26*/ PSYCHO_IMAP_KMS, +/*0x27*/ PSYCHO_IMAP_FLPY, +/*0x28*/ PSYCHO_IMAP_SHW, +/*0x29*/ PSYCHO_IMAP_KBD, +/*0x2a*/ PSYCHO_IMAP_MS, +/*0x2b*/ PSYCHO_IMAP_SER, +/*0x2c*/ PSYCHO_IMAP_TIM0, +/*0x2d*/ PSYCHO_IMAP_TIM1, +/*0x2e*/ PSYCHO_IMAP_UE, +/*0x2f*/ PSYCHO_IMAP_CE, +/*0x30*/ PSYCHO_IMAP_A_ERR, +/*0x31*/ PSYCHO_IMAP_B_ERR, +/*0x32*/ PSYCHO_IMAP_PMGMT +}; +#define PSYCHO_ONBOARD_IRQ_BASE 0x20 +#define PSYCHO_ONBOARD_IRQ_LAST 0x32 +#define psycho_onboard_imap_offset(__ino) \ + __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] + +#define PSYCHO_ICLR_A_SLOT0 0x1400UL +#define PSYCHO_ICLR_SCSI 0x1800UL + +#define psycho_iclr_offset(ino) \ + ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +static unsigned int psycho_irq_build(struct device_node *dp, + unsigned int ino, + void *_data) +{ + unsigned long controller_regs = (unsigned long) _data; + unsigned long imap, iclr; + unsigned long imap_off, iclr_off; + int inofixup = 0; + + ino &= 0x3f; + if (ino < PSYCHO_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = psycho_pcislot_imap_offset(ino); + } else { + /* Onboard device */ + if (ino > PSYCHO_ONBOARD_IRQ_LAST) { + prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = psycho_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + imap = controller_regs + imap_off; + imap += 4; + + iclr_off = psycho_iclr_offset(ino); + iclr = controller_regs + iclr_off; + iclr += 4; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + return build_irq(inofixup, iclr, imap); +} + +static void psycho_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = psycho_irq_build; + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = (void *) regs[2].phys_addr; +} + +#define sabre_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) + +struct sabre_irq_data { + unsigned long controller_regs; + unsigned int pci_first_busno; +}; +#define SABRE_CONFIGSPACE 0x001000000UL +#define SABRE_WRSYNC 0x1c20UL + +#define SABRE_CONFIG_BASE(CONFIG_SPACE) \ + (CONFIG_SPACE | (1UL << 24)) +#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ + (((unsigned long)(BUS) << 16) | \ + ((unsigned long)(DEVFN) << 8) | \ + ((unsigned long)(REG))) + +/* When a device lives behind a bridge deeper in the PCI bus topology + * than APB, a special sequence must run to make sure all pending DMA + * transfers at the time of IRQ delivery are visible in the coherency + * domain by the cpu. This sequence is to perform a read on the far + * side of the non-APB bridge, then perform a read of Sabre's DMA + * write-sync register. + */ +static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) +{ + unsigned int phys_hi = (unsigned int) (unsigned long) _arg1; + struct sabre_irq_data *irq_data = _arg2; + unsigned long controller_regs = irq_data->controller_regs; + unsigned long sync_reg = controller_regs + SABRE_WRSYNC; + unsigned long config_space = controller_regs + SABRE_CONFIGSPACE; + unsigned int bus, devfn; + u16 _unused; + + config_space = SABRE_CONFIG_BASE(config_space); + + bus = (phys_hi >> 16) & 0xff; + devfn = (phys_hi >> 8) & 0xff; + + config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00); + + __asm__ __volatile__("membar #Sync\n\t" + "lduha [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (_unused) + : "r" ((u16 *) config_space), + "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + + sabre_read(sync_reg); +} + +#define SABRE_IMAP_A_SLOT0 0x0c00UL +#define SABRE_IMAP_B_SLOT0 0x0c20UL +#define SABRE_IMAP_SCSI 0x1000UL +#define SABRE_IMAP_ETH 0x1008UL +#define SABRE_IMAP_BPP 0x1010UL +#define SABRE_IMAP_AU_REC 0x1018UL +#define SABRE_IMAP_AU_PLAY 0x1020UL +#define SABRE_IMAP_PFAIL 0x1028UL +#define SABRE_IMAP_KMS 0x1030UL +#define SABRE_IMAP_FLPY 0x1038UL +#define SABRE_IMAP_SHW 0x1040UL +#define SABRE_IMAP_KBD 0x1048UL +#define SABRE_IMAP_MS 0x1050UL +#define SABRE_IMAP_SER 0x1058UL +#define SABRE_IMAP_UE 0x1070UL +#define SABRE_IMAP_CE 0x1078UL +#define SABRE_IMAP_PCIERR 0x1080UL +#define SABRE_IMAP_GFX 0x1098UL +#define SABRE_IMAP_EUPA 0x10a0UL +#define SABRE_ICLR_A_SLOT0 0x1400UL +#define SABRE_ICLR_B_SLOT0 0x1480UL +#define SABRE_ICLR_SCSI 0x1800UL +#define SABRE_ICLR_ETH 0x1808UL +#define SABRE_ICLR_BPP 0x1810UL +#define SABRE_ICLR_AU_REC 0x1818UL +#define SABRE_ICLR_AU_PLAY 0x1820UL +#define SABRE_ICLR_PFAIL 0x1828UL +#define SABRE_ICLR_KMS 0x1830UL +#define SABRE_ICLR_FLPY 0x1838UL +#define SABRE_ICLR_SHW 0x1840UL +#define SABRE_ICLR_KBD 0x1848UL +#define SABRE_ICLR_MS 0x1850UL +#define SABRE_ICLR_SER 0x1858UL +#define SABRE_ICLR_UE 0x1870UL +#define SABRE_ICLR_CE 0x1878UL +#define SABRE_ICLR_PCIERR 0x1880UL + +static unsigned long sabre_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return SABRE_IMAP_A_SLOT0 + (slot * 8); + else + return SABRE_IMAP_B_SLOT0 + (slot * 8); +} + +static unsigned long __sabre_onboard_imap_off[] = { +/*0x20*/ SABRE_IMAP_SCSI, +/*0x21*/ SABRE_IMAP_ETH, +/*0x22*/ SABRE_IMAP_BPP, +/*0x23*/ SABRE_IMAP_AU_REC, +/*0x24*/ SABRE_IMAP_AU_PLAY, +/*0x25*/ SABRE_IMAP_PFAIL, +/*0x26*/ SABRE_IMAP_KMS, +/*0x27*/ SABRE_IMAP_FLPY, +/*0x28*/ SABRE_IMAP_SHW, +/*0x29*/ SABRE_IMAP_KBD, +/*0x2a*/ SABRE_IMAP_MS, +/*0x2b*/ SABRE_IMAP_SER, +/*0x2c*/ 0 /* reserved */, +/*0x2d*/ 0 /* reserved */, +/*0x2e*/ SABRE_IMAP_UE, +/*0x2f*/ SABRE_IMAP_CE, +/*0x30*/ SABRE_IMAP_PCIERR, +}; +#define SABRE_ONBOARD_IRQ_BASE 0x20 +#define SABRE_ONBOARD_IRQ_LAST 0x30 +#define sabre_onboard_imap_offset(__ino) \ + __sabre_onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE] + +#define sabre_iclr_offset(ino) \ + ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +static unsigned int sabre_irq_build(struct device_node *dp, + unsigned int ino, + void *_data) +{ + struct sabre_irq_data *irq_data = _data; + unsigned long controller_regs = irq_data->controller_regs; + struct linux_prom_pci_registers *regs; + unsigned long imap, iclr; + unsigned long imap_off, iclr_off; + int inofixup = 0; + int virt_irq; + + ino &= 0x3f; + if (ino < SABRE_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = sabre_pcislot_imap_offset(ino); + } else { + /* onboard device */ + if (ino > SABRE_ONBOARD_IRQ_LAST) { + prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = sabre_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + imap = controller_regs + imap_off; + imap += 4; + + iclr_off = sabre_iclr_offset(ino); + iclr = controller_regs + iclr_off; + iclr += 4; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + virt_irq = build_irq(inofixup, iclr, imap); + + regs = of_get_property(dp, "reg", NULL); + if (regs && + ((regs->phys_hi >> 16) & 0xff) != irq_data->pci_first_busno) { + irq_install_pre_handler(virt_irq, + sabre_wsync_handler, + (void *) (long) regs->phys_hi, + (void *) + controller_regs + + SABRE_WRSYNC); + } + + return virt_irq; +} + +static void sabre_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + struct sabre_irq_data *irq_data; + u32 *busrange; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = sabre_irq_build; + + irq_data = prom_early_alloc(sizeof(struct sabre_irq_data)); + + regs = of_get_property(dp, "reg", NULL); + irq_data->controller_regs = regs[0].phys_addr; + + busrange = of_get_property(dp, "bus-range", NULL); + irq_data->pci_first_busno = busrange[0]; + + dp->irq_trans->data = irq_data; +} + +/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the + * imap/iclr registers are per-PBM. + */ +#define SCHIZO_IMAP_BASE 0x1000UL +#define SCHIZO_ICLR_BASE 0x1400UL + +static unsigned long schizo_imap_offset(unsigned long ino) +{ + return SCHIZO_IMAP_BASE + (ino * 8UL); +} + +static unsigned long schizo_iclr_offset(unsigned long ino) +{ + return SCHIZO_ICLR_BASE + (ino * 8UL); +} + +static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs, + unsigned int ino) +{ + return pbm_regs + schizo_iclr_offset(ino) + 4; +} + +static unsigned long schizo_ino_to_imap(unsigned long pbm_regs, + unsigned int ino) +{ + return pbm_regs + schizo_imap_offset(ino) + 4; +} + +#define schizo_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define schizo_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory") + +static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) +{ + unsigned long sync_reg = (unsigned long) _arg2; + u64 mask = 1UL << (ino & IMAP_INO); + u64 val; + int limit; + + schizo_write(sync_reg, mask); + + limit = 100000; + val = 0; + while (--limit) { + val = schizo_read(sync_reg); + if (!(val & mask)) + break; + } + if (limit <= 0) { + printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n", + val, mask); + } + + if (_arg1) { + static unsigned char cacheline[64] + __attribute__ ((aligned (64))); + + __asm__ __volatile__("rd %%fprs, %0\n\t" + "or %0, %4, %1\n\t" + "wr %1, 0x0, %%fprs\n\t" + "stda %%f0, [%5] %6\n\t" + "wr %0, 0x0, %%fprs\n\t" + "membar #Sync" + : "=&r" (mask), "=&r" (val) + : "0" (mask), "1" (val), + "i" (FPRS_FEF), "r" (&cacheline[0]), + "i" (ASI_BLK_COMMIT_P)); + } +} + +struct schizo_irq_data { + unsigned long pbm_regs; + unsigned long sync_reg; + u32 portid; + int chip_version; +}; + +static unsigned int schizo_irq_build(struct device_node *dp, + unsigned int ino, + void *_data) +{ + struct schizo_irq_data *irq_data = _data; + unsigned long pbm_regs = irq_data->pbm_regs; + unsigned long imap, iclr; + int ign_fixup; + int virt_irq; + int is_tomatillo; + + ino &= 0x3f; + + /* Now build the IRQ bucket. */ + imap = schizo_ino_to_imap(pbm_regs, ino); + iclr = schizo_ino_to_iclr(pbm_regs, ino); + + /* On Schizo, no inofixup occurs. This is because each + * INO has it's own IMAP register. On Psycho and Sabre + * there is only one IMAP register for each PCI slot even + * though four different INOs can be generated by each + * PCI slot. + * + * But, for JBUS variants (essentially, Tomatillo), we have + * to fixup the lowest bit of the interrupt group number. + */ + ign_fixup = 0; + + is_tomatillo = (irq_data->sync_reg != 0UL); + + if (is_tomatillo) { + if (irq_data->portid & 1) + ign_fixup = (1 << 6); + } + + virt_irq = build_irq(ign_fixup, iclr, imap); + + if (is_tomatillo) { + irq_install_pre_handler(virt_irq, + tomatillo_wsync_handler, + ((irq_data->chip_version <= 4) ? + (void *) 1 : (void *) 0), + (void *) irq_data->sync_reg); + } + + return virt_irq; +} + +static void schizo_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + struct schizo_irq_data *irq_data; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = schizo_irq_build; + + irq_data = prom_early_alloc(sizeof(struct schizo_irq_data)); + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = irq_data; + + irq_data->pbm_regs = regs[0].phys_addr; + irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL; + irq_data->portid = of_getintprop_default(dp, "portid", 0); + irq_data->chip_version = of_getintprop_default(dp, "version#", 0); +} + +static unsigned int pci_sun4v_irq_build(struct device_node *dp, + unsigned int devino, + void *_data) +{ + u32 devhandle = (u32) (unsigned long) _data; + + return sun4v_build_irq(devhandle, devino); +} + +static void pci_sun4v_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = pci_sun4v_irq_build; + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = (void *) (unsigned long) + ((regs->phys_addr >> 32UL) & 0x0fffffff); +} +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_SBUS +/* INO number to IMAP register offset for SYSIO external IRQ's. + * This should conform to both Sunfire/Wildfire server and Fusion + * desktop designs. + */ +#define SYSIO_IMAP_SLOT0 0x2c04UL +#define SYSIO_IMAP_SLOT1 0x2c0cUL +#define SYSIO_IMAP_SLOT2 0x2c14UL +#define SYSIO_IMAP_SLOT3 0x2c1cUL +#define SYSIO_IMAP_SCSI 0x3004UL +#define SYSIO_IMAP_ETH 0x300cUL +#define SYSIO_IMAP_BPP 0x3014UL +#define SYSIO_IMAP_AUDIO 0x301cUL +#define SYSIO_IMAP_PFAIL 0x3024UL +#define SYSIO_IMAP_KMS 0x302cUL +#define SYSIO_IMAP_FLPY 0x3034UL +#define SYSIO_IMAP_SHW 0x303cUL +#define SYSIO_IMAP_KBD 0x3044UL +#define SYSIO_IMAP_MS 0x304cUL +#define SYSIO_IMAP_SER 0x3054UL +#define SYSIO_IMAP_TIM0 0x3064UL +#define SYSIO_IMAP_TIM1 0x306cUL +#define SYSIO_IMAP_UE 0x3074UL +#define SYSIO_IMAP_CE 0x307cUL +#define SYSIO_IMAP_SBERR 0x3084UL +#define SYSIO_IMAP_PMGMT 0x308cUL +#define SYSIO_IMAP_GFX 0x3094UL +#define SYSIO_IMAP_EUPA 0x309cUL + +#define bogon ((unsigned long) -1) +static unsigned long sysio_irq_offsets[] = { + /* SBUS Slot 0 --> 3, level 1 --> 7 */ + SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, + SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, + SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, + SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, + SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, + SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, + SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, + SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, + + /* Onboard devices (not relevant/used on SunFire). */ + SYSIO_IMAP_SCSI, + SYSIO_IMAP_ETH, + SYSIO_IMAP_BPP, + bogon, + SYSIO_IMAP_AUDIO, + SYSIO_IMAP_PFAIL, + bogon, + bogon, + SYSIO_IMAP_KMS, + SYSIO_IMAP_FLPY, + SYSIO_IMAP_SHW, + SYSIO_IMAP_KBD, + SYSIO_IMAP_MS, + SYSIO_IMAP_SER, + bogon, + bogon, + SYSIO_IMAP_TIM0, + SYSIO_IMAP_TIM1, + bogon, + bogon, + SYSIO_IMAP_UE, + SYSIO_IMAP_CE, + SYSIO_IMAP_SBERR, + SYSIO_IMAP_PMGMT, +}; + +#undef bogon + +#define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets) + +/* Convert Interrupt Mapping register pointer to associated + * Interrupt Clear register pointer, SYSIO specific version. + */ +#define SYSIO_ICLR_UNUSED0 0x3400UL +#define SYSIO_ICLR_SLOT0 0x340cUL +#define SYSIO_ICLR_SLOT1 0x344cUL +#define SYSIO_ICLR_SLOT2 0x348cUL +#define SYSIO_ICLR_SLOT3 0x34ccUL +static unsigned long sysio_imap_to_iclr(unsigned long imap) +{ + unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; + return imap + diff; +} + +static unsigned int sbus_of_build_irq(struct device_node *dp, + unsigned int ino, + void *_data) +{ + unsigned long reg_base = (unsigned long) _data; + struct linux_prom_registers *regs; + unsigned long imap, iclr; + int sbus_slot = 0; + int sbus_level = 0; + + ino &= 0x3f; + + regs = of_get_property(dp, "reg", NULL); + if (regs) + sbus_slot = regs->which_io; + + if (ino < 0x20) + ino += (sbus_slot * 8); + + imap = sysio_irq_offsets[ino]; + if (imap == ((unsigned long)-1)) { + prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n", + ino); + prom_halt(); + } + imap += reg_base; + + /* SYSIO inconsistency. For external SLOTS, we have to select + * the right ICLR register based upon the lower SBUS irq level + * bits. + */ + if (ino >= 0x20) { + iclr = sysio_imap_to_iclr(imap); + } else { + sbus_level = ino & 0x7; + + switch(sbus_slot) { + case 0: + iclr = reg_base + SYSIO_ICLR_SLOT0; + break; + case 1: + iclr = reg_base + SYSIO_ICLR_SLOT1; + break; + case 2: + iclr = reg_base + SYSIO_ICLR_SLOT2; + break; + default: + case 3: + iclr = reg_base + SYSIO_ICLR_SLOT3; + break; + }; + + iclr += ((unsigned long)sbus_level - 1UL) * 8UL; + } + return build_irq(sbus_level, iclr, imap); +} + +static void sbus_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = sbus_of_build_irq; + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr; +} +#endif /* CONFIG_SBUS */ + + +static unsigned int central_build_irq(struct device_node *dp, + unsigned int ino, + void *_data) +{ + struct device_node *central_dp = _data; + struct of_device *central_op = of_find_device_by_node(central_dp); + struct resource *res; + unsigned long imap, iclr; + u32 tmp; + + if (!strcmp(dp->name, "eeprom")) { + res = ¢ral_op->resource[5]; + } else if (!strcmp(dp->name, "zs")) { + res = ¢ral_op->resource[4]; + } else if (!strcmp(dp->name, "clock-board")) { + res = ¢ral_op->resource[3]; + } else { + return ino; + } + + imap = res->start + 0x00UL; + iclr = res->start + 0x10UL; + + /* Set the INO state to idle, and disable. */ + upa_writel(0, iclr); + upa_readl(iclr); + + tmp = upa_readl(imap); + tmp &= ~0x80000000; + upa_writel(tmp, imap); + + return build_irq(0, iclr, imap); +} + +static void central_irq_trans_init(struct device_node *dp) +{ + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = central_build_irq; + + dp->irq_trans->data = dp; +} + +struct irq_trans { + const char *name; + void (*init)(struct device_node *); +}; + +#ifdef CONFIG_PCI +static struct irq_trans pci_irq_trans_table[] = { + { "SUNW,sabre", sabre_irq_trans_init }, + { "pci108e,a000", sabre_irq_trans_init }, + { "pci108e,a001", sabre_irq_trans_init }, + { "SUNW,psycho", psycho_irq_trans_init }, + { "pci108e,8000", psycho_irq_trans_init }, + { "SUNW,schizo", schizo_irq_trans_init }, + { "pci108e,8001", schizo_irq_trans_init }, + { "SUNW,schizo+", schizo_irq_trans_init }, + { "pci108e,8002", schizo_irq_trans_init }, + { "SUNW,tomatillo", schizo_irq_trans_init }, + { "pci108e,a801", schizo_irq_trans_init }, + { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init }, +}; +#endif + +static void irq_trans_init(struct device_node *dp) +{ + const char *model; + int i; + + model = of_get_property(dp, "model", NULL); + if (!model) + model = of_get_property(dp, "compatible", NULL); + if (!model) + return; + +#ifdef CONFIG_PCI + for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) { + struct irq_trans *t = &pci_irq_trans_table[i]; + + if (!strcmp(model, t->name)) + return t->init(dp); + } +#endif +#ifdef CONFIG_SBUS + if (!strcmp(dp->name, "sbus") || + !strcmp(dp->name, "sbi")) + return sbus_irq_trans_init(dp); +#endif + if (!strcmp(dp->name, "central")) + return central_irq_trans_init(dp->child); +} + static int is_root_node(const struct device_node *dp) { if (!dp) @@ -706,10 +1459,10 @@ static struct device_node * __init create_node(phandle node) dp->type = get_one_property(node, "device_type"); dp->node = node; - /* Build interrupts later... */ - dp->properties = build_prop_list(node); + irq_trans_init(dp); + return dp; } diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h index 37c5856fae1..a62c7b997d6 100644 --- a/include/asm-sparc64/of_device.h +++ b/include/asm-sparc64/of_device.h @@ -22,7 +22,8 @@ struct of_device struct device_node *node; struct device dev; struct resource resource[PROMREG_MAX]; - unsigned int irq; + unsigned int irqs[PROMINTR_MAX]; + int num_irqs; void *sysdata; @@ -35,6 +36,8 @@ struct of_device extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); extern void of_iounmap(void __iomem *base, unsigned long size); +extern struct of_device *of_find_device_by_node(struct device_node *); + extern const struct of_device_id *of_match_device( const struct of_device_id *matches, const struct of_device *dev); diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 83b3c26cd06..dcfa7629358 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -16,6 +16,7 @@ #include #include #include +#include #include /* The abstraction used here is that there are PCI controllers, @@ -209,7 +210,6 @@ struct pci_controller_info { /* Operations which are controller specific. */ void (*scan_bus)(struct pci_controller_info *); - unsigned int (*irq_build)(struct pci_pbm_info *, struct pci_dev *, unsigned int); void (*base_address_update)(struct pci_dev *, int); void (*resource_adjust)(struct pci_dev *, struct resource *, struct resource *); @@ -226,6 +226,7 @@ struct pci_controller_info { struct pcidev_cookie { struct pci_pbm_info *pbm; struct device_node *prom_node; + struct of_device *op; struct linux_prom_pci_registers prom_regs[PROMREG_MAX]; int num_prom_regs; struct linux_prom_pci_registers prom_assignments[PROMREG_MAX]; diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index aad16c2aa5e..99671ed6625 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -34,6 +34,7 @@ struct property { unsigned int unique_id; }; +struct of_irq_controller; struct device_node { char *name; char *type; @@ -53,6 +54,13 @@ struct device_node { unsigned long _flags; void *data; unsigned int unique_id; + + struct of_irq_controller *irq_trans; +}; + +struct of_irq_controller { + unsigned int (*irq_build)(struct device_node *, unsigned int, void *); + void *data; }; /* flag descriptions */ -- cgit v1.2.3-70-g09d2 From 877ce7c1b3afd69a9b1caeb1b9964c992641f52a Mon Sep 17 00:00:00 2001 From: Catherine Zhang Date: Thu, 29 Jun 2006 12:27:47 -0700 Subject: [AF_UNIX]: Datagram getpeersec This patch implements an API whereby an application can determine the label of its peer's Unix datagram sockets via the auxiliary data mechanism of recvmsg. Patch purpose: This patch enables a security-aware application to retrieve the security context of the peer of a Unix datagram socket. The application can then use this security context to determine the security context for processing on behalf of the peer who sent the packet. Patch design and implementation: The design and implementation is very similar to the UDP case for INET sockets. Basically we build upon the existing Unix domain socket API for retrieving user credentials. Linux offers the API for obtaining user credentials via ancillary messages (i.e., out of band/control messages that are bundled together with a normal message). To retrieve the security context, the application first indicates to the kernel such desire by setting the SO_PASSSEC option via getsockopt. Then the application retrieves the security context using the auxiliary data mechanism. An example server application for Unix datagram socket should look like this: toggle = 1; toggle_len = sizeof(toggle); setsockopt(sockfd, SOL_SOCKET, SO_PASSSEC, &toggle, &toggle_len); recvmsg(sockfd, &msg_hdr, 0); if (msg_hdr.msg_controllen > sizeof(struct cmsghdr)) { cmsg_hdr = CMSG_FIRSTHDR(&msg_hdr); if (cmsg_hdr->cmsg_len <= CMSG_LEN(sizeof(scontext)) && cmsg_hdr->cmsg_level == SOL_SOCKET && cmsg_hdr->cmsg_type == SCM_SECURITY) { memcpy(&scontext, CMSG_DATA(cmsg_hdr), sizeof(scontext)); } } sock_setsockopt is enhanced with a new socket option SOCK_PASSSEC to allow a server socket to receive security context of the peer. Testing: We have tested the patch by setting up Unix datagram client and server applications. We verified that the server can retrieve the security context using the auxiliary data mechanism of recvmsg. Signed-off-by: Catherine Zhang Acked-by: Acked-by: James Morris Signed-off-by: David S. Miller --- include/asm-alpha/socket.h | 1 + include/asm-arm/socket.h | 1 + include/asm-arm26/socket.h | 1 + include/asm-cris/socket.h | 1 + include/asm-frv/socket.h | 1 + include/asm-h8300/socket.h | 1 + include/asm-i386/socket.h | 1 + include/asm-ia64/socket.h | 1 + include/asm-m32r/socket.h | 1 + include/asm-m68k/socket.h | 1 + include/asm-mips/socket.h | 1 + include/asm-parisc/socket.h | 1 + include/asm-powerpc/socket.h | 1 + include/asm-s390/socket.h | 1 + include/asm-sh/socket.h | 1 + include/asm-sparc/socket.h | 1 + include/asm-sparc64/socket.h | 1 + include/asm-v850/socket.h | 1 + include/asm-x86_64/socket.h | 1 + include/asm-xtensa/socket.h | 1 + include/linux/net.h | 1 + include/net/af_unix.h | 6 ++++++ include/net/scm.h | 17 +++++++++++++++++ net/core/sock.c | 11 +++++++++++ net/unix/af_unix.c | 27 +++++++++++++++++++++++++++ security/selinux/hooks.c | 11 ++++++++--- 26 files changed, 90 insertions(+), 3 deletions(-) (limited to 'include/asm-sparc64') diff --git a/include/asm-alpha/socket.h b/include/asm-alpha/socket.h index b5193229132..d22ab97ea72 100644 --- a/include/asm-alpha/socket.h +++ b/include/asm-alpha/socket.h @@ -51,6 +51,7 @@ #define SCM_TIMESTAMP SO_TIMESTAMP #define SO_PEERSEC 30 +#define SO_PASSSEC 34 /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 19 diff --git a/include/asm-arm/socket.h b/include/asm-arm/socket.h index 3c51da6438c..19f7df702b0 100644 --- a/include/asm-arm/socket.h +++ b/include/asm-arm/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-arm26/socket.h b/include/asm-arm26/socket.h index 3c51da6438c..19f7df702b0 100644 --- a/include/asm-arm26/socket.h +++ b/include/asm-arm26/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-cris/socket.h b/include/asm-cris/socket.h index 8b1da3e58c5..01cfdf1d6d3 100644 --- a/include/asm-cris/socket.h +++ b/include/asm-cris/socket.h @@ -50,6 +50,7 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-frv/socket.h b/include/asm-frv/socket.h index 7177f8b9817..31db18fc871 100644 --- a/include/asm-frv/socket.h +++ b/include/asm-frv/socket.h @@ -48,6 +48,7 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-h8300/socket.h b/include/asm-h8300/socket.h index d98cf85bafc..ebc830fee0d 100644 --- a/include/asm-h8300/socket.h +++ b/include/asm-h8300/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-i386/socket.h b/include/asm-i386/socket.h index 802ae76195b..5755d57c4e9 100644 --- a/include/asm-i386/socket.h +++ b/include/asm-i386/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-ia64/socket.h b/include/asm-ia64/socket.h index a255006fb7b..d638ef3d50c 100644 --- a/include/asm-ia64/socket.h +++ b/include/asm-ia64/socket.h @@ -57,5 +57,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_IA64_SOCKET_H */ diff --git a/include/asm-m32r/socket.h b/include/asm-m32r/socket.h index 8b6680f223c..acdf748fcdc 100644 --- a/include/asm-m32r/socket.h +++ b/include/asm-m32r/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_M32R_SOCKET_H */ diff --git a/include/asm-m68k/socket.h b/include/asm-m68k/socket.h index f578ca4b776..a5966ec005a 100644 --- a/include/asm-m68k/socket.h +++ b/include/asm-m68k/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-mips/socket.h b/include/asm-mips/socket.h index 0bb31e5aaca..36ebe4e186a 100644 --- a/include/asm-mips/socket.h +++ b/include/asm-mips/socket.h @@ -69,6 +69,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_PEERSEC 30 #define SO_SNDBUFFORCE 31 #define SO_RCVBUFFORCE 33 +#define SO_PASSSEC 34 #ifdef __KERNEL__ diff --git a/include/asm-parisc/socket.h b/include/asm-parisc/socket.h index 1bf54dc53c1..ce2eae1708b 100644 --- a/include/asm-parisc/socket.h +++ b/include/asm-parisc/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 0x401c #define SO_PEERSEC 0x401d +#define SO_PASSSEC 0x401e #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-powerpc/socket.h b/include/asm-powerpc/socket.h index e4b8177d4ac..c8b1da50e72 100644 --- a/include/asm-powerpc/socket.h +++ b/include/asm-powerpc/socket.h @@ -55,5 +55,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/include/asm-s390/socket.h b/include/asm-s390/socket.h index 15a5298c874..1778a49a74c 100644 --- a/include/asm-s390/socket.h +++ b/include/asm-s390/socket.h @@ -56,5 +56,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-sh/socket.h b/include/asm-sh/socket.h index 553904ff933..ca70362eb56 100644 --- a/include/asm-sh/socket.h +++ b/include/asm-sh/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* __ASM_SH_SOCKET_H */ diff --git a/include/asm-sparc/socket.h b/include/asm-sparc/socket.h index 4e0ce3a35ea..f6c4e5baf3f 100644 --- a/include/asm-sparc/socket.h +++ b/include/asm-sparc/socket.h @@ -48,6 +48,7 @@ #define SCM_TIMESTAMP SO_TIMESTAMP #define SO_PEERSEC 0x001e +#define SO_PASSSEC 0x001f /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 diff --git a/include/asm-sparc64/socket.h b/include/asm-sparc64/socket.h index 59987dad335..754d46a50af 100644 --- a/include/asm-sparc64/socket.h +++ b/include/asm-sparc64/socket.h @@ -48,6 +48,7 @@ #define SCM_TIMESTAMP SO_TIMESTAMP #define SO_PEERSEC 0x001e +#define SO_PASSSEC 0x001f /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 diff --git a/include/asm-v850/socket.h b/include/asm-v850/socket.h index 0240d366a0a..0dfe55ac2ef 100644 --- a/include/asm-v850/socket.h +++ b/include/asm-v850/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* __V850_SOCKET_H__ */ diff --git a/include/asm-x86_64/socket.h b/include/asm-x86_64/socket.h index f2cdbeae5d5..b4670260793 100644 --- a/include/asm-x86_64/socket.h +++ b/include/asm-x86_64/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-xtensa/socket.h b/include/asm-xtensa/socket.h index 00f83f3a6d7..971d231be60 100644 --- a/include/asm-xtensa/socket.h +++ b/include/asm-xtensa/socket.h @@ -59,5 +59,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _XTENSA_SOCKET_H */ diff --git a/include/linux/net.h b/include/linux/net.h index 385e68f5bd9..b20c53c7441 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -61,6 +61,7 @@ typedef enum { #define SOCK_ASYNC_WAITDATA 1 #define SOCK_NOSPACE 2 #define SOCK_PASSCRED 3 +#define SOCK_PASSSEC 4 #ifndef ARCH_HAS_SOCKET_TYPES /** diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 795f81f9ec7..5ba72d95280 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -53,10 +53,16 @@ struct unix_address { struct unix_skb_parms { struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ +#ifdef CONFIG_SECURITY_NETWORK + char *secdata; /* Security context */ + u32 seclen; /* Security length */ +#endif }; #define UNIXCB(skb) (*(struct unix_skb_parms*)&((skb)->cb)) #define UNIXCREDS(skb) (&UNIXCB((skb)).creds) +#define UNIXSECDATA(skb) (&UNIXCB((skb)).secdata) +#define UNIXSECLEN(skb) (&UNIXCB((skb)).seclen) #define unix_state_rlock(s) spin_lock(&unix_sk(s)->lock) #define unix_state_runlock(s) spin_unlock(&unix_sk(s)->lock) diff --git a/include/net/scm.h b/include/net/scm.h index 540619cb716..02daa097cdc 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -19,6 +19,10 @@ struct scm_cookie { struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ +#ifdef CONFIG_SECURITY_NETWORK + char *secdata; /* Security context */ + u32 seclen; /* Security length */ +#endif unsigned long seq; /* Connection seqno */ }; @@ -48,6 +52,17 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, return __scm_send(sock, msg, scm); } +#ifdef CONFIG_SECURITY_NETWORK +static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) +{ + if (test_bit(SOCK_PASSSEC, &sock->flags) && scm->secdata != NULL) + put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, scm->seclen, scm->secdata); +} +#else +static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) +{ } +#endif /* CONFIG_SECURITY_NETWORK */ + static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm, int flags) { @@ -62,6 +77,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, if (test_bit(SOCK_PASSCRED, &sock->flags)) put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); + scm_passec(sock, msg, scm); + if (!scm->fp) return; diff --git a/net/core/sock.c b/net/core/sock.c index 5d820c37665..204a8dec65c 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -565,6 +565,13 @@ set_rcvbuf: ret = -ENONET; break; + case SO_PASSSEC: + if (valbool) + set_bit(SOCK_PASSSEC, &sock->flags); + else + clear_bit(SOCK_PASSSEC, &sock->flags); + break; + /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */ default: @@ -723,6 +730,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = sk->sk_state == TCP_LISTEN; break; + case SO_PASSSEC: + v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0; + break; + case SO_PEERSEC: return security_socket_getpeersec_stream(sock, optval, optlen, len); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index d901465ce01..fd11d4048b5 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -128,6 +128,30 @@ static atomic_t unix_nr_socks = ATOMIC_INIT(0); #define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash != UNIX_HASH_SIZE) +#ifdef CONFIG_SECURITY_NETWORK +static void unix_get_peersec_dgram(struct sk_buff *skb) +{ + int err; + + err = security_socket_getpeersec_dgram(skb, UNIXSECDATA(skb), + UNIXSECLEN(skb)); + if (err) + *(UNIXSECDATA(skb)) = NULL; +} + +static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) +{ + scm->secdata = *UNIXSECDATA(skb); + scm->seclen = *UNIXSECLEN(skb); +} +#else +static void unix_get_peersec_dgram(struct sk_buff *skb) +{ } + +static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) +{ } +#endif /* CONFIG_SECURITY_NETWORK */ + /* * SMP locking strategy: * hash table is protected with spinlock unix_table_lock @@ -1291,6 +1315,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, if (siocb->scm->fp) unix_attach_fds(siocb->scm, skb); + unix_get_peersec_dgram(skb); + skb->h.raw = skb->data; err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); if (err) @@ -1570,6 +1596,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, memset(&tmp_scm, 0, sizeof(tmp_scm)); } siocb->scm->creds = *UNIXCREDS(skb); + unix_set_secdata(siocb->scm, skb); if (!(flags & MSG_PEEK)) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b6c378dd4f1..b85afcf3852 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -69,6 +69,7 @@ #include #include #include +#include #include "avc.h" #include "objsec.h" @@ -3420,7 +3421,13 @@ out: static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen) { int err = 0; - u32 peer_sid = selinux_socket_getpeer_dgram(skb); + u32 peer_sid; + + if (skb->sk->sk_family == PF_UNIX) + selinux_get_inode_sid(SOCK_INODE(skb->sk->sk_socket), + &peer_sid); + else + peer_sid = selinux_socket_getpeer_dgram(skb); if (peer_sid == SECSID_NULL) return -EINVAL; @@ -3432,8 +3439,6 @@ static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, return 0; } - - static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) { return sk_alloc_security(sk, family, priority); -- cgit v1.2.3-70-g09d2 From 6e990b50ed0b45d506ff6809034508d3e210497d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 30 Jun 2006 00:07:40 -0700 Subject: [SPARC64]: Kill sun4v virtual device layer. Replace with a simple IRQ translater in the PROM device tree builder. Signed-off-by: David S. Miller --- arch/sparc64/kernel/devices.c | 97 ------------------------------------------- arch/sparc64/kernel/prom.c | 23 ++++++++++ include/asm-sparc64/vdev.h | 17 -------- 3 files changed, 23 insertions(+), 114 deletions(-) delete mode 100644 include/asm-sparc64/vdev.h (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 389301c95cb..26adb64ddb3 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -21,8 +21,6 @@ #include #include #include -#include -#include /* Used to synchronize acceses to NatSemi SUPER I/O chip configure * operations in asm/ns87303.h @@ -32,100 +30,6 @@ DEFINE_SPINLOCK(ns87303_lock); extern void cpu_probe(void); extern void central_probe(void); -u32 sun4v_vdev_devhandle; -struct device_node *sun4v_vdev_root; - -struct vdev_intmap { - unsigned int phys; - unsigned int irq; - unsigned int cnode; - unsigned int cinterrupt; -}; - -struct vdev_intmask { - unsigned int phys; - unsigned int interrupt; - unsigned int __unused; -}; - -static struct vdev_intmap *vdev_intmap; -static int vdev_num_intmap; -static struct vdev_intmask *vdev_intmask; - -static void __init sun4v_virtual_device_probe(void) -{ - struct linux_prom64_registers *regs; - struct property *prop; - struct device_node *dp; - int sz; - - if (tlb_type != hypervisor) - return; - - dp = of_find_node_by_name(NULL, "virtual-devices"); - if (!dp) { - prom_printf("SUN4V: Fatal error, no virtual-devices node.\n"); - prom_halt(); - } - - sun4v_vdev_root = dp; - - prop = of_find_property(dp, "reg", NULL); - regs = prop->value; - sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff; - - prop = of_find_property(dp, "interrupt-map", &sz); - vdev_intmap = prop->value; - vdev_num_intmap = sz / sizeof(struct vdev_intmap); - - prop = of_find_property(dp, "interrupt-map-mask", NULL); - vdev_intmask = prop->value; - - printk("%s: Virtual Device Bus devhandle[%x]\n", - dp->full_name, sun4v_vdev_devhandle); -} - -unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node) -{ - struct property *prop; - unsigned int irq, reg; - int i; - - prop = of_find_property(dev_node, "interrupts", NULL); - if (!prop) { - printk("VDEV: Cannot get \"interrupts\" " - "property for OBP node %s\n", - dev_node->full_name); - return 0; - } - irq = *(unsigned int *) prop->value; - - prop = of_find_property(dev_node, "reg", NULL); - if (!prop) { - printk("VDEV: Cannot get \"reg\" " - "property for OBP node %s\n", - dev_node->full_name); - return 0; - } - reg = *(unsigned int *) prop->value; - - for (i = 0; i < vdev_num_intmap; i++) { - if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) && - vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) { - irq = vdev_intmap[i].cinterrupt; - break; - } - } - - if (i == vdev_num_intmap) { - printk("VDEV: No matching interrupt map entry " - "for OBP node %s\n", dev_node->full_name); - return 0; - } - - return sun4v_build_irq(sun4v_vdev_devhandle, irq); -} - static const char *cpu_mid_prop(void) { if (tlb_type == spitfire) @@ -290,7 +194,6 @@ void __init device_scan(void) } #endif - sun4v_virtual_device_probe(); central_probe(); cpu_probe(); diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 8a70c52c044..fa484d4f241 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -1008,6 +1008,27 @@ static struct irq_trans pci_irq_trans_table[] = { }; #endif +static unsigned int sun4v_vdev_irq_build(struct device_node *dp, + unsigned int devino, + void *_data) +{ + u32 devhandle = (u32) (unsigned long) _data; + + return sun4v_build_irq(devhandle, devino); +} + +static void sun4v_vdev_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = sun4v_vdev_irq_build; + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = (void *) (unsigned long) + ((regs->phys_addr >> 32UL) & 0x0fffffff); +} + static void irq_trans_init(struct device_node *dp) { const char *model; @@ -1034,6 +1055,8 @@ static void irq_trans_init(struct device_node *dp) #endif if (!strcmp(dp->name, "central")) return central_irq_trans_init(dp->child); + if (!strcmp(dp->name, "virtual-devices")) + return sun4v_vdev_irq_trans_init(dp); } static int is_root_node(const struct device_node *dp) diff --git a/include/asm-sparc64/vdev.h b/include/asm-sparc64/vdev.h deleted file mode 100644 index 25637c57675..00000000000 --- a/include/asm-sparc64/vdev.h +++ /dev/null @@ -1,17 +0,0 @@ -/* vdev.h: SUN4V virtual device interfaces and defines. - * - * Copyright (C) 2006 David S. Miller - */ - -#ifndef _SPARC64_VDEV_H -#define _SPARC64_VDEV_H - -#include -#include - -extern u32 sun4v_vdev_devhandle; -extern struct device_node *sun4v_vdev_root; - -extern unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node); - -#endif /* !(_SPARC64_VDEV_H) */ -- cgit v1.2.3-70-g09d2 From d356d7f4f2761b1391ec41404eefe280e4f11f76 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 1 Jul 2006 19:29:26 -0700 Subject: [PATCH] irq-flags: SPARC64: Use the new IRQF_ constants Use the new IRQF_ constants and remove the SA_INTERRUPT define Signed-off-by: Thomas Gleixner Cc: Ingo Molnar Cc: "David S. Miller" Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/sparc64/kernel/ebus.c | 2 +- arch/sparc64/kernel/pci_psycho.c | 8 ++++---- arch/sparc64/kernel/pci_sabre.c | 6 +++--- arch/sparc64/kernel/pci_schizo.c | 20 ++++++++++---------- arch/sparc64/kernel/sbus.c | 6 +++--- include/asm-sparc64/floppy.h | 2 +- include/asm-sparc64/signal.h | 3 --- 7 files changed, 22 insertions(+), 25 deletions(-) (limited to 'include/asm-sparc64') diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index a1023bb1a21..8a9b470e1b6 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -140,7 +140,7 @@ int ebus_dma_irq_enable(struct ebus_dma_info *p, int on) if (on) { if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) { - if (request_irq(p->irq, ebus_dma_irq, SA_SHIRQ, p->name, p)) + if (request_irq(p->irq, ebus_dma_irq, IRQF_SHARED, p->name, p)) return -EBUSY; } diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index bf7b32b3670..197a7ffd57e 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -863,11 +863,11 @@ static void psycho_register_error_handlers(struct pci_controller_info *p) if (op->num_irqs < 6) return; - request_irq(op->irqs[1], psycho_ue_intr, SA_SHIRQ, "PSYCHO UE", p); - request_irq(op->irqs[2], psycho_ce_intr, SA_SHIRQ, "PSYCHO CE", p); - request_irq(op->irqs[5], psycho_pcierr_intr, SA_SHIRQ, + request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO UE", p); + request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO CE", p); + request_irq(op->irqs[5], psycho_pcierr_intr, IRQF_SHARED, "PSYCHO PCIERR-A", &p->pbm_A); - request_irq(op->irqs[0], psycho_pcierr_intr, SA_SHIRQ, + request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED, "PSYCHO PCIERR-B", &p->pbm_B); /* Enable UE and CE interrupts for controller. */ diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 5e087b0fb4c..45891850b90 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -854,14 +854,14 @@ static void sabre_register_error_handlers(struct pci_controller_info *p) SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE)); - request_irq(op->irqs[1], sabre_ue_intr, SA_SHIRQ, "SABRE UE", p); + request_irq(op->irqs[1], sabre_ue_intr, IRQF_SHARED, "SABRE UE", p); sabre_write(base + SABRE_CE_AFSR, (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR)); - request_irq(op->irqs[2], sabre_ce_intr, SA_SHIRQ, "SABRE CE", p); - request_irq(op->irqs[0], sabre_pcierr_intr, SA_SHIRQ, + request_irq(op->irqs[2], sabre_ce_intr, IRQF_SHARED, "SABRE CE", p); + request_irq(op->irqs[0], sabre_pcierr_intr, IRQF_SHARED, "SABRE PCIERR", p); tmp = sabre_read(base + SABRE_PCICTRL); diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 5c6e2a9b91f..75ade83ecc6 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -998,32 +998,32 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm = pbm_for_ino(p, SCHIZO_UE_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[1], schizo_ue_intr, SA_SHIRQ, + request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED, "TOMATILLO_UE", p); pbm = pbm_for_ino(p, SCHIZO_CE_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[2], schizo_ce_intr, SA_SHIRQ, + request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED, "TOMATILLO CE", p); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED, "TOMATILLO PCIERR-A", pbm); pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED, "TOMATILLO PCIERR-B", pbm); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[3], schizo_safarierr_intr, SA_SHIRQ, + request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED, "TOMATILLO SERR", p); /* Enable UE and CE interrupts for controller. */ @@ -1106,32 +1106,32 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm = pbm_for_ino(p, SCHIZO_UE_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[1], schizo_ue_intr, SA_SHIRQ, + request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED, "SCHIZO_UE", p); pbm = pbm_for_ino(p, SCHIZO_CE_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[2], schizo_ce_intr, SA_SHIRQ, + request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED, "SCHIZO CE", p); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED, "SCHIZO PCIERR-A", pbm); pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED, "SCHIZO PCIERR-B", pbm); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); op = of_find_device_by_node(pbm->prom_node); if (op) - request_irq(op->irqs[3], schizo_safarierr_intr, SA_SHIRQ, + request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED, "SCHIZO SERR", p); /* Enable UE and CE interrupts for controller. */ diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index ef68aa4fec6..c49a5779574 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -1065,7 +1065,7 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus) irq = sbus_build_irq(sbus, SYSIO_UE_INO); if (request_irq(irq, sysio_ue_handler, - SA_SHIRQ, "SYSIO UE", sbus) < 0) { + IRQF_SHARED, "SYSIO UE", sbus) < 0) { prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n", sbus->portid); prom_halt(); @@ -1073,7 +1073,7 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus) irq = sbus_build_irq(sbus, SYSIO_CE_INO); if (request_irq(irq, sysio_ce_handler, - SA_SHIRQ, "SYSIO CE", sbus) < 0) { + IRQF_SHARED, "SYSIO CE", sbus) < 0) { prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n", sbus->portid); prom_halt(); @@ -1081,7 +1081,7 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus) irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO); if (request_irq(irq, sysio_sbus_error_handler, - SA_SHIRQ, "SYSIO SBUS Error", sbus) < 0) { + IRQF_SHARED, "SYSIO SBUS Error", sbus) < 0) { prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n", sbus->portid); prom_halt(); diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index b591d0e8d8f..abf15003801 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -267,7 +267,7 @@ static int sun_fd_request_irq(void) once = 1; error = request_irq(FLOPPY_IRQ, sparc_floppy_irq, - SA_INTERRUPT, "floppy", NULL); + IRQF_DISABLED, "floppy", NULL); return ((error == 0) ? 0 : -1); } diff --git a/include/asm-sparc64/signal.h b/include/asm-sparc64/signal.h index fdc42a14d4e..9968871103b 100644 --- a/include/asm-sparc64/signal.h +++ b/include/asm-sparc64/signal.h @@ -133,16 +133,13 @@ struct sigstack { * usage of signal stacks by using the (now obsolete) sa_restorer field in * the sigaction structure as a stack pointer. This is now possible due to * the changes in signal handling. LBT 010493. - * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the * SA_RESTART flag to get restarting signals (which were the default long ago) - * SA_SHIRQ flag is for shared interrupt support on PCI and EISA. */ #define SA_NOCLDSTOP _SV_IGNCHILD #define SA_STACK _SV_SSTACK #define SA_ONSTACK _SV_SSTACK #define SA_RESTART _SV_INTR #define SA_ONESHOT _SV_RESET -#define SA_INTERRUPT 0x10u #define SA_NOMASK 0x20u #define SA_NOCLDWAIT 0x100u #define SA_SIGINFO 0x200u -- cgit v1.2.3-70-g09d2