From 0016a4cf5582415849fafbf9f019dd9530824789 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 15 Jun 2010 14:48:58 +1000 Subject: powerpc: Emulate most Book I instructions in emulate_step() This extends the emulate_step() function to handle a large proportion of the Book I instructions implemented on current 64-bit server processors. The aim is to handle all the load and store instructions used in the kernel, plus all of the instructions that appear between l[wd]arx and st[wd]cx., so this handles the Altivec/VMX lvx and stvx and the VSX lxv2dx and stxv2dx instructions (implemented in POWER7). The new code can emulate user mode instructions, and checks the effective address for a load or store if the saved state is for user mode. It doesn't handle little-endian mode at present. For floating-point, Altivec/VMX and VSX instructions, it checks that the saved MSR has the enable bit for the relevant facility set, and if so, assumes that the FP/VMX/VSX registers contain valid state, and does loads or stores directly to/from the FP/VMX/VSX registers, using assembly helpers in ldstfp.S. Instructions supported now include: * Loads and stores, including some but not all VMX and VSX instructions, and lmw/stmw * Atomic loads and stores (l[dw]arx, st[dw]cx.) * Arithmetic instructions (add, subtract, multiply, divide, etc.) * Compare instructions * Rotate and mask instructions * Shift instructions * Logical instructions (and, or, xor, etc.) * Condition register logical instructions * mtcrf, cntlz[wd], exts[bhw] * isync, sync, lwsync, ptesync, eieio * Cache operations (dcbf, dcbst, dcbt, dcbtst) The overflow-checking arithmetic instructions are not included, but they appear not to be ever used in C code. This uses decimal values for the minor opcodes in the switch statements because that is what appears in the Power ISA specification, thus it is easier to check that they are correct if they are in decimal. If this is used to single-step an instruction where a data breakpoint interrupt occurred, then there is the possibility that the instruction is a lwarx or ldarx. In that case we have to be careful not to lose the reservation until we get to the matching st[wd]cx., or we'll never make forward progress. One alternative is to try to arrange that we can return from interrupts and handle data breakpoint interrupts without losing the reservation, which means not using any spinlocks, mutexes, or atomic ops (including bitops). That seems rather fragile. The other alternative is to emulate the larx/stcx and all the instructions in between. This is why this commit adds support for a wide range of integer instructions. Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/asm-compat.h | 2 + arch/powerpc/include/asm/ppc-opcode.h | 7 + arch/powerpc/lib/Makefile | 4 +- arch/powerpc/lib/ldstfp.S | 375 ++++++++ arch/powerpc/lib/sstep.c | 1514 ++++++++++++++++++++++++++++++++- 5 files changed, 1855 insertions(+), 47 deletions(-) create mode 100644 arch/powerpc/lib/ldstfp.S (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h index 2048a6aeea91..decad950f11a 100644 --- a/arch/powerpc/include/asm/asm-compat.h +++ b/arch/powerpc/include/asm/asm-compat.h @@ -30,6 +30,7 @@ #define PPC_STLCX stringify_in_c(stdcx.) #define PPC_CNTLZL stringify_in_c(cntlzd) #define PPC_LR_STKOFF 16 +#define PPC_MIN_STKFRM 112 /* Move to CR, single-entry optimized version. Only available * on POWER4 and later. @@ -55,6 +56,7 @@ #define PPC_CNTLZL stringify_in_c(cntlzw) #define PPC_MTOCRF stringify_in_c(mtcrf) #define PPC_LR_STKOFF 4 +#define PPC_MIN_STKFRM 16 #endif diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index d553bbeb726c..43adc8b819ed 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -52,13 +52,17 @@ #define PPC_INST_WAIT 0x7c00007c #define PPC_INST_TLBIVAX 0x7c000624 #define PPC_INST_TLBSRX_DOT 0x7c0006a5 +#define PPC_INST_XXLOR 0xf0000510 /* macros to insert fields into opcodes */ #define __PPC_RA(a) (((a) & 0x1f) << 16) #define __PPC_RB(b) (((b) & 0x1f) << 11) #define __PPC_RS(s) (((s) & 0x1f) << 21) #define __PPC_RT(s) __PPC_RS(s) +#define __PPC_XA(a) ((((a) & 0x1f) << 16) | (((a) & 0x20) >> 3)) +#define __PPC_XB(b) ((((b) & 0x1f) << 11) | (((b) & 0x20) >> 4)) #define __PPC_XS(s) ((((s) & 0x1f) << 21) | (((s) & 0x20) >> 5)) +#define __PPC_XT(s) __PPC_XS(s) #define __PPC_T_TLB(t) (((t) & 0x3) << 21) #define __PPC_WC(w) (((w) & 0x3) << 21) /* @@ -106,9 +110,12 @@ * the 128 bit load store instructions based on that. */ #define VSX_XX1(s, a, b) (__PPC_XS(s) | __PPC_RA(a) | __PPC_RB(b)) +#define VSX_XX3(t, a, b) (__PPC_XT(t) | __PPC_XA(a) | __PPC_XB(b)) #define STXVD2X(s, a, b) stringify_in_c(.long PPC_INST_STXVD2X | \ VSX_XX1((s), (a), (b))) #define LXVD2X(s, a, b) stringify_in_c(.long PPC_INST_LXVD2X | \ VSX_XX1((s), (a), (b))) +#define XXLOR(t, a, b) stringify_in_c(.long PPC_INST_XXLOR | \ + VSX_XX3((t), (a), (b))) #endif /* _ASM_POWERPC_PPC_OPCODE_H */ diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 3040dac18a37..7581dbffa18e 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -18,8 +18,8 @@ obj-$(CONFIG_HAS_IOMEM) += devres.o obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ memcpy_64.o usercopy_64.o mem_64.o string.o -obj-$(CONFIG_XMON) += sstep.o -obj-$(CONFIG_KPROBES) += sstep.o +obj-$(CONFIG_XMON) += sstep.o ldstfp.o +obj-$(CONFIG_KPROBES) += sstep.o ldstfp.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o diff --git a/arch/powerpc/lib/ldstfp.S b/arch/powerpc/lib/ldstfp.S new file mode 100644 index 000000000000..f6448636baf5 --- /dev/null +++ b/arch/powerpc/lib/ldstfp.S @@ -0,0 +1,375 @@ +/* + * Floating-point, VMX/Altivec and VSX loads and stores + * for use in instruction emulation. + * + * Copyright 2010 Paul Mackerras, IBM Corp. + * + * 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 + +#define STKFRM (PPC_MIN_STKFRM + 16) + + .macro extab instr,handler + .section __ex_table,"a" + PPC_LONG \instr,\handler + .previous + .endm + + .macro inst32 op +reg = 0 + .rept 32 +20: \op reg,0,r4 + b 3f + extab 20b,99f +reg = reg + 1 + .endr + .endm + +/* Get the contents of frN into fr0; N is in r3. */ +_GLOBAL(get_fpr) + mflr r0 + rlwinm r3,r3,3,0xf8 + bcl 20,31,1f + blr /* fr0 is already in fr0 */ + nop +reg = 1 + .rept 31 + fmr fr0,reg + blr +reg = reg + 1 + .endr +1: mflr r5 + add r5,r3,r5 + mtctr r5 + mtlr r0 + bctr + +/* Put the contents of fr0 into frN; N is in r3. */ +_GLOBAL(put_fpr) + mflr r0 + rlwinm r3,r3,3,0xf8 + bcl 20,31,1f + blr /* fr0 is already in fr0 */ + nop +reg = 1 + .rept 31 + fmr reg,fr0 + blr +reg = reg + 1 + .endr +1: mflr r5 + add r5,r3,r5 + mtctr r5 + mtlr r0 + bctr + +/* Load FP reg N from float at *p. N is in r3, p in r4. */ +_GLOBAL(do_lfs) + PPC_STLU r1,-STKFRM(r1) + mflr r0 + PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) + mfmsr r6 + ori r7,r6,MSR_FP + cmpwi cr7,r3,0 + mtmsrd r7 + isync + beq cr7,1f + stfd fr0,STKFRM-16(r1) +1: li r9,-EFAULT +2: lfs fr0,0(r4) + li r9,0 +3: bl put_fpr + beq cr7,4f + lfd fr0,STKFRM-16(r1) +4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) + mtlr r0 + mtmsrd r6 + isync + mr r3,r9 + addi r1,r1,STKFRM + blr + extab 2b,3b + +/* Load FP reg N from double at *p. N is in r3, p in r4. */ +_GLOBAL(do_lfd) + PPC_STLU r1,-STKFRM(r1) + mflr r0 + PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) + mfmsr r6 + ori r7,r6,MSR_FP + cmpwi cr7,r3,0 + mtmsrd r7 + isync + beq cr7,1f + stfd fr0,STKFRM-16(r1) +1: li r9,-EFAULT +2: lfd fr0,0(r4) + li r9,0 +3: beq cr7,4f + bl put_fpr + lfd fr0,STKFRM-16(r1) +4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) + mtlr r0 + mtmsrd r6 + isync + mr r3,r9 + addi r1,r1,STKFRM + blr + extab 2b,3b + +/* Store FP reg N to float at *p. N is in r3, p in r4. */ +_GLOBAL(do_stfs) + PPC_STLU r1,-STKFRM(r1) + mflr r0 + PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) + mfmsr r6 + ori r7,r6,MSR_FP + cmpwi cr7,r3,0 + mtmsrd r7 + isync + beq cr7,1f + stfd fr0,STKFRM-16(r1) + bl get_fpr +1: li r9,-EFAULT +2: stfs fr0,0(r4) + li r9,0 +3: beq cr7,4f + lfd fr0,STKFRM-16(r1) +4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) + mtlr r0 + mtmsrd r6 + isync + mr r3,r9 + addi r1,r1,STKFRM + blr + extab 2b,3b + +/* Store FP reg N to double at *p. N is in r3, p in r4. */ +_GLOBAL(do_stfd) + PPC_STLU r1,-STKFRM(r1) + mflr r0 + PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) + mfmsr r6 + ori r7,r6,MSR_FP + cmpwi cr7,r3,0 + mtmsrd r7 + isync + beq cr7,1f + stfd fr0,STKFRM-16(r1) + bl get_fpr +1: li r9,-EFAULT +2: stfd fr0,0(r4) + li r9,0 +3: beq cr7,4f + lfd fr0,STKFRM-16(r1) +4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) + mtlr r0 + mtmsrd r6 + isync + mr r3,r9 + addi r1,r1,STKFRM + blr + extab 2b,3b + +#ifdef CONFIG_ALTIVEC +/* Get the contents of vrN into vr0; N is in r3. */ +_GLOBAL(get_vr) + mflr r0 + rlwinm r3,r3,3,0xf8 + bcl 20,31,1f + blr /* vr0 is already in vr0 */ + nop +reg = 1 + .rept 31 + vor vr0,reg,reg /* assembler doesn't know vmr? */ + blr +reg = reg + 1 + .endr +1: mflr r5 + add r5,r3,r5 + mtctr r5 + mtlr r0 + bctr + +/* Put the contents of vr0 into vrN; N is in r3. */ +_GLOBAL(put_vr) + mflr r0 + rlwinm r3,r3,3,0xf8 + bcl 20,31,1f + blr /* vr0 is already in vr0 */ + nop +reg = 1 + .rept 31 + vor reg,vr0,vr0 + blr +reg = reg + 1 + .endr +1: mflr r5 + add r5,r3,r5 + mtctr r5 + mtlr r0 + bctr + +/* Load vector reg N from *p. N is in r3, p in r4. */ +_GLOBAL(do_lvx) + PPC_STLU r1,-STKFRM(r1) + mflr r0 + PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) + mfmsr r6 + oris r7,r6,MSR_VEC@h + cmpwi cr7,r3,0 + li r8,STKFRM-16 + mtmsrd r7 + isync + beq cr7,1f + stvx vr0,r1,r8 +1: li r9,-EFAULT +2: lvx vr0,0,r4 + li r9,0 +3: beq cr7,4f + bl put_vr + lvx vr0,r1,r8 +4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) + mtlr r0 + mtmsrd r6 + isync + mr r3,r9 + addi r1,r1,STKFRM + blr + extab 2b,3b + +/* Store vector reg N to *p. N is in r3, p in r4. */ +_GLOBAL(do_stvx) + PPC_STLU r1,-STKFRM(r1) + mflr r0 + PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) + mfmsr r6 + oris r7,r6,MSR_VEC@h + cmpwi cr7,r3,0 + li r8,STKFRM-16 + mtmsrd r7 + isync + beq cr7,1f + stvx vr0,r1,r8 + bl get_vr +1: li r9,-EFAULT +2: stvx vr0,0,r4 + li r9,0 +3: beq cr7,4f + lvx vr0,r1,r8 +4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) + mtlr r0 + mtmsrd r6 + isync + mr r3,r9 + addi r1,r1,STKFRM + blr + extab 2b,3b +#endif /* CONFIG_ALTIVEC */ + +#ifdef CONFIG_VSX +/* Get the contents of vsrN into vsr0; N is in r3. */ +_GLOBAL(get_vsr) + mflr r0 + rlwinm r3,r3,3,0x1f8 + bcl 20,31,1f + blr /* vsr0 is already in vsr0 */ + nop +reg = 1 + .rept 63 + XXLOR(0,reg,reg) + blr +reg = reg + 1 + .endr +1: mflr r5 + add r5,r3,r5 + mtctr r5 + mtlr r0 + bctr + +/* Put the contents of vsr0 into vsrN; N is in r3. */ +_GLOBAL(put_vsr) + mflr r0 + rlwinm r3,r3,3,0x1f8 + bcl 20,31,1f + blr /* vr0 is already in vr0 */ + nop +reg = 1 + .rept 63 + XXLOR(reg,0,0) + blr +reg = reg + 1 + .endr +1: mflr r5 + add r5,r3,r5 + mtctr r5 + mtlr r0 + bctr + +/* Load VSX reg N from vector doubleword *p. N is in r3, p in r4. */ +_GLOBAL(do_lxvd2x) + PPC_STLU r1,-STKFRM(r1) + mflr r0 + PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) + mfmsr r6 + oris r7,r6,MSR_VSX@h + cmpwi cr7,r3,0 + li r8,STKFRM-16 + mtmsrd r7 + isync + beq cr7,1f + STXVD2X(0,r1,r8) +1: li r9,-EFAULT +2: LXVD2X(0,0,r4) + li r9,0 +3: beq cr7,4f + bl put_vsr + LXVD2X(0,r1,r8) +4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) + mtlr r0 + mtmsrd r6 + isync + mr r3,r9 + addi r1,r1,STKFRM + blr + extab 2b,3b + +/* Store VSX reg N to vector doubleword *p. N is in r3, p in r4. */ +_GLOBAL(do_stxvd2x) + PPC_STLU r1,-STKFRM(r1) + mflr r0 + PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) + mfmsr r6 + oris r7,r6,MSR_VSX@h + cmpwi cr7,r3,0 + li r8,STKFRM-16 + mtmsrd r7 + isync + beq cr7,1f + STXVD2X(0,r1,r8) + bl get_vsr +1: li r9,-EFAULT +2: STXVD2X(0,0,r4) + li r9,0 +3: beq cr7,4f + LXVD2X(0,r1,r8) +4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) + mtlr r0 + mtmsrd r6 + isync + mr r3,r9 + addi r1,r1,STKFRM + blr + extab 2b,3b + +#endif /* CONFIG_VSX */ diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 13b7d54f185b..e0a9858d537e 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include extern char system_call_common[]; @@ -23,6 +25,23 @@ extern char system_call_common[]; #define MSR_MASK 0x87c0ffff #endif +/* Bits in XER */ +#define XER_SO 0x80000000U +#define XER_OV 0x40000000U +#define XER_CA 0x20000000U + +/* + * Functions in ldstfp.S + */ +extern int do_lfs(int rn, unsigned long ea); +extern int do_lfd(int rn, unsigned long ea); +extern int do_stfs(int rn, unsigned long ea); +extern int do_stfd(int rn, unsigned long ea); +extern int do_lvx(int rn, unsigned long ea); +extern int do_stvx(int rn, unsigned long ea); +extern int do_lxvd2x(int rn, unsigned long ea); +extern int do_stxvd2x(int rn, unsigned long ea); + /* * Determine whether a conditional branch instruction would branch. */ @@ -46,16 +65,499 @@ static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs) return 1; } + +static long __kprobes address_ok(struct pt_regs *regs, unsigned long ea, int nb) +{ + if (!user_mode(regs)) + return 1; + return __access_ok(ea, nb, USER_DS); +} + +/* + * Calculate effective address for a D-form instruction + */ +static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs) +{ + int ra; + unsigned long ea; + + ra = (instr >> 16) & 0x1f; + ea = (signed short) instr; /* sign-extend */ + if (ra) { + ea += regs->gpr[ra]; + if (instr & 0x04000000) /* update forms */ + regs->gpr[ra] = ea; + } +#ifdef __powerpc64__ + if (!(regs->msr & MSR_SF)) + ea &= 0xffffffffUL; +#endif + return ea; +} + +#ifdef __powerpc64__ +/* + * Calculate effective address for a DS-form instruction + */ +static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *regs) +{ + int ra; + unsigned long ea; + + ra = (instr >> 16) & 0x1f; + ea = (signed short) (instr & ~3); /* sign-extend */ + if (ra) { + ea += regs->gpr[ra]; + if ((instr & 3) == 1) /* update forms */ + regs->gpr[ra] = ea; + } + if (!(regs->msr & MSR_SF)) + ea &= 0xffffffffUL; + return ea; +} +#endif /* __powerpc64 */ + +/* + * Calculate effective address for an X-form instruction + */ +static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs, + int do_update) +{ + int ra, rb; + unsigned long ea; + + ra = (instr >> 16) & 0x1f; + rb = (instr >> 11) & 0x1f; + ea = regs->gpr[rb]; + if (ra) { + ea += regs->gpr[ra]; + if (do_update) /* update forms */ + regs->gpr[ra] = ea; + } +#ifdef __powerpc64__ + if (!(regs->msr & MSR_SF)) + ea &= 0xffffffffUL; +#endif + return ea; +} + +/* + * Return the largest power of 2, not greater than sizeof(unsigned long), + * such that x is a multiple of it. + */ +static inline unsigned long max_align(unsigned long x) +{ + x |= sizeof(unsigned long); + return x & -x; /* isolates rightmost bit */ +} + + +static inline unsigned long byterev_2(unsigned long x) +{ + return ((x >> 8) & 0xff) | ((x & 0xff) << 8); +} + +static inline unsigned long byterev_4(unsigned long x) +{ + return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | + ((x & 0xff00) << 8) | ((x & 0xff) << 24); +} + +#ifdef __powerpc64__ +static inline unsigned long byterev_8(unsigned long x) +{ + return (byterev_4(x) << 32) | byterev_4(x >> 32); +} +#endif + +static int __kprobes read_mem_aligned(unsigned long *dest, unsigned long ea, + int nb) +{ + int err = 0; + unsigned long x = 0; + + switch (nb) { + case 1: + err = __get_user(x, (unsigned char __user *) ea); + break; + case 2: + err = __get_user(x, (unsigned short __user *) ea); + break; + case 4: + err = __get_user(x, (unsigned int __user *) ea); + break; +#ifdef __powerpc64__ + case 8: + err = __get_user(x, (unsigned long __user *) ea); + break; +#endif + } + if (!err) + *dest = x; + return err; +} + +static int __kprobes read_mem_unaligned(unsigned long *dest, unsigned long ea, + int nb, struct pt_regs *regs) +{ + int err; + unsigned long x, b, c; + + /* unaligned, do this in pieces */ + x = 0; + for (; nb > 0; nb -= c) { + c = max_align(ea); + if (c > nb) + c = max_align(nb); + err = read_mem_aligned(&b, ea, c); + if (err) + return err; + x = (x << (8 * c)) + b; + ea += c; + } + *dest = x; + return 0; +} + +/* + * Read memory at address ea for nb bytes, return 0 for success + * or -EFAULT if an error occurred. + */ +static int __kprobes read_mem(unsigned long *dest, unsigned long ea, int nb, + struct pt_regs *regs) +{ + if (!address_ok(regs, ea, nb)) + return -EFAULT; + if ((ea & (nb - 1)) == 0) + return read_mem_aligned(dest, ea, nb); + return read_mem_unaligned(dest, ea, nb, regs); +} + +static int __kprobes write_mem_aligned(unsigned long val, unsigned long ea, + int nb) +{ + int err = 0; + + switch (nb) { + case 1: + err = __put_user(val, (unsigned char __user *) ea); + break; + case 2: + err = __put_user(val, (unsigned short __user *) ea); + break; + case 4: + err = __put_user(val, (unsigned int __user *) ea); + break; +#ifdef __powerpc64__ + case 8: + err = __put_user(val, (unsigned long __user *) ea); + break; +#endif + } + return err; +} + +static int __kprobes write_mem_unaligned(unsigned long val, unsigned long ea, + int nb, struct pt_regs *regs) +{ + int err; + unsigned long c; + + /* unaligned or little-endian, do this in pieces */ + for (; nb > 0; nb -= c) { + c = max_align(ea); + if (c > nb) + c = max_align(nb); + err = write_mem_aligned(val >> (nb - c) * 8, ea, c); + if (err) + return err; + ++ea; + } + return 0; +} + +/* + * Write memory at address ea for nb bytes, return 0 for success + * or -EFAULT if an error occurred. + */ +static int __kprobes write_mem(unsigned long val, unsigned long ea, int nb, + struct pt_regs *regs) +{ + if (!address_ok(regs, ea, nb)) + return -EFAULT; + if ((ea & (nb - 1)) == 0) + return write_mem_aligned(val, ea, nb); + return write_mem_unaligned(val, ea, nb, regs); +} + /* - * Emulate instructions that cause a transfer of control. + * Check the address and alignment, and call func to do the actual + * load or store. + */ +static int __kprobes do_fp_load(int rn, int (*func)(int, unsigned long), + unsigned long ea, int nb, + struct pt_regs *regs) +{ + int err; + unsigned long val[sizeof(double) / sizeof(long)]; + unsigned long ptr; + + if (!address_ok(regs, ea, nb)) + return -EFAULT; + if ((ea & 3) == 0) + return (*func)(rn, ea); + ptr = (unsigned long) &val[0]; + if (sizeof(unsigned long) == 8 || nb == 4) { + err = read_mem_unaligned(&val[0], ea, nb, regs); + ptr += sizeof(unsigned long) - nb; + } else { + /* reading a double on 32-bit */ + err = read_mem_unaligned(&val[0], ea, 4, regs); + if (!err) + err = read_mem_unaligned(&val[1], ea + 4, 4, regs); + } + if (err) + return err; + return (*func)(rn, ptr); +} + +static int __kprobes do_fp_store(int rn, int (*func)(int, unsigned long), + unsigned long ea, int nb, + struct pt_regs *regs) +{ + int err; + unsigned long val[sizeof(double) / sizeof(long)]; + unsigned long ptr; + + if (!address_ok(regs, ea, nb)) + return -EFAULT; + if ((ea & 3) == 0) + return (*func)(rn, ea); + ptr = (unsigned long) &val[0]; + if (sizeof(unsigned long) == 8 || nb == 4) { + ptr += sizeof(unsigned long) - nb; + err = (*func)(rn, ptr); + if (err) + return err; + err = write_mem_unaligned(val[0], ea, nb, regs); + } else { + /* writing a double on 32-bit */ + err = (*func)(rn, ptr); + if (err) + return err; + err = write_mem_unaligned(val[0], ea, 4, regs); + if (!err) + err = write_mem_unaligned(val[1], ea + 4, 4, regs); + } + return err; +} + +#ifdef CONFIG_ALTIVEC +/* For Altivec/VMX, no need to worry about alignment */ +static int __kprobes do_vec_load(int rn, int (*func)(int, unsigned long), + unsigned long ea, struct pt_regs *regs) +{ + if (!address_ok(regs, ea & ~0xfUL, 16)) + return -EFAULT; + return (*func)(rn, ea); +} + +static int __kprobes do_vec_store(int rn, int (*func)(int, unsigned long), + unsigned long ea, struct pt_regs *regs) +{ + if (!address_ok(regs, ea & ~0xfUL, 16)) + return -EFAULT; + return (*func)(rn, ea); +} +#endif /* CONFIG_ALTIVEC */ + +#ifdef CONFIG_VSX +static int __kprobes do_vsx_load(int rn, int (*func)(int, unsigned long), + unsigned long ea, struct pt_regs *regs) +{ + int err; + unsigned long val[2]; + + if (!address_ok(regs, ea, 16)) + return -EFAULT; + if ((ea & 3) == 0) + return (*func)(rn, ea); + err = read_mem_unaligned(&val[0], ea, 8, regs); + if (!err) + err = read_mem_unaligned(&val[1], ea + 8, 8, regs); + if (!err) + err = (*func)(rn, (unsigned long) &val[0]); + return err; +} + +static int __kprobes do_vsx_store(int rn, int (*func)(int, unsigned long), + unsigned long ea, struct pt_regs *regs) +{ + int err; + unsigned long val[2]; + + if (!address_ok(regs, ea, 16)) + return -EFAULT; + if ((ea & 3) == 0) + return (*func)(rn, ea); + err = (*func)(rn, (unsigned long) &val[0]); + if (err) + return err; + err = write_mem_unaligned(val[0], ea, 8, regs); + if (!err) + err = write_mem_unaligned(val[1], ea + 8, 8, regs); + return err; +} +#endif /* CONFIG_VSX */ + +#define __put_user_asmx(x, addr, err, op, cr) \ + __asm__ __volatile__( \ + "1: " op " %2,0,%3\n" \ + " mfcr %1\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,%4\n" \ + " b 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + PPC_LONG_ALIGN "\n" \ + PPC_LONG "1b,3b\n" \ + ".previous" \ + : "=r" (err), "=r" (cr) \ + : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err)) + +#define __get_user_asmx(x, addr, err, op) \ + __asm__ __volatile__( \ + "1: "op" %1,0,%2\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,%3\n" \ + " b 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + PPC_LONG_ALIGN "\n" \ + PPC_LONG "1b,3b\n" \ + ".previous" \ + : "=r" (err), "=r" (x) \ + : "r" (addr), "i" (-EFAULT), "0" (err)) + +#define __cacheop_user_asmx(addr, err, op) \ + __asm__ __volatile__( \ + "1: "op" 0,%1\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,%3\n" \ + " b 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + PPC_LONG_ALIGN "\n" \ + PPC_LONG "1b,3b\n" \ + ".previous" \ + : "=r" (err) \ + : "r" (addr), "i" (-EFAULT), "0" (err)) + +static void __kprobes set_cr0(struct pt_regs *regs, int rd) +{ + long val = regs->gpr[rd]; + + regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000); +#ifdef __powerpc64__ + if (!(regs->msr & MSR_SF)) + val = (int) val; +#endif + if (val < 0) + regs->ccr |= 0x80000000; + else if (val > 0) + regs->ccr |= 0x40000000; + else + regs->ccr |= 0x20000000; +} + +static void __kprobes add_with_carry(struct pt_regs *regs, int rd, + unsigned long val1, unsigned long val2, + unsigned long carry_in) +{ + unsigned long val = val1 + val2; + + if (carry_in) + ++val; + regs->gpr[rd] = val; +#ifdef __powerpc64__ + if (!(regs->msr & MSR_SF)) { + val = (unsigned int) val; + val1 = (unsigned int) val1; + } +#endif + if (val < val1 || (carry_in && val == val1)) + regs->xer |= XER_CA; + else + regs->xer &= ~XER_CA; +} + +static void __kprobes do_cmp_signed(struct pt_regs *regs, long v1, long v2, + int crfld) +{ + unsigned int crval, shift; + + crval = (regs->xer >> 31) & 1; /* get SO bit */ + if (v1 < v2) + crval |= 8; + else if (v1 > v2) + crval |= 4; + else + crval |= 2; + shift = (7 - crfld) * 4; + regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift); +} + +static void __kprobes do_cmp_unsigned(struct pt_regs *regs, unsigned long v1, + unsigned long v2, int crfld) +{ + unsigned int crval, shift; + + crval = (regs->xer >> 31) & 1; /* get SO bit */ + if (v1 < v2) + crval |= 8; + else if (v1 > v2) + crval |= 4; + else + crval |= 2; + shift = (7 - crfld) * 4; + regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift); +} + +/* + * Elements of 32-bit rotate and mask instructions. + */ +#define MASK32(mb, me) ((0xffffffffUL >> (mb)) + \ + ((signed long)-0x80000000L >> (me)) + ((me) >= (mb))) +#ifdef __powerpc64__ +#define MASK64_L(mb) (~0UL >> (mb)) +#define MASK64_R(me) ((signed long)-0x8000000000000000L >> (me)) +#define MASK64(mb, me) (MASK64_L(mb) + MASK64_R(me) + ((me) >= (mb))) +#define DATA32(x) (((x) & 0xffffffffUL) | (((x) & 0xffffffffUL) << 32)) +#else +#define DATA32(x) (x) +#endif +#define ROTATE(x, n) ((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x)) + +/* + * Emulate instructions that cause a transfer of control, + * loads and stores, and a few other instructions. * Returns 1 if the step was emulated, 0 if not, * or -1 if the instruction is one that should not be stepped, * such as an rfid, or a mtmsrd that would clear MSR_RI. */ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) { - unsigned int opcode, rs, rb, rd, spr; + unsigned int opcode, ra, rb, rd, spr, u; unsigned long int imm; + unsigned long int val, val2; + unsigned long int ea; + unsigned int cr, mb, me, sh; + int err; + unsigned long old_ra; + long ival; opcode = instr >> 26; switch (opcode) { @@ -78,7 +580,13 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) * entry code works. If that is changed, this will * need to be changed also. */ + if (regs->gpr[0] == 0x1ebe && + cpu_has_feature(CPU_FTR_REAL_LE)) { + regs->msr ^= MSR_LE; + goto instr_done; + } regs->gpr[9] = regs->gpr[13]; + regs->gpr[10] = MSR_KERNEL; regs->gpr[11] = regs->nip + 4; regs->gpr[12] = regs->msr & MSR_MASK; regs->gpr[13] = (unsigned long) get_paca(); @@ -102,9 +610,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) regs->nip = imm; return 1; case 19: - switch (instr & 0x7fe) { - case 0x20: /* bclr */ - case 0x420: /* bcctr */ + switch ((instr >> 1) & 0x3ff) { + case 16: /* bclr */ + case 528: /* bcctr */ imm = (instr & 0x400)? regs->ctr: regs->link; regs->nip += 4; if ((regs->msr & MSR_SF) == 0) { @@ -116,30 +624,233 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) if (branch_taken(instr, regs)) regs->nip = imm; return 1; - case 0x24: /* rfid, scary */ + + case 18: /* rfid, scary */ return -1; + + case 150: /* isync */ + isync(); + goto instr_done; + + case 33: /* crnor */ + case 129: /* crandc */ + case 193: /* crxor */ + case 225: /* crnand */ + case 257: /* crand */ + case 289: /* creqv */ + case 417: /* crorc */ + case 449: /* cror */ + ra = (instr >> 16) & 0x1f; + rb = (instr >> 11) & 0x1f; + rd = (instr >> 21) & 0x1f; + ra = (regs->ccr >> (31 - ra)) & 1; + rb = (regs->ccr >> (31 - rb)) & 1; + val = (instr >> (6 + ra * 2 + rb)) & 1; + regs->ccr = (regs->ccr & ~(1UL << (31 - rd))) | + (val << (31 - rd)); + goto instr_done; + } + break; + case 31: + switch ((instr >> 1) & 0x3ff) { + case 598: /* sync */ +#ifdef __powerpc64__ + switch ((instr >> 21) & 3) { + case 1: /* lwsync */ + asm volatile("lwsync" : : : "memory"); + goto instr_done; + case 2: /* ptesync */ + asm volatile("ptesync" : : : "memory"); + goto instr_done; + } +#endif + mb(); + goto instr_done; + + case 854: /* eieio */ + eieio(); + goto instr_done; + } + break; + } + + /* Following cases refer to regs->gpr[], so we need all regs */ + if (!FULL_REGS(regs)) + return 0; + + rd = (instr >> 21) & 0x1f; + ra = (instr >> 16) & 0x1f; + rb = (instr >> 11) & 0x1f; + + switch (opcode) { + case 7: /* mulli */ + regs->gpr[rd] = regs->gpr[ra] * (short) instr; + goto instr_done; + + case 8: /* subfic */ + imm = (short) instr; + add_with_carry(regs, rd, ~regs->gpr[ra], imm, 1); + goto instr_done; + + case 10: /* cmpli */ + imm = (unsigned short) instr; + val = regs->gpr[ra]; +#ifdef __powerpc64__ + if ((rd & 1) == 0) + val = (unsigned int) val; +#endif + do_cmp_unsigned(regs, val, imm, rd >> 2); + goto instr_done; + + case 11: /* cmpi */ + imm = (short) instr; + val = regs->gpr[ra]; +#ifdef __powerpc64__ + if ((rd & 1) == 0) + val = (int) val; +#endif + do_cmp_signed(regs, val, imm, rd >> 2); + goto instr_done; + + case 12: /* addic */ + imm = (short) instr; + add_with_carry(regs, rd, regs->gpr[ra], imm, 0); + goto instr_done; + + case 13: /* addic. */ + imm = (short) instr; + add_with_carry(regs, rd, regs->gpr[ra], imm, 0); + set_cr0(regs, rd); + goto instr_done; + + case 14: /* addi */ + imm = (short) instr; + if (ra) + imm += regs->gpr[ra]; + regs->gpr[rd] = imm; + goto instr_done; + + case 15: /* addis */ + imm = ((short) instr) << 16; + if (ra) + imm += regs->gpr[ra]; + regs->gpr[rd] = imm; + goto instr_done; + + case 20: /* rlwimi */ + mb = (instr >> 6) & 0x1f; + me = (instr >> 1) & 0x1f; + val = DATA32(regs->gpr[rd]); + imm = MASK32(mb, me); + regs->gpr[ra] = (regs->gpr[ra] & ~imm) | (ROTATE(val, rb) & imm); + goto logical_done; + + case 21: /* rlwinm */ + mb = (instr >> 6) & 0x1f; + me = (instr >> 1) & 0x1f; + val = DATA32(regs->gpr[rd]); + regs->gpr[ra] = ROTATE(val, rb) & MASK32(mb, me); + goto logical_done; + + case 23: /* rlwnm */ + mb = (instr >> 6) & 0x1f; + me = (instr >> 1) & 0x1f; + rb = regs->gpr[rb] & 0x1f; + val = DATA32(regs->gpr[rd]); + regs->gpr[ra] = ROTATE(val, rb) & MASK32(mb, me); + goto logical_done; + + case 24: /* ori */ + imm = (unsigned short) instr; + regs->gpr[ra] = regs->gpr[rd] | imm; + goto instr_done; + + case 25: /* oris */ + imm = (unsigned short) instr; + regs->gpr[ra] = regs->gpr[rd] | (imm << 16); + goto instr_done; + + case 26: /* xori */ + imm = (unsigned short) instr; + regs->gpr[ra] = regs->gpr[rd] ^ imm; + goto instr_done; + + case 27: /* xoris */ + imm = (unsigned short) instr; + regs->gpr[ra] = regs->gpr[rd] ^ (imm << 16); + goto instr_done; + + case 28: /* andi. */ + imm = (unsigned short) instr; + regs->gpr[ra] = regs->gpr[rd] & imm; + set_cr0(regs, ra); + goto instr_done; + + case 29: /* andis. */ + imm = (unsigned short) instr; + regs->gpr[ra] = regs->gpr[rd] & (imm << 16); + set_cr0(regs, ra); + goto instr_done; + +#ifdef __powerpc64__ + case 30: /* rld* */ + mb = ((instr >> 6) & 0x1f) | (instr & 0x20); + val = regs->gpr[rd]; + if ((instr & 0x10) == 0) { + sh = rb | ((instr & 2) << 4); + val = ROTATE(val, sh); + switch ((instr >> 2) & 3) { + case 0: /* rldicl */ + regs->gpr[ra] = val & MASK64_L(mb); + goto logical_done; + case 1: /* rldicr */ + regs->gpr[ra] = val & MASK64_R(mb); + goto logical_done; + case 2: /* rldic */ + regs->gpr[ra] = val & MASK64(mb, 63 - sh); + goto logical_done; + case 3: /* rldimi */ + imm = MASK64(mb, 63 - sh); + regs->gpr[ra] = (regs->gpr[ra] & ~imm) | + (val & imm); + goto logical_done; + } + } else { + sh = regs->gpr[rb] & 0x3f; + val = ROTATE(val, sh); + switch ((instr >> 1) & 7) { + case 0: /* rldcl */ + regs->gpr[ra] = val & MASK64_L(mb); + goto logical_done; + case 1: /* rldcr */ + regs->gpr[ra] = val & MASK64_R(mb); + goto logical_done; + } } +#endif + case 31: - rd = (instr >> 21) & 0x1f; - switch (instr & 0x7fe) { - case 0xa6: /* mfmsr */ + switch ((instr >> 1) & 0x3ff) { + case 83: /* mfmsr */ + if (regs->msr & MSR_PR) + break; regs->gpr[rd] = regs->msr & MSR_MASK; - regs->nip += 4; - if ((regs->msr & MSR_SF) == 0) - regs->nip &= 0xffffffffUL; - return 1; - case 0x124: /* mtmsr */ + goto instr_done; + case 146: /* mtmsr */ + if (regs->msr & MSR_PR) + break; imm = regs->gpr[rd]; if ((imm & MSR_RI) == 0) /* can't step mtmsr that would clear MSR_RI */ return -1; regs->msr = imm; - regs->nip += 4; - return 1; + goto instr_done; #ifdef CONFIG_PPC64 - case 0x164: /* mtmsrd */ + case 178: /* mtmsrd */ /* only MSR_EE and MSR_RI get changed if bit 15 set */ /* mtmsrd doesn't change MSR_HV and MSR_ME */ + if (regs->msr & MSR_PR) + break; imm = (instr & 0x10000)? 0x8002: 0xefffffffffffefffUL; imm = (regs->msr & MSR_MASK & ~imm) | (regs->gpr[rd] & imm); @@ -147,57 +858,770 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) /* can't step mtmsrd that would clear MSR_RI */ return -1; regs->msr = imm; - regs->nip += 4; - if ((imm & MSR_SF) == 0) - regs->nip &= 0xffffffffUL; - return 1; + goto instr_done; #endif - case 0x26: /* mfcr */ + case 19: /* mfcr */ regs->gpr[rd] = regs->ccr; regs->gpr[rd] &= 0xffffffffUL; - goto mtspr_out; - case 0x2a6: /* mfspr */ + goto instr_done; + + case 144: /* mtcrf */ + imm = 0xf0000000UL; + val = regs->gpr[rd]; + for (sh = 0; sh < 8; ++sh) { + if (instr & (0x80000 >> sh)) + regs->ccr = (regs->ccr & ~imm) | + (val & imm); + imm >>= 4; + } + goto instr_done; + + case 339: /* mfspr */ spr = (instr >> 11) & 0x3ff; switch (spr) { case 0x20: /* mfxer */ regs->gpr[rd] = regs->xer; regs->gpr[rd] &= 0xffffffffUL; - goto mtspr_out; + goto instr_done; case 0x100: /* mflr */ regs->gpr[rd] = regs->link; - goto mtspr_out; + goto instr_done; case 0x120: /* mfctr */ regs->gpr[rd] = regs->ctr; - goto mtspr_out; - } - break; - case 0x378: /* orx */ - if (instr & 1) - break; - rs = (instr >> 21) & 0x1f; - rb = (instr >> 11) & 0x1f; - if (rs == rb) { /* mr */ - rd = (instr >> 16) & 0x1f; - regs->gpr[rd] = regs->gpr[rs]; - goto mtspr_out; + goto instr_done; } break; - case 0x3a6: /* mtspr */ + + case 467: /* mtspr */ spr = (instr >> 11) & 0x3ff; switch (spr) { case 0x20: /* mtxer */ regs->xer = (regs->gpr[rd] & 0xffffffffUL); - goto mtspr_out; + goto instr_done; case 0x100: /* mtlr */ regs->link = regs->gpr[rd]; - goto mtspr_out; + goto instr_done; case 0x120: /* mtctr */ regs->ctr = regs->gpr[rd]; -mtspr_out: - regs->nip += 4; - return 1; + goto instr_done; } + break; + +/* + * Compare instructions + */ + case 0: /* cmp */ + val = regs->gpr[ra]; + val2 = regs->gpr[rb]; +#ifdef __powerpc64__ + if ((rd & 1) == 0) { + /* word (32-bit) compare */ + val = (int) val; + val2 = (int) val2; + } +#endif + do_cmp_signed(regs, val, val2, rd >> 2); + goto instr_done; + + case 32: /* cmpl */ + val = regs->gpr[ra]; + val2 = regs->gpr[rb]; +#ifdef __powerpc64__ + if ((rd & 1) == 0) { + /* word (32-bit) compare */ + val = (unsigned int) val; + val2 = (unsigned int) val2; + } +#endif + do_cmp_unsigned(regs, val, val2, rd >> 2); + goto instr_done; + +/* + * Arithmetic instructions + */ + case 8: /* subfc */ + add_with_carry(regs, rd, ~regs->gpr[ra], + regs->gpr[rb], 1); + goto arith_done; +#ifdef __powerpc64__ + case 9: /* mulhdu */ + asm("mulhdu %0,%1,%2" : "=r" (regs->gpr[rd]) : + "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); + goto arith_done; +#endif + case 10: /* addc */ + add_with_carry(regs, rd, regs->gpr[ra], + regs->gpr[rb], 0); + goto arith_done; + + case 11: /* mulhwu */ + asm("mulhwu %0,%1,%2" : "=r" (regs->gpr[rd]) : + "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); + goto arith_done; + + case 40: /* subf */ + regs->gpr[rd] = regs->gpr[rb] - regs->gpr[ra]; + goto arith_done; +#ifdef __powerpc64__ + case 73: /* mulhd */ + asm("mulhd %0,%1,%2" : "=r" (regs->gpr[rd]) : + "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); + goto arith_done; +#endif + case 75: /* mulhw */ + asm("mulhw %0,%1,%2" : "=r" (regs->gpr[rd]) : + "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); + goto arith_done; + + case 104: /* neg */ + regs->gpr[rd] = -regs->gpr[ra]; + goto arith_done; + + case 136: /* subfe */ + add_with_carry(regs, rd, ~regs->gpr[ra], regs->gpr[rb], + regs->xer & XER_CA); + goto arith_done; + + case 138: /* adde */ + add_with_carry(regs, rd, regs->gpr[ra], regs->gpr[rb], + regs->xer & XER_CA); + goto arith_done; + + case 200: /* subfze */ + add_with_carry(regs, rd, ~regs->gpr[ra], 0L, + regs->xer & XER_CA); + goto arith_done; + + case 202: /* addze */ + add_with_carry(regs, rd, regs->gpr[ra], 0L, + regs->xer & XER_CA); + goto arith_done; + + case 232: /* subfme */ + add_with_carry(regs, rd, ~regs->gpr[ra], -1L, + regs->xer & XER_CA); + goto arith_done; +#ifdef __powerpc64__ + case 233: /* mulld */ + regs->gpr[rd] = regs->gpr[ra] * regs->gpr[rb]; + goto arith_done; +#endif + case 234: /* addme */ + add_with_carry(regs, rd, regs->gpr[ra], -1L, + regs->xer & XER_CA); + goto arith_done; + + case 235: /* mullw */ + regs->gpr[rd] = (unsigned int) regs->gpr[ra] * + (unsigned int) regs->gpr[rb]; + goto arith_done; + + case 266: /* add */ + regs->gpr[rd] = regs->gpr[ra] + regs->gpr[rb]; + goto arith_done; +#ifdef __powerpc64__ + case 457: /* divdu */ + regs->gpr[rd] = regs->gpr[ra] / regs->gpr[rb]; + goto arith_done; +#endif + case 459: /* divwu */ + regs->gpr[rd] = (unsigned int) regs->gpr[ra] / + (unsigned int) regs->gpr[rb]; + goto arith_done; +#ifdef __powerpc64__ + case 489: /* divd */ + regs->gpr[rd] = (long int) regs->gpr[ra] / + (long int) regs->gpr[rb]; + goto arith_done; +#endif + case 491: /* divw */ + regs->gpr[rd] = (int) regs->gpr[ra] / + (int) regs->gpr[rb]; + goto arith_done; + + +/* + * Logical instructions + */ + case 26: /* cntlzw */ + asm("cntlzw %0,%1" : "=r" (regs->gpr[ra]) : + "r" (regs->gpr[rd])); + goto logical_done; +#ifdef __powerpc64__ + case 58: /* cntlzd */ + asm("cntlzd %0,%1" : "=r" (regs->gpr[ra]) : + "r" (regs->gpr[rd])); + goto logical_done; +#endif + case 28: /* and */ + regs->gpr[ra] = regs->gpr[rd] & regs->gpr[rb]; + goto logical_done; + + case 60: /* andc */ + regs->gpr[ra] = regs->gpr[rd] & ~regs->gpr[rb]; + goto logical_done; + + case 124: /* nor */ + regs->gpr[ra] = ~(regs->gpr[rd] | regs->gpr[rb]); + goto logical_done; + + case 284: /* xor */ + regs->gpr[ra] = ~(regs->gpr[rd] ^ regs->gpr[rb]); + goto logical_done; + + case 316: /* xor */ + regs->gpr[ra] = regs->gpr[rd] ^ regs->gpr[rb]; + goto logical_done; + + case 412: /* orc */ + regs->gpr[ra] = regs->gpr[rd] | ~regs->gpr[rb]; + goto logical_done; + + case 444: /* or */ + regs->gpr[ra] = regs->gpr[rd] | regs->gpr[rb]; + goto logical_done; + + case 476: /* nand */ + regs->gpr[ra] = ~(regs->gpr[rd] & regs->gpr[rb]); + goto logical_done; + + case 922: /* extsh */ + regs->gpr[ra] = (signed short) regs->gpr[rd]; + goto logical_done; + + case 954: /* extsb */ + regs->gpr[ra] = (signed char) regs->gpr[rd]; + goto logical_done; +#ifdef __powerpc64__ + case 986: /* extsw */ + regs->gpr[ra] = (signed int) regs->gpr[rd]; + goto logical_done; +#endif + +/* + * Shift instructions + */ + case 24: /* slw */ + sh = regs->gpr[rb] & 0x3f; + if (sh < 32) + regs->gpr[ra] = (regs->gpr[rd] << sh) & 0xffffffffUL; + else + regs->gpr[ra] = 0; + goto logical_done; + + case 536: /* srw */ + sh = regs->gpr[rb] & 0x3f; + if (sh < 32) + regs->gpr[ra] = (regs->gpr[rd] & 0xffffffffUL) >> sh; + else + regs->gpr[ra] = 0; + goto logical_done; + + case 792: /* sraw */ + sh = regs->gpr[rb] & 0x3f; + ival = (signed int) regs->gpr[rd]; + regs->gpr[ra] = ival >> (sh < 32 ? sh : 31); + if (ival < 0 && (sh >= 32 || (ival & ((1 << sh) - 1)) != 0)) + regs->xer |= XER_CA; + else + regs->xer &= ~XER_CA; + goto logical_done; + + case 824: /* srawi */ + sh = rb; + ival = (signed int) regs->gpr[rd]; + regs->gpr[ra] = ival >> sh; + if (ival < 0 && (ival & ((1 << sh) - 1)) != 0) + regs->xer |= XER_CA; + else + regs->xer &= ~XER_CA; + goto logical_done; + +#ifdef __powerpc64__ + case 27: /* sld */ + sh = regs->gpr[rd] & 0x7f; + if (sh < 64) + regs->gpr[ra] = regs->gpr[rd] << sh; + else + regs->gpr[ra] = 0; + goto logical_done; + + case 539: /* srd */ + sh = regs->gpr[rb] & 0x7f; + if (sh < 64) + regs->gpr[ra] = regs->gpr[rd] >> sh; + else + regs->gpr[ra] = 0; + goto logical_done; + + case 794: /* srad */ + sh = regs->gpr[rb] & 0x7f; + ival = (signed long int) regs->gpr[rd]; + regs->gpr[ra] = ival >> (sh < 64 ? sh : 63); + if (ival < 0 && (sh >= 64 || (ival & ((1 << sh) - 1)) != 0)) + regs->xer |= XER_CA; + else + regs->xer &= ~XER_CA; + goto logical_done; + + case 826: /* sradi with sh_5 = 0 */ + case 827: /* sradi with sh_5 = 1 */ + sh = rb | ((instr & 2) << 4); + ival = (signed long int) regs->gpr[rd]; + regs->gpr[ra] = ival >> sh; + if (ival < 0 && (ival & ((1 << sh) - 1)) != 0) + regs->xer |= XER_CA; + else + regs->xer &= ~XER_CA; + goto logical_done; +#endif /* __powerpc64__ */ + +/* + * Cache instructions + */ + case 54: /* dcbst */ + ea = xform_ea(instr, regs, 0); + if (!address_ok(regs, ea, 8)) + return 0; + err = 0; + __cacheop_user_asmx(ea, err, "dcbst"); + if (err) + return 0; + goto instr_done; + + case 86: /* dcbf */ + ea = xform_ea(instr, regs, 0); + if (!address_ok(regs, ea, 8)) + return 0; + err = 0; + __cacheop_user_asmx(ea, err, "dcbf"); + if (err) + return 0; + goto instr_done; + + case 246: /* dcbtst */ + if (rd == 0) { + ea = xform_ea(instr, regs, 0); + prefetchw((void *) ea); + } + goto instr_done; + + case 278: /* dcbt */ + if (rd == 0) { + ea = xform_ea(instr, regs, 0); + prefetch((void *) ea); + } + goto instr_done; + } + break; } - return 0; + + /* + * Following cases are for loads and stores, so bail out + * if we're in little-endian mode. + */ + if (regs->msr & MSR_LE) + return 0; + + /* + * Save register RA in case it's an update form load or store + * and the access faults. + */ + old_ra = regs->gpr[ra]; + + switch (opcode) { + case 31: + u = instr & 0x40; + switch ((instr >> 1) & 0x3ff) { + case 20: /* lwarx */ + ea = xform_ea(instr, regs, 0); + if (ea & 3) + break; /* can't handle misaligned */ + err = -EFAULT; + if (!address_ok(regs, ea, 4)) + goto ldst_done; + err = 0; + __get_user_asmx(val, ea, err, "lwarx"); + if (!err) + regs->gpr[rd] = val; + goto ldst_done; + + case 150: /* stwcx. */ + ea = xform_ea(instr, regs, 0); + if (ea & 3) + break; /* can't handle misaligned */ + err = -EFAULT; + if (!address_ok(regs, ea, 4)) + goto ldst_done; + err = 0; + __put_user_asmx(regs->gpr[rd], ea, err, "stwcx.", cr); + if (!err) + regs->ccr = (regs->ccr & 0x0fffffff) | + (cr & 0xe0000000) | + ((regs->xer >> 3) & 0x10000000); + goto ldst_done; + +#ifdef __powerpc64__ + case 84: /* ldarx */ + ea = xform_ea(instr, regs, 0); + if (ea & 7) + break; /* can't handle misaligned */ + err = -EFAULT; + if (!address_ok(regs, ea, 8)) + goto ldst_done; + err = 0; + __get_user_asmx(val, ea, err, "ldarx"); + if (!err) + regs->gpr[rd] = val; + goto ldst_done; + + case 214: /* stdcx. */ + ea = xform_ea(instr, regs, 0); + if (ea & 7) + break; /* can't handle misaligned */ + err = -EFAULT; + if (!address_ok(regs, ea, 8)) + goto ldst_done; + err = 0; + __put_user_asmx(regs->gpr[rd], ea, err, "stdcx.", cr); + if (!err) + regs->ccr = (regs->ccr & 0x0fffffff) | + (cr & 0xe0000000) | + ((regs->xer >> 3) & 0x10000000); + goto ldst_done; + + case 21: /* ldx */ + case 53: /* ldux */ + err = read_mem(®s->gpr[rd], xform_ea(instr, regs, u), + 8, regs); + goto ldst_done; +#endif + + case 23: /* lwzx */ + case 55: /* lwzux */ + err = read_mem(®s->gpr[rd], xform_ea(instr, regs, u), + 4, regs); + goto ldst_done; + + case 87: /* lbzx */ + case 119: /* lbzux */ + err = read_mem(®s->gpr[rd], xform_ea(instr, regs, u), + 1, regs); + goto ldst_done; + +#ifdef CONFIG_ALTIVEC + case 103: /* lvx */ + case 359: /* lvxl */ + if (!(regs->msr & MSR_VEC)) + break; + ea = xform_ea(instr, regs, 0); + err = do_vec_load(rd, do_lvx, ea, regs); + goto ldst_done; + + case 231: /* stvx */ + case 487: /* stvxl */ + if (!(regs->msr & MSR_VEC)) + break; + ea = xform_ea(instr, regs, 0); + err = do_vec_store(rd, do_stvx, ea, regs); + goto ldst_done; +#endif /* CONFIG_ALTIVEC */ + +#ifdef __powerpc64__ + case 149: /* stdx */ + case 181: /* stdux */ + val = regs->gpr[rd]; + err = write_mem(val, xform_ea(instr, regs, u), 8, regs); + goto ldst_done; +#endif + + case 151: /* stwx */ + case 183: /* stwux */ + val = regs->gpr[rd]; + err = write_mem(val, xform_ea(instr, regs, u), 4, regs); + goto ldst_done; + + case 215: /* stbx */ + case 247: /* stbux */ + val = regs->gpr[rd]; + err = write_mem(val, xform_ea(instr, regs, u), 1, regs); + goto ldst_done; + + case 279: /* lhzx */ + case 311: /* lhzux */ + err = read_mem(®s->gpr[rd], xform_ea(instr, regs, u), + 2, regs); + goto ldst_done; + +#ifdef __powerpc64__ + case 341: /* lwax */ + case 373: /* lwaux */ + err = read_mem(®s->gpr[rd], xform_ea(instr, regs, u), + 4, regs); + if (!err) + regs->gpr[rd] = (signed int) regs->gpr[rd]; + goto ldst_done; +#endif + + case 343: /* lhax */ + case 375: /* lhaux */ + err = read_mem(®s->gpr[rd], xform_ea(instr, regs, u), + 2, regs); + if (!err) + regs->gpr[rd] = (signed short) regs->gpr[rd]; + goto ldst_done; + + case 407: /* sthx */ + case 439: /* sthux */ + val = regs->gpr[rd]; + err = write_mem(val, xform_ea(instr, regs, u), 2, regs); + goto ldst_done; + +#ifdef __powerpc64__ + case 532: /* ldbrx */ + err = read_mem(&val, xform_ea(instr, regs, 0), 8, regs); + if (!err) + regs->gpr[rd] = byterev_8(val); + goto ldst_done; + +#endif + + case 534: /* lwbrx */ + err = read_mem(&val, xform_ea(instr, regs, 0), 4, regs); + if (!err) + regs->gpr[rd] = byterev_4(val); + goto ldst_done; + + case 535: /* lfsx */ + case 567: /* lfsux */ + if (!(regs->msr & MSR_FP)) + break; + ea = xform_ea(instr, regs, u); + err = do_fp_load(rd, do_lfs, ea, 4, regs); + goto ldst_done; + + case 599: /* lfdx */ + case 631: /* lfdux */ + if (!(regs->msr & MSR_FP)) + break; + ea = xform_ea(instr, regs, u); + err = do_fp_load(rd, do_lfd, ea, 8, regs); + goto ldst_done; + + case 663: /* stfsx */ + case 695: /* stfsux */ + if (!(regs->msr & MSR_FP)) + break; + ea = xform_ea(instr, regs, u); + err = do_fp_store(rd, do_stfs, ea, 4, regs); + goto ldst_done; + + case 727: /* stfdx */ + case 759: /* stfdux */ + if (!(regs->msr & MSR_FP)) + break; + ea = xform_ea(instr, regs, u); + err = do_fp_store(rd, do_stfd, ea, 8, regs); + goto ldst_done; + +#ifdef __powerpc64__ + case 660: /* stdbrx */ + val = byterev_8(regs->gpr[rd]); + err = write_mem(val, xform_ea(instr, regs, 0), 8, regs); + goto ldst_done; + +#endif + case 662: /* stwbrx */ + val = byterev_4(regs->gpr[rd]); + err = write_mem(val, xform_ea(instr, regs, 0), 4, regs); + goto ldst_done; + + case 790: /* lhbrx */ + err = read_mem(&val, xform_ea(instr, regs, 0), 2, regs); + if (!err) + regs->gpr[rd] = byterev_2(val); + goto ldst_done; + + case 918: /* sthbrx */ + val = byterev_2(regs->gpr[rd]); + err = write_mem(val, xform_ea(instr, regs, 0), 2, regs); + goto ldst_done; + +#ifdef CONFIG_VSX + case 844: /* lxvd2x */ + case 876: /* lxvd2ux */ + if (!(regs->msr & MSR_VSX)) + break; + rd |= (instr & 1) << 5; + ea = xform_ea(instr, regs, u); + err = do_vsx_load(rd, do_lxvd2x, ea, regs); + goto ldst_done; + + case 972: /* stxvd2x */ + case 1004: /* stxvd2ux */ + if (!(regs->msr & MSR_VSX)) + break; + rd |= (instr & 1) << 5; + ea = xform_ea(instr, regs, u); + err = do_vsx_store(rd, do_stxvd2x, ea, regs); + goto ldst_done; + +#endif /* CONFIG_VSX */ + } + break; + + case 32: /* lwz */ + case 33: /* lwzu */ + err = read_mem(®s->gpr[rd], dform_ea(instr, regs), 4, regs); + goto ldst_done; + + case 34: /* lbz */ + case 35: /* lbzu */ + err = read_mem(®s->gpr[rd], dform_ea(instr, regs), 1, regs); + goto ldst_done; + + case 36: /* stw */ + case 37: /* stwu */ + val = regs->gpr[rd]; + err = write_mem(val, dform_ea(instr, regs), 4, regs); + goto ldst_done; + + case 38: /* stb */ + case 39: /* stbu */ + val = regs->gpr[rd]; + err = write_mem(val, dform_ea(instr, regs), 1, regs); + goto ldst_done; + + case 40: /* lhz */ + case 41: /* lhzu */ + err = read_mem(®s->gpr[rd], dform_ea(instr, regs), 2, regs); + goto ldst_done; + + case 42: /* lha */ + case 43: /* lhau */ + err = read_mem(®s->gpr[rd], dform_ea(instr, regs), 2, regs); + if (!err) + regs->gpr[rd] = (signed short) regs->gpr[rd]; + goto ldst_done; + + case 44: /* sth */ + case 45: /* sthu */ + val = regs->gpr[rd]; + err = write_mem(val, dform_ea(instr, regs), 2, regs); + goto ldst_done; + + case 46: /* lmw */ + ra = (instr >> 16) & 0x1f; + if (ra >= rd) + break; /* invalid form, ra in range to load */ + ea = dform_ea(instr, regs); + do { + err = read_mem(®s->gpr[rd], ea, 4, regs); + if (err) + return 0; + ea += 4; + } while (++rd < 32); + goto instr_done; + + case 47: /* stmw */ + ea = dform_ea(instr, regs); + do { + err = write_mem(regs->gpr[rd], ea, 4, regs); + if (err) + return 0; + ea += 4; + } while (++rd < 32); + goto instr_done; + + case 48: /* lfs */ + case 49: /* lfsu */ + if (!(regs->msr & MSR_FP)) + break; + ea = dform_ea(instr, regs); + err = do_fp_load(rd, do_lfs, ea, 4, regs); + goto ldst_done; + + case 50: /* lfd */ + case 51: /* lfdu */ + if (!(regs->msr & MSR_FP)) + break; + ea = dform_ea(instr, regs); + err = do_fp_load(rd, do_lfd, ea, 8, regs); + goto ldst_done; + + case 52: /* stfs */ + case 53: /* stfsu */ + if (!(regs->msr & MSR_FP)) + break; + ea = dform_ea(instr, regs); + err = do_fp_store(rd, do_stfs, ea, 4, regs); + goto ldst_done; + + case 54: /* stfd */ + case 55: /* stfdu */ + if (!(regs->msr & MSR_FP)) + break; + ea = dform_ea(instr, regs); + err = do_fp_store(rd, do_stfd, ea, 8, regs); + goto ldst_done; + +#ifdef __powerpc64__ + case 58: /* ld[u], lwa */ + switch (instr & 3) { + case 0: /* ld */ + err = read_mem(®s->gpr[rd], dsform_ea(instr, regs), + 8, regs); + goto ldst_done; + case 1: /* ldu */ + err = read_mem(®s->gpr[rd], dsform_ea(instr, regs), + 8, regs); + goto ldst_done; + case 2: /* lwa */ + err = read_mem(®s->gpr[rd], dsform_ea(instr, regs), + 4, regs); + if (!err) + regs->gpr[rd] = (signed int) regs->gpr[rd]; + goto ldst_done; + } + break; + + case 62: /* std[u] */ + val = regs->gpr[rd]; + switch (instr & 3) { + case 0: /* std */ + err = write_mem(val, dsform_ea(instr, regs), 8, regs); + goto ldst_done; + case 1: /* stdu */ + err = write_mem(val, dsform_ea(instr, regs), 8, regs); + goto ldst_done; + } + break; +#endif /* __powerpc64__ */ + + } + err = -EINVAL; + + ldst_done: + if (err) { + regs->gpr[ra] = old_ra; + return 0; /* invoke DSI if -EFAULT? */ + } + instr_done: + regs->nip += 4; +#ifdef __powerpc64__ + if ((regs->msr & MSR_SF) == 0) + regs->nip &= 0xffffffffUL; +#endif + return 1; + + logical_done: + if (instr & 1) + set_cr0(regs, ra); + goto instr_done; + + arith_done: + if (instr & 1) + set_cr0(regs, rd); + goto instr_done; } -- cgit v1.2.3 From 5aae8a53708025d4e718f0d2e7c2f766779ddc71 Mon Sep 17 00:00:00 2001 From: "K.Prasad" Date: Tue, 15 Jun 2010 11:35:19 +0530 Subject: powerpc, hw_breakpoints: Implement hw_breakpoints for 64-bit server processors Implement perf-events based hw-breakpoint interfaces for PowerPC 64-bit server (Book III S) processors. This allows access to a given location to be used as an event that can be counted or profiled by the perf_events subsystem. This is done using the DABR (data breakpoint register), which can also be used for process debugging via ptrace. When perf_event hw_breakpoint support is configured in, the perf_event subsystem manages the DABR and arbitrates access to it, and ptrace then creates a perf_event when it is requested to set a data breakpoint. [Adopted suggestions from Paul Mackerras to - emulate_step() all system-wide breakpoints and single-step only the per-task breakpoints - perform arch-specific cleanup before unregistration through arch_unregister_hw_breakpoint() ] Signed-off-by: K.Prasad Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 1 + arch/powerpc/include/asm/cputable.h | 4 + arch/powerpc/include/asm/hw_breakpoint.h | 73 +++++++ arch/powerpc/include/asm/processor.h | 8 + arch/powerpc/kernel/Makefile | 1 + arch/powerpc/kernel/exceptions-64s.S | 1 + arch/powerpc/kernel/hw_breakpoint.c | 325 +++++++++++++++++++++++++++++++ arch/powerpc/kernel/machine_kexec_64.c | 3 + arch/powerpc/kernel/process.c | 14 ++ arch/powerpc/kernel/ptrace.c | 64 ++++++ arch/powerpc/lib/Makefile | 1 + 11 files changed, 495 insertions(+) create mode 100644 arch/powerpc/include/asm/hw_breakpoint.h create mode 100644 arch/powerpc/kernel/hw_breakpoint.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 328774bd41ee..7949afc861dd 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -141,6 +141,7 @@ config PPC select GENERIC_ATOMIC64 if PPC32 select HAVE_PERF_EVENTS select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64 config EARLY_PRINTK bool diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index b0b21134f61a..5e2e2cfcc81b 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -517,6 +517,10 @@ static inline int cpu_has_feature(unsigned long feature) & feature); } +#ifdef CONFIG_HAVE_HW_BREAKPOINT +#define HBP_NUM 1 +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ + #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h new file mode 100644 index 000000000000..b111713b593e --- /dev/null +++ b/arch/powerpc/include/asm/hw_breakpoint.h @@ -0,0 +1,73 @@ +/* + * PowerPC BookIII S hardware breakpoint definitions + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2010, IBM Corporation. + * Author: K.Prasad + * + */ + +#ifndef _PPC_BOOK3S_64_HW_BREAKPOINT_H +#define _PPC_BOOK3S_64_HW_BREAKPOINT_H + +#ifdef __KERNEL__ +#ifdef CONFIG_HAVE_HW_BREAKPOINT + +struct arch_hw_breakpoint { + u8 len; /* length of the target data symbol */ + int type; + unsigned long address; +}; + +#include +#include +#include + +static inline int hw_breakpoint_slots(int type) +{ + return HBP_NUM; +} +struct perf_event; +struct pmu; +struct perf_sample_data; + +#define HW_BREAKPOINT_ALIGN 0x7 +/* Maximum permissible length of any HW Breakpoint */ +#define HW_BREAKPOINT_LEN 0x8 + +extern int arch_bp_generic_fields(int type, int *gen_bp_type); +extern int arch_check_bp_in_kernelspace(struct perf_event *bp); +extern int arch_validate_hwbkpt_settings(struct perf_event *bp); +extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, + unsigned long val, void *data); +int arch_install_hw_breakpoint(struct perf_event *bp); +void arch_uninstall_hw_breakpoint(struct perf_event *bp); +void hw_breakpoint_pmu_read(struct perf_event *bp); +extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk); + +extern struct pmu perf_ops_bp; +extern void ptrace_triggered(struct perf_event *bp, int nmi, + struct perf_sample_data *data, struct pt_regs *regs); +static inline void hw_breakpoint_disable(void) +{ + set_dabr(0); +} + +#else /* CONFIG_HAVE_HW_BREAKPOINT */ +static inline void hw_breakpoint_disable(void) { } +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ +#endif /* __KERNEL__ */ +#endif /* _PPC_BOOK3S_64_HW_BREAKPOINT_H */ diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 7492fe8ad6e4..19c05b0f74be 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -209,6 +209,14 @@ struct thread_struct { #ifdef CONFIG_PPC64 unsigned long start_tb; /* Start purr when proc switched in */ unsigned long accum_tb; /* Total accumilated purr for process */ +#ifdef CONFIG_HAVE_HW_BREAKPOINT + struct perf_event *ptrace_bps[HBP_NUM]; + /* + * Helps identify source of single-step exception and subsequent + * hw-breakpoint enablement + */ + struct perf_event *last_hit_ubp; +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif unsigned long dabr; /* Data address breakpoint register */ #ifdef CONFIG_ALTIVEC diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 58d0572de6f9..01006040f59e 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -34,6 +34,7 @@ obj-y += vdso32/ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ signal_64.o ptrace32.o \ paca.o nvram_64.o firmware.o +obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 3e423fbad6bc..f53029a01554 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -828,6 +828,7 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) /* We have a data breakpoint exception - handle it */ handle_dabr_fault: + bl .save_nvgprs ld r4,_DAR(r1) ld r5,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c new file mode 100644 index 000000000000..7a2ad5e84c16 --- /dev/null +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -0,0 +1,325 @@ +/* + * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility, + * using the CPU's debug registers. Derived from + * "arch/x86/kernel/hw_breakpoint.c" + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2010 IBM Corporation + * Author: K.Prasad + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Stores the breakpoints currently in use on each breakpoint address + * register for every cpu + */ +static DEFINE_PER_CPU(struct perf_event *, bp_per_reg); + +/* + * Install a perf counter breakpoint. + * + * We seek a free debug address register and use it for this + * breakpoint. + * + * Atomic: we hold the counter->ctx->lock and we only handle variables + * and registers local to this cpu. + */ +int arch_install_hw_breakpoint(struct perf_event *bp) +{ + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + struct perf_event **slot = &__get_cpu_var(bp_per_reg); + + *slot = bp; + + /* + * Do not install DABR values if the instruction must be single-stepped. + * If so, DABR will be populated in single_step_dabr_instruction(). + */ + if (current->thread.last_hit_ubp != bp) + set_dabr(info->address | info->type | DABR_TRANSLATION); + + return 0; +} + +/* + * Uninstall the breakpoint contained in the given counter. + * + * First we search the debug address register it uses and then we disable + * it. + * + * Atomic: we hold the counter->ctx->lock and we only handle variables + * and registers local to this cpu. + */ +void arch_uninstall_hw_breakpoint(struct perf_event *bp) +{ + struct perf_event **slot = &__get_cpu_var(bp_per_reg); + + if (*slot != bp) { + WARN_ONCE(1, "Can't find the breakpoint"); + return; + } + + *slot = NULL; + set_dabr(0); +} + +/* + * Perform cleanup of arch-specific counters during unregistration + * of the perf-event + */ +void arch_unregister_hw_breakpoint(struct perf_event *bp) +{ + /* + * If the breakpoint is unregistered between a hw_breakpoint_handler() + * and the single_step_dabr_instruction(), then cleanup the breakpoint + * restoration variables to prevent dangling pointers. + */ + if (bp->ctx->task) + bp->ctx->task->thread.last_hit_ubp = NULL; +} + +/* + * Check for virtual address in kernel space. + */ +int arch_check_bp_in_kernelspace(struct perf_event *bp) +{ + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + + return is_kernel_addr(info->address); +} + +int arch_bp_generic_fields(int type, int *gen_bp_type) +{ + switch (type) { + case DABR_DATA_READ: + *gen_bp_type = HW_BREAKPOINT_R; + break; + case DABR_DATA_WRITE: + *gen_bp_type = HW_BREAKPOINT_W; + break; + case (DABR_DATA_WRITE | DABR_DATA_READ): + *gen_bp_type = (HW_BREAKPOINT_W | HW_BREAKPOINT_R); + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * Validate the arch-specific HW Breakpoint register settings + */ +int arch_validate_hwbkpt_settings(struct perf_event *bp) +{ + int ret = -EINVAL; + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + + if (!bp) + return ret; + + switch (bp->attr.bp_type) { + case HW_BREAKPOINT_R: + info->type = DABR_DATA_READ; + break; + case HW_BREAKPOINT_W: + info->type = DABR_DATA_WRITE; + break; + case HW_BREAKPOINT_R | HW_BREAKPOINT_W: + info->type = (DABR_DATA_READ | DABR_DATA_WRITE); + break; + default: + return ret; + } + + info->address = bp->attr.bp_addr; + info->len = bp->attr.bp_len; + + /* + * Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8) + * and breakpoint addresses are aligned to nearest double-word + * HW_BREAKPOINT_ALIGN by rounding off to the lower address, the + * 'symbolsize' should satisfy the check below. + */ + if (info->len > + (HW_BREAKPOINT_LEN - (info->address & HW_BREAKPOINT_ALIGN))) + return -EINVAL; + return 0; +} + +/* + * Handle debug exception notifications. + */ +int __kprobes hw_breakpoint_handler(struct die_args *args) +{ + bool is_ptrace_bp = false; + int rc = NOTIFY_STOP; + struct perf_event *bp; + struct pt_regs *regs = args->regs; + int stepped = 1; + struct arch_hw_breakpoint *info; + unsigned int instr; + + /* Disable breakpoints during exception handling */ + set_dabr(0); + /* + * The counter may be concurrently released but that can only + * occur from a call_rcu() path. We can then safely fetch + * the breakpoint, use its callback, touch its counter + * while we are in an rcu_read_lock() path. + */ + rcu_read_lock(); + + bp = __get_cpu_var(bp_per_reg); + if (!bp) + goto out; + info = counter_arch_bp(bp); + is_ptrace_bp = (bp->overflow_handler == ptrace_triggered) ? + true : false; + + /* + * Return early after invoking user-callback function without restoring + * DABR if the breakpoint is from ptrace which always operates in + * one-shot mode. The ptrace-ed process will receive the SIGTRAP signal + * generated in do_dabr(). + */ + if (is_ptrace_bp) { + perf_bp_event(bp, regs); + rc = NOTIFY_DONE; + goto out; + } + + /* Do not emulate user-space instructions, instead single-step them */ + if (user_mode(regs)) { + bp->ctx->task->thread.last_hit_ubp = bp; + regs->msr |= MSR_SE; + goto out; + } + + stepped = 0; + instr = 0; + if (!__get_user_inatomic(instr, (unsigned int *) regs->nip)) + stepped = emulate_step(regs, instr); + + /* + * emulate_step() could not execute it. We've failed in reliably + * handling the hw-breakpoint. Unregister it and throw a warning + * message to let the user know about it. + */ + if (!stepped) { + WARN(1, "Unable to handle hardware breakpoint. Breakpoint at " + "0x%lx will be disabled.", info->address); + perf_event_disable(bp); + goto out; + } + /* + * As a policy, the callback is invoked in a 'trigger-after-execute' + * fashion + */ + perf_bp_event(bp, regs); + + set_dabr(info->address | info->type | DABR_TRANSLATION); +out: + rcu_read_unlock(); + return rc; +} + +/* + * Handle single-step exceptions following a DABR hit. + */ +int __kprobes single_step_dabr_instruction(struct die_args *args) +{ + struct pt_regs *regs = args->regs; + struct perf_event *bp = NULL; + struct arch_hw_breakpoint *bp_info; + + bp = current->thread.last_hit_ubp; + /* + * Check if we are single-stepping as a result of a + * previous HW Breakpoint exception + */ + if (!bp) + return NOTIFY_DONE; + + bp_info = counter_arch_bp(bp); + + /* + * We shall invoke the user-defined callback function in the single + * stepping handler to confirm to 'trigger-after-execute' semantics + */ + perf_bp_event(bp, regs); + + /* + * Do not disable MSR_SE if the process was already in + * single-stepping mode. + */ + if (!test_thread_flag(TIF_SINGLESTEP)) + regs->msr &= ~MSR_SE; + + set_dabr(bp_info->address | bp_info->type | DABR_TRANSLATION); + current->thread.last_hit_ubp = NULL; + return NOTIFY_STOP; +} + +/* + * Handle debug exception notifications. + */ +int __kprobes hw_breakpoint_exceptions_notify( + struct notifier_block *unused, unsigned long val, void *data) +{ + int ret = NOTIFY_DONE; + + switch (val) { + case DIE_DABR_MATCH: + ret = hw_breakpoint_handler(data); + break; + case DIE_SSTEP: + ret = single_step_dabr_instruction(data); + break; + } + + return ret; +} + +/* + * Release the user breakpoints used by ptrace + */ +void flush_ptrace_hw_breakpoint(struct task_struct *tsk) +{ + struct thread_struct *t = &tsk->thread; + + unregister_hw_breakpoint(t->ptrace_bps[0]); + t->ptrace_bps[0] = NULL; +} + +void hw_breakpoint_pmu_read(struct perf_event *bp) +{ + /* TODO */ +} diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 26f9900f773c..6c7c546aa1be 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -25,6 +25,7 @@ #include /* _end */ #include #include +#include int default_machine_kexec_prepare(struct kimage *image) { @@ -165,6 +166,7 @@ static void kexec_smp_down(void *arg) while(kexec_all_irq_disabled == 0) cpu_relax(); mb(); /* make sure all irqs are disabled before this */ + hw_breakpoint_disable(); /* * Now every CPU has IRQs off, we can clear out any pending * IPIs and be sure that no more will come in after this. @@ -180,6 +182,7 @@ static void kexec_prepare_cpus_wait(int wait_state) { int my_cpu, i, notified=-1; + hw_breakpoint_disable(); my_cpu = get_cpu(); /* Make sure each CPU has atleast made it to the state we need */ for (i=0; i < NR_CPUS; i++) { diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 9d255b4f0a0e..cbf3521d50b6 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -462,8 +463,14 @@ struct task_struct *__switch_to(struct task_struct *prev, #ifdef CONFIG_PPC_ADV_DEBUG_REGS switch_booke_debug_regs(&new->thread); #else +/* + * For PPC_BOOK3S_64, we use the hw-breakpoint interfaces that would + * schedule DABR + */ +#ifndef CONFIG_HAVE_HW_BREAKPOINT if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) set_dabr(new->thread.dabr); +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif @@ -642,7 +649,11 @@ void flush_thread(void) { discard_lazy_cpu_state(); +#ifdef CONFIG_HAVE_HW_BREAKPOINTS + flush_ptrace_hw_breakpoint(current); +#else /* CONFIG_HAVE_HW_BREAKPOINTS */ set_debug_reg_defaults(¤t->thread); +#endif /* CONFIG_HAVE_HW_BREAKPOINTS */ } void @@ -660,6 +671,9 @@ void prepare_to_copy(struct task_struct *tsk) flush_altivec_to_thread(current); flush_vsx_to_thread(current); flush_spe_to_thread(current); +#ifdef CONFIG_HAVE_HW_BREAKPOINT + flush_ptrace_hw_breakpoint(tsk); +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ } /* diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 7a0c0199ea28..11f3cd9c832f 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -32,6 +32,8 @@ #ifdef CONFIG_PPC32 #include #endif +#include +#include #include #include @@ -866,9 +868,34 @@ void user_disable_single_step(struct task_struct *task) clear_tsk_thread_flag(task, TIF_SINGLESTEP); } +#ifdef CONFIG_HAVE_HW_BREAKPOINT +void ptrace_triggered(struct perf_event *bp, int nmi, + struct perf_sample_data *data, struct pt_regs *regs) +{ + struct perf_event_attr attr; + + /* + * Disable the breakpoint request here since ptrace has defined a + * one-shot behaviour for breakpoint exceptions in PPC64. + * The SIGTRAP signal is generated automatically for us in do_dabr(). + * We don't have to do anything about that here + */ + attr = bp->attr; + attr.disabled = true; + modify_user_hw_breakpoint(bp, &attr); +} +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ + int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned long data) { +#ifdef CONFIG_HAVE_HW_BREAKPOINT + int ret; + struct thread_struct *thread = &(task->thread); + struct perf_event *bp; + struct perf_event_attr attr; +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ + /* For ppc64 we support one DABR and no IABR's at the moment (ppc64). * For embedded processors we support one DAC and no IAC's at the * moment. @@ -896,6 +923,43 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, /* Ensure breakpoint translation bit is set */ if (data && !(data & DABR_TRANSLATION)) return -EIO; +#ifdef CONFIG_HAVE_HW_BREAKPOINT + bp = thread->ptrace_bps[0]; + if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) { + if (bp) { + unregister_hw_breakpoint(bp); + thread->ptrace_bps[0] = NULL; + } + return 0; + } + if (bp) { + attr = bp->attr; + attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN; + arch_bp_generic_fields(data & + (DABR_DATA_WRITE | DABR_DATA_READ), + &attr.bp_type); + ret = modify_user_hw_breakpoint(bp, &attr); + if (ret) + return ret; + thread->ptrace_bps[0] = bp; + thread->dabr = data; + return 0; + } + + /* Create a new breakpoint request if one doesn't exist already */ + hw_breakpoint_init(&attr); + attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN; + arch_bp_generic_fields(data & (DABR_DATA_WRITE | DABR_DATA_READ), + &attr.bp_type); + + thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr, + ptrace_triggered, task); + if (IS_ERR(bp)) { + thread->ptrace_bps[0] = NULL; + return PTR_ERR(bp); + } + +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ /* Move contents to the DABR register */ task->thread.dabr = data; diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 7581dbffa18e..a52ed2e47ac6 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ memcpy_64.o usercopy_64.o mem_64.o string.o obj-$(CONFIG_XMON) += sstep.o ldstfp.o obj-$(CONFIG_KPROBES) += sstep.o ldstfp.o +obj-$(CONFIG_HAVE_HW_BREAKPOINT) += sstep.o ldstfp.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o -- cgit v1.2.3 From 2538c2d08f46141550a1e68819efa8fe31c6e3dc Mon Sep 17 00:00:00 2001 From: "K.Prasad" Date: Tue, 15 Jun 2010 11:35:31 +0530 Subject: powerpc, hw_breakpoint: Handle concurrent alignment interrupts If an alignment interrupt occurs on an instruction that is being single-stepped, the alignment interrupt handler currently handles the single-step condition by unconditionally sending a SIGTRAP to the process. Other synchronous interrupts that result in the instruction being emulated do likewise. With hw_breakpoint support, the hw_breakpoint code needs to be able to intercept these single-step events as well as those where the instruction executes normally and a trace interrupt happens. Fix this by making emulate_single_step() use the existing single_step_exception() function instead of calling _exception() directly. We then make single_step_exception() use the abstracted clear_single_step() rather than clearing bits in the MSR image directly so that emulate_single_step() will continue to work correctly on Book 3E processors. Signed-off-by: K.Prasad Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/traps.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 25fc33984c2b..e5fe5a8522a6 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -688,7 +688,7 @@ void RunModeException(struct pt_regs *regs) void __kprobes single_step_exception(struct pt_regs *regs) { - regs->msr &= ~(MSR_SE | MSR_BE); /* Turn off 'trace' bits */ + clear_single_step(regs); if (notify_die(DIE_SSTEP, "single_step", regs, 5, 5, SIGTRAP) == NOTIFY_STOP) @@ -707,10 +707,8 @@ void __kprobes single_step_exception(struct pt_regs *regs) */ static void emulate_single_step(struct pt_regs *regs) { - if (single_stepping(regs)) { - clear_single_step(regs); - _exception(SIGTRAP, regs, TRAP_TRACE, 0); - } + if (single_stepping(regs)) + single_step_exception(regs); } static inline int __parse_fpscr(unsigned long fpscr) -- cgit v1.2.3 From 06532a6743d83fac4b79389fc8c86c88cb4e3302 Mon Sep 17 00:00:00 2001 From: "K.Prasad" Date: Tue, 15 Jun 2010 11:35:41 +0530 Subject: powerpc, hw_breakpoint: Enable hw-breakpoints while handling intervening signals A signal delivered between a hw_breakpoint_handler() and the single_step_dabr_instruction() will not have the breakpoint active while the signal handler is running -- the signal delivery will set up a new MSR value which will not have MSR_SE set, so we won't get the signal step interrupt until and unless the signal handler returns (which it may never do). To fix this, we restore the breakpoint when delivering a signal -- we clear the MSR_SE bit and set the DABR again. If the signal handler returns, the DABR interrupt will occur again when the instruction that we were originally trying to single-step gets re-executed. [Paul Mackerras pointed out the need to do this.] Signed-off-by: K.Prasad Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/hw_breakpoint.h | 3 +++ arch/powerpc/kernel/hw_breakpoint.c | 18 ++++++++++++++++++ arch/powerpc/kernel/signal.c | 3 +++ 3 files changed, 24 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h index b111713b593e..6576bad1069c 100644 --- a/arch/powerpc/include/asm/hw_breakpoint.h +++ b/arch/powerpc/include/asm/hw_breakpoint.h @@ -65,9 +65,12 @@ static inline void hw_breakpoint_disable(void) { set_dabr(0); } +extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs); #else /* CONFIG_HAVE_HW_BREAKPOINT */ static inline void hw_breakpoint_disable(void) { } +static inline void thread_change_pc(struct task_struct *tsk, + struct pt_regs *regs) { } #endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif /* __KERNEL__ */ #endif /* _PPC_BOOK3S_64_HW_BREAKPOINT_H */ diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 7a2ad5e84c16..7bd01a56d194 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -174,6 +174,24 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) return 0; } +/* + * Restores the breakpoint on the debug registers. + * Invoke this function if it is known that the execution context is + * about to change to cause loss of MSR_SE settings. + */ +void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs) +{ + struct arch_hw_breakpoint *info; + + if (likely(!tsk->thread.last_hit_ubp)) + return; + + info = counter_arch_bp(tsk->thread.last_hit_ubp); + regs->msr &= ~MSR_SE; + set_dabr(info->address | info->type | DABR_TRANSLATION); + tsk->thread.last_hit_ubp = NULL; +} + /* * Handle debug exception notifications. */ diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index a0afb555a7c9..7109f5b1baa8 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -149,6 +150,8 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs) if (current->thread.dabr) set_dabr(current->thread.dabr); #endif + /* Re-enable the breakpoints for the signal stack */ + thread_change_pc(current, regs); if (is32) { if (ka.sa.sa_flags & SA_SIGINFO) -- cgit v1.2.3 From e3e94084adb5610987283367574ebc771e8206e1 Mon Sep 17 00:00:00 2001 From: "K.Prasad" Date: Tue, 15 Jun 2010 11:36:12 +0530 Subject: powerpc, hw_breakpoint: Discard extraneous interrupt due to accesses outside symbol length Many a times, the requested breakpoint length can be less than the fixed breakpoint length i.e. 8 bytes supported by PowerPC 64-bit server (Book III S) processors. This could lead to extraneous interrupts resulting in false breakpoint notifications. This detects and discards such interrupts for non-ptrace requests. We don't change ptrace behaviour to avoid breaking compatability. [Suggestion from Paul Mackerras to add a new flag in 'struct arch_hw_breakpoint' to identify extraneous interrupts] Signed-off-by: K.Prasad Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/hw_breakpoint.h | 1 + arch/powerpc/kernel/hw_breakpoint.c | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h index 6576bad1069c..ea87f8ae7bdb 100644 --- a/arch/powerpc/include/asm/hw_breakpoint.h +++ b/arch/powerpc/include/asm/hw_breakpoint.h @@ -27,6 +27,7 @@ #ifdef CONFIG_HAVE_HW_BREAKPOINT struct arch_hw_breakpoint { + bool extraneous_interrupt; u8 len; /* length of the target data symbol */ int type; unsigned long address; diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 7bd01a56d194..ed39805a3b84 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -204,6 +204,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) int stepped = 1; struct arch_hw_breakpoint *info; unsigned int instr; + unsigned long dar = regs->dar; /* Disable breakpoints during exception handling */ set_dabr(0); @@ -234,6 +235,22 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) goto out; } + /* + * Verify if dar lies within the address range occupied by the symbol + * being watched to filter extraneous exceptions. + */ + if (!((bp->attr.bp_addr <= dar) && + (dar <= (bp->attr.bp_addr + bp->attr.bp_len)))) { + /* + * This exception is triggered not because of a memory access + * on the monitored variable but in the double-word address + * range in which it is contained. We will consume this + * exception, considering it as 'noise'. + */ + info->extraneous_interrupt = true; + } else + info->extraneous_interrupt = false; + /* Do not emulate user-space instructions, instead single-step them */ if (user_mode(regs)) { bp->ctx->task->thread.last_hit_ubp = bp; @@ -261,7 +278,8 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) * As a policy, the callback is invoked in a 'trigger-after-execute' * fashion */ - perf_bp_event(bp, regs); + if (!info->extraneous_interrupt) + perf_bp_event(bp, regs); set_dabr(info->address | info->type | DABR_TRANSLATION); out: @@ -292,7 +310,8 @@ int __kprobes single_step_dabr_instruction(struct die_args *args) * We shall invoke the user-defined callback function in the single * stepping handler to confirm to 'trigger-after-execute' semantics */ - perf_bp_event(bp, regs); + if (!bp_info->extraneous_interrupt) + perf_bp_event(bp, regs); /* * Do not disable MSR_SE if the process was already in -- cgit v1.2.3 From 574cb24899d35e71be1d8fb1add2c3306804e4bf Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 23 Jun 2010 15:42:43 +1000 Subject: powerpc, hw_breakpoint: Fix off-by-one in checking access address The code would accept an access to an address one byte past the end of the requested range as legitimate, due to having a "<=" rather than a "<". This fixes that and cleans up the code a bit. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/hw_breakpoint.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index ed39805a3b84..241e09712314 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -197,7 +197,6 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs) */ int __kprobes hw_breakpoint_handler(struct die_args *args) { - bool is_ptrace_bp = false; int rc = NOTIFY_STOP; struct perf_event *bp; struct pt_regs *regs = args->regs; @@ -208,6 +207,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) /* Disable breakpoints during exception handling */ set_dabr(0); + /* * The counter may be concurrently released but that can only * occur from a call_rcu() path. We can then safely fetch @@ -220,8 +220,6 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) if (!bp) goto out; info = counter_arch_bp(bp); - is_ptrace_bp = (bp->overflow_handler == ptrace_triggered) ? - true : false; /* * Return early after invoking user-callback function without restoring @@ -229,7 +227,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) * one-shot mode. The ptrace-ed process will receive the SIGTRAP signal * generated in do_dabr(). */ - if (is_ptrace_bp) { + if (bp->overflow_handler == ptrace_triggered) { perf_bp_event(bp, regs); rc = NOTIFY_DONE; goto out; @@ -237,19 +235,12 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) /* * Verify if dar lies within the address range occupied by the symbol - * being watched to filter extraneous exceptions. + * being watched to filter extraneous exceptions. If it doesn't, + * we still need to single-step the instruction, but we don't + * generate an event. */ - if (!((bp->attr.bp_addr <= dar) && - (dar <= (bp->attr.bp_addr + bp->attr.bp_len)))) { - /* - * This exception is triggered not because of a memory access - * on the monitored variable but in the double-word address - * range in which it is contained. We will consume this - * exception, considering it as 'noise'. - */ - info->extraneous_interrupt = true; - } else - info->extraneous_interrupt = false; + info->extraneous_interrupt = !((bp->attr.bp_addr <= dar) && + (dar - bp->attr.bp_addr < bp->attr.bp_len)); /* Do not emulate user-space instructions, instead single-step them */ if (user_mode(regs)) { -- cgit v1.2.3 From 76b0f1337690d223811c852ad3a5078eb89276c5 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 23 Jun 2010 15:46:55 +1000 Subject: powerpc, hw_breakpoint: Cooperate better with other single-steppers The code we had to clear the MSR_SE bit was not doing anything because the caller (ultimately single_step_exception() in traps.c) had already cleared. Instead of trying to leave MSR_SE set if the TIF_SINGLESTEP flag is set (which indicates that the process is being single-stepped by ptrace), we instead return NOTIFY_DONE in that case, which means the caller will generate a SIGTRAP for the process. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/hw_breakpoint.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 241e09712314..5a1d55d06a08 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -304,15 +304,16 @@ int __kprobes single_step_dabr_instruction(struct die_args *args) if (!bp_info->extraneous_interrupt) perf_bp_event(bp, regs); + set_dabr(bp_info->address | bp_info->type | DABR_TRANSLATION); + current->thread.last_hit_ubp = NULL; + /* - * Do not disable MSR_SE if the process was already in - * single-stepping mode. + * If the process was being single-stepped by ptrace, let the + * other single-step actions occur (e.g. generate SIGTRAP). */ - if (!test_thread_flag(TIF_SINGLESTEP)) - regs->msr &= ~MSR_SE; + if (test_thread_flag(TIF_SINGLESTEP)) + return NOTIFY_DONE; - set_dabr(bp_info->address | bp_info->type | DABR_TRANSLATION); - current->thread.last_hit_ubp = NULL; return NOTIFY_STOP; } -- cgit v1.2.3 From b505ff5e7291cca6379549297e3852ce3622d550 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 18 Jun 2010 11:09:59 -0600 Subject: of: kill struct of_device Now that the device tree node pointer has been moved out of struct of_device and into the common struct device, there isn't anything unique about of_device anymore. In fact, there isn't much need for a separate of_bus when all busses have access to OF style probing. arch/powerpc and arch/microblaze are moving away from using the of_bus and using the regular platform bus instead for mmio devices. This patch makes of_device the same as platform_device as a stepping stone in migrating of_platform_drivers over to the platform bus. Signed-off-by: Grant Likely Acked-by: David S. Miller Cc: Michal Simek Cc: Benjamin Herrenschmidt Cc: Stephen Rothwell --- arch/microblaze/include/asm/of_device.h | 10 ---------- arch/powerpc/include/asm/of_device.h | 11 ----------- arch/powerpc/include/asm/smu.h | 4 ++-- arch/sparc/include/asm/device.h | 4 ++-- arch/sparc/include/asm/of_device.h | 14 -------------- drivers/net/niu.h | 4 ++-- include/linux/of_device.h | 17 +++++++++++++++++ 7 files changed, 23 insertions(+), 41 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/of_device.h b/arch/microblaze/include/asm/of_device.h index 73cb98040982..0a5f3f914b42 100644 --- a/arch/microblaze/include/asm/of_device.h +++ b/arch/microblaze/include/asm/of_device.h @@ -15,16 +15,6 @@ #include #include -/* - * 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 dev; /* Generic device interface */ - struct pdev_archdata archdata; -}; - extern ssize_t of_device_get_modalias(struct of_device *ofdev, char *str, ssize_t len); diff --git a/arch/powerpc/include/asm/of_device.h b/arch/powerpc/include/asm/of_device.h index 444e97e2982e..cb36632f953c 100644 --- a/arch/powerpc/include/asm/of_device.h +++ b/arch/powerpc/include/asm/of_device.h @@ -5,17 +5,6 @@ #include #include -/* - * 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 dev; /* Generic device interface */ - struct pdev_archdata archdata; -}; - extern struct of_device *of_device_alloc(struct device_node *np, const char *bus_id, struct device *parent); diff --git a/arch/powerpc/include/asm/smu.h b/arch/powerpc/include/asm/smu.h index 7ae2753da565..e3bdada8c542 100644 --- a/arch/powerpc/include/asm/smu.h +++ b/arch/powerpc/include/asm/smu.h @@ -457,8 +457,8 @@ extern void smu_poll(void); */ extern int smu_init(void); extern int smu_present(void); -struct of_device; -extern struct of_device *smu_get_ofdev(void); +struct platform_device; +extern struct platform_device *smu_get_ofdev(void); /* diff --git a/arch/sparc/include/asm/device.h b/arch/sparc/include/asm/device.h index f9740d065fe7..fb220e482039 100644 --- a/arch/sparc/include/asm/device.h +++ b/arch/sparc/include/asm/device.h @@ -9,13 +9,13 @@ #include struct device_node; -struct of_device; +struct platform_device; struct dev_archdata { void *iommu; void *stc; void *host_controller; - struct of_device *op; + struct platform_device *op; int numa_node; }; diff --git a/arch/sparc/include/asm/of_device.h b/arch/sparc/include/asm/of_device.h index 6d1844a547b4..22b9828fe693 100644 --- a/arch/sparc/include/asm/of_device.h +++ b/arch/sparc/include/asm/of_device.h @@ -7,20 +7,6 @@ #include #include -/* - * 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 dev; - u32 num_resources; - struct resource *resource; - - struct pdev_archdata archdata; -}; - extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size); diff --git a/drivers/net/niu.h b/drivers/net/niu.h index d6715465f35d..a41fa8ebe05f 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -3236,7 +3236,7 @@ struct niu_phy_ops { int (*link_status)(struct niu *np, int *); }; -struct of_device; +struct platform_device; struct niu { void __iomem *regs; struct net_device *dev; @@ -3297,7 +3297,7 @@ struct niu { struct niu_vpd vpd; u32 eeprom_len; - struct of_device *op; + struct platform_device *op; void __iomem *vir_regs_1; void __iomem *vir_regs_2; }; diff --git a/include/linux/of_device.h b/include/linux/of_device.h index 11651facc5f1..a3ae5900fc58 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -3,9 +3,26 @@ #ifdef CONFIG_OF_DEVICE #include +#include #include #include + +/* + * The of_device *was* a kind of "base class" that was a superset of + * struct device for use by devices attached to an OF node and probed + * using OF properties. However, the important bit of OF-style + * probing, namely the device node pointer, has been moved into the + * common struct device when CONFIG_OF is set to make OF-style probing + * available to all bus types. So now, just make of_device and + * platform_device equivalent so that current of_platform bus users + * can be transparently migrated over to using the platform bus. + * + * This line will go away once all references to of_device are removed + * from the kernel. + */ +#define of_device platform_device + #include #define to_of_device(d) container_of(d, struct of_device, dev) -- cgit v1.2.3 From e3873444990dd6f8a095d1f72b5ad45192f8c506 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 18 Jun 2010 11:09:59 -0600 Subject: of/irq: Move irq_of_parse_and_map() to common code Merge common code between PowerPC and Microblaze. SPARC implements irq_of_parse_and_map(), but the implementation is different, so it does not use this code. Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Cc: Michal Simek Cc: "David S. Miller" Cc: Stephen Rothwell Cc: Jeremy Kerr --- arch/microblaze/include/asm/irq.h | 24 -------------------- arch/microblaze/include/asm/prom.h | 26 +--------------------- arch/microblaze/kernel/irq.c | 14 ++---------- arch/powerpc/include/asm/irq.h | 28 ------------------------ arch/powerpc/include/asm/prom.h | 27 +---------------------- arch/powerpc/kernel/irq.c | 14 ++---------- arch/sparc/include/asm/prom.h | 1 - drivers/of/Kconfig | 4 ++++ drivers/of/Makefile | 1 + drivers/of/irq.c | 45 ++++++++++++++++++++++++++++++++++++++ drivers/of/of_mdio.c | 1 + drivers/of/of_spi.c | 1 + include/linux/of_irq.h | 41 ++++++++++++++++++++++++++++++++++ 13 files changed, 99 insertions(+), 128 deletions(-) create mode 100644 drivers/of/irq.c create mode 100644 include/linux/of_irq.h (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h index 31a35c33df63..ec5583d6111c 100644 --- a/arch/microblaze/include/asm/irq.h +++ b/arch/microblaze/include/asm/irq.h @@ -27,17 +27,6 @@ extern unsigned int nr_irq; struct pt_regs; extern void do_IRQ(struct pt_regs *regs); -/** - * irq_of_parse_and_map - Parse and Map an interrupt into linux virq space - * @device: Device node of the device whose interrupt is to be mapped - * @index: Index of the interrupt to map - * - * This function is a wrapper that chains of_irq_map_one() and - * irq_create_of_mapping() to make things easier to callers - */ -struct device_node; -extern unsigned int irq_of_parse_and_map(struct device_node *dev, int index); - /** FIXME - not implement * irq_dispose_mapping - Unmap an interrupt * @virq: linux virq number of the interrupt to unmap @@ -62,17 +51,4 @@ struct irq_host; extern unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq); -/** - * irq_create_of_mapping - Map a hardware interrupt into linux virq space - * @controller: Device node of the interrupt controller - * @inspec: Interrupt specifier from the device-tree - * @intsize: Size of the interrupt specifier from the device-tree - * - * This function is identical to irq_create_mapping except that it takes - * as input informations straight from the device-tree (typically the results - * of the of_irq_map_*() functions. - */ -extern unsigned int irq_create_of_mapping(struct device_node *controller, - u32 *intspec, unsigned int intsize); - #endif /* _ASM_MICROBLAZE_IRQ_H */ diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index e7d67a329bd7..e9fb2eb0035d 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -20,6 +20,7 @@ #ifndef __ASSEMBLY__ #include +#include #include #include #include @@ -92,18 +93,6 @@ extern const void *of_get_mac_address(struct device_node *np); * OF interrupt mapping */ -/* This structure is returned when an interrupt is mapped. The controller - * field needs to be put() after use - */ - -#define OF_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */ - -struct of_irq { - struct device_node *controller; /* Interrupt controller node */ - u32 size; /* Specifier size */ - u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */ -}; - /** * of_irq_map_init - Initialize the irq remapper * @flags: flags defining workarounds to enable @@ -138,19 +127,6 @@ extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, const u32 *addr, struct of_irq *out_irq); -/** - * of_irq_map_one - Resolve an interrupt for a device - * @device: the device whose interrupt is to be resolved - * @index: index of the interrupt to resolve - * @out_irq: structure of_irq filled by this function - * - * This function resolves an interrupt, walking the tree, for a given - * device-tree node. It's the high level pendant to of_irq_map_raw(). - * It also implements the workarounds for OldWolrd Macs. - */ -extern int of_irq_map_one(struct device_node *device, int index, - struct of_irq *out_irq); - /** * of_irq_map_pci - Resolve the interrupt for a PCI device * @pdev: the device whose interrupt is to be resolved diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index 8f120aca123d..dd32b09b4a3c 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c @@ -17,20 +17,10 @@ #include #include #include +#include #include -unsigned int irq_of_parse_and_map(struct device_node *dev, int index) -{ - struct of_irq oirq; - - if (of_irq_map_one(dev, index, &oirq)) - return NO_IRQ; - - return oirq.specifier[0]; -} -EXPORT_SYMBOL_GPL(irq_of_parse_and_map); - static u32 concurrent_irq; void __irq_entry do_IRQ(struct pt_regs *regs) @@ -104,7 +94,7 @@ unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq) EXPORT_SYMBOL_GPL(irq_create_mapping); unsigned int irq_create_of_mapping(struct device_node *controller, - u32 *intspec, unsigned int intsize) + const u32 *intspec, unsigned int intsize) { return intspec[0]; } diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index e054baef1845..4e3051595b2b 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -300,34 +300,6 @@ extern unsigned int irq_alloc_virt(struct irq_host *host, */ extern void irq_free_virt(unsigned int virq, unsigned int count); - -/* -- OF helpers -- */ - -/** - * irq_create_of_mapping - Map a hardware interrupt into linux virq space - * @controller: Device node of the interrupt controller - * @inspec: Interrupt specifier from the device-tree - * @intsize: Size of the interrupt specifier from the device-tree - * - * This function is identical to irq_create_mapping except that it takes - * as input informations straight from the device-tree (typically the results - * of the of_irq_map_*() functions. - */ -extern unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize); - -/** - * irq_of_parse_and_map - Parse and Map an interrupt into linux virq space - * @device: Device node of the device whose interrupt is to be mapped - * @index: Index of the interrupt to map - * - * This function is a wrapper that chains of_irq_map_one() and - * irq_create_of_mapping() to make things easier to callers - */ -extern unsigned int irq_of_parse_and_map(struct device_node *dev, int index); - -/* -- End OF helpers -- */ - /** * irq_early_init - Init irq remapping subsystem */ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index ddd408a93b5a..47d41b67c94d 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -18,6 +18,7 @@ */ #include #include +#include #include #include #include @@ -108,18 +109,6 @@ extern const void *of_get_mac_address(struct device_node *np); * OF interrupt mapping */ -/* This structure is returned when an interrupt is mapped. The controller - * field needs to be put() after use - */ - -#define OF_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */ - -struct of_irq { - struct device_node *controller; /* Interrupt controller node */ - u32 size; /* Specifier size */ - u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */ -}; - /** * of_irq_map_init - Initialize the irq remapper * @flags: flags defining workarounds to enable @@ -154,20 +143,6 @@ extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, const u32 *addr, struct of_irq *out_irq); - -/** - * of_irq_map_one - Resolve an interrupt for a device - * @device: the device whose interrupt is to be resolved - * @index: index of the interrupt to resolve - * @out_irq: structure of_irq filled by this function - * - * This function resolves an interrupt, walking the tree, for a given - * device-tree node. It's the high level pendant to of_irq_map_raw(). - * It also implements the workarounds for OldWolrd Macs. - */ -extern int of_irq_map_one(struct device_node *device, int index, - struct of_irq *out_irq); - /** * of_irq_map_pci - Resolve the interrupt for a PCI device * @pdev: the device whose interrupt is to be resolved diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 30817d9b20cb..2676ef288bf5 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -53,6 +53,8 @@ #include #include #include +#include +#include #include #include @@ -813,18 +815,6 @@ unsigned int irq_create_of_mapping(struct device_node *controller, } EXPORT_SYMBOL_GPL(irq_create_of_mapping); -unsigned int irq_of_parse_and_map(struct device_node *dev, int index) -{ - struct of_irq oirq; - - if (of_irq_map_one(dev, index, &oirq)) - return NO_IRQ; - - return irq_create_of_mapping(oirq.controller, oirq.specifier, - oirq.size); -} -EXPORT_SYMBOL_GPL(irq_of_parse_and_map); - void irq_dispose_mapping(unsigned int virq) { struct irq_host *host; diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index f845828ca4c6..ac695742df85 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -56,7 +56,6 @@ extern void of_fill_in_cpu_data(void); * register them in the of_device objects, whereas powerpc computes them * on request. */ -extern unsigned int irq_of_parse_and_map(struct device_node *node, int index); static inline void irq_dispose_mapping(unsigned int virq) { } diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 7cecc8fea9bd..b87495efa16e 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -6,6 +6,10 @@ config OF_DYNAMIC def_bool y depends on OF && PPC_OF +config OF_IRQ + def_bool y + depends on OF && !SPARC + config OF_DEVICE def_bool y depends on OF && (SPARC || PPC_OF || MICROBLAZE) diff --git a/drivers/of/Makefile b/drivers/of/Makefile index f232cc98ce00..3631a5ea0b47 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,5 +1,6 @@ obj-y = base.o obj-$(CONFIG_OF_FLATTREE) += fdt.o +obj-$(CONFIG_OF_IRQ) += irq.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o diff --git a/drivers/of/irq.c b/drivers/of/irq.c new file mode 100644 index 000000000000..9b3397c27096 --- /dev/null +++ b/drivers/of/irq.c @@ -0,0 +1,45 @@ +/* + * Derived from arch/i386/kernel/irq.c + * Copyright (C) 1992 Linus Torvalds + * Adapted from arch/i386 by Gary Thomas + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Updated and modified by Cort Dougan + * Copyright (C) 1996-2001 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * + * 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. + * + * This file contains the code used to make IRQ descriptions in the + * device tree to actual irq numbers on an interrupt controller + * driver. + */ + +#include +#include +#include +#include +#include + +/** + * irq_of_parse_and_map - Parse and map an interrupt into linux virq space + * @device: Device node of the device whose interrupt is to be mapped + * @index: Index of the interrupt to map + * + * This function is a wrapper that chains of_irq_map_one() and + * irq_create_of_mapping() to make things easier to callers + */ +unsigned int irq_of_parse_and_map(struct device_node *dev, int index) +{ + struct of_irq oirq; + + if (of_irq_map_one(dev, index, &oirq)) + return NO_IRQ; + + return irq_create_of_mapping(oirq.controller, oirq.specifier, + oirq.size); +} +EXPORT_SYMBOL_GPL(irq_of_parse_and_map); diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 42a6715f8e84..1fce00eb421b 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c index 5fed7e3c7da3..d504f1d1324b 100644 --- a/drivers/of/of_spi.c +++ b/drivers/of/of_spi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include /** diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h new file mode 100644 index 000000000000..0e37c05b7dd8 --- /dev/null +++ b/include/linux/of_irq.h @@ -0,0 +1,41 @@ +#ifndef __OF_IRQ_H +#define __OF_IRQ_H + +#if defined(CONFIG_OF) +struct of_irq; +#include +#include + +/* + * irq_of_parse_and_map() is used ba all OF enabled platforms; but SPARC + * implements it differently. However, the prototype is the same for all, + * so declare it here regardless of the CONFIG_OF_IRQ setting. + */ +extern unsigned int irq_of_parse_and_map(struct device_node *node, int index); + +#if defined(CONFIG_OF_IRQ) +/** + * of_irq - container for device_node/irq_specifier pair for an irq controller + * @controller: pointer to interrupt controller device tree node + * @size: size of interrupt specifier + * @specifier: array of cells @size long specifing the specific interrupt + * + * This structure is returned when an interrupt is mapped. The controller + * field needs to be put() after use + */ +#define OF_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */ +struct of_irq { + struct device_node *controller; /* Interrupt controller node */ + u32 size; /* Specifier size */ + u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */ +}; + +extern int of_irq_map_one(struct device_node *device, int index, + struct of_irq *out_irq); +extern unsigned int irq_create_of_mapping(struct device_node *controller, + const u32 *intspec, + unsigned int intsize); + +#endif /* CONFIG_OF_IRQ */ +#endif /* CONFIG_OF */ +#endif /* __OF_IRQ_H */ -- cgit v1.2.3 From d09ec7387184eba9e3030496f0451204090ff610 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 29 Jun 2010 12:50:32 +1000 Subject: powerpc, hw_breakpoint: Tell generic code we have no instruction breakpoints At present, hw_breakpoint_slots() returns 1 regardless of what type of breakpoint is specified in the type argument. Since we don't define CONFIG_HAVE_MIXED_BREAKPOINTS_REGS, there are separate values for TYPE_INST and TYPE_DATA, and hw_breakpoint_slots() returns 1 for both, effectively advertising instruction breakpoint support which doesn't exist. This fixes it by making hw_breakpoint_slots return 1 for TYPE_DATA and 0 for TYPE_INST. This moves hw_breakpoint_slots() from the powerpc hw_breakpoint.h to hw_breakpoint.c because the definitions of TYPE_INST and TYPE_DATA aren't available in . They are defined in but we can't include that header in , and nor can we rely on being included before . Since hw_breakpoint_slots() is only called at boot time, there is no performance impact from making it a real function rather than a static inline. Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/hw_breakpoint.h | 5 +---- arch/powerpc/kernel/hw_breakpoint.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h index ea87f8ae7bdb..1c33ec17ca36 100644 --- a/arch/powerpc/include/asm/hw_breakpoint.h +++ b/arch/powerpc/include/asm/hw_breakpoint.h @@ -37,10 +37,6 @@ struct arch_hw_breakpoint { #include #include -static inline int hw_breakpoint_slots(int type) -{ - return HBP_NUM; -} struct perf_event; struct pmu; struct perf_sample_data; @@ -49,6 +45,7 @@ struct perf_sample_data; /* Maximum permissible length of any HW Breakpoint */ #define HW_BREAKPOINT_LEN 0x8 +extern int hw_breakpoint_slots(int type); extern int arch_bp_generic_fields(int type, int *gen_bp_type); extern int arch_check_bp_in_kernelspace(struct perf_event *bp); extern int arch_validate_hwbkpt_settings(struct perf_event *bp); diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 5a1d55d06a08..5ecd0401cdb1 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -43,6 +43,16 @@ */ static DEFINE_PER_CPU(struct perf_event *, bp_per_reg); +/* + * Returns total number of data or instruction breakpoints available. + */ +int hw_breakpoint_slots(int type) +{ + if (type == TYPE_DATA) + return HBP_NUM; + return 0; /* no instruction breakpoints available */ +} + /* * Install a perf counter breakpoint. * -- cgit v1.2.3 From b83da291b4c73eaddc20e2edb614123a6d681b3b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 18 Jun 2010 11:10:01 -0600 Subject: of/powerpc: Move Powermac irq quirk code into powermac pic driver code The code that figures out what is wrong with the powermac irq device tree data belongs with the rest of the powermac irq code. This patch moves it out of prom_parse.c and into powermac/pic.c so that it is only compiled in when actually needed. Signed-off-by: Grant Likely Cc: Benjamin Herrenschmidt Cc: Stephen Rothwell --- arch/powerpc/include/asm/prom.h | 24 ++++++---- arch/powerpc/kernel/prom_parse.c | 85 ----------------------------------- arch/powerpc/platforms/powermac/pic.c | 72 ++++++++++++++++++++++++++--- 3 files changed, 81 insertions(+), 100 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index 47d41b67c94d..4486765db6e7 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -109,18 +109,24 @@ extern const void *of_get_mac_address(struct device_node *np); * OF interrupt mapping */ -/** - * of_irq_map_init - Initialize the irq remapper - * @flags: flags defining workarounds to enable - * - * Some machines have bugs in the device-tree which require certain workarounds - * to be applied. Call this before any interrupt mapping attempts to enable - * those workarounds. - */ #define OF_IMAP_OLDWORLD_MAC 0x00000001 #define OF_IMAP_NO_PHANDLE 0x00000002 -extern void of_irq_map_init(unsigned int flags); +#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_PMAC) +/* Workarounds only needed for 32bit powermac machines */ +extern unsigned int of_irq_workarounds; +extern struct device_node *of_irq_dflt_pic; +extern int of_irq_map_oldworld(struct device_node *device, int index, + struct of_irq *out_irq); +#else +#define of_irq_workarounds (0) +#define of_irq_dflt_pic (NULL) +static inline int of_irq_map_oldworld(struct device_node *device, int index, + struct of_irq *out_irq) +{ + return -EINVAL; +} +#endif /** * of_irq_map_raw - Low level interrupt tree parsing diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 8362620c9e6f..dfa6de6572bb 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -682,9 +682,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, * Interrupt remapper */ -static unsigned int of_irq_workarounds; -static struct device_node *of_irq_dflt_pic; - static struct device_node *of_irq_find_parent(struct device_node *child) { struct device_node *p; @@ -710,44 +707,6 @@ static struct device_node *of_irq_find_parent(struct device_node *child) return p; } -/* This doesn't need to be called if you don't have any special workaround - * flags to pass - */ -void of_irq_map_init(unsigned int flags) -{ - of_irq_workarounds = flags; - - /* OldWorld, don't bother looking at other things */ - if (flags & OF_IMAP_OLDWORLD_MAC) - return; - - /* If we don't have phandles, let's try to locate a default interrupt - * controller (happens when booting with BootX). We do a first match - * here, hopefully, that only ever happens on machines with one - * controller. - */ - if (flags & OF_IMAP_NO_PHANDLE) { - struct device_node *np; - - for_each_node_with_property(np, "interrupt-controller") { - /* Skip /chosen/interrupt-controller */ - if (strcmp(np->name, "chosen") == 0) - continue; - /* It seems like at least one person on this planet wants - * to use BootX on a machine with an AppleKiwi controller - * which happens to pretend to be an interrupt - * controller too. - */ - if (strcmp(np->name, "AppleKiwi") == 0) - continue; - /* I think we found one ! */ - of_irq_dflt_pic = np; - break; - } - } - -} - int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, const u32 *addr, struct of_irq *out_irq) { @@ -922,50 +881,6 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, } EXPORT_SYMBOL_GPL(of_irq_map_raw); -#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) -static int of_irq_map_oldworld(struct device_node *device, int index, - struct of_irq *out_irq) -{ - const u32 *ints = NULL; - int intlen; - - /* - * Old machines just have a list of interrupt numbers - * and no interrupt-controller nodes. We also have dodgy - * cases where the APPL,interrupts property is completely - * missing behind pci-pci bridges and we have to get it - * from the parent (the bridge itself, as apple just wired - * everything together on these) - */ - while (device) { - ints = of_get_property(device, "AAPL,interrupts", &intlen); - if (ints != NULL) - break; - device = device->parent; - if (device && strcmp(device->type, "pci") != 0) - break; - } - if (ints == NULL) - return -EINVAL; - intlen /= sizeof(u32); - - if (index >= intlen) - return -EINVAL; - - out_irq->controller = NULL; - out_irq->specifier[0] = ints[index]; - out_irq->size = 1; - - return 0; -} -#else /* defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) */ -static int of_irq_map_oldworld(struct device_node *device, int index, - struct of_irq *out_irq) -{ - return -EINVAL; -} -#endif /* !(defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)) */ - int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq) { struct device_node *p; diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 630a533d0e59..890d5f72b198 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -46,6 +46,10 @@ struct pmac_irq_hw { unsigned int level; }; +/* Workaround flags for 32bit powermac machines */ +unsigned int of_irq_workarounds; +struct device_node *of_irq_dflt_pic; + /* Default addresses */ static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4]; @@ -428,6 +432,42 @@ static void __init pmac_pic_probe_oldstyle(void) setup_irq(irq_create_mapping(NULL, 20), &xmon_action); #endif } + +int of_irq_map_oldworld(struct device_node *device, int index, + struct of_irq *out_irq) +{ + const u32 *ints = NULL; + int intlen; + + /* + * Old machines just have a list of interrupt numbers + * and no interrupt-controller nodes. We also have dodgy + * cases where the APPL,interrupts property is completely + * missing behind pci-pci bridges and we have to get it + * from the parent (the bridge itself, as apple just wired + * everything together on these) + */ + while (device) { + ints = of_get_property(device, "AAPL,interrupts", &intlen); + if (ints != NULL) + break; + device = device->parent; + if (device && strcmp(device->type, "pci") != 0) + break; + } + if (ints == NULL) + return -EINVAL; + intlen /= sizeof(u32); + + if (index >= intlen) + return -EINVAL; + + out_irq->controller = NULL; + out_irq->specifier[0] = ints[index]; + out_irq->size = 1; + + return 0; +} #endif /* CONFIG_PPC32 */ static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc) @@ -559,19 +599,39 @@ static int __init pmac_pic_probe_mpic(void) void __init pmac_pic_init(void) { - unsigned int flags = 0; - /* We configure the OF parsing based on our oldworld vs. newworld * platform type and wether we were booted by BootX. */ #ifdef CONFIG_PPC32 if (!pmac_newworld) - flags |= OF_IMAP_OLDWORLD_MAC; + of_irq_workarounds |= OF_IMAP_OLDWORLD_MAC; if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL) - flags |= OF_IMAP_NO_PHANDLE; -#endif /* CONFIG_PPC_32 */ + of_irq_workarounds |= OF_IMAP_NO_PHANDLE; - of_irq_map_init(flags); + /* If we don't have phandles on a newworld, then try to locate a + * default interrupt controller (happens when booting with BootX). + * We do a first match here, hopefully, that only ever happens on + * machines with one controller. + */ + if (pmac_newworld && (of_irq_workarounds & OF_IMAP_NO_PHANDLE)) { + struct device_node *np; + + for_each_node_with_property(np, "interrupt-controller") { + /* Skip /chosen/interrupt-controller */ + if (strcmp(np->name, "chosen") == 0) + continue; + /* It seems like at least one person wants + * to use BootX on a machine with an AppleKiwi + * controller which happens to pretend to be an + * interrupt controller too. */ + if (strcmp(np->name, "AppleKiwi") == 0) + continue; + /* I think we found one ! */ + of_irq_dflt_pic = np; + break; + } + } +#endif /* CONFIG_PPC32 */ /* We first try to detect Apple's new Core99 chipset, since mac-io * is quite different on those machines and contains an IBM MPIC2. -- cgit v1.2.3 From 7dc2e1134a22dc242175d5321c0c9e97d16eb87b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:06 -0600 Subject: of/irq: merge irq mapping code Merge common irq mapping code between PowerPC and Microblaze. This patch merges of_irq_find_parent(), of_irq_map_raw() and of_irq_map_one(). The functions are dependent on one another, so all three are merged in a single patch. Other than cosmetic difference (ie. DBG() vs. pr_debug()), the implementations are identical. of_irq_to_resource() is also merged, but in this case the implementations are different. This patch drops the microblaze version and uses the powerpc implementation unchanged. The microblaze version essentially open-coded irq_of_parse_and_map() which it does not need to do. Therefore the powerpc version is safe to adopt. Signed-off-by: Grant Likely CC: Michal Simek CC: Benjamin Herrenschmidt CC: Stephen Rothwell --- arch/microblaze/include/asm/prom.h | 31 ---- arch/microblaze/kernel/prom_parse.c | 290 ---------------------------------- arch/powerpc/include/asm/prom.h | 47 ------ arch/powerpc/kernel/prom_parse.c | 266 ------------------------------- drivers/of/irq.c | 301 ++++++++++++++++++++++++++++++++++++ include/linux/of_irq.h | 29 ++++ 6 files changed, 330 insertions(+), 634 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index 4f34bc5baa83..5fbdfe76fe76 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -89,34 +89,6 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); /* Get the MAC address */ extern const void *of_get_mac_address(struct device_node *np); -/* - * OF interrupt mapping - */ - -#define OF_IMAP_OLDWORLD_MAC 0x00000001 -#define OF_IMAP_NO_PHANDLE 0x00000002 - -/** - * of_irq_map_raw - Low level interrupt tree parsing - * @parent: the device interrupt parent - * @intspec: interrupt specifier ("interrupts" property of the device) - * @ointsize: size of the passed in interrupt specifier - * @addr: address specifier (start of "reg" property of the device) - * @out_irq: structure of_irq filled by this function - * - * Returns 0 on success and a negative number on error - * - * This function is a low-level interrupt tree walking function. It - * can be used to do a partial walk with synthetized reg and interrupts - * properties, for example when resolving PCI interrupts when no device - * node exist for the parent. - * - */ - -extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec, - u32 ointsize, const u32 *addr, - struct of_irq *out_irq); - /** * of_irq_map_pci - Resolve the interrupt for a PCI device * @pdev: the device whose interrupt is to be resolved @@ -131,9 +103,6 @@ extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec, struct pci_dev; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); -extern int of_irq_to_resource(struct device_node *dev, int index, - struct resource *r); - /** * of_iomap - Maps the memory mapped IO for a given device_node * @device: the device whose io range will be mapped diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c index cba05812ab46..e28968fa34c1 100644 --- a/arch/microblaze/kernel/prom_parse.c +++ b/arch/microblaze/kernel/prom_parse.c @@ -644,267 +644,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, *size = of_read_number(dma_window, cells); } -/* - * Interrupt remapper - */ - -static unsigned int of_irq_workarounds; -static struct device_node *of_irq_dflt_pic; - -static struct device_node *of_irq_find_parent(struct device_node *child) -{ - struct device_node *p; - const phandle *parp; - - if (!of_node_get(child)) - return NULL; - - do { - parp = of_get_property(child, "interrupt-parent", NULL); - if (parp == NULL) - p = of_get_parent(child); - else { - if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) - p = of_node_get(of_irq_dflt_pic); - else - p = of_find_node_by_phandle(*parp); - } - of_node_put(child); - child = p; - } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL); - - return p; -} - -int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, - const u32 *addr, struct of_irq *out_irq) -{ - struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; - const u32 *tmp, *imap, *imask; - u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; - int imaplen, match, i; - - pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...]," - "ointsize=%d\n", - parent->full_name, intspec[0], intspec[1], ointsize); - - ipar = of_node_get(parent); - - /* First get the #interrupt-cells property of the current cursor - * that tells us how to interpret the passed-in intspec. If there - * is none, we are nice and just walk up the tree - */ - do { - tmp = of_get_property(ipar, "#interrupt-cells", NULL); - if (tmp != NULL) { - intsize = *tmp; - break; - } - tnode = ipar; - ipar = of_irq_find_parent(ipar); - of_node_put(tnode); - } while (ipar); - if (ipar == NULL) { - pr_debug(" -> no parent found !\n"); - goto fail; - } - - pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", - ipar->full_name, intsize); - - if (ointsize != intsize) - return -EINVAL; - - /* Look for this #address-cells. We have to implement the old linux - * trick of looking for the parent here as some device-trees rely on it - */ - old = of_node_get(ipar); - do { - tmp = of_get_property(old, "#address-cells", NULL); - tnode = of_get_parent(old); - of_node_put(old); - old = tnode; - } while (old && tmp == NULL); - of_node_put(old); - old = NULL; - addrsize = (tmp == NULL) ? 2 : *tmp; - - pr_debug(" -> addrsize=%d\n", addrsize); - - /* Now start the actual "proper" walk of the interrupt tree */ - while (ipar != NULL) { - /* Now check if cursor is an interrupt-controller and if it is - * then we are done - */ - if (of_get_property(ipar, "interrupt-controller", NULL) != - NULL) { - pr_debug(" -> got it !\n"); - memcpy(out_irq->specifier, intspec, - intsize * sizeof(u32)); - out_irq->size = intsize; - out_irq->controller = ipar; - of_node_put(old); - return 0; - } - - /* Now look for an interrupt-map */ - imap = of_get_property(ipar, "interrupt-map", &imaplen); - /* No interrupt map, check for an interrupt parent */ - if (imap == NULL) { - pr_debug(" -> no map, getting parent\n"); - newpar = of_irq_find_parent(ipar); - goto skiplevel; - } - imaplen /= sizeof(u32); - - /* Look for a mask */ - imask = of_get_property(ipar, "interrupt-map-mask", NULL); - - /* If we were passed no "reg" property and we attempt to parse - * an interrupt-map, then #address-cells must be 0. - * Fail if it's not. - */ - if (addr == NULL && addrsize != 0) { - pr_debug(" -> no reg passed in when needed !\n"); - goto fail; - } - - /* Parse interrupt-map */ - match = 0; - while (imaplen > (addrsize + intsize + 1) && !match) { - /* Compare specifiers */ - match = 1; - for (i = 0; i < addrsize && match; ++i) { - u32 mask = imask ? imask[i] : 0xffffffffu; - match = ((addr[i] ^ imap[i]) & mask) == 0; - } - for (; i < (addrsize + intsize) && match; ++i) { - u32 mask = imask ? imask[i] : 0xffffffffu; - match = - ((intspec[i-addrsize] ^ imap[i]) - & mask) == 0; - } - imap += addrsize + intsize; - imaplen -= addrsize + intsize; - - pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); - - /* Get the interrupt parent */ - if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) - newpar = of_node_get(of_irq_dflt_pic); - else - newpar = - of_find_node_by_phandle((phandle)*imap); - imap++; - --imaplen; - - /* Check if not found */ - if (newpar == NULL) { - pr_debug(" -> imap parent not found !\n"); - goto fail; - } - - /* Get #interrupt-cells and #address-cells of new - * parent - */ - tmp = of_get_property(newpar, "#interrupt-cells", NULL); - if (tmp == NULL) { - pr_debug(" -> parent lacks " - "#interrupt-cells!\n"); - goto fail; - } - newintsize = *tmp; - tmp = of_get_property(newpar, "#address-cells", NULL); - newaddrsize = (tmp == NULL) ? 0 : *tmp; - - pr_debug(" -> newintsize=%d, newaddrsize=%d\n", - newintsize, newaddrsize); - - /* Check for malformed properties */ - if (imaplen < (newaddrsize + newintsize)) - goto fail; - - imap += newaddrsize + newintsize; - imaplen -= newaddrsize + newintsize; - - pr_debug(" -> imaplen=%d\n", imaplen); - } - if (!match) - goto fail; - - of_node_put(old); - old = of_node_get(newpar); - addrsize = newaddrsize; - intsize = newintsize; - intspec = imap - intsize; - addr = intspec - addrsize; - -skiplevel: - /* Iterate again with new parent */ - pr_debug(" -> new parent: %s\n", - newpar ? newpar->full_name : "<>"); - of_node_put(ipar); - ipar = newpar; - newpar = NULL; - } -fail: - of_node_put(ipar); - of_node_put(old); - of_node_put(newpar); - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(of_irq_map_raw); - -int of_irq_map_one(struct device_node *device, - int index, struct of_irq *out_irq) -{ - struct device_node *p; - const u32 *intspec, *tmp, *addr; - u32 intsize, intlen; - int res; - - pr_debug("of_irq_map_one: dev=%s, index=%d\n", - device->full_name, index); - - /* Get the interrupts property */ - intspec = of_get_property(device, "interrupts", (int *) &intlen); - if (intspec == NULL) - return -EINVAL; - intlen /= sizeof(u32); - - pr_debug(" intspec=%d intlen=%d\n", *intspec, intlen); - - /* Get the reg property (if any) */ - addr = of_get_property(device, "reg", NULL); - - /* Look for the interrupt parent. */ - p = of_irq_find_parent(device); - if (p == NULL) - return -EINVAL; - - /* Get size of interrupt specifier */ - tmp = of_get_property(p, "#interrupt-cells", NULL); - if (tmp == NULL) { - of_node_put(p); - return -EINVAL; - } - intsize = *tmp; - - pr_debug(" intsize=%d intlen=%d\n", intsize, intlen); - - /* Check index */ - if ((index + 1) * intsize > intlen) - return -EINVAL; - - /* Get new specifier and map it */ - res = of_irq_map_raw(p, intspec + index * intsize, intsize, - addr, out_irq); - of_node_put(p); - return res; -} -EXPORT_SYMBOL_GPL(of_irq_map_one); - /** * Search the device tree for the best MAC address to use. 'mac-address' is * checked first, because that is supposed to contain to "most recent" MAC @@ -943,35 +682,6 @@ const void *of_get_mac_address(struct device_node *np) } EXPORT_SYMBOL(of_get_mac_address); -int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) -{ - struct of_irq out_irq; - int irq; - int res; - - res = of_irq_map_one(dev, index, &out_irq); - - /* Get irq for the device */ - if (res) { - pr_debug("IRQ not found... code = %d", res); - return NO_IRQ; - } - /* Assuming single interrupt controller... */ - irq = out_irq.specifier[0]; - - pr_debug("IRQ found = %d", irq); - - /* Only dereference the resource if both the - * resource and the irq are valid. */ - if (r && irq != NO_IRQ) { - r->start = r->end = irq; - r->flags = IORESOURCE_IRQ; - } - - return irq; -} -EXPORT_SYMBOL_GPL(of_irq_to_resource); - void __iomem *of_iomap(struct device_node *np, int index) { struct resource res; diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index 4486765db6e7..10d5ee556702 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -105,50 +105,6 @@ struct device_node *of_find_next_cache_node(struct device_node *np); /* Get the MAC address */ extern const void *of_get_mac_address(struct device_node *np); -/* - * OF interrupt mapping - */ - -#define OF_IMAP_OLDWORLD_MAC 0x00000001 -#define OF_IMAP_NO_PHANDLE 0x00000002 - -#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_PMAC) -/* Workarounds only needed for 32bit powermac machines */ -extern unsigned int of_irq_workarounds; -extern struct device_node *of_irq_dflt_pic; -extern int of_irq_map_oldworld(struct device_node *device, int index, - struct of_irq *out_irq); -#else -#define of_irq_workarounds (0) -#define of_irq_dflt_pic (NULL) -static inline int of_irq_map_oldworld(struct device_node *device, int index, - struct of_irq *out_irq) -{ - return -EINVAL; -} -#endif - -/** - * of_irq_map_raw - Low level interrupt tree parsing - * @parent: the device interrupt parent - * @intspec: interrupt specifier ("interrupts" property of the device) - * @ointsize: size of the passed in interrupt specifier - * @addr: address specifier (start of "reg" property of the device) - * @out_irq: structure of_irq filled by this function - * - * Returns 0 on success and a negative number on error - * - * This function is a low-level interrupt tree walking function. It - * can be used to do a partial walk with synthetized reg and interrupts - * properties, for example when resolving PCI interrupts when no device - * node exist for the parent. - * - */ - -extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec, - u32 ointsize, const u32 *addr, - struct of_irq *out_irq); - /** * of_irq_map_pci - Resolve the interrupt for a PCI device * @pdev: the device whose interrupt is to be resolved @@ -163,9 +119,6 @@ extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec, struct pci_dev; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); -extern int of_irq_to_resource(struct device_node *dev, int index, - struct resource *r); - /** * of_iomap - Maps the memory mapped IO for a given device_node * @device: the device whose io range will be mapped diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index dfa6de6572bb..d61a5c5fe690 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -678,257 +678,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, *size = of_read_number(dma_window, cells); } -/* - * Interrupt remapper - */ - -static struct device_node *of_irq_find_parent(struct device_node *child) -{ - struct device_node *p; - const phandle *parp; - - if (!of_node_get(child)) - return NULL; - - do { - parp = of_get_property(child, "interrupt-parent", NULL); - if (parp == NULL) - p = of_get_parent(child); - else { - if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) - p = of_node_get(of_irq_dflt_pic); - else - p = of_find_node_by_phandle(*parp); - } - of_node_put(child); - child = p; - } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL); - - return p; -} - -int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, - const u32 *addr, struct of_irq *out_irq) -{ - struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; - const u32 *tmp, *imap, *imask; - u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; - int imaplen, match, i; - - DBG("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", - parent->full_name, intspec[0], intspec[1], ointsize); - - ipar = of_node_get(parent); - - /* First get the #interrupt-cells property of the current cursor - * that tells us how to interpret the passed-in intspec. If there - * is none, we are nice and just walk up the tree - */ - do { - tmp = of_get_property(ipar, "#interrupt-cells", NULL); - if (tmp != NULL) { - intsize = *tmp; - break; - } - tnode = ipar; - ipar = of_irq_find_parent(ipar); - of_node_put(tnode); - } while (ipar); - if (ipar == NULL) { - DBG(" -> no parent found !\n"); - goto fail; - } - - DBG("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); - - if (ointsize != intsize) - return -EINVAL; - - /* Look for this #address-cells. We have to implement the old linux - * trick of looking for the parent here as some device-trees rely on it - */ - old = of_node_get(ipar); - do { - tmp = of_get_property(old, "#address-cells", NULL); - tnode = of_get_parent(old); - of_node_put(old); - old = tnode; - } while(old && tmp == NULL); - of_node_put(old); - old = NULL; - addrsize = (tmp == NULL) ? 2 : *tmp; - - DBG(" -> addrsize=%d\n", addrsize); - - /* Now start the actual "proper" walk of the interrupt tree */ - while (ipar != NULL) { - /* Now check if cursor is an interrupt-controller and if it is - * then we are done - */ - if (of_get_property(ipar, "interrupt-controller", NULL) != - NULL) { - DBG(" -> got it !\n"); - memcpy(out_irq->specifier, intspec, - intsize * sizeof(u32)); - out_irq->size = intsize; - out_irq->controller = ipar; - of_node_put(old); - return 0; - } - - /* Now look for an interrupt-map */ - imap = of_get_property(ipar, "interrupt-map", &imaplen); - /* No interrupt map, check for an interrupt parent */ - if (imap == NULL) { - DBG(" -> no map, getting parent\n"); - newpar = of_irq_find_parent(ipar); - goto skiplevel; - } - imaplen /= sizeof(u32); - - /* Look for a mask */ - imask = of_get_property(ipar, "interrupt-map-mask", NULL); - - /* If we were passed no "reg" property and we attempt to parse - * an interrupt-map, then #address-cells must be 0. - * Fail if it's not. - */ - if (addr == NULL && addrsize != 0) { - DBG(" -> no reg passed in when needed !\n"); - goto fail; - } - - /* Parse interrupt-map */ - match = 0; - while (imaplen > (addrsize + intsize + 1) && !match) { - /* Compare specifiers */ - match = 1; - for (i = 0; i < addrsize && match; ++i) { - u32 mask = imask ? imask[i] : 0xffffffffu; - match = ((addr[i] ^ imap[i]) & mask) == 0; - } - for (; i < (addrsize + intsize) && match; ++i) { - u32 mask = imask ? imask[i] : 0xffffffffu; - match = - ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; - } - imap += addrsize + intsize; - imaplen -= addrsize + intsize; - - DBG(" -> match=%d (imaplen=%d)\n", match, imaplen); - - /* Get the interrupt parent */ - if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) - newpar = of_node_get(of_irq_dflt_pic); - else - newpar = of_find_node_by_phandle((phandle)*imap); - imap++; - --imaplen; - - /* Check if not found */ - if (newpar == NULL) { - DBG(" -> imap parent not found !\n"); - goto fail; - } - - /* Get #interrupt-cells and #address-cells of new - * parent - */ - tmp = of_get_property(newpar, "#interrupt-cells", NULL); - if (tmp == NULL) { - DBG(" -> parent lacks #interrupt-cells !\n"); - goto fail; - } - newintsize = *tmp; - tmp = of_get_property(newpar, "#address-cells", NULL); - newaddrsize = (tmp == NULL) ? 0 : *tmp; - - DBG(" -> newintsize=%d, newaddrsize=%d\n", - newintsize, newaddrsize); - - /* Check for malformed properties */ - if (imaplen < (newaddrsize + newintsize)) - goto fail; - - imap += newaddrsize + newintsize; - imaplen -= newaddrsize + newintsize; - - DBG(" -> imaplen=%d\n", imaplen); - } - if (!match) - goto fail; - - of_node_put(old); - old = of_node_get(newpar); - addrsize = newaddrsize; - intsize = newintsize; - intspec = imap - intsize; - addr = intspec - addrsize; - - skiplevel: - /* Iterate again with new parent */ - DBG(" -> new parent: %s\n", newpar ? newpar->full_name : "<>"); - of_node_put(ipar); - ipar = newpar; - newpar = NULL; - } - fail: - of_node_put(ipar); - of_node_put(old); - of_node_put(newpar); - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(of_irq_map_raw); - -int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq) -{ - struct device_node *p; - const u32 *intspec, *tmp, *addr; - u32 intsize, intlen; - int res = -EINVAL; - - DBG("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index); - - /* OldWorld mac stuff is "special", handle out of line */ - if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) - return of_irq_map_oldworld(device, index, out_irq); - - /* Get the interrupts property */ - intspec = of_get_property(device, "interrupts", &intlen); - if (intspec == NULL) - return -EINVAL; - intlen /= sizeof(u32); - - /* Get the reg property (if any) */ - addr = of_get_property(device, "reg", NULL); - - /* Look for the interrupt parent. */ - p = of_irq_find_parent(device); - if (p == NULL) - return -EINVAL; - - /* Get size of interrupt specifier */ - tmp = of_get_property(p, "#interrupt-cells", NULL); - if (tmp == NULL) - goto out; - intsize = *tmp; - - DBG(" intsize=%d intlen=%d\n", intsize, intlen); - - /* Check index */ - if ((index + 1) * intsize > intlen) - goto out; - - /* Get new specifier and map it */ - res = of_irq_map_raw(p, intspec + index * intsize, intsize, - addr, out_irq); -out: - of_node_put(p); - return res; -} -EXPORT_SYMBOL_GPL(of_irq_map_one); - /** * Search the device tree for the best MAC address to use. 'mac-address' is * checked first, because that is supposed to contain to "most recent" MAC @@ -967,21 +716,6 @@ const void *of_get_mac_address(struct device_node *np) } EXPORT_SYMBOL(of_get_mac_address); -int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) -{ - int irq = irq_of_parse_and_map(dev, index); - - /* Only dereference the resource if both the - * resource and the irq are valid. */ - if (r && irq != NO_IRQ) { - r->start = r->end = irq; - r->flags = IORESOURCE_IRQ; - } - - return irq; -} -EXPORT_SYMBOL_GPL(of_irq_to_resource); - void __iomem *of_iomap(struct device_node *np, int index) { struct resource res; diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 9b3397c27096..598454fbdd1e 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -43,3 +43,304 @@ unsigned int irq_of_parse_and_map(struct device_node *dev, int index) oirq.size); } EXPORT_SYMBOL_GPL(irq_of_parse_and_map); + +/** + * of_irq_find_parent - Given a device node, find its interrupt parent node + * @child: pointer to device node + * + * Returns a pointer to the interrupt parent node, or NULL if the interrupt + * parent could not be determined. + */ +static struct device_node *of_irq_find_parent(struct device_node *child) +{ + struct device_node *p; + const phandle *parp; + + if (!of_node_get(child)) + return NULL; + + do { + parp = of_get_property(child, "interrupt-parent", NULL); + if (parp == NULL) + p = of_get_parent(child); + else { + if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) + p = of_node_get(of_irq_dflt_pic); + else + p = of_find_node_by_phandle(*parp); + } + of_node_put(child); + child = p; + } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL); + + return p; +} + +/** + * of_irq_map_raw - Low level interrupt tree parsing + * @parent: the device interrupt parent + * @intspec: interrupt specifier ("interrupts" property of the device) + * @ointsize: size of the passed in interrupt specifier + * @addr: address specifier (start of "reg" property of the device) + * @out_irq: structure of_irq filled by this function + * + * Returns 0 on success and a negative number on error + * + * This function is a low-level interrupt tree walking function. It + * can be used to do a partial walk with synthetized reg and interrupts + * properties, for example when resolving PCI interrupts when no device + * node exist for the parent. + */ +int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, + const u32 *addr, struct of_irq *out_irq) +{ + struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; + const u32 *tmp, *imap, *imask; + u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; + int imaplen, match, i; + + pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", + parent->full_name, intspec[0], intspec[1], ointsize); + + ipar = of_node_get(parent); + + /* First get the #interrupt-cells property of the current cursor + * that tells us how to interpret the passed-in intspec. If there + * is none, we are nice and just walk up the tree + */ + do { + tmp = of_get_property(ipar, "#interrupt-cells", NULL); + if (tmp != NULL) { + intsize = *tmp; + break; + } + tnode = ipar; + ipar = of_irq_find_parent(ipar); + of_node_put(tnode); + } while (ipar); + if (ipar == NULL) { + pr_debug(" -> no parent found !\n"); + goto fail; + } + + pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); + + if (ointsize != intsize) + return -EINVAL; + + /* Look for this #address-cells. We have to implement the old linux + * trick of looking for the parent here as some device-trees rely on it + */ + old = of_node_get(ipar); + do { + tmp = of_get_property(old, "#address-cells", NULL); + tnode = of_get_parent(old); + of_node_put(old); + old = tnode; + } while (old && tmp == NULL); + of_node_put(old); + old = NULL; + addrsize = (tmp == NULL) ? 2 : *tmp; + + pr_debug(" -> addrsize=%d\n", addrsize); + + /* Now start the actual "proper" walk of the interrupt tree */ + while (ipar != NULL) { + /* Now check if cursor is an interrupt-controller and if it is + * then we are done + */ + if (of_get_property(ipar, "interrupt-controller", NULL) != + NULL) { + pr_debug(" -> got it !\n"); + memcpy(out_irq->specifier, intspec, + intsize * sizeof(u32)); + out_irq->size = intsize; + out_irq->controller = ipar; + of_node_put(old); + return 0; + } + + /* Now look for an interrupt-map */ + imap = of_get_property(ipar, "interrupt-map", &imaplen); + /* No interrupt map, check for an interrupt parent */ + if (imap == NULL) { + pr_debug(" -> no map, getting parent\n"); + newpar = of_irq_find_parent(ipar); + goto skiplevel; + } + imaplen /= sizeof(u32); + + /* Look for a mask */ + imask = of_get_property(ipar, "interrupt-map-mask", NULL); + + /* If we were passed no "reg" property and we attempt to parse + * an interrupt-map, then #address-cells must be 0. + * Fail if it's not. + */ + if (addr == NULL && addrsize != 0) { + pr_debug(" -> no reg passed in when needed !\n"); + goto fail; + } + + /* Parse interrupt-map */ + match = 0; + while (imaplen > (addrsize + intsize + 1) && !match) { + /* Compare specifiers */ + match = 1; + for (i = 0; i < addrsize && match; ++i) { + u32 mask = imask ? imask[i] : 0xffffffffu; + match = ((addr[i] ^ imap[i]) & mask) == 0; + } + for (; i < (addrsize + intsize) && match; ++i) { + u32 mask = imask ? imask[i] : 0xffffffffu; + match = + ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; + } + imap += addrsize + intsize; + imaplen -= addrsize + intsize; + + pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); + + /* Get the interrupt parent */ + if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) + newpar = of_node_get(of_irq_dflt_pic); + else + newpar = of_find_node_by_phandle((phandle)*imap); + imap++; + --imaplen; + + /* Check if not found */ + if (newpar == NULL) { + pr_debug(" -> imap parent not found !\n"); + goto fail; + } + + /* Get #interrupt-cells and #address-cells of new + * parent + */ + tmp = of_get_property(newpar, "#interrupt-cells", NULL); + if (tmp == NULL) { + pr_debug(" -> parent lacks #interrupt-cells!\n"); + goto fail; + } + newintsize = *tmp; + tmp = of_get_property(newpar, "#address-cells", NULL); + newaddrsize = (tmp == NULL) ? 0 : *tmp; + + pr_debug(" -> newintsize=%d, newaddrsize=%d\n", + newintsize, newaddrsize); + + /* Check for malformed properties */ + if (imaplen < (newaddrsize + newintsize)) + goto fail; + + imap += newaddrsize + newintsize; + imaplen -= newaddrsize + newintsize; + + pr_debug(" -> imaplen=%d\n", imaplen); + } + if (!match) + goto fail; + + of_node_put(old); + old = of_node_get(newpar); + addrsize = newaddrsize; + intsize = newintsize; + intspec = imap - intsize; + addr = intspec - addrsize; + + skiplevel: + /* Iterate again with new parent */ + pr_debug(" -> new parent: %s\n", newpar ? newpar->full_name : "<>"); + of_node_put(ipar); + ipar = newpar; + newpar = NULL; + } + fail: + of_node_put(ipar); + of_node_put(old); + of_node_put(newpar); + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(of_irq_map_raw); + +/** + * of_irq_map_one - Resolve an interrupt for a device + * @device: the device whose interrupt is to be resolved + * @index: index of the interrupt to resolve + * @out_irq: structure of_irq filled by this function + * + * This function resolves an interrupt, walking the tree, for a given + * device-tree node. It's the high level pendant to of_irq_map_raw(). + */ +int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq) +{ + struct device_node *p; + const u32 *intspec, *tmp, *addr; + u32 intsize, intlen; + int res = -EINVAL; + + pr_debug("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index); + + /* OldWorld mac stuff is "special", handle out of line */ + if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) + return of_irq_map_oldworld(device, index, out_irq); + + /* Get the interrupts property */ + intspec = of_get_property(device, "interrupts", &intlen); + if (intspec == NULL) + return -EINVAL; + intlen /= sizeof(u32); + + pr_debug(" intspec=%d intlen=%d\n", *intspec, intlen); + + /* Get the reg property (if any) */ + addr = of_get_property(device, "reg", NULL); + + /* Look for the interrupt parent. */ + p = of_irq_find_parent(device); + if (p == NULL) + return -EINVAL; + + /* Get size of interrupt specifier */ + tmp = of_get_property(p, "#interrupt-cells", NULL); + if (tmp == NULL) + goto out; + intsize = *tmp; + + pr_debug(" intsize=%d intlen=%d\n", intsize, intlen); + + /* Check index */ + if ((index + 1) * intsize > intlen) + goto out; + + /* Get new specifier and map it */ + res = of_irq_map_raw(p, intspec + index * intsize, intsize, + addr, out_irq); + out: + of_node_put(p); + return res; +} +EXPORT_SYMBOL_GPL(of_irq_map_one); + +/** + * of_irq_to_resource - Decode a node's IRQ and return it as a resource + * @dev: pointer to device tree node + * @index: zero-based index of the irq + * @r: pointer to resource structure to return result into. + */ +int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) +{ + int irq = irq_of_parse_and_map(dev, index); + + /* Only dereference the resource if both the + * resource and the irq are valid. */ + if (r && irq != NO_IRQ) { + r->start = r->end = irq; + r->flags = IORESOURCE_IRQ; + } + + return irq; +} +EXPORT_SYMBOL_GPL(of_irq_to_resource); diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index 0e37c05b7dd8..5929781c104d 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -4,6 +4,8 @@ #if defined(CONFIG_OF) struct of_irq; #include +#include +#include #include /* @@ -30,11 +32,38 @@ struct of_irq { u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */ }; +/* + * Workarounds only applied to 32bit powermac machines + */ +#define OF_IMAP_OLDWORLD_MAC 0x00000001 +#define OF_IMAP_NO_PHANDLE 0x00000002 + +#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_PMAC) +extern unsigned int of_irq_workarounds; +extern struct device_node *of_irq_dflt_pic; +extern int of_irq_map_oldworld(struct device_node *device, int index, + struct of_irq *out_irq); +#else /* CONFIG_PPC32 && CONFIG_PPC_PMAC */ +#define of_irq_workarounds (0) +#define of_irq_dflt_pic (NULL) +static inline int of_irq_map_oldworld(struct device_node *device, int index, + struct of_irq *out_irq) +{ + return -EINVAL; +} +#endif /* CONFIG_PPC32 && CONFIG_PPC_PMAC */ + + +extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec, + u32 ointsize, const u32 *addr, + struct of_irq *out_irq); extern int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq); extern unsigned int irq_create_of_mapping(struct device_node *controller, const u32 *intspec, unsigned int intsize); +extern int of_irq_to_resource(struct device_node *dev, int index, + struct resource *r); #endif /* CONFIG_OF_IRQ */ #endif /* CONFIG_OF */ -- cgit v1.2.3 From 6b884a8d50a6eea2fb3dad7befe748f67193073b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:09 -0600 Subject: of/address: merge of_iomap() Merge common code between Microblaze and PowerPC. This patch creates new of_address.h and address.c files to containing address translation and mapping routines. First routine to be moved it of_iomap() Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt CC: Michal Simek CC: Stephen Rothwell --- arch/microblaze/include/asm/prom.h | 10 +--------- arch/microblaze/kernel/prom_parse.c | 11 ----------- arch/powerpc/include/asm/prom.h | 10 +--------- arch/powerpc/kernel/prom_parse.c | 11 ----------- drivers/of/Kconfig | 4 ++++ drivers/of/Makefile | 1 + drivers/of/address.c | 22 ++++++++++++++++++++++ include/linux/of_address.h | 9 +++++++++ 8 files changed, 38 insertions(+), 40 deletions(-) create mode 100644 drivers/of/address.c create mode 100644 include/linux/of_address.h (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index 5fbdfe76fe76..6411c3b3a80f 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -20,6 +20,7 @@ #ifndef __ASSEMBLY__ #include +#include #include #include #include @@ -103,15 +104,6 @@ extern const void *of_get_mac_address(struct device_node *np); struct pci_dev; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); -/** - * of_iomap - Maps the memory mapped IO for a given device_node - * @device: the device whose io range will be mapped - * @index: index of the io range - * - * Returns a pointer to the mapped memory - */ -extern void __iomem *of_iomap(struct device_node *device, int index); - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_MICROBLAZE_PROM_H */ diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c index e28968fa34c1..1159ba52ad4a 100644 --- a/arch/microblaze/kernel/prom_parse.c +++ b/arch/microblaze/kernel/prom_parse.c @@ -681,14 +681,3 @@ const void *of_get_mac_address(struct device_node *np) return NULL; } EXPORT_SYMBOL(of_get_mac_address); - -void __iomem *of_iomap(struct device_node *np, int index) -{ - struct resource res; - - if (of_address_to_resource(np, index, &res)) - return NULL; - - return ioremap(res.start, 1 + res.end - res.start); -} -EXPORT_SYMBOL(of_iomap); diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index 10d5ee556702..0abe379c6f33 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -18,6 +18,7 @@ */ #include #include +#include #include #include #include @@ -119,14 +120,5 @@ extern const void *of_get_mac_address(struct device_node *np); struct pci_dev; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); -/** - * of_iomap - Maps the memory mapped IO for a given device_node - * @device: the device whose io range will be mapped - * @index: index of the io range - * - * Returns a pointer to the mapped memory - */ -extern void __iomem *of_iomap(struct device_node *device, int index); - #endif /* __KERNEL__ */ #endif /* _POWERPC_PROM_H */ diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index d61a5c5fe690..1d5d4f6dfef5 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -715,14 +715,3 @@ const void *of_get_mac_address(struct device_node *np) return NULL; } EXPORT_SYMBOL(of_get_mac_address); - -void __iomem *of_iomap(struct device_node *np, int index) -{ - struct resource res; - - if (of_address_to_resource(np, index, &res)) - return NULL; - - return ioremap(res.start, 1 + res.end - res.start); -} -EXPORT_SYMBOL(of_iomap); diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index b87495efa16e..097f42aebe90 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -6,6 +6,10 @@ config OF_DYNAMIC def_bool y depends on OF && PPC_OF +config OF_ADDRESS + def_bool y + depends on OF && !SPARC + config OF_IRQ def_bool y depends on OF && !SPARC diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 3631a5ea0b47..0052c405463a 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,5 +1,6 @@ obj-y = base.o obj-$(CONFIG_OF_FLATTREE) += fdt.o +obj-$(CONFIG_OF_ADDRESS) += address.o obj-$(CONFIG_OF_IRQ) += irq.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o diff --git a/drivers/of/address.c b/drivers/of/address.c new file mode 100644 index 000000000000..258528d6c4fe --- /dev/null +++ b/drivers/of/address.c @@ -0,0 +1,22 @@ + +#include +#include +#include + +/** + * of_iomap - Maps the memory mapped IO for a given device_node + * @device: the device whose io range will be mapped + * @index: index of the io range + * + * Returns a pointer to the mapped memory + */ +void __iomem *of_iomap(struct device_node *np, int index) +{ + struct resource res; + + if (of_address_to_resource(np, index, &res)) + return NULL; + + return ioremap(res.start, 1 + res.end - res.start); +} +EXPORT_SYMBOL(of_iomap); diff --git a/include/linux/of_address.h b/include/linux/of_address.h new file mode 100644 index 000000000000..570831d7e795 --- /dev/null +++ b/include/linux/of_address.h @@ -0,0 +1,9 @@ +#ifndef __OF_ADDRESS_H +#define __OF_ADDRESS_H +#include +#include + +extern void __iomem *of_iomap(struct device_node *device, int index); + +#endif /* __OF_ADDRESS_H */ + -- cgit v1.2.3 From 1f5bef30cf6c66f097ea5dfc580a41924df888d1 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:09 -0600 Subject: of/address: merge of_address_to_resource() Merge common code between PowerPC and Microblaze. This patch also moves the prototype of pci_address_to_pio() out of pci-bridge.h and into prom.h because the only user of pci_address_to_pio() is of_address_to_resource(). Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt CC: Michal Simek CC: Stephen Rothwell --- arch/microblaze/include/asm/pci-bridge.h | 5 ---- arch/microblaze/include/asm/prom.h | 17 ++++++----- arch/microblaze/kernel/prom_parse.c | 46 +--------------------------- arch/powerpc/include/asm/pci-bridge.h | 5 ---- arch/powerpc/include/asm/prom.h | 17 ++++++----- arch/powerpc/kernel/prom_parse.c | 47 +---------------------------- drivers/of/address.c | 51 ++++++++++++++++++++++++++++++++ include/linux/of_address.h | 5 ++++ 8 files changed, 76 insertions(+), 117 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h index 0c77cda9f5d8..0c68764ab547 100644 --- a/arch/microblaze/include/asm/pci-bridge.h +++ b/arch/microblaze/include/asm/pci-bridge.h @@ -172,13 +172,8 @@ static inline int pci_has_flag(int flag) extern struct list_head hose_list; -extern unsigned long pci_address_to_pio(phys_addr_t address); extern int pcibios_vaddr_is_ioport(void __iomem *address); #else -static inline unsigned long pci_address_to_pio(phys_addr_t address) -{ - return (unsigned long)-1; -} static inline int pcibios_vaddr_is_ioport(void __iomem *address) { return 0; diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index 6411c3b3a80f..4e94c0706c50 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -65,17 +65,18 @@ extern const u32 *of_get_address(struct device_node *dev, int index, extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags); -/* Get an address as a resource. Note that if your address is - * a PIO address, the conversion will fail if the physical address - * can't be internally converted to an IO token with - * pci_address_to_pio(), that is because it's either called to early - * or it can't be matched to any host bridge IO space - */ -extern int of_address_to_resource(struct device_node *dev, int index, - struct resource *r); extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); +#ifdef CONFIG_PCI +extern unsigned long pci_address_to_pio(phys_addr_t address); +#else +static inline unsigned long pci_address_to_pio(phys_addr_t address) +{ + return (unsigned long)-1; +} +#endif /* CONFIG_PCI */ + /* Parse the ibm,dma-window property of an OF node into the busno, phys and * size parameters. */ diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c index 1159ba52ad4a..2f9cdd26ca12 100644 --- a/arch/microblaze/kernel/prom_parse.c +++ b/arch/microblaze/kernel/prom_parse.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -17,9 +18,6 @@ (ns) > 0) static struct of_bus *of_match_bus(struct device_node *np); -static int __of_address_to_resource(struct device_node *dev, - const u32 *addrp, u64 size, unsigned int flags, - struct resource *r); /* Debug utility */ #ifdef DEBUG @@ -576,48 +574,6 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, } EXPORT_SYMBOL(of_get_address); -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, - struct resource *r) -{ - u64 taddr; - - if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) - return -EINVAL; - taddr = of_translate_address(dev, addrp); - if (taddr == OF_BAD_ADDR) - return -EINVAL; - memset(r, 0, sizeof(struct resource)); - if (flags & IORESOURCE_IO) { - unsigned long port; - port = -1; /* pci_address_to_pio(taddr); */ - if (port == (unsigned long)-1) - return -EINVAL; - r->start = port; - r->end = port + size - 1; - } else { - r->start = taddr; - r->end = taddr + size - 1; - } - r->flags = flags; - r->name = dev->name; - return 0; -} - -int of_address_to_resource(struct device_node *dev, int index, - struct resource *r) -{ - const u32 *addrp; - u64 size; - unsigned int flags; - - addrp = of_get_address(dev, index, &size, &flags); - if (addrp == NULL) - return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); -} -EXPORT_SYMBOL_GPL(of_address_to_resource); - void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, unsigned long *busno, unsigned long *phys, unsigned long *size) { diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 76e1f313a58e..51e9e6f90d12 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -303,13 +303,8 @@ extern void pcibios_free_controller(struct pci_controller *phb); extern void pcibios_setup_phb_resources(struct pci_controller *hose); #ifdef CONFIG_PCI -extern unsigned long pci_address_to_pio(phys_addr_t address); extern int pcibios_vaddr_is_ioport(void __iomem *address); #else -static inline unsigned long pci_address_to_pio(phys_addr_t address) -{ - return (unsigned long)-1; -} static inline int pcibios_vaddr_is_ioport(void __iomem *address) { return 0; diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index 0abe379c6f33..ceace966c51c 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -70,14 +70,6 @@ static inline const u32 *of_get_pci_address(struct device_node *dev, } #endif /* CONFIG_PCI */ -/* Get an address as a resource. Note that if your address is - * a PIO address, the conversion will fail if the physical address - * can't be internally converted to an IO token with - * pci_address_to_pio(), that is because it's either called to early - * or it can't be matched to any host bridge IO space - */ -extern int of_address_to_resource(struct device_node *dev, int index, - struct resource *r); #ifdef CONFIG_PCI extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); @@ -89,6 +81,15 @@ static inline int of_pci_address_to_resource(struct device_node *dev, int bar, } #endif /* CONFIG_PCI */ +#ifdef CONFIG_PCI +extern unsigned long pci_address_to_pio(phys_addr_t address); +#else +static inline unsigned long pci_address_to_pio(phys_addr_t address) +{ + return (unsigned long)-1; +} +#endif /* CONFIG_PCI */ + /* Parse the ibm,dma-window property of an OF node into the busno, phys and * size parameters. */ diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 1d5d4f6dfef5..1dac535de78f 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -27,10 +28,6 @@ (ns) > 0) static struct of_bus *of_match_bus(struct device_node *np); -static int __of_address_to_resource(struct device_node *dev, - const u32 *addrp, u64 size, unsigned int flags, - struct resource *r); - /* Debug utility */ #ifdef DEBUG @@ -610,48 +607,6 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, } EXPORT_SYMBOL(of_get_address); -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, - struct resource *r) -{ - u64 taddr; - - if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) - return -EINVAL; - taddr = of_translate_address(dev, addrp); - if (taddr == OF_BAD_ADDR) - return -EINVAL; - memset(r, 0, sizeof(struct resource)); - if (flags & IORESOURCE_IO) { - unsigned long port; - port = pci_address_to_pio(taddr); - if (port == (unsigned long)-1) - return -EINVAL; - r->start = port; - r->end = port + size - 1; - } else { - r->start = taddr; - r->end = taddr + size - 1; - } - r->flags = flags; - r->name = dev->name; - return 0; -} - -int of_address_to_resource(struct device_node *dev, int index, - struct resource *r) -{ - const u32 *addrp; - u64 size; - unsigned int flags; - - addrp = of_get_address(dev, index, &size, &flags); - if (addrp == NULL) - return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); -} -EXPORT_SYMBOL_GPL(of_address_to_resource); - void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, unsigned long *busno, unsigned long *phys, unsigned long *size) { diff --git a/drivers/of/address.c b/drivers/of/address.c index 258528d6c4fe..c3819550f907 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -3,6 +3,57 @@ #include #include +int __of_address_to_resource(struct device_node *dev, const u32 *addrp, + u64 size, unsigned int flags, + struct resource *r) +{ + u64 taddr; + + if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) + return -EINVAL; + taddr = of_translate_address(dev, addrp); + if (taddr == OF_BAD_ADDR) + return -EINVAL; + memset(r, 0, sizeof(struct resource)); + if (flags & IORESOURCE_IO) { + unsigned long port; + port = pci_address_to_pio(taddr); + if (port == (unsigned long)-1) + return -EINVAL; + r->start = port; + r->end = port + size - 1; + } else { + r->start = taddr; + r->end = taddr + size - 1; + } + r->flags = flags; + r->name = dev->name; + return 0; +} + +/** + * of_address_to_resource - Translate device tree address and return as resource + * + * Note that if your address is a PIO address, the conversion will fail if + * the physical address can't be internally converted to an IO token with + * pci_address_to_pio(), that is because it's either called to early or it + * can't be matched to any host bridge IO space + */ +int of_address_to_resource(struct device_node *dev, int index, + struct resource *r) +{ + const u32 *addrp; + u64 size; + unsigned int flags; + + addrp = of_get_address(dev, index, &size, &flags); + if (addrp == NULL) + return -EINVAL; + return __of_address_to_resource(dev, addrp, size, flags, r); +} +EXPORT_SYMBOL_GPL(of_address_to_resource); + + /** * of_iomap - Maps the memory mapped IO for a given device_node * @device: the device whose io range will be mapped diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 570831d7e795..474b794ed9d2 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -3,6 +3,11 @@ #include #include +extern int __of_address_to_resource(struct device_node *dev, const u32 *addrp, + u64 size, unsigned int flags, + struct resource *r); +extern int of_address_to_resource(struct device_node *dev, int index, + struct resource *r); extern void __iomem *of_iomap(struct device_node *device, int index); #endif /* __OF_ADDRESS_H */ -- cgit v1.2.3 From dbbdee94734bf6f1db7af42008a53655e77cab8f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:10 -0600 Subject: of/address: Merge all of the bus translation code Microblaze and PowerPC share a large chunk of code for translating OF device tree data into usable addresses. Differences between the two consist of cosmetic differences, and the addition of dma-ranges support code to powerpc but not microblaze. This patch moves the powerpc version into common code and applies many of the cosmetic (non-functional) changes from the microblaze version. Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt CC: Michal Simek CC: Wolfram Sang CC: Stephen Rothwell --- arch/microblaze/include/asm/prom.h | 4 - arch/microblaze/kernel/prom_parse.c | 489 ---------------------------------- arch/powerpc/include/asm/prom.h | 4 - arch/powerpc/kernel/prom_parse.c | 515 ----------------------------------- drivers/of/address.c | 517 +++++++++++++++++++++++++++++++++++- include/linux/of_address.h | 4 +- 6 files changed, 515 insertions(+), 1018 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index 4e94c0706c50..cb9c3dd9a23b 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -52,10 +52,6 @@ extern void pci_create_OF_bus_map(void); * OF address retreival & translation */ -/* Translate an OF address block into a CPU physical address - */ -extern u64 of_translate_address(struct device_node *np, const u32 *addr); - /* Extract an address from a device, returns the region size and * the address space flags too. The PCI version uses a BAR number * instead of an absolute index diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c index 2f9cdd26ca12..d33ba17601fa 100644 --- a/arch/microblaze/kernel/prom_parse.c +++ b/arch/microblaze/kernel/prom_parse.c @@ -10,213 +10,7 @@ #include #include -#define PRu64 "%llx" - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 -#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ - (ns) > 0) - -static struct of_bus *of_match_bus(struct device_node *np); - -/* Debug utility */ -#ifdef DEBUG -static void of_dump_addr(const char *s, const u32 *addr, int na) -{ - printk(KERN_INFO "%s", s); - while (na--) - printk(KERN_INFO " %08x", *(addr++)); - printk(KERN_INFO "\n"); -} -#else -static void of_dump_addr(const char *s, const u32 *addr, int na) { } -#endif - -/* Callbacks for bus specific translators */ -struct of_bus { - const char *name; - const char *addresses; - int (*match)(struct device_node *parent); - void (*count_cells)(struct device_node *child, - int *addrc, int *sizec); - u64 (*map)(u32 *addr, const u32 *range, - int na, int ns, int pna); - int (*translate)(u32 *addr, u64 offset, int na); - unsigned int (*get_flags)(const u32 *addr); -}; - -/* - * Default translator (generic bus) - */ - -static void of_bus_default_count_cells(struct device_node *dev, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = of_n_addr_cells(dev); - if (sizec) - *sizec = of_n_size_cells(dev); -} - -static u64 of_bus_default_map(u32 *addr, const u32 *range, - int na, int ns, int pna) -{ - u64 cp, s, da; - - cp = of_read_number(range, na); - s = of_read_number(range + na + pna, ns); - da = of_read_number(addr, na); - - pr_debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n", - cp, s, da); - - 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_number(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(const u32 *addr) -{ - return IORESOURCE_MEM; -} - #ifdef CONFIG_PCI -/* - * PCI bus specific translator - */ - -static int of_bus_pci_match(struct device_node *np) -{ - /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */ - return !strcmp(np->type, "pci") || !strcmp(np->type, "vci"); -} - -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, const 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_number(range + 1, na - 1); - s = of_read_number(range + na + pna, ns); - da = of_read_number(addr + 1, na - 1); - - pr_debug("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); - - 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(const u32 *addr) -{ - unsigned int flags = 0; - u32 w = addr[0]; - - switch ((w >> 24) & 0x03) { - case 0x01: - flags |= IORESOURCE_IO; - break; - case 0x02: /* 32 bits */ - case 0x03: /* 64 bits */ - flags |= IORESOURCE_MEM; - break; - } - if (w & 0x40000000) - flags |= IORESOURCE_PREFETCH; - return flags; -} - -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, - unsigned int *flags) -{ - const u32 *prop; - unsigned int psize; - struct device_node *parent; - struct of_bus *bus; - int onesize, i, na, ns; - - /* Get parent & match bus type */ - parent = of_get_parent(dev); - if (parent == NULL) - return NULL; - bus = of_match_bus(parent); - if (strcmp(bus->name, "pci")) { - of_node_put(parent); - return NULL; - } - bus->count_cells(dev, &na, &ns); - of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) - return NULL; - - /* Get "reg" or "assigned-addresses" property */ - prop = of_get_property(dev, bus->addresses, &psize); - if (prop == NULL) - return NULL; - psize /= 4; - - onesize = na + ns; - for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) - if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { - if (size) - *size = of_read_number(prop + na, ns); - if (flags) - *flags = bus->get_flags(prop); - return prop; - } - return NULL; -} -EXPORT_SYMBOL(of_get_pci_address); - -int of_pci_address_to_resource(struct device_node *dev, int bar, - struct resource *r) -{ - const u32 *addrp; - u64 size; - unsigned int flags; - - addrp = of_get_pci_address(dev, bar, &size, &flags); - if (addrp == NULL) - return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); -} -EXPORT_SYMBOL_GPL(of_pci_address_to_resource); - -static u8 of_irq_pci_swizzle(u8 slot, u8 pin) -{ - return (((pin - 1) + slot) % 4) + 1; -} - int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) { struct device_node *dn, *ppnode; @@ -291,289 +85,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) EXPORT_SYMBOL_GPL(of_irq_map_pci); #endif /* CONFIG_PCI */ -/* - * 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, const 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_number(range + 1, na - 1); - s = of_read_number(range + na + pna, ns); - da = of_read_number(addr + 1, na - 1); - - pr_debug("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); - - 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(const u32 *addr) -{ - unsigned int flags = 0; - u32 w = addr[0]; - - if (w & 1) - flags |= IORESOURCE_IO; - else - flags |= IORESOURCE_MEM; - return flags; -} - -/* - * Array of bus specific translators - */ - -static struct of_bus of_busses[] = { -#ifdef CONFIG_PCI - /* PCI */ - { - .name = "pci", - .addresses = "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, - }, -#endif /* CONFIG_PCI */ - /* ISA */ - { - .name = "isa", - .addresses = "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, - }, - /* Default */ - { - .name = "default", - .addresses = "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 of_translate_one(struct device_node *parent, struct of_bus *bus, - struct of_bus *pbus, u32 *addr, - int na, int ns, int pna) -{ - const u32 *ranges; - unsigned int rlen; - int rone; - u64 offset = OF_BAD_ADDR; - - /* Normally, an absence of a "ranges" property means we are - * crossing a non-translatable boundary, and thus the addresses - * below the current not cannot be converted to CPU physical ones. - * Unfortunately, while this is very clear in the spec, it's not - * what Apple understood, and they do have things like /uni-n or - * /ht nodes with no "ranges" property and a lot of perfectly - * useable mapped devices below them. Thus we treat the absence of - * "ranges" as equivalent to an empty "ranges" property which means - * a 1:1 translation at that level. It's up to the caller not to try - * to translate addresses that aren't supposed to be translated in - * the first place. --BenH. - */ - ranges = of_get_property(parent, "ranges", (int *) &rlen); - if (ranges == NULL || rlen == 0) { - offset = of_read_number(addr, na); - memset(addr, 0, pna * 4); - pr_debug("OF: no ranges, 1:1 translation\n"); - goto finish; - } - - pr_debug("OF: walking ranges...\n"); - - /* 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) { - pr_debug("OF: not found !\n"); - return 1; - } - memcpy(addr, ranges + na, 4 * pna); - - finish: - of_dump_addr("OF: parent translation for:", addr, pna); - pr_debug("OF: with offset: "PRu64"\n", offset); - - /* Translate it into parent bus space */ - return pbus->translate(addr, offset, pna); -} - -/* - * Translate an address from the device-tree into a CPU physical address, - * this walks up the tree and applies the various bus mappings on the - * way. - * - * Note: We consider that crossing any level with #size-cells == 0 to mean - * that translation is impossible (that is we are not dealing with a value - * that can be mapped to a cpu physical address). This is not really specified - * that way, but this is traditionally the way IBM at least do things - */ -u64 of_translate_address(struct device_node *dev, const u32 *in_addr) -{ - struct device_node *parent = NULL; - struct of_bus *bus, *pbus; - u32 addr[OF_MAX_ADDR_CELLS]; - int na, ns, pna, pns; - u64 result = OF_BAD_ADDR; - - pr_debug("OF: ** translation for device %s **\n", dev->full_name); - - /* Increase refcount at current level */ - of_node_get(dev); - - /* Get parent & match bus type */ - parent = of_get_parent(dev); - if (parent == NULL) - goto bail; - bus = of_match_bus(parent); - - /* Cound address cells & copy address locally */ - bus->count_cells(dev, &na, &ns); - if (!OF_CHECK_COUNTS(na, ns)) { - printk(KERN_ERR "prom_parse: Bad cell count for %s\n", - dev->full_name); - goto bail; - } - memcpy(addr, in_addr, na * 4); - - pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n", - bus->name, na, ns, parent->full_name); - of_dump_addr("OF: translating address:", addr, na); - - /* Translate */ - for (;;) { - /* Switch to parent bus */ - of_node_put(dev); - dev = parent; - parent = of_get_parent(dev); - - /* If root, we have finished */ - if (parent == NULL) { - pr_debug("OF: reached root node\n"); - result = of_read_number(addr, na); - break; - } - - /* Get new parent bus and counts */ - pbus = of_match_bus(parent); - pbus->count_cells(dev, &pna, &pns); - if (!OF_CHECK_COUNTS(pna, pns)) { - printk(KERN_ERR "prom_parse: Bad cell count for %s\n", - dev->full_name); - break; - } - - pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", - pbus->name, pna, pns, parent->full_name); - - /* Apply bus translation */ - if (of_translate_one(dev, bus, pbus, addr, na, ns, pna)) - break; - - /* Complete the move up one level */ - na = pna; - ns = pns; - bus = pbus; - - of_dump_addr("OF: one level translation:", addr, na); - } - bail: - of_node_put(parent); - of_node_put(dev); - - return result; -} -EXPORT_SYMBOL(of_translate_address); - -const u32 *of_get_address(struct device_node *dev, int index, u64 *size, - unsigned int *flags) -{ - const u32 *prop; - unsigned int psize; - struct device_node *parent; - struct of_bus *bus; - int onesize, i, na, ns; - - /* Get parent & match bus type */ - parent = of_get_parent(dev); - if (parent == NULL) - return NULL; - bus = of_match_bus(parent); - bus->count_cells(dev, &na, &ns); - of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) - return NULL; - - /* Get "reg" or "assigned-addresses" property */ - prop = of_get_property(dev, bus->addresses, (int *) &psize); - if (prop == NULL) - return NULL; - psize /= 4; - - onesize = na + ns; - for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) - if (i == index) { - if (size) - *size = of_read_number(prop + na, ns); - if (flags) - *flags = bus->get_flags(prop); - return prop; - } - return NULL; -} -EXPORT_SYMBOL(of_get_address); - void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, unsigned long *busno, unsigned long *phys, unsigned long *size) { diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index ceace966c51c..f864722679e8 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -45,10 +45,6 @@ extern void pci_create_OF_bus_map(void); * OF address retreival & translation */ -/* Translate an OF address block into a CPU physical address - */ -extern u64 of_translate_address(struct device_node *np, const u32 *addr); - /* Translate a DMA address from device space to CPU space */ extern u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr); diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 1dac535de78f..88334af038e5 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -10,225 +10,7 @@ #include #include -#ifdef DEBUG -#define DBG(fmt...) do { printk(fmt); } while(0) -#else -#define DBG(fmt...) do { } while(0) -#endif - -#ifdef CONFIG_PPC64 -#define PRu64 "%lx" -#else -#define PRu64 "%llx" -#endif - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 -#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ - (ns) > 0) - -static struct of_bus *of_match_bus(struct device_node *np); - -/* Debug utility */ -#ifdef DEBUG -static void of_dump_addr(const char *s, const u32 *addr, int na) -{ - printk("%s", s); - while(na--) - printk(" %08x", *(addr++)); - printk("\n"); -} -#else -static void of_dump_addr(const char *s, const u32 *addr, int na) { } -#endif - - -/* Callbacks for bus specific translators */ -struct of_bus { - const char *name; - const char *addresses; - int (*match)(struct device_node *parent); - void (*count_cells)(struct device_node *child, - int *addrc, int *sizec); - u64 (*map)(u32 *addr, const u32 *range, - int na, int ns, int pna); - int (*translate)(u32 *addr, u64 offset, int na); - unsigned int (*get_flags)(const u32 *addr); -}; - - -/* - * Default translator (generic bus) - */ - -static void of_bus_default_count_cells(struct device_node *dev, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = of_n_addr_cells(dev); - if (sizec) - *sizec = of_n_size_cells(dev); -} - -static u64 of_bus_default_map(u32 *addr, const u32 *range, - int na, int ns, int pna) -{ - u64 cp, s, da; - - cp = of_read_number(range, na); - s = of_read_number(range + na + pna, ns); - da = of_read_number(addr, na); - - DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n", - cp, s, da); - - 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_number(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(const u32 *addr) -{ - return IORESOURCE_MEM; -} - - #ifdef CONFIG_PCI -/* - * PCI bus specific translator - */ - -static int of_bus_pci_match(struct device_node *np) -{ - /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */ - return !strcmp(np->type, "pci") || !strcmp(np->type, "vci"); -} - -static void of_bus_pci_count_cells(struct device_node *np, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 3; - if (sizec) - *sizec = 2; -} - -static unsigned int of_bus_pci_get_flags(const u32 *addr) -{ - unsigned int flags = 0; - u32 w = addr[0]; - - switch((w >> 24) & 0x03) { - case 0x01: - flags |= IORESOURCE_IO; - break; - case 0x02: /* 32 bits */ - case 0x03: /* 64 bits */ - flags |= IORESOURCE_MEM; - break; - } - if (w & 0x40000000) - flags |= IORESOURCE_PREFETCH; - return flags; -} - -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) -{ - u64 cp, s, da; - unsigned int af, rf; - - af = of_bus_pci_get_flags(addr); - rf = of_bus_pci_get_flags(range); - - /* Check address type match */ - if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO)) - return OF_BAD_ADDR; - - /* Read address values, skipping high cell */ - cp = of_read_number(range + 1, na - 1); - s = of_read_number(range + na + pna, ns); - da = of_read_number(addr + 1, na - 1); - - DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); - - 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); -} - -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, - unsigned int *flags) -{ - const u32 *prop; - unsigned int psize; - struct device_node *parent; - struct of_bus *bus; - int onesize, i, na, ns; - - /* Get parent & match bus type */ - parent = of_get_parent(dev); - if (parent == NULL) - return NULL; - bus = of_match_bus(parent); - if (strcmp(bus->name, "pci")) { - of_node_put(parent); - return NULL; - } - bus->count_cells(dev, &na, &ns); - of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) - return NULL; - - /* Get "reg" or "assigned-addresses" property */ - prop = of_get_property(dev, bus->addresses, &psize); - if (prop == NULL) - return NULL; - psize /= 4; - - onesize = na + ns; - for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) - if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { - if (size) - *size = of_read_number(prop + na, ns); - if (flags) - *flags = bus->get_flags(prop); - return prop; - } - return NULL; -} -EXPORT_SYMBOL(of_get_pci_address); - -int of_pci_address_to_resource(struct device_node *dev, int bar, - struct resource *r) -{ - const u32 *addrp; - u64 size; - unsigned int flags; - - addrp = of_get_pci_address(dev, bar, &size, &flags); - if (addrp == NULL) - return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); -} -EXPORT_SYMBOL_GPL(of_pci_address_to_resource); - int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) { struct device_node *dn, *ppnode; @@ -310,303 +92,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) EXPORT_SYMBOL_GPL(of_irq_map_pci); #endif /* CONFIG_PCI */ -/* - * 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, const 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_number(range + 1, na - 1); - s = of_read_number(range + na + pna, ns); - da = of_read_number(addr + 1, na - 1); - - DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); - - 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(const u32 *addr) -{ - unsigned int flags = 0; - u32 w = addr[0]; - - if (w & 1) - flags |= IORESOURCE_IO; - else - flags |= IORESOURCE_MEM; - return flags; -} - - -/* - * Array of bus specific translators - */ - -static struct of_bus of_busses[] = { -#ifdef CONFIG_PCI - /* PCI */ - { - .name = "pci", - .addresses = "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, - }, -#endif /* CONFIG_PCI */ - /* ISA */ - { - .name = "isa", - .addresses = "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, - }, - /* Default */ - { - .name = "default", - .addresses = "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 of_translate_one(struct device_node *parent, struct of_bus *bus, - struct of_bus *pbus, u32 *addr, - int na, int ns, int pna, const char *rprop) -{ - const u32 *ranges; - unsigned int rlen; - int rone; - u64 offset = OF_BAD_ADDR; - - /* Normally, an absence of a "ranges" property means we are - * crossing a non-translatable boundary, and thus the addresses - * below the current not cannot be converted to CPU physical ones. - * Unfortunately, while this is very clear in the spec, it's not - * what Apple understood, and they do have things like /uni-n or - * /ht nodes with no "ranges" property and a lot of perfectly - * useable mapped devices below them. Thus we treat the absence of - * "ranges" as equivalent to an empty "ranges" property which means - * a 1:1 translation at that level. It's up to the caller not to try - * to translate addresses that aren't supposed to be translated in - * the first place. --BenH. - */ - ranges = of_get_property(parent, rprop, &rlen); - if (ranges == NULL || rlen == 0) { - offset = of_read_number(addr, na); - memset(addr, 0, pna * 4); - DBG("OF: no ranges, 1:1 translation\n"); - goto finish; - } - - DBG("OF: walking ranges...\n"); - - /* 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) { - DBG("OF: not found !\n"); - return 1; - } - memcpy(addr, ranges + na, 4 * pna); - - finish: - of_dump_addr("OF: parent translation for:", addr, pna); - DBG("OF: with offset: "PRu64"\n", offset); - - /* Translate it into parent bus space */ - return pbus->translate(addr, offset, pna); -} - - -/* - * Translate an address from the device-tree into a CPU physical address, - * this walks up the tree and applies the various bus mappings on the - * way. - * - * Note: We consider that crossing any level with #size-cells == 0 to mean - * that translation is impossible (that is we are not dealing with a value - * that can be mapped to a cpu physical address). This is not really specified - * that way, but this is traditionally the way IBM at least do things - */ -u64 __of_translate_address(struct device_node *dev, const u32 *in_addr, - const char *rprop) -{ - struct device_node *parent = NULL; - struct of_bus *bus, *pbus; - u32 addr[OF_MAX_ADDR_CELLS]; - int na, ns, pna, pns; - u64 result = OF_BAD_ADDR; - - DBG("OF: ** translation for device %s **\n", dev->full_name); - - /* Increase refcount at current level */ - of_node_get(dev); - - /* Get parent & match bus type */ - parent = of_get_parent(dev); - if (parent == NULL) - goto bail; - bus = of_match_bus(parent); - - /* Cound address cells & copy address locally */ - bus->count_cells(dev, &na, &ns); - if (!OF_CHECK_COUNTS(na, ns)) { - printk(KERN_ERR "prom_parse: Bad cell count for %s\n", - dev->full_name); - goto bail; - } - memcpy(addr, in_addr, na * 4); - - DBG("OF: bus is %s (na=%d, ns=%d) on %s\n", - bus->name, na, ns, parent->full_name); - of_dump_addr("OF: translating address:", addr, na); - - /* Translate */ - for (;;) { - /* Switch to parent bus */ - of_node_put(dev); - dev = parent; - parent = of_get_parent(dev); - - /* If root, we have finished */ - if (parent == NULL) { - DBG("OF: reached root node\n"); - result = of_read_number(addr, na); - break; - } - - /* Get new parent bus and counts */ - pbus = of_match_bus(parent); - pbus->count_cells(dev, &pna, &pns); - if (!OF_CHECK_COUNTS(pna, pns)) { - printk(KERN_ERR "prom_parse: Bad cell count for %s\n", - dev->full_name); - break; - } - - DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n", - pbus->name, pna, pns, parent->full_name); - - /* Apply bus translation */ - if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)) - break; - - /* Complete the move up one level */ - na = pna; - ns = pns; - bus = pbus; - - of_dump_addr("OF: one level translation:", addr, na); - } - bail: - of_node_put(parent); - of_node_put(dev); - - return result; -} - -u64 of_translate_address(struct device_node *dev, const u32 *in_addr) -{ - return __of_translate_address(dev, in_addr, "ranges"); -} -EXPORT_SYMBOL(of_translate_address); - -u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr) -{ - return __of_translate_address(dev, in_addr, "dma-ranges"); -} -EXPORT_SYMBOL(of_translate_dma_address); - -const u32 *of_get_address(struct device_node *dev, int index, u64 *size, - unsigned int *flags) -{ - const u32 *prop; - unsigned int psize; - struct device_node *parent; - struct of_bus *bus; - int onesize, i, na, ns; - - /* Get parent & match bus type */ - parent = of_get_parent(dev); - if (parent == NULL) - return NULL; - bus = of_match_bus(parent); - bus->count_cells(dev, &na, &ns); - of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) - return NULL; - - /* Get "reg" or "assigned-addresses" property */ - prop = of_get_property(dev, bus->addresses, &psize); - if (prop == NULL) - return NULL; - psize /= 4; - - onesize = na + ns; - for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) - if (i == index) { - if (size) - *size = of_read_number(prop + na, ns); - if (flags) - *flags = bus->get_flags(prop); - return prop; - } - return NULL; -} -EXPORT_SYMBOL(of_get_address); - void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, unsigned long *busno, unsigned long *phys, unsigned long *size) { diff --git a/drivers/of/address.c b/drivers/of/address.c index c3819550f907..2a905d560c1c 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -1,11 +1,522 @@ #include #include +#include #include +#include +#include -int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, - struct resource *r) +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 +#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ + (ns) > 0) + +static struct of_bus *of_match_bus(struct device_node *np); +static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, + u64 size, unsigned int flags, + struct resource *r); + +/* Debug utility */ +#ifdef DEBUG +static void of_dump_addr(const char *s, const u32 *addr, int na) +{ + printk(KERN_DEBUG "%s", s); + while (na--) + printk(" %08x", *(addr++)); + printk("\n"); +} +#else +static void of_dump_addr(const char *s, const u32 *addr, int na) { } +#endif + +/* Callbacks for bus specific translators */ +struct of_bus { + const char *name; + const char *addresses; + int (*match)(struct device_node *parent); + void (*count_cells)(struct device_node *child, + int *addrc, int *sizec); + u64 (*map)(u32 *addr, const u32 *range, + int na, int ns, int pna); + int (*translate)(u32 *addr, u64 offset, int na); + unsigned int (*get_flags)(const u32 *addr); +}; + +/* + * Default translator (generic bus) + */ + +static void of_bus_default_count_cells(struct device_node *dev, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = of_n_addr_cells(dev); + if (sizec) + *sizec = of_n_size_cells(dev); +} + +static u64 of_bus_default_map(u32 *addr, const u32 *range, + int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = of_read_number(range, na); + s = of_read_number(range + na + pna, ns); + da = of_read_number(addr, na); + + pr_debug("OF: default map, cp=%llx, s=%llx, da=%llx\n", + (unsigned long long)cp, (unsigned long long)s, + (unsigned long long)da); + + 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_number(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(const u32 *addr) +{ + return IORESOURCE_MEM; +} + +#ifdef CONFIG_PCI +/* + * PCI bus specific translator + */ + +static int of_bus_pci_match(struct device_node *np) +{ + /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */ + return !strcmp(np->type, "pci") || !strcmp(np->type, "vci"); +} + +static void of_bus_pci_count_cells(struct device_node *np, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 3; + if (sizec) + *sizec = 2; +} + +static unsigned int of_bus_pci_get_flags(const u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + switch((w >> 24) & 0x03) { + case 0x01: + flags |= IORESOURCE_IO; + break; + case 0x02: /* 32 bits */ + case 0x03: /* 64 bits */ + flags |= IORESOURCE_MEM; + break; + } + if (w & 0x40000000) + flags |= IORESOURCE_PREFETCH; + return flags; +} + +static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + unsigned int af, rf; + + af = of_bus_pci_get_flags(addr); + rf = of_bus_pci_get_flags(range); + + /* Check address type match */ + if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO)) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_number(range + 1, na - 1); + s = of_read_number(range + na + pna, ns); + da = of_read_number(addr + 1, na - 1); + + pr_debug("OF: PCI map, cp=%llx, s=%llx, da=%llx\n", + (unsigned long long)cp, (unsigned long long)s, + (unsigned long long)da); + + 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); +} + +const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, + unsigned int *flags) +{ + const u32 *prop; + unsigned int psize; + struct device_node *parent; + struct of_bus *bus; + int onesize, i, na, ns; + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + return NULL; + bus = of_match_bus(parent); + if (strcmp(bus->name, "pci")) { + of_node_put(parent); + return NULL; + } + bus->count_cells(dev, &na, &ns); + of_node_put(parent); + if (!OF_CHECK_COUNTS(na, ns)) + return NULL; + + /* Get "reg" or "assigned-addresses" property */ + prop = of_get_property(dev, bus->addresses, &psize); + if (prop == NULL) + return NULL; + psize /= 4; + + onesize = na + ns; + for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) + if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { + if (size) + *size = of_read_number(prop + na, ns); + if (flags) + *flags = bus->get_flags(prop); + return prop; + } + return NULL; +} +EXPORT_SYMBOL(of_get_pci_address); + +int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r) +{ + const u32 *addrp; + u64 size; + unsigned int flags; + + addrp = of_get_pci_address(dev, bar, &size, &flags); + if (addrp == NULL) + return -EINVAL; + return __of_address_to_resource(dev, addrp, size, flags, r); +} +EXPORT_SYMBOL_GPL(of_pci_address_to_resource); +#endif /* CONFIG_PCI */ + +/* + * 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, const 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_number(range + 1, na - 1); + s = of_read_number(range + na + pna, ns); + da = of_read_number(addr + 1, na - 1); + + pr_debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n", + (unsigned long long)cp, (unsigned long long)s, + (unsigned long long)da); + + 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(const u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + if (w & 1) + flags |= IORESOURCE_IO; + else + flags |= IORESOURCE_MEM; + return flags; +} + +/* + * Array of bus specific translators + */ + +static struct of_bus of_busses[] = { +#ifdef CONFIG_PCI + /* PCI */ + { + .name = "pci", + .addresses = "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, + }, +#endif /* CONFIG_PCI */ + /* ISA */ + { + .name = "isa", + .addresses = "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, + }, + /* Default */ + { + .name = "default", + .addresses = "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 of_translate_one(struct device_node *parent, struct of_bus *bus, + struct of_bus *pbus, u32 *addr, + int na, int ns, int pna, const char *rprop) +{ + const u32 *ranges; + unsigned int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + /* Normally, an absence of a "ranges" property means we are + * crossing a non-translatable boundary, and thus the addresses + * below the current not cannot be converted to CPU physical ones. + * Unfortunately, while this is very clear in the spec, it's not + * what Apple understood, and they do have things like /uni-n or + * /ht nodes with no "ranges" property and a lot of perfectly + * useable mapped devices below them. Thus we treat the absence of + * "ranges" as equivalent to an empty "ranges" property which means + * a 1:1 translation at that level. It's up to the caller not to try + * to translate addresses that aren't supposed to be translated in + * the first place. --BenH. + */ + ranges = of_get_property(parent, rprop, &rlen); + if (ranges == NULL || rlen == 0) { + offset = of_read_number(addr, na); + memset(addr, 0, pna * 4); + pr_debug("OF: no ranges, 1:1 translation\n"); + goto finish; + } + + pr_debug("OF: walking ranges...\n"); + + /* 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) { + pr_debug("OF: not found !\n"); + return 1; + } + memcpy(addr, ranges + na, 4 * pna); + + finish: + of_dump_addr("OF: parent translation for:", addr, pna); + pr_debug("OF: with offset: %llx\n", (unsigned long long)offset); + + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +/* + * Translate an address from the device-tree into a CPU physical address, + * this walks up the tree and applies the various bus mappings on the + * way. + * + * Note: We consider that crossing any level with #size-cells == 0 to mean + * that translation is impossible (that is we are not dealing with a value + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + */ +u64 __of_translate_address(struct device_node *dev, const u32 *in_addr, + const char *rprop) +{ + struct device_node *parent = NULL; + struct of_bus *bus, *pbus; + u32 addr[OF_MAX_ADDR_CELLS]; + int na, ns, pna, pns; + u64 result = OF_BAD_ADDR; + + pr_debug("OF: ** translation for device %s **\n", dev->full_name); + + /* Increase refcount at current level */ + of_node_get(dev); + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + goto bail; + bus = of_match_bus(parent); + + /* Cound address cells & copy address locally */ + bus->count_cells(dev, &na, &ns); + if (!OF_CHECK_COUNTS(na, ns)) { + printk(KERN_ERR "prom_parse: Bad cell count for %s\n", + dev->full_name); + goto bail; + } + memcpy(addr, in_addr, na * 4); + + pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n", + bus->name, na, ns, parent->full_name); + of_dump_addr("OF: translating address:", addr, na); + + /* Translate */ + for (;;) { + /* Switch to parent bus */ + of_node_put(dev); + dev = parent; + parent = of_get_parent(dev); + + /* If root, we have finished */ + if (parent == NULL) { + pr_debug("OF: reached root node\n"); + result = of_read_number(addr, na); + break; + } + + /* Get new parent bus and counts */ + pbus = of_match_bus(parent); + pbus->count_cells(dev, &pna, &pns); + if (!OF_CHECK_COUNTS(pna, pns)) { + printk(KERN_ERR "prom_parse: Bad cell count for %s\n", + dev->full_name); + break; + } + + pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", + pbus->name, pna, pns, parent->full_name); + + /* Apply bus translation */ + if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)) + break; + + /* Complete the move up one level */ + na = pna; + ns = pns; + bus = pbus; + + of_dump_addr("OF: one level translation:", addr, na); + } + bail: + of_node_put(parent); + of_node_put(dev); + + return result; +} + +u64 of_translate_address(struct device_node *dev, const u32 *in_addr) +{ + return __of_translate_address(dev, in_addr, "ranges"); +} +EXPORT_SYMBOL(of_translate_address); + +u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr) +{ + return __of_translate_address(dev, in_addr, "dma-ranges"); +} +EXPORT_SYMBOL(of_translate_dma_address); + +const u32 *of_get_address(struct device_node *dev, int index, u64 *size, + unsigned int *flags) +{ + const u32 *prop; + unsigned int psize; + struct device_node *parent; + struct of_bus *bus; + int onesize, i, na, ns; + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + return NULL; + bus = of_match_bus(parent); + bus->count_cells(dev, &na, &ns); + of_node_put(parent); + if (!OF_CHECK_COUNTS(na, ns)) + return NULL; + + /* Get "reg" or "assigned-addresses" property */ + prop = of_get_property(dev, bus->addresses, &psize); + if (prop == NULL) + return NULL; + psize /= 4; + + onesize = na + ns; + for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) + if (i == index) { + if (size) + *size = of_read_number(prop + na, ns); + if (flags) + *flags = bus->get_flags(prop); + return prop; + } + return NULL; +} +EXPORT_SYMBOL(of_get_address); + +static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, + u64 size, unsigned int flags, + struct resource *r) { u64 taddr; diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 474b794ed9d2..cc567df9a00d 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -3,9 +3,7 @@ #include #include -extern int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, - struct resource *r); +extern u64 of_translate_address(struct device_node *np, const u32 *addr); extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); extern void __iomem *of_iomap(struct device_node *device, int index); -- cgit v1.2.3 From dd27dcda37f0b1a3b674760fb411abc5c8fe309c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:12 -0600 Subject: of/device: merge of_device_uevent Merge common code between powerpc and microblaze Signed-off-by: Grant Likely CC: Michal Simek CC: Wolfram Sang CC: Stephen Rothwell CC: Benjamin Herrenschmidt CC: microblaze-uclinux@itee.uq.edu.au CC: linuxppc-dev@ozlabs.org --- arch/microblaze/include/asm/of_device.h | 3 -- arch/microblaze/kernel/of_device.c | 48 -------------------------------- arch/powerpc/include/asm/of_device.h | 3 -- arch/powerpc/kernel/of_device.c | 49 --------------------------------- drivers/of/device.c | 48 ++++++++++++++++++++++++++++++++ include/linux/of_device.h | 4 +++ 6 files changed, 52 insertions(+), 103 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/of_device.h b/arch/microblaze/include/asm/of_device.h index 0a5f3f914b42..58e627dc1412 100644 --- a/arch/microblaze/include/asm/of_device.h +++ b/arch/microblaze/include/asm/of_device.h @@ -22,9 +22,6 @@ extern struct of_device *of_device_alloc(struct device_node *np, const char *bus_id, struct device *parent); -extern int of_device_uevent(struct device *dev, - struct kobj_uevent_env *env); - extern void of_device_make_bus_id(struct of_device *dev); /* This is just here during the transition */ diff --git a/arch/microblaze/kernel/of_device.c b/arch/microblaze/kernel/of_device.c index b372787886ed..3a367d788451 100644 --- a/arch/microblaze/kernel/of_device.c +++ b/arch/microblaze/kernel/of_device.c @@ -62,51 +62,3 @@ struct of_device *of_device_alloc(struct device_node *np, return dev; } EXPORT_SYMBOL(of_device_alloc); - -int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct of_device *ofdev; - const char *compat; - int seen = 0, cplen, sl; - - if (!dev) - return -ENODEV; - - ofdev = to_of_device(dev); - - if (add_uevent_var(env, "OF_NAME=%s", ofdev->dev.of_node->name)) - return -ENOMEM; - - if (add_uevent_var(env, "OF_TYPE=%s", ofdev->dev.of_node->type)) - return -ENOMEM; - - /* Since the compatible field can contain pretty much anything - * it's not really legal to split it out with commas. We split it - * up using a number of environment variables instead. */ - - compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen); - while (compat && *compat && cplen > 0) { - if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) - return -ENOMEM; - - sl = strlen(compat) + 1; - compat += sl; - cplen -= sl; - seen++; - } - - if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) - return -ENOMEM; - - /* modalias is trickier, we add it in 2 steps */ - if (add_uevent_var(env, "MODALIAS=")) - return -ENOMEM; - sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1], - sizeof(env->buf) - env->buflen); - if (sl >= (sizeof(env->buf) - env->buflen)) - return -ENOMEM; - env->buflen += sl; - - return 0; -} -EXPORT_SYMBOL(of_device_uevent); diff --git a/arch/powerpc/include/asm/of_device.h b/arch/powerpc/include/asm/of_device.h index cb36632f953c..5d5103cac641 100644 --- a/arch/powerpc/include/asm/of_device.h +++ b/arch/powerpc/include/asm/of_device.h @@ -9,8 +9,5 @@ extern struct of_device *of_device_alloc(struct device_node *np, const char *bus_id, struct device *parent); -extern int of_device_uevent(struct device *dev, - struct kobj_uevent_env *env); - #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_OF_DEVICE_H */ diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index df78e0236a02..db91a9dbafb5 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c @@ -82,52 +82,3 @@ struct of_device *of_device_alloc(struct device_node *np, return dev; } EXPORT_SYMBOL(of_device_alloc); - -int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct of_device *ofdev; - const char *compat; - int seen = 0, cplen, sl; - - if (!dev) - return -ENODEV; - - ofdev = to_of_device(dev); - - if (add_uevent_var(env, "OF_NAME=%s", ofdev->dev.of_node->name)) - return -ENOMEM; - - if (add_uevent_var(env, "OF_TYPE=%s", ofdev->dev.of_node->type)) - return -ENOMEM; - - /* Since the compatible field can contain pretty much anything - * it's not really legal to split it out with commas. We split it - * up using a number of environment variables instead. */ - - compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen); - while (compat && *compat && cplen > 0) { - if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) - return -ENOMEM; - - sl = strlen (compat) + 1; - compat += sl; - cplen -= sl; - seen++; - } - - if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) - return -ENOMEM; - - /* modalias is trickier, we add it in 2 steps */ - if (add_uevent_var(env, "MODALIAS=")) - return -ENOMEM; - sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1], - sizeof(env->buf) - env->buflen); - if (sl >= (sizeof(env->buf) - env->buflen)) - return -ENOMEM; - env->buflen += sl; - - return 0; -} -EXPORT_SYMBOL(of_device_uevent); -EXPORT_SYMBOL(of_device_get_modalias); diff --git a/drivers/of/device.c b/drivers/of/device.c index 7d18f8e0b013..275cc9cee14c 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -170,3 +170,51 @@ ssize_t of_device_get_modalias(struct of_device *ofdev, return tsize; } + +/** + * of_device_uevent - Display OF related uevent information + */ +int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + const char *compat; + int seen = 0, cplen, sl; + + if ((!dev) || (!dev->of_node)) + return -ENODEV; + + if (add_uevent_var(env, "OF_NAME=%s", dev->of_node->name)) + return -ENOMEM; + + if (add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type)) + return -ENOMEM; + + /* Since the compatible field can contain pretty much anything + * it's not really legal to split it out with commas. We split it + * up using a number of environment variables instead. */ + + compat = of_get_property(dev->of_node, "compatible", &cplen); + while (compat && *compat && cplen > 0) { + if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) + return -ENOMEM; + + sl = strlen(compat) + 1; + compat += sl; + cplen -= sl; + seen++; + } + + if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) + return -ENOMEM; + + /* modalias is trickier, we add it in 2 steps */ + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + + sl = of_device_get_modalias(to_of_device(dev), &env->buf[env->buflen-1], + sizeof(env->buf) - env->buflen); + if (sl >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += sl; + + return 0; +} diff --git a/include/linux/of_device.h b/include/linux/of_device.h index a3ae5900fc58..da83e734c026 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -44,6 +44,10 @@ static inline void of_device_free(struct of_device *dev) extern ssize_t of_device_get_modalias(struct of_device *ofdev, char *str, ssize_t len); + +extern int of_device_uevent(struct device *dev, struct kobj_uevent_env *env); + + #endif /* CONFIG_OF_DEVICE */ #endif /* _LINUX_OF_DEVICE_H */ -- cgit v1.2.3 From 5fd200f3b351183b5489cef69961c60af9cead2f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:13 -0600 Subject: of/device: Merge of_platform_bus_probe() Merge common code between PowerPC and microblaze. This patch merges the code that scans the tree and registers devices. The functions merged are of_platform_bus_probe(), of_platform_bus_create(), and of_platform_device_create(). This patch also move the of_default_bus_ids[] table out of a Microblaze header file and makes it non-static. The device ids table isn't merged because powerpc and microblaze use different default data. Signed-off-by: Grant Likely CC: Michal Simek CC: Grant Likely CC: Benjamin Herrenschmidt CC: Stephen Rothwell CC: microblaze-uclinux@itee.uq.edu.au CC: linuxppc-dev@ozlabs.org --- arch/microblaze/include/asm/of_platform.h | 33 ------- arch/microblaze/kernel/of_platform.c | 141 ++++------------------------- arch/powerpc/include/asm/of_platform.h | 11 --- arch/powerpc/kernel/of_platform.c | 131 +-------------------------- drivers/of/platform.c | 143 ++++++++++++++++++++++++++++++ include/linux/of_platform.h | 17 ++++ 6 files changed, 179 insertions(+), 297 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/of_platform.h b/arch/microblaze/include/asm/of_platform.h index 37491276c6ca..625003f70888 100644 --- a/arch/microblaze/include/asm/of_platform.h +++ b/arch/microblaze/include/asm/of_platform.h @@ -14,39 +14,6 @@ /* This is just here during the transition */ #include -/* - * The list of OF IDs below is used for matching bus types in the - * system whose devices are to be exposed as of_platform_devices. - * - * This is the default list valid for most platforms. This file provides - * functions who can take an explicit list if necessary though - * - * The search is always performed recursively looking for children of - * the provided device_node and recursively if such a children matches - * a bus type in the list - */ - -static const struct of_device_id of_default_bus_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .type = "plb5", }, - { .type = "plb4", }, - { .type = "opb", }, - { .type = "simple", }, - {}, -}; - -/* Platform devices and busses creation */ -extern struct of_device *of_platform_device_create(struct device_node *np, - const char *bus_id, - struct device *parent); -/* pseudo "matches" value to not do deep probe */ -#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1) - -extern int of_platform_bus_probe(struct device_node *root, - const struct of_device_id *matches, - struct device *parent); - extern struct of_device *of_find_device_by_phandle(phandle ph); extern void of_instantiate_rtc(void); diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c index ccf6f4257f4b..a07abdd6859b 100644 --- a/arch/microblaze/kernel/of_platform.c +++ b/arch/microblaze/kernel/of_platform.c @@ -37,132 +37,27 @@ static int __init of_bus_driver_init(void) } postcore_initcall(of_bus_driver_init); -struct of_device *of_platform_device_create(struct device_node *np, - const char *bus_id, - struct device *parent) -{ - struct of_device *dev; - - dev = of_device_alloc(np, bus_id, parent); - if (!dev) - return NULL; - - dev->archdata.dma_mask = 0xffffffffUL; - dev->dev.bus = &of_platform_bus_type; - - /* We do not fill the DMA ops for platform devices by default. - * This is currently the responsibility of the platform code - * to do such, possibly using a device notifier - */ - - if (of_device_register(dev) != 0) { - of_device_free(dev); - return NULL; - } - - return dev; -} -EXPORT_SYMBOL(of_platform_device_create); - -/** - * of_platform_bus_create - Create an OF device for a bus node and all its - * children. Optionally recursively instanciate matching busses. - * @bus: device node of the bus to instanciate - * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to - * disallow recursive creation of child busses - */ -static int of_platform_bus_create(const struct device_node *bus, - const struct of_device_id *matches, - struct device *parent) -{ - struct device_node *child; - struct of_device *dev; - int rc = 0; - - for_each_child_of_node(bus, child) { - pr_debug(" create child: %s\n", child->full_name); - dev = of_platform_device_create(child, NULL, parent); - if (dev == NULL) - rc = -ENOMEM; - else if (!of_match_node(matches, child)) - continue; - if (rc == 0) { - pr_debug(" and sub busses\n"); - rc = of_platform_bus_create(child, matches, &dev->dev); - } - if (rc) { - of_node_put(child); - break; - } - } - return rc; -} - - -/** - * of_platform_bus_probe - Probe the device-tree for platform busses - * @root: parent of the first level to probe or NULL for the root of the tree - * @matches: match table, NULL to use the default - * @parent: parent to hook devices from, NULL for toplevel +/* + * The list of OF IDs below is used for matching bus types in the + * system whose devices are to be exposed as of_platform_devices. * - * Note that children of the provided root are not instanciated as devices - * unless the specified root itself matches the bus list and is not NULL. + * This is the default list valid for most platforms. This file provides + * functions who can take an explicit list if necessary though + * + * The search is always performed recursively looking for children of + * the provided device_node and recursively if such a children matches + * a bus type in the list */ -int of_platform_bus_probe(struct device_node *root, - const struct of_device_id *matches, - struct device *parent) -{ - struct device_node *child; - struct of_device *dev; - int rc = 0; - - if (matches == NULL) - matches = of_default_bus_ids; - if (matches == OF_NO_DEEP_PROBE) - return -EINVAL; - if (root == NULL) - root = of_find_node_by_path("/"); - else - of_node_get(root); - - pr_debug("of_platform_bus_probe()\n"); - pr_debug(" starting at: %s\n", root->full_name); - - /* Do a self check of bus type, if there's a match, create - * children - */ - if (of_match_node(matches, root)) { - pr_debug(" root match, create all sub devices\n"); - dev = of_platform_device_create(root, NULL, parent); - if (dev == NULL) { - rc = -ENOMEM; - goto bail; - } - pr_debug(" create all sub busses\n"); - rc = of_platform_bus_create(root, matches, &dev->dev); - goto bail; - } - for_each_child_of_node(root, child) { - if (!of_match_node(matches, child)) - continue; - - pr_debug(" match: %s\n", child->full_name); - dev = of_platform_device_create(child, NULL, parent); - if (dev == NULL) - rc = -ENOMEM; - else - rc = of_platform_bus_create(child, matches, &dev->dev); - if (rc) { - of_node_put(child); - break; - } - } - bail: - of_node_put(root); - return rc; -} -EXPORT_SYMBOL(of_platform_bus_probe); +const struct of_device_id of_default_bus_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .type = "plb5", }, + { .type = "plb4", }, + { .type = "opb", }, + { .type = "simple", }, + {}, +}; static int of_dev_node_match(struct device *dev, void *data) { diff --git a/arch/powerpc/include/asm/of_platform.h b/arch/powerpc/include/asm/of_platform.h index d4aaa3489440..b37d2dcddb97 100644 --- a/arch/powerpc/include/asm/of_platform.h +++ b/arch/powerpc/include/asm/of_platform.h @@ -11,17 +11,6 @@ * */ -/* Platform devices and busses creation */ -extern struct of_device *of_platform_device_create(struct device_node *np, - const char *bus_id, - struct device *parent); -/* pseudo "matches" value to not do deep probe */ -#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1) - -extern int of_platform_bus_probe(struct device_node *root, - const struct of_device_id *matches, - struct device *parent); - extern struct of_device *of_find_device_by_phandle(phandle ph); extern void of_instantiate_rtc(void); diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 487a98851ba6..0b5cc6d892a7 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -40,7 +40,7 @@ * a bus type in the list */ -static const struct of_device_id of_default_bus_ids[] = { +const struct of_device_id of_default_bus_ids[] = { { .type = "soc", }, { .compatible = "soc", }, { .type = "spider", }, @@ -64,135 +64,6 @@ static int __init of_bus_driver_init(void) postcore_initcall(of_bus_driver_init); -struct of_device* of_platform_device_create(struct device_node *np, - const char *bus_id, - struct device *parent) -{ - struct of_device *dev; - - dev = of_device_alloc(np, bus_id, parent); - if (!dev) - return NULL; - - dev->archdata.dma_mask = 0xffffffffUL; - dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - - dev->dev.bus = &of_platform_bus_type; - - /* We do not fill the DMA ops for platform devices by default. - * This is currently the responsibility of the platform code - * to do such, possibly using a device notifier - */ - - if (of_device_register(dev) != 0) { - of_device_free(dev); - return NULL; - } - - return dev; -} -EXPORT_SYMBOL(of_platform_device_create); - - - -/** - * of_platform_bus_create - Create an OF device for a bus node and all its - * children. Optionally recursively instanciate matching busses. - * @bus: device node of the bus to instanciate - * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to - * disallow recursive creation of child busses - */ -static int of_platform_bus_create(const struct device_node *bus, - const struct of_device_id *matches, - struct device *parent) -{ - struct device_node *child; - struct of_device *dev; - int rc = 0; - - for_each_child_of_node(bus, child) { - pr_debug(" create child: %s\n", child->full_name); - dev = of_platform_device_create(child, NULL, parent); - if (dev == NULL) - rc = -ENOMEM; - else if (!of_match_node(matches, child)) - continue; - if (rc == 0) { - pr_debug(" and sub busses\n"); - rc = of_platform_bus_create(child, matches, &dev->dev); - } if (rc) { - of_node_put(child); - break; - } - } - return rc; -} - -/** - * of_platform_bus_probe - Probe the device-tree for platform busses - * @root: parent of the first level to probe or NULL for the root of the tree - * @matches: match table, NULL to use the default - * @parent: parent to hook devices from, NULL for toplevel - * - * Note that children of the provided root are not instanciated as devices - * unless the specified root itself matches the bus list and is not NULL. - */ - -int of_platform_bus_probe(struct device_node *root, - const struct of_device_id *matches, - struct device *parent) -{ - struct device_node *child; - struct of_device *dev; - int rc = 0; - - if (matches == NULL) - matches = of_default_bus_ids; - if (matches == OF_NO_DEEP_PROBE) - return -EINVAL; - if (root == NULL) - root = of_find_node_by_path("/"); - else - of_node_get(root); - - pr_debug("of_platform_bus_probe()\n"); - pr_debug(" starting at: %s\n", root->full_name); - - /* Do a self check of bus type, if there's a match, create - * children - */ - if (of_match_node(matches, root)) { - pr_debug(" root match, create all sub devices\n"); - dev = of_platform_device_create(root, NULL, parent); - if (dev == NULL) { - rc = -ENOMEM; - goto bail; - } - pr_debug(" create all sub busses\n"); - rc = of_platform_bus_create(root, matches, &dev->dev); - goto bail; - } - for_each_child_of_node(root, child) { - if (!of_match_node(matches, child)) - continue; - - pr_debug(" match: %s\n", child->full_name); - dev = of_platform_device_create(child, NULL, parent); - if (dev == NULL) - rc = -ENOMEM; - else - rc = of_platform_bus_create(child, matches, &dev->dev); - if (rc) { - of_node_put(child); - break; - } - } - bail: - of_node_put(root); - return rc; -} -EXPORT_SYMBOL(of_platform_bus_probe); - static int of_dev_node_match(struct device *dev, void *data) { return to_of_device(dev)->dev.of_node == data; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 7dacc1ebe91e..d9c81e93bdd0 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -396,3 +397,145 @@ void of_unregister_driver(struct of_platform_driver *drv) driver_unregister(&drv->driver); } EXPORT_SYMBOL(of_unregister_driver); + +#if !defined(CONFIG_SPARC) +/* + * The following routines scan a subtree and registers a device for + * each applicable node. + * + * Note: sparc doesn't use these routines because it has a different + * mechanism for creating devices from device tree nodes. + */ + +/** + * of_platform_device_create - Alloc, initialize and register an of_device + * @np: pointer to node to create device for + * @bus_id: name to assign device + * @parent: Linux device model parent device. + */ +struct of_device *of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent) +{ + struct of_device *dev; + + dev = of_device_alloc(np, bus_id, parent); + if (!dev) + return NULL; + + dev->archdata.dma_mask = 0xffffffffUL; + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + dev->dev.bus = &of_platform_bus_type; + + /* We do not fill the DMA ops for platform devices by default. + * This is currently the responsibility of the platform code + * to do such, possibly using a device notifier + */ + + if (of_device_register(dev) != 0) { + of_device_free(dev); + return NULL; + } + + return dev; +} +EXPORT_SYMBOL(of_platform_device_create); + +/** + * of_platform_bus_create - Create an OF device for a bus node and all its + * children. Optionally recursively instantiate matching busses. + * @bus: device node of the bus to instantiate + * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to + * disallow recursive creation of child busses + */ +static int of_platform_bus_create(const struct device_node *bus, + const struct of_device_id *matches, + struct device *parent) +{ + struct device_node *child; + struct of_device *dev; + int rc = 0; + + for_each_child_of_node(bus, child) { + pr_debug(" create child: %s\n", child->full_name); + dev = of_platform_device_create(child, NULL, parent); + if (dev == NULL) + rc = -ENOMEM; + else if (!of_match_node(matches, child)) + continue; + if (rc == 0) { + pr_debug(" and sub busses\n"); + rc = of_platform_bus_create(child, matches, &dev->dev); + } + if (rc) { + of_node_put(child); + break; + } + } + return rc; +} + +/** + * of_platform_bus_probe - Probe the device-tree for platform busses + * @root: parent of the first level to probe or NULL for the root of the tree + * @matches: match table, NULL to use the default + * @parent: parent to hook devices from, NULL for toplevel + * + * Note that children of the provided root are not instantiated as devices + * unless the specified root itself matches the bus list and is not NULL. + */ +int of_platform_bus_probe(struct device_node *root, + const struct of_device_id *matches, + struct device *parent) +{ + struct device_node *child; + struct of_device *dev; + int rc = 0; + + if (matches == NULL) + matches = of_default_bus_ids; + if (matches == OF_NO_DEEP_PROBE) + return -EINVAL; + if (root == NULL) + root = of_find_node_by_path("/"); + else + of_node_get(root); + + pr_debug("of_platform_bus_probe()\n"); + pr_debug(" starting at: %s\n", root->full_name); + + /* Do a self check of bus type, if there's a match, create + * children + */ + if (of_match_node(matches, root)) { + pr_debug(" root match, create all sub devices\n"); + dev = of_platform_device_create(root, NULL, parent); + if (dev == NULL) { + rc = -ENOMEM; + goto bail; + } + pr_debug(" create all sub busses\n"); + rc = of_platform_bus_create(root, matches, &dev->dev); + goto bail; + } + for_each_child_of_node(root, child) { + if (!of_match_node(matches, child)) + continue; + + pr_debug(" match: %s\n", child->full_name); + dev = of_platform_device_create(child, NULL, parent); + if (dev == NULL) + rc = -ENOMEM; + else + rc = of_platform_bus_create(child, matches, &dev->dev); + if (rc) { + of_node_put(child); + break; + } + } + bail: + of_node_put(root); + return rc; +} +EXPORT_SYMBOL(of_platform_bus_probe); +#endif /* !CONFIG_SPARC */ diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 1643d3761eb4..4bbba41396ef 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -25,6 +25,8 @@ */ extern struct bus_type of_platform_bus_type; +extern const struct of_device_id of_default_bus_ids[]; + /* * An of_platform_driver driver is attached to a basic of_device on * the "platform bus" (of_platform_bus_type). @@ -63,6 +65,21 @@ static inline void of_unregister_platform_driver(struct of_platform_driver *drv) extern struct of_device *of_find_device_by_node(struct device_node *np); extern int of_bus_type_init(struct bus_type *bus, const char *name); + +#if !defined(CONFIG_SPARC) /* SPARC has its own device registration method */ +/* Platform devices and busses creation */ +extern struct of_device *of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent); + +/* pseudo "matches" value to not do deep probe */ +#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1) + +extern int of_platform_bus_probe(struct device_node *root, + const struct of_device_id *matches, + struct device *parent); +#endif /* !CONFIG_SPARC */ + #endif /* CONFIG_OF_DEVICE */ #endif /* _LINUX_OF_PLATFORM_H */ -- cgit v1.2.3 From 94c0931983ee9d1cd96c32d52ac64c17464f0bbd Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:14 -0600 Subject: of: Merge of_device_alloc() and of_device_make_bus_id() This patch merges the common routines of_device_alloc() and of_device_make_bus_id() from powerpc and microblaze. Signed-off-by: Grant Likely CC: Michal Simek CC: Grant Likely CC: Benjamin Herrenschmidt CC: Stephen Rothwell CC: microblaze-uclinux@itee.uq.edu.au CC: linuxppc-dev@ozlabs.org CC: devicetree-discuss@lists.ozlabs.org --- arch/microblaze/include/asm/of_device.h | 15 ------ arch/microblaze/kernel/Makefile | 2 +- arch/microblaze/kernel/of_device.c | 64 ------------------------ arch/powerpc/include/asm/of_device.h | 10 ---- arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/of_device.c | 84 ------------------------------- drivers/of/platform.c | 87 +++++++++++++++++++++++++++++++++ include/linux/of_platform.h | 3 ++ 8 files changed, 92 insertions(+), 175 deletions(-) delete mode 100644 arch/microblaze/kernel/of_device.c delete mode 100644 arch/powerpc/kernel/of_device.c (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/of_device.h b/arch/microblaze/include/asm/of_device.h index c9be53487434..47e8d42aee8f 100644 --- a/arch/microblaze/include/asm/of_device.h +++ b/arch/microblaze/include/asm/of_device.h @@ -10,19 +10,4 @@ #ifndef _ASM_MICROBLAZE_OF_DEVICE_H #define _ASM_MICROBLAZE_OF_DEVICE_H -#ifdef __KERNEL__ - -#include -#include - -extern struct of_device *of_device_alloc(struct device_node *np, - const char *bus_id, - struct device *parent); - -extern void of_device_make_bus_id(struct of_device *dev); - -/* This is just here during the transition */ -#include - -#endif /* __KERNEL__ */ #endif /* _ASM_MICROBLAZE_OF_DEVICE_H */ diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index e51bc1520825..727e2cbff9c6 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile @@ -15,7 +15,7 @@ endif extra-y := head.o vmlinux.lds obj-y += dma.o exceptions.o \ - hw_exception_handler.o init_task.o intc.o irq.o of_device.o \ + hw_exception_handler.o init_task.o intc.o irq.o \ of_platform.o process.o prom.o prom_parse.o ptrace.o \ setup.o signal.o sys_microblaze.o timer.o traps.o reset.o diff --git a/arch/microblaze/kernel/of_device.c b/arch/microblaze/kernel/of_device.c deleted file mode 100644 index 3a367d788451..000000000000 --- a/arch/microblaze/kernel/of_device.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -void of_device_make_bus_id(struct of_device *dev) -{ - static atomic_t bus_no_reg_magic; - struct device_node *node = dev->dev.of_node; - const u32 *reg; - u64 addr; - int magic; - - /* - * For MMIO, get the physical address - */ - reg = of_get_property(node, "reg", NULL); - if (reg) { - addr = of_translate_address(node, reg); - if (addr != OF_BAD_ADDR) { - dev_set_name(&dev->dev, "%llx.%s", - (unsigned long long)addr, node->name); - return; - } - } - - /* - * No BusID, use the node name and add a globally incremented - * counter (and pray...) - */ - magic = atomic_add_return(1, &bus_no_reg_magic); - dev_set_name(&dev->dev, "%s.%d", node->name, magic - 1); -} -EXPORT_SYMBOL(of_device_make_bus_id); - -struct of_device *of_device_alloc(struct device_node *np, - const char *bus_id, - struct device *parent) -{ - struct of_device *dev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - - dev->dev.of_node = of_node_get(np); - dev->dev.dma_mask = &dev->archdata.dma_mask; - dev->dev.parent = parent; - dev->dev.release = of_release_dev; - - if (bus_id) - dev_set_name(&dev->dev, bus_id); - else - of_device_make_bus_id(dev); - - return dev; -} -EXPORT_SYMBOL(of_device_alloc); diff --git a/arch/powerpc/include/asm/of_device.h b/arch/powerpc/include/asm/of_device.h index 5d5103cac641..04f76717f82c 100644 --- a/arch/powerpc/include/asm/of_device.h +++ b/arch/powerpc/include/asm/of_device.h @@ -1,13 +1,3 @@ #ifndef _ASM_POWERPC_OF_DEVICE_H #define _ASM_POWERPC_OF_DEVICE_H -#ifdef __KERNEL__ - -#include -#include - -extern struct of_device *of_device_alloc(struct device_node *np, - const char *bus_id, - struct device *parent); - -#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_OF_DEVICE_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 58d0572de6f9..83aa1fd0908f 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -40,7 +40,7 @@ obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o obj-$(CONFIG_PPC_970_NAP) += idle_power4.o -obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o +obj-$(CONFIG_PPC_OF) += of_platform.o prom_parse.o obj-$(CONFIG_PPC_CLOCK) += clock.o procfs-y := proc_powerpc.o obj-$(CONFIG_PROC_FS) += $(procfs-y) diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c deleted file mode 100644 index db91a9dbafb5..000000000000 --- a/arch/powerpc/kernel/of_device.c +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static void of_device_make_bus_id(struct of_device *dev) -{ - static atomic_t bus_no_reg_magic; - struct device_node *node = dev->dev.of_node; - const u32 *reg; - u64 addr; - int magic; - - /* - * If it's a DCR based device, use 'd' for native DCRs - * and 'D' for MMIO DCRs. - */ -#ifdef CONFIG_PPC_DCR - reg = of_get_property(node, "dcr-reg", NULL); - if (reg) { -#ifdef CONFIG_PPC_DCR_NATIVE - dev_set_name(&dev->dev, "d%x.%s", *reg, node->name); -#else /* CONFIG_PPC_DCR_NATIVE */ - addr = of_translate_dcr_address(node, *reg, NULL); - if (addr != OF_BAD_ADDR) { - dev_set_name(&dev->dev, "D%llx.%s", - (unsigned long long)addr, node->name); - return; - } -#endif /* !CONFIG_PPC_DCR_NATIVE */ - } -#endif /* CONFIG_PPC_DCR */ - - /* - * For MMIO, get the physical address - */ - reg = of_get_property(node, "reg", NULL); - if (reg) { - addr = of_translate_address(node, reg); - if (addr != OF_BAD_ADDR) { - dev_set_name(&dev->dev, "%llx.%s", - (unsigned long long)addr, node->name); - return; - } - } - - /* - * No BusID, use the node name and add a globally incremented - * counter (and pray...) - */ - magic = atomic_add_return(1, &bus_no_reg_magic); - dev_set_name(&dev->dev, "%s.%d", node->name, magic - 1); -} - -struct of_device *of_device_alloc(struct device_node *np, - const char *bus_id, - struct device *parent) -{ - struct of_device *dev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - - dev->dev.of_node = of_node_get(np); - dev->dev.dma_mask = &dev->archdata.dma_mask; - dev->dev.parent = parent; - dev->dev.release = of_release_dev; - - if (bus_id) - dev_set_name(&dev->dev, "%s", bus_id); - else - of_device_make_bus_id(dev); - - return dev; -} -EXPORT_SYMBOL(of_device_alloc); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index d9c81e93bdd0..ea87a3cf7860 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -407,6 +407,93 @@ EXPORT_SYMBOL(of_unregister_driver); * mechanism for creating devices from device tree nodes. */ +/** + * of_device_make_bus_id - Use the device node data to assign a unique name + * @dev: pointer to device structure that is linked to a device tree node + * + * This routine will first try using either the dcr-reg or the reg property + * value to derive a unique name. As a last resort it will use the node + * name followed by a unique number. + */ +static void of_device_make_bus_id(struct device *dev) +{ + static atomic_t bus_no_reg_magic; + struct device_node *node = dev->of_node; + const u32 *reg; + u64 addr; + int magic; + +#ifdef CONFIG_PPC_DCR + /* + * If it's a DCR based device, use 'd' for native DCRs + * and 'D' for MMIO DCRs. + */ + reg = of_get_property(node, "dcr-reg", NULL); + if (reg) { +#ifdef CONFIG_PPC_DCR_NATIVE + dev_set_name(dev, "d%x.%s", *reg, node->name); +#else /* CONFIG_PPC_DCR_NATIVE */ + u64 addr = of_translate_dcr_address(node, *reg, NULL); + if (addr != OF_BAD_ADDR) { + dev_set_name(dev, "D%llx.%s", + (unsigned long long)addr, node->name); + return; + } +#endif /* !CONFIG_PPC_DCR_NATIVE */ + } +#endif /* CONFIG_PPC_DCR */ + + /* + * For MMIO, get the physical address + */ + reg = of_get_property(node, "reg", NULL); + if (reg) { + addr = of_translate_address(node, reg); + if (addr != OF_BAD_ADDR) { + dev_set_name(dev, "%llx.%s", + (unsigned long long)addr, node->name); + return; + } + } + + /* + * No BusID, use the node name and add a globally incremented + * counter (and pray...) + */ + magic = atomic_add_return(1, &bus_no_reg_magic); + dev_set_name(dev, "%s.%d", node->name, magic - 1); +} + +/** + * of_device_alloc - Allocate and initialize an of_device + * @np: device node to assign to device + * @bus_id: Name to assign to the device. May be null to use default name. + * @parent: Parent device. + */ +struct of_device *of_device_alloc(struct device_node *np, + const char *bus_id, + struct device *parent) +{ + struct of_device *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->dev.of_node = of_node_get(np); + dev->dev.dma_mask = &dev->archdata.dma_mask; + dev->dev.parent = parent; + dev->dev.release = of_release_dev; + + if (bus_id) + dev_set_name(&dev->dev, "%s", bus_id); + else + of_device_make_bus_id(&dev->dev); + + return dev; +} +EXPORT_SYMBOL(of_device_alloc); + /** * of_platform_device_create - Alloc, initialize and register an of_device * @np: pointer to node to create device for diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 4bbba41396ef..a51fd30176aa 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -60,6 +60,9 @@ static inline void of_unregister_platform_driver(struct of_platform_driver *drv) of_unregister_driver(drv); } +extern struct of_device *of_device_alloc(struct device_node *np, + const char *bus_id, + struct device *parent); #include extern struct of_device *of_find_device_by_node(struct device_node *np); -- cgit v1.2.3 From a19e3da5bc5fc6c10ab73f310bea80f3845b4531 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 8 Jun 2010 07:48:16 -0600 Subject: of/gpio: Kill of_gpio_chip and add members directly to gpio_chip The OF gpio infrastructure is great for describing GPIO connections within the device tree. However, using a GPIO binding still requires changes to the gpio controller just to add an of_gpio structure. In most cases, the gpio controller doesn't actually need any special support and the simple OF gpio mapping function is more than sufficient. Additional, the current scheme of using of_gpio_chip requires a convoluted scheme to maintain 1:1 mappings between of_gpio_chip and gpio_chip instances. If the struct of_gpio_chip data members were moved into struct gpio_chip, then it would simplify the processing of OF gpio bindings, and it would make it trivial to use device tree OF connections on existing gpiolib controller drivers. This patch eliminates the of_gpio_chip structure and moves the relevant fields into struct gpio_chip (conditional on CONFIG_OF_GPIO). This move simplifies the existing code and prepares for adding automatic device tree support to existing drivers. Signed-off-by: Grant Likely Cc: Andrew Morton Cc: Anton Vorontsov Cc: Grant Likely Cc: David Brownell Cc: Bill Gatliff Cc: Dmitry Eremin-Solenikov Cc: Benjamin Herrenschmidt Cc: Jean Delvare --- arch/microblaze/kernel/reset.c | 12 +++---- arch/powerpc/platforms/52xx/mpc52xx_gpio.c | 32 ++++++++--------- arch/powerpc/platforms/52xx/mpc52xx_gpt.c | 29 ++++++++------- arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c | 15 ++++---- arch/powerpc/platforms/86xx/gef_gpio.c | 24 ++++++------- arch/powerpc/sysdev/cpm1.c | 12 +++---- arch/powerpc/sysdev/cpm_common.c | 6 ++-- arch/powerpc/sysdev/mpc8xxx_gpio.c | 6 ++-- arch/powerpc/sysdev/ppc4xx_gpio.c | 6 ++-- arch/powerpc/sysdev/qe_lib/gpio.c | 32 ++++++++--------- arch/powerpc/sysdev/simple_gpio.c | 6 ++-- drivers/gpio/xilinx_gpio.c | 16 ++++----- drivers/of/gpio.c | 50 +++++++++++++------------- include/asm-generic/gpio.h | 12 +++++++ include/linux/of_gpio.h | 29 +++------------ 15 files changed, 129 insertions(+), 158 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c index a1721a33042e..5476d3caf045 100644 --- a/arch/microblaze/kernel/reset.c +++ b/arch/microblaze/kernel/reset.c @@ -24,8 +24,8 @@ static int of_reset_gpio_handle(void) int ret; /* variable which stored handle reset gpio pin */ struct device_node *root; /* root node */ struct device_node *gpio; /* gpio node */ - struct of_gpio_chip *of_gc = NULL; - enum of_gpio_flags flags ; + struct gpio_chip *gc; + u32 flags; const void *gpio_spec; /* find out root node */ @@ -39,19 +39,19 @@ static int of_reset_gpio_handle(void) goto err0; } - of_gc = gpio->data; - if (!of_gc) { + gc = gpio->data; + if (!gc) { pr_debug("%s: gpio controller %s isn't registered\n", root->full_name, gpio->full_name); ret = -ENODEV; goto err1; } - ret = of_gc->xlate(of_gc, root, gpio_spec, &flags); + ret = gc->of_xlate(gc, root, gpio_spec, &flags); if (ret < 0) goto err1; - ret += of_gc->gc.base; + ret += gc->base; err1: of_node_put(gpio); err0: diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c index ca5305a5bd61..fd0912eeffe2 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c @@ -152,21 +152,21 @@ static int __devinit mpc52xx_wkup_gpiochip_probe(struct of_device *ofdev, { struct mpc52xx_gpiochip *chip; struct mpc52xx_gpio_wkup __iomem *regs; - struct of_gpio_chip *ofchip; + struct gpio_chip *gc; int ret; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - ofchip = &chip->mmchip.of_gc; + gc = &chip->mmchip.gc; - ofchip->gpio_cells = 2; - ofchip->gc.ngpio = 8; - ofchip->gc.direction_input = mpc52xx_wkup_gpio_dir_in; - ofchip->gc.direction_output = mpc52xx_wkup_gpio_dir_out; - ofchip->gc.get = mpc52xx_wkup_gpio_get; - ofchip->gc.set = mpc52xx_wkup_gpio_set; + gc->of_gpio_n_cells = 2; + gc->ngpio = 8; + gc->direction_input = mpc52xx_wkup_gpio_dir_in; + gc->direction_output = mpc52xx_wkup_gpio_dir_out; + gc->get = mpc52xx_wkup_gpio_get; + gc->set = mpc52xx_wkup_gpio_set; ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip); if (ret) @@ -315,7 +315,7 @@ static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev, const struct of_device_id *match) { struct mpc52xx_gpiochip *chip; - struct of_gpio_chip *ofchip; + struct gpio_chip *gc; struct mpc52xx_gpio __iomem *regs; int ret; @@ -323,14 +323,14 @@ static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev, if (!chip) return -ENOMEM; - ofchip = &chip->mmchip.of_gc; + gc = &chip->mmchip.gc; - ofchip->gpio_cells = 2; - ofchip->gc.ngpio = 32; - ofchip->gc.direction_input = mpc52xx_simple_gpio_dir_in; - ofchip->gc.direction_output = mpc52xx_simple_gpio_dir_out; - ofchip->gc.get = mpc52xx_simple_gpio_get; - ofchip->gc.set = mpc52xx_simple_gpio_set; + gc->of_gpio_n_cells = 2; + gc->ngpio = 32; + gc->direction_input = mpc52xx_simple_gpio_dir_in; + gc->direction_output = mpc52xx_simple_gpio_dir_out; + gc->get = mpc52xx_simple_gpio_get; + gc->set = mpc52xx_simple_gpio_set; ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip); if (ret) diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index 46c93578cbf0..3f2ee47f1d01 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -78,7 +78,7 @@ MODULE_LICENSE("GPL"); * @dev: pointer to device structure * @regs: virtual address of GPT registers * @lock: spinlock to coordinate between different functions. - * @of_gc: of_gpio_chip instance structure; used when GPIO is enabled + * @gc: gpio_chip instance structure; used when GPIO is enabled * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported * @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates * if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates @@ -94,7 +94,7 @@ struct mpc52xx_gpt_priv { u8 wdt_mode; #if defined(CONFIG_GPIOLIB) - struct of_gpio_chip of_gc; + struct gpio_chip gc; #endif }; @@ -280,7 +280,7 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) #if defined(CONFIG_GPIOLIB) static inline struct mpc52xx_gpt_priv *gc_to_mpc52xx_gpt(struct gpio_chip *gc) { - return container_of(to_of_gpio_chip(gc), struct mpc52xx_gpt_priv,of_gc); + return container_of(gc, struct mpc52xx_gpt_priv, gc); } static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio) @@ -336,28 +336,27 @@ mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) if (!of_find_property(node, "gpio-controller", NULL)) return; - gpt->of_gc.gc.label = kstrdup(node->full_name, GFP_KERNEL); - if (!gpt->of_gc.gc.label) { + gpt->gc.label = kstrdup(node->full_name, GFP_KERNEL); + if (!gpt->gc.label) { dev_err(gpt->dev, "out of memory\n"); return; } - gpt->of_gc.gpio_cells = 2; - gpt->of_gc.gc.ngpio = 1; - gpt->of_gc.gc.direction_input = mpc52xx_gpt_gpio_dir_in; - gpt->of_gc.gc.direction_output = mpc52xx_gpt_gpio_dir_out; - gpt->of_gc.gc.get = mpc52xx_gpt_gpio_get; - gpt->of_gc.gc.set = mpc52xx_gpt_gpio_set; - gpt->of_gc.gc.base = -1; - gpt->of_gc.xlate = of_gpio_simple_xlate; - node->data = &gpt->of_gc; + gpt->gc.ngpio = 1; + gpt->gc.direction_input = mpc52xx_gpt_gpio_dir_in; + gpt->gc.direction_output = mpc52xx_gpt_gpio_dir_out; + gpt->gc.get = mpc52xx_gpt_gpio_get; + gpt->gc.set = mpc52xx_gpt_gpio_set; + gpt->gc.base = -1; + gpt->gc.of_gpio_n_cells = 2; + gpt->gc.of_xlate = of_gpio_simple_xlate; of_node_get(node); /* Setup external pin in GPIO mode */ clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_MS_MASK, MPC52xx_GPT_MODE_MS_GPIO); - rc = gpiochip_add(&gpt->of_gc.gc); + rc = gpiochip_add(&gpt->gc); if (rc) dev_err(gpt->dev, "gpiochip_add() failed; rc=%i\n", rc); diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index d119a7c1c17a..e49f4bd2f991 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -37,7 +37,7 @@ struct mcu { struct mutex lock; struct device_node *np; struct i2c_client *client; - struct of_gpio_chip of_gc; + struct gpio_chip gc; u8 reg_ctrl; }; @@ -56,8 +56,7 @@ static void mcu_power_off(void) static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { - struct of_gpio_chip *of_gc = to_of_gpio_chip(gc); - struct mcu *mcu = container_of(of_gc, struct mcu, of_gc); + struct mcu *mcu = container_of(gc, struct mcu, gc); u8 bit = 1 << (4 + gpio); mutex_lock(&mcu->lock); @@ -79,8 +78,7 @@ static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int mcu_gpiochip_add(struct mcu *mcu) { struct device_node *np; - struct of_gpio_chip *of_gc = &mcu->of_gc; - struct gpio_chip *gc = &of_gc->gc; + struct gpio_chip *gc = &mcu->gc; int ret; np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx"); @@ -94,10 +92,9 @@ static int mcu_gpiochip_add(struct mcu *mcu) gc->base = -1; gc->set = mcu_gpio_set; gc->direction_output = mcu_gpio_dir_out; - of_gc->gpio_cells = 2; - of_gc->xlate = of_gpio_simple_xlate; + gc->of_gpio_n_cells = 2; + gc->of_xlate = of_gpio_simple_xlate; - np->data = of_gc; mcu->np = np; /* @@ -114,7 +111,7 @@ static int mcu_gpiochip_remove(struct mcu *mcu) { int ret; - ret = gpiochip_remove(&mcu->of_gc.gc); + ret = gpiochip_remove(&mcu->gc); if (ret) return ret; of_node_put(mcu->np); diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c index b8cb08dbd89c..4ff7b1e7bbad 100644 --- a/arch/powerpc/platforms/86xx/gef_gpio.c +++ b/arch/powerpc/platforms/86xx/gef_gpio.c @@ -118,12 +118,12 @@ static int __init gef_gpio_init(void) } /* Setup pointers to chip functions */ - gef_gpio_chip->of_gc.gpio_cells = 2; - gef_gpio_chip->of_gc.gc.ngpio = 19; - gef_gpio_chip->of_gc.gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->of_gc.gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->of_gc.gc.get = gef_gpio_get; - gef_gpio_chip->of_gc.gc.set = gef_gpio_set; + gef_gpio_chip->gc.of_gpio_n_cells = 2; + gef_gpio_chip->gc.ngpio = 19; + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; + gef_gpio_chip->gc.get = gef_gpio_get; + gef_gpio_chip->gc.set = gef_gpio_set; /* This function adds a memory mapped GPIO chip */ retval = of_mm_gpiochip_add(np, gef_gpio_chip); @@ -146,12 +146,12 @@ static int __init gef_gpio_init(void) } /* Setup pointers to chip functions */ - gef_gpio_chip->of_gc.gpio_cells = 2; - gef_gpio_chip->of_gc.gc.ngpio = 6; - gef_gpio_chip->of_gc.gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->of_gc.gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->of_gc.gc.get = gef_gpio_get; - gef_gpio_chip->of_gc.gc.set = gef_gpio_set; + gef_gpio_chip->gc.of_gpio_n_cells = 2; + gef_gpio_chip->gc.ngpio = 6; + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; + gef_gpio_chip->gc.get = gef_gpio_get; + gef_gpio_chip->gc.set = gef_gpio_set; /* This function adds a memory mapped GPIO chip */ retval = of_mm_gpiochip_add(np, gef_gpio_chip); diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 8d103ca6d6ab..d5cf7d4ccf81 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -621,7 +621,6 @@ int cpm1_gpiochip_add16(struct device_node *np) { struct cpm1_gpio16_chip *cpm1_gc; struct of_mm_gpio_chip *mm_gc; - struct of_gpio_chip *of_gc; struct gpio_chip *gc; cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); @@ -631,11 +630,10 @@ int cpm1_gpiochip_add16(struct device_node *np) spin_lock_init(&cpm1_gc->lock); mm_gc = &cpm1_gc->mm_gc; - of_gc = &mm_gc->of_gc; - gc = &of_gc->gc; + gc = &mm_gc->gc; mm_gc->save_regs = cpm1_gpio16_save_regs; - of_gc->gpio_cells = 2; + gc->of_gpio_n_cells = 2; gc->ngpio = 16; gc->direction_input = cpm1_gpio16_dir_in; gc->direction_output = cpm1_gpio16_dir_out; @@ -745,7 +743,6 @@ int cpm1_gpiochip_add32(struct device_node *np) { struct cpm1_gpio32_chip *cpm1_gc; struct of_mm_gpio_chip *mm_gc; - struct of_gpio_chip *of_gc; struct gpio_chip *gc; cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); @@ -755,11 +752,10 @@ int cpm1_gpiochip_add32(struct device_node *np) spin_lock_init(&cpm1_gc->lock); mm_gc = &cpm1_gc->mm_gc; - of_gc = &mm_gc->of_gc; - gc = &of_gc->gc; + gc = &mm_gc->gc; mm_gc->save_regs = cpm1_gpio32_save_regs; - of_gc->gpio_cells = 2; + gc->of_gpio_n_cells = 2; gc->ngpio = 32; gc->direction_input = cpm1_gpio32_dir_in; gc->direction_output = cpm1_gpio32_dir_out; diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index 88b9812c854f..67e9b47dcf8e 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c @@ -325,7 +325,6 @@ int cpm2_gpiochip_add32(struct device_node *np) { struct cpm2_gpio32_chip *cpm2_gc; struct of_mm_gpio_chip *mm_gc; - struct of_gpio_chip *of_gc; struct gpio_chip *gc; cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL); @@ -335,11 +334,10 @@ int cpm2_gpiochip_add32(struct device_node *np) spin_lock_init(&cpm2_gc->lock); mm_gc = &cpm2_gc->mm_gc; - of_gc = &mm_gc->of_gc; - gc = &of_gc->gc; + gc = &mm_gc->gc; mm_gc->save_regs = cpm2_gpio32_save_regs; - of_gc->gpio_cells = 2; + gc->of_gpio_n_cells = 2; gc->ngpio = 32; gc->direction_input = cpm2_gpio32_dir_in; gc->direction_output = cpm2_gpio32_dir_out; diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c index 83f519655fac..ec8fcd42101e 100644 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c @@ -257,7 +257,6 @@ static void __init mpc8xxx_add_controller(struct device_node *np) { struct mpc8xxx_gpio_chip *mpc8xxx_gc; struct of_mm_gpio_chip *mm_gc; - struct of_gpio_chip *of_gc; struct gpio_chip *gc; unsigned hwirq; int ret; @@ -271,11 +270,10 @@ static void __init mpc8xxx_add_controller(struct device_node *np) spin_lock_init(&mpc8xxx_gc->lock); mm_gc = &mpc8xxx_gc->mm_gc; - of_gc = &mm_gc->of_gc; - gc = &of_gc->gc; + gc = &mm_gc->gc; mm_gc->save_regs = mpc8xxx_gpio_save_regs; - of_gc->gpio_cells = 2; + gc->of_gpio_n_cells = 2; gc->ngpio = MPC8XXX_GPIO_PINS; gc->direction_input = mpc8xxx_gpio_dir_in; gc->direction_output = mpc8xxx_gpio_dir_out; diff --git a/arch/powerpc/sysdev/ppc4xx_gpio.c b/arch/powerpc/sysdev/ppc4xx_gpio.c index 3812fc366bec..42e7a5eea665 100644 --- a/arch/powerpc/sysdev/ppc4xx_gpio.c +++ b/arch/powerpc/sysdev/ppc4xx_gpio.c @@ -181,7 +181,6 @@ static int __init ppc4xx_add_gpiochips(void) int ret; struct ppc4xx_gpio_chip *ppc4xx_gc; struct of_mm_gpio_chip *mm_gc; - struct of_gpio_chip *of_gc; struct gpio_chip *gc; ppc4xx_gc = kzalloc(sizeof(*ppc4xx_gc), GFP_KERNEL); @@ -193,10 +192,9 @@ static int __init ppc4xx_add_gpiochips(void) spin_lock_init(&ppc4xx_gc->lock); mm_gc = &ppc4xx_gc->mm_gc; - of_gc = &mm_gc->of_gc; - gc = &of_gc->gc; + gc = &mm_gc->gc; - of_gc->gpio_cells = 2; + gc->of_gpio_n_cells = 2; gc->ngpio = 32; gc->direction_input = ppc4xx_gpio_dir_in; gc->direction_output = ppc4xx_gpio_dir_out; diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c index dc8f8d618074..194478c2f4b4 100644 --- a/arch/powerpc/sysdev/qe_lib/gpio.c +++ b/arch/powerpc/sysdev/qe_lib/gpio.c @@ -138,8 +138,8 @@ struct qe_pin { struct qe_pin *qe_pin_request(struct device_node *np, int index) { struct qe_pin *qe_pin; - struct device_node *gc; - struct of_gpio_chip *of_gc = NULL; + struct device_node *gpio_np; + struct gpio_chip *gc; struct of_mm_gpio_chip *mm_gc; struct qe_gpio_chip *qe_gc; int err; @@ -155,40 +155,40 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index) } err = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, - &gc, &gpio_spec); + &gpio_np, &gpio_spec); if (err) { pr_debug("%s: can't parse gpios property\n", __func__); goto err0; } - if (!of_device_is_compatible(gc, "fsl,mpc8323-qe-pario-bank")) { + if (!of_device_is_compatible(gpio_np, "fsl,mpc8323-qe-pario-bank")) { pr_debug("%s: tried to get a non-qe pin\n", __func__); err = -EINVAL; goto err1; } - of_gc = gc->data; - if (!of_gc) { + gc = gpio_np->data; + if (!gc) { pr_debug("%s: gpio controller %s isn't registered\n", - np->full_name, gc->full_name); + np->full_name, gpio_np->full_name); err = -ENODEV; goto err1; } - gpio_cells = of_get_property(gc, "#gpio-cells", &size); + gpio_cells = of_get_property(gpio_np, "#gpio-cells", &size); if (!gpio_cells || size != sizeof(*gpio_cells) || - *gpio_cells != of_gc->gpio_cells) { + *gpio_cells != gc->of_gpio_n_cells) { pr_debug("%s: wrong #gpio-cells for %s\n", - np->full_name, gc->full_name); + np->full_name, gpio_np->full_name); err = -EINVAL; goto err1; } - err = of_gc->xlate(of_gc, np, gpio_spec, NULL); + err = gc->of_xlate(gc, np, gpio_spec, NULL); if (err < 0) goto err1; - mm_gc = to_of_mm_gpio_chip(&of_gc->gc); + mm_gc = to_of_mm_gpio_chip(gc); qe_gc = to_qe_gpio_chip(mm_gc); spin_lock_irqsave(&qe_gc->lock, flags); @@ -206,7 +206,7 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index) if (!err) return qe_pin; err1: - of_node_put(gc); + of_node_put(gpio_np); err0: kfree(qe_pin); pr_debug("%s failed with status %d\n", __func__, err); @@ -307,7 +307,6 @@ static int __init qe_add_gpiochips(void) int ret; struct qe_gpio_chip *qe_gc; struct of_mm_gpio_chip *mm_gc; - struct of_gpio_chip *of_gc; struct gpio_chip *gc; qe_gc = kzalloc(sizeof(*qe_gc), GFP_KERNEL); @@ -319,11 +318,10 @@ static int __init qe_add_gpiochips(void) spin_lock_init(&qe_gc->lock); mm_gc = &qe_gc->mm_gc; - of_gc = &mm_gc->of_gc; - gc = &of_gc->gc; + gc = &mm_gc->gc; mm_gc->save_regs = qe_gpio_save_regs; - of_gc->gpio_cells = 2; + gc->of_gpio_n_cells = 2; gc->ngpio = QE_PIO_PINS; gc->direction_input = qe_gpio_dir_in; gc->direction_output = qe_gpio_dir_out; diff --git a/arch/powerpc/sysdev/simple_gpio.c b/arch/powerpc/sysdev/simple_gpio.c index d5fb173e588c..b7559aa0c165 100644 --- a/arch/powerpc/sysdev/simple_gpio.c +++ b/arch/powerpc/sysdev/simple_gpio.c @@ -91,7 +91,6 @@ static int __init u8_simple_gpiochip_add(struct device_node *np) int ret; struct u8_gpio_chip *u8_gc; struct of_mm_gpio_chip *mm_gc; - struct of_gpio_chip *of_gc; struct gpio_chip *gc; u8_gc = kzalloc(sizeof(*u8_gc), GFP_KERNEL); @@ -101,11 +100,10 @@ static int __init u8_simple_gpiochip_add(struct device_node *np) spin_lock_init(&u8_gc->lock); mm_gc = &u8_gc->mm_gc; - of_gc = &mm_gc->of_gc; - gc = &of_gc->gc; + gc = &mm_gc->gc; mm_gc->save_regs = u8_gpio_save_regs; - of_gc->gpio_cells = 2; + gc->of_gpio_n_cells = 2; gc->ngpio = 8; gc->direction_input = u8_gpio_dir_in; gc->direction_output = u8_gpio_dir_out; diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c index b8fa65b5bfca..2993c40b48e1 100644 --- a/drivers/gpio/xilinx_gpio.c +++ b/drivers/gpio/xilinx_gpio.c @@ -161,14 +161,12 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) static int __devinit xgpio_of_probe(struct device_node *np) { struct xgpio_instance *chip; - struct of_gpio_chip *ofchip; int status = 0; const u32 *tree_info; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - ofchip = &chip->mmchip.of_gc; /* Update GPIO state shadow register with default value */ tree_info = of_get_property(np, "xlnx,dout-default", NULL); @@ -182,21 +180,21 @@ static int __devinit xgpio_of_probe(struct device_node *np) chip->gpio_dir = *tree_info; /* Check device node and parent device node for device width */ - ofchip->gc.ngpio = 32; /* By default assume full GPIO controller */ + chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */ tree_info = of_get_property(np, "xlnx,gpio-width", NULL); if (!tree_info) tree_info = of_get_property(np->parent, "xlnx,gpio-width", NULL); if (tree_info) - ofchip->gc.ngpio = *tree_info; + chip->mmchip.gc.ngpio = *tree_info; spin_lock_init(&chip->gpio_lock); - ofchip->gpio_cells = 2; - ofchip->gc.direction_input = xgpio_dir_in; - ofchip->gc.direction_output = xgpio_dir_out; - ofchip->gc.get = xgpio_get; - ofchip->gc.set = xgpio_set; + chip->mmchip.gc.of_gpio_n_cells = 2; + chip->mmchip.gc.direction_input = xgpio_dir_in; + chip->mmchip.gc.direction_output = xgpio_dir_out; + chip->mmchip.gc.get = xgpio_get; + chip->mmchip.gc.set = xgpio_set; chip->mmchip.save_regs = xgpio_save_regs; diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index a1b31a4abae4..fde53a3a45a3 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -33,32 +33,32 @@ int of_get_gpio_flags(struct device_node *np, int index, enum of_gpio_flags *flags) { int ret; - struct device_node *gc; - struct of_gpio_chip *of_gc = NULL; + struct device_node *gpio_np; + struct gpio_chip *gc; int size; const void *gpio_spec; const __be32 *gpio_cells; ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, - &gc, &gpio_spec); + &gpio_np, &gpio_spec); if (ret) { pr_debug("%s: can't parse gpios property\n", __func__); goto err0; } - of_gc = gc->data; - if (!of_gc) { + gc = gpio_np->data; + if (!gc) { pr_debug("%s: gpio controller %s isn't registered\n", - np->full_name, gc->full_name); + np->full_name, gpio_np->full_name); ret = -ENODEV; goto err1; } - gpio_cells = of_get_property(gc, "#gpio-cells", &size); + gpio_cells = of_get_property(gpio_np, "#gpio-cells", &size); if (!gpio_cells || size != sizeof(*gpio_cells) || - be32_to_cpup(gpio_cells) != of_gc->gpio_cells) { + be32_to_cpup(gpio_cells) != gc->of_gpio_n_cells) { pr_debug("%s: wrong #gpio-cells for %s\n", - np->full_name, gc->full_name); + np->full_name, gpio_np->full_name); ret = -EINVAL; goto err1; } @@ -67,13 +67,13 @@ int of_get_gpio_flags(struct device_node *np, int index, if (flags) *flags = 0; - ret = of_gc->xlate(of_gc, np, gpio_spec, flags); + ret = gc->of_xlate(gc, np, gpio_spec, flags); if (ret < 0) goto err1; - ret += of_gc->gc.base; + ret += gc->base; err1: - of_node_put(gc); + of_node_put(gpio_np); err0: pr_debug("%s exited with status %d\n", __func__, ret); return ret; @@ -116,7 +116,7 @@ EXPORT_SYMBOL(of_gpio_count); /** * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags - * @of_gc: pointer to the of_gpio_chip structure + * @gc: pointer to the gpio_chip structure * @np: device node of the GPIO chip * @gpio_spec: gpio specifier as found in the device tree * @flags: a flags pointer to fill in @@ -125,8 +125,8 @@ EXPORT_SYMBOL(of_gpio_count); * gpio chips. This function performs only one sanity check: whether gpio * is less than ngpios (that is specified in the gpio_chip). */ -int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, - const void *gpio_spec, enum of_gpio_flags *flags) +int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np, + const void *gpio_spec, u32 *flags) { const __be32 *gpio = gpio_spec; const u32 n = be32_to_cpup(gpio); @@ -137,12 +137,12 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, * number and the flags from a single gpio cell -- this is possible, * but not recommended). */ - if (of_gc->gpio_cells < 2) { + if (gc->of_gpio_n_cells < 2) { WARN_ON(1); return -EINVAL; } - if (n > of_gc->gc.ngpio) + if (n > gc->ngpio) return -EINVAL; if (flags) @@ -161,10 +161,8 @@ EXPORT_SYMBOL(of_gpio_simple_xlate); * * 1) In the gpio_chip structure: * - all the callbacks - * - * 2) In the of_gpio_chip structure: - * - gpio_cells - * - xlate callback (optional) + * - of_gpio_n_cells + * - of_xlate callback (optional) * * 3) In the of_mm_gpio_chip structure: * - save_regs callback (optional) @@ -177,8 +175,7 @@ int of_mm_gpiochip_add(struct device_node *np, struct of_mm_gpio_chip *mm_gc) { int ret = -ENOMEM; - struct of_gpio_chip *of_gc = &mm_gc->of_gc; - struct gpio_chip *gc = &of_gc->gc; + struct gpio_chip *gc = &mm_gc->gc; gc->label = kstrdup(np->full_name, GFP_KERNEL); if (!gc->label) @@ -190,13 +187,14 @@ int of_mm_gpiochip_add(struct device_node *np, gc->base = -1; - if (!of_gc->xlate) - of_gc->xlate = of_gpio_simple_xlate; + if (!gc->of_xlate) + gc->of_xlate = of_gpio_simple_xlate; if (mm_gc->save_regs) mm_gc->save_regs(mm_gc); - np->data = of_gc; + np->data = &mm_gc->gc; + mm_gc->gc.of_node = np; ret = gpiochip_add(gc); if (ret) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 4f3d75e1ad39..af2544ef0b59 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -31,6 +31,7 @@ static inline int gpio_is_valid(int number) struct device; struct seq_file; struct module; +struct device_node; /** * struct gpio_chip - abstract a GPIO controller @@ -106,6 +107,17 @@ struct gpio_chip { const char *const *names; unsigned can_sleep:1; unsigned exported:1; + +#if defined(CONFIG_OF_GPIO) + /* + * If CONFIG_OF is enabled, then all GPIO controllers described in the + * device tree automatically may have an OF translation + */ + struct device_node *of_node; + int of_gpio_n_cells; + int (*of_xlate)(struct gpio_chip *gc, struct device_node *np, + const void *gpio_spec, u32 *flags); +#endif }; extern const char *gpiochip_is_requested(struct gpio_chip *chip, diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index fc2472c3c254..460d6810c5eb 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -32,35 +32,18 @@ enum of_gpio_flags { #ifdef CONFIG_OF_GPIO -/* - * Generic OF GPIO chip - */ -struct of_gpio_chip { - struct gpio_chip gc; - int gpio_cells; - int (*xlate)(struct of_gpio_chip *of_gc, struct device_node *np, - const void *gpio_spec, enum of_gpio_flags *flags); -}; - -static inline struct of_gpio_chip *to_of_gpio_chip(struct gpio_chip *gc) -{ - return container_of(gc, struct of_gpio_chip, gc); -} - /* * OF GPIO chip for memory mapped banks */ struct of_mm_gpio_chip { - struct of_gpio_chip of_gc; + struct gpio_chip gc; void (*save_regs)(struct of_mm_gpio_chip *mm_gc); void __iomem *regs; }; static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc) { - struct of_gpio_chip *of_gc = to_of_gpio_chip(gc); - - return container_of(of_gc, struct of_mm_gpio_chip, of_gc); + return container_of(gc, struct of_mm_gpio_chip, gc); } extern int of_get_gpio_flags(struct device_node *np, int index, @@ -69,11 +52,9 @@ extern unsigned int of_gpio_count(struct device_node *np); extern int of_mm_gpiochip_add(struct device_node *np, struct of_mm_gpio_chip *mm_gc); -extern int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, - struct device_node *np, - const void *gpio_spec, - enum of_gpio_flags *flags); -#else +extern int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np, + const void *gpio_spec, u32 *flags); +#else /* CONFIG_OF_GPIO */ /* Drivers may not strictly depend on the GPIO support, so let them link. */ static inline int of_get_gpio_flags(struct device_node *np, int index, -- cgit v1.2.3 From 594fa265e084073443390c5b93d5410fd28e9bcd Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:16 -0600 Subject: of/gpio: stop using device_node data pointer to find gpio_chip Currently the kernel uses the struct device_node.data pointer to resolve a struct gpio_chip pointer from a device tree node. However, the .data member doesn't provide any type checking and there aren't any rules enforced on what it should be used for. There's no guarantee that the data stored in it actually points to an gpio_chip pointer. Instead of relying on the .data pointer, this patch modifies the code to add a lookup function which scans through the registered gpio_chips and returns the gpio_chip that has a pointer to the specified device_node. Signed-off-by: Grant Likely CC: Andrew Morton CC: Anton Vorontsov CC: Grant Likely CC: David Brownell CC: Bill Gatliff CC: Dmitry Eremin-Solenikov CC: Benjamin Herrenschmidt CC: Jean Delvare CC: linux-kernel@vger.kernel.org CC: devicetree-discuss@lists.ozlabs.org --- arch/microblaze/kernel/reset.c | 2 +- arch/powerpc/platforms/52xx/mpc52xx_gpt.c | 1 + arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c | 23 +++--------------- arch/powerpc/sysdev/qe_lib/gpio.c | 2 +- drivers/gpio/gpiolib.c | 32 ++++++++++++++++++++++++++ drivers/of/gpio.c | 15 +++++++++--- include/asm-generic/gpio.h | 3 +++ include/linux/of_gpio.h | 3 +++ 8 files changed, 56 insertions(+), 25 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c index 5476d3caf045..bd8ccab5ceff 100644 --- a/arch/microblaze/kernel/reset.c +++ b/arch/microblaze/kernel/reset.c @@ -39,7 +39,7 @@ static int of_reset_gpio_handle(void) goto err0; } - gc = gpio->data; + gc = of_node_to_gpiochip(gpio); if (!gc) { pr_debug("%s: gpio controller %s isn't registered\n", root->full_name, gpio->full_name); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index 3f2ee47f1d01..6e82bd27132c 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -350,6 +350,7 @@ mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) gpt->gc.base = -1; gpt->gc.of_gpio_n_cells = 2; gpt->gc.of_xlate = of_gpio_simple_xlate; + gpt->gc.of_node = node; of_node_get(node); /* Setup external pin in GPIO mode */ diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index e49f4bd2f991..f0dbace6185a 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -35,7 +35,6 @@ struct mcu { struct mutex lock; - struct device_node *np; struct i2c_client *client; struct gpio_chip gc; u8 reg_ctrl; @@ -79,7 +78,6 @@ static int mcu_gpiochip_add(struct mcu *mcu) { struct device_node *np; struct gpio_chip *gc = &mcu->gc; - int ret; np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx"); if (!np) @@ -94,29 +92,14 @@ static int mcu_gpiochip_add(struct mcu *mcu) gc->direction_output = mcu_gpio_dir_out; gc->of_gpio_n_cells = 2; gc->of_xlate = of_gpio_simple_xlate; + gc->of_node = np; - mcu->np = np; - - /* - * We don't want to lose the node, its ->data and ->full_name... - * So, if succeeded, we don't put the node here. - */ - ret = gpiochip_add(gc); - if (ret) - of_node_put(np); - return ret; + return gpiochip_add(gc); } static int mcu_gpiochip_remove(struct mcu *mcu) { - int ret; - - ret = gpiochip_remove(&mcu->gc); - if (ret) - return ret; - of_node_put(mcu->np); - - return 0; + return gpiochip_remove(&mcu->gc); } static int __devinit mcu_probe(struct i2c_client *client, diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c index 194478c2f4b4..32e9440010a1 100644 --- a/arch/powerpc/sysdev/qe_lib/gpio.c +++ b/arch/powerpc/sysdev/qe_lib/gpio.c @@ -167,7 +167,7 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index) goto err1; } - gc = gpio_np->data; + gc = of_node_to_gpiochip(gpio_np); if (!gc) { pr_debug("%s: gpio controller %s isn't registered\n", np->full_name, gpio_np->full_name); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 713ca0e37f23..73fd328f6fe4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1153,6 +1153,38 @@ int gpiochip_remove(struct gpio_chip *chip) } EXPORT_SYMBOL_GPL(gpiochip_remove); +/** + * gpiochip_find() - iterator for locating a specific gpio_chip + * @data: data to pass to match function + * @callback: Callback function to check gpio_chip + * + * Similar to bus_find_device. It returns a reference to a gpio_chip as + * determined by a user supplied @match callback. The callback should return + * 0 if the device doesn't match and non-zero if it does. If the callback is + * non-zero, this function will return to the caller and not iterate over any + * more gpio_chips. + */ +struct gpio_chip *gpiochip_find(void *data, + int (*match)(struct gpio_chip *chip, void *data)) +{ + struct gpio_chip *chip = NULL; + unsigned long flags; + int i; + + spin_lock_irqsave(&gpio_lock, flags); + for (i = 0; i < ARCH_NR_GPIOS; i++) { + if (!gpio_desc[i].chip) + continue; + + if (match(gpio_desc[i].chip, data)) { + chip = gpio_desc[i].chip; + break; + } + } + spin_unlock_irqrestore(&gpio_lock, flags); + + return chip; +} /* These "optional" allocation calls help prevent drivers from stomping * on each other, and help provide better diagnostics in debugfs. diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index fde53a3a45a3..c8618d3282cf 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -46,7 +46,7 @@ int of_get_gpio_flags(struct device_node *np, int index, goto err0; } - gc = gpio_np->data; + gc = of_node_to_gpiochip(gpio_np); if (!gc) { pr_debug("%s: gpio controller %s isn't registered\n", np->full_name, gpio_np->full_name); @@ -193,7 +193,6 @@ int of_mm_gpiochip_add(struct device_node *np, if (mm_gc->save_regs) mm_gc->save_regs(mm_gc); - np->data = &mm_gc->gc; mm_gc->gc.of_node = np; ret = gpiochip_add(gc); @@ -207,7 +206,6 @@ int of_mm_gpiochip_add(struct device_node *np, np->full_name, gc->base); return 0; err2: - np->data = NULL; iounmap(mm_gc->regs); err1: kfree(gc->label); @@ -217,3 +215,14 @@ err0: return ret; } EXPORT_SYMBOL(of_mm_gpiochip_add); + +/* Private function for resolving node pointer to gpio_chip */ +static int of_gpiochip_is_match(struct gpio_chip *chip, void *data) +{ + return chip->of_node == data; +} + +struct gpio_chip *of_node_to_gpiochip(struct device_node *np) +{ + return gpiochip_find(np, of_gpiochip_is_match); +} diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index af2544ef0b59..c7376bf80b06 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -127,6 +127,9 @@ extern int __must_check gpiochip_reserve(int start, int ngpio); /* add/remove chips */ extern int gpiochip_add(struct gpio_chip *chip); extern int __must_check gpiochip_remove(struct gpio_chip *chip); +extern struct gpio_chip *gpiochip_find(void *data, + int (*match)(struct gpio_chip *chip, + void *data)); /* Always use the library code for GPIO management calls, diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 460d6810c5eb..1020587efed1 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -54,6 +54,9 @@ extern int of_mm_gpiochip_add(struct device_node *np, struct of_mm_gpio_chip *mm_gc); extern int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np, const void *gpio_spec, u32 *flags); + +extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np); + #else /* CONFIG_OF_GPIO */ /* Drivers may not strictly depend on the GPIO support, so let them link. */ -- cgit v1.2.3 From 391c970c0dd1100e3b9e1681f7d0f20aac35455a Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 8 Jun 2010 07:48:17 -0600 Subject: of/gpio: add default of_xlate function if device has a node pointer Implement generic OF gpio hooks and thus make device-enabled GPIO chips (i.e. the ones that have gpio_chip->dev specified) automatically attach to the OpenFirmware subsystem. Which means that now we can handle I2C and SPI GPIO chips almost* transparently. * "Almost" because some chips still require platform data, and for these chips OF-glue is still needed, though with this change the glue will be much smaller. Signed-off-by: Anton Vorontsov Signed-off-by: Grant Likely Cc: David Brownell Cc: Bill Gatliff Cc: Dmitry Eremin-Solenikov Cc: Benjamin Herrenschmidt Cc: Jean Delvare Cc: Andrew Morton CC: linux-kernel@vger.kernel.org CC: devicetree-discuss@lists.ozlabs.org --- arch/powerpc/platforms/52xx/mpc52xx_gpio.c | 2 -- arch/powerpc/platforms/52xx/mpc52xx_gpt.c | 3 --- arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c | 2 -- arch/powerpc/sysdev/cpm1.c | 2 -- arch/powerpc/sysdev/cpm_common.c | 1 - arch/powerpc/sysdev/mpc8xxx_gpio.c | 1 - arch/powerpc/sysdev/ppc4xx_gpio.c | 1 - arch/powerpc/sysdev/qe_lib/gpio.c | 1 - arch/powerpc/sysdev/simple_gpio.c | 1 - drivers/gpio/gpiolib.c | 5 ++++ drivers/gpio/xilinx_gpio.c | 1 - drivers/of/gpio.c | 33 +++++++++++++++++++------- include/linux/of_gpio.h | 7 ++++-- 13 files changed, 34 insertions(+), 26 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c index fd0912eeffe2..0855e804fc0d 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c @@ -161,7 +161,6 @@ static int __devinit mpc52xx_wkup_gpiochip_probe(struct of_device *ofdev, gc = &chip->mmchip.gc; - gc->of_gpio_n_cells = 2; gc->ngpio = 8; gc->direction_input = mpc52xx_wkup_gpio_dir_in; gc->direction_output = mpc52xx_wkup_gpio_dir_out; @@ -325,7 +324,6 @@ static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev, gc = &chip->mmchip.gc; - gc->of_gpio_n_cells = 2; gc->ngpio = 32; gc->direction_input = mpc52xx_simple_gpio_dir_in; gc->direction_output = mpc52xx_simple_gpio_dir_out; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index 6e82bd27132c..5d7d607617cd 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -348,10 +348,7 @@ mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) gpt->gc.get = mpc52xx_gpt_gpio_get; gpt->gc.set = mpc52xx_gpt_gpio_set; gpt->gc.base = -1; - gpt->gc.of_gpio_n_cells = 2; - gpt->gc.of_xlate = of_gpio_simple_xlate; gpt->gc.of_node = node; - of_node_get(node); /* Setup external pin in GPIO mode */ clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_MS_MASK, diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index f0dbace6185a..59b0ed1a56b1 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -90,8 +90,6 @@ static int mcu_gpiochip_add(struct mcu *mcu) gc->base = -1; gc->set = mcu_gpio_set; gc->direction_output = mcu_gpio_dir_out; - gc->of_gpio_n_cells = 2; - gc->of_xlate = of_gpio_simple_xlate; gc->of_node = np; return gpiochip_add(gc); diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index d5cf7d4ccf81..00852124ff4a 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -633,7 +633,6 @@ int cpm1_gpiochip_add16(struct device_node *np) gc = &mm_gc->gc; mm_gc->save_regs = cpm1_gpio16_save_regs; - gc->of_gpio_n_cells = 2; gc->ngpio = 16; gc->direction_input = cpm1_gpio16_dir_in; gc->direction_output = cpm1_gpio16_dir_out; @@ -755,7 +754,6 @@ int cpm1_gpiochip_add32(struct device_node *np) gc = &mm_gc->gc; mm_gc->save_regs = cpm1_gpio32_save_regs; - gc->of_gpio_n_cells = 2; gc->ngpio = 32; gc->direction_input = cpm1_gpio32_dir_in; gc->direction_output = cpm1_gpio32_dir_out; diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index 67e9b47dcf8e..2b69aa0315b3 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c @@ -337,7 +337,6 @@ int cpm2_gpiochip_add32(struct device_node *np) gc = &mm_gc->gc; mm_gc->save_regs = cpm2_gpio32_save_regs; - gc->of_gpio_n_cells = 2; gc->ngpio = 32; gc->direction_input = cpm2_gpio32_dir_in; gc->direction_output = cpm2_gpio32_dir_out; diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c index ec8fcd42101e..2b69084d0f0c 100644 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c @@ -273,7 +273,6 @@ static void __init mpc8xxx_add_controller(struct device_node *np) gc = &mm_gc->gc; mm_gc->save_regs = mpc8xxx_gpio_save_regs; - gc->of_gpio_n_cells = 2; gc->ngpio = MPC8XXX_GPIO_PINS; gc->direction_input = mpc8xxx_gpio_dir_in; gc->direction_output = mpc8xxx_gpio_dir_out; diff --git a/arch/powerpc/sysdev/ppc4xx_gpio.c b/arch/powerpc/sysdev/ppc4xx_gpio.c index 42e7a5eea665..fc65ad1b3293 100644 --- a/arch/powerpc/sysdev/ppc4xx_gpio.c +++ b/arch/powerpc/sysdev/ppc4xx_gpio.c @@ -194,7 +194,6 @@ static int __init ppc4xx_add_gpiochips(void) mm_gc = &ppc4xx_gc->mm_gc; gc = &mm_gc->gc; - gc->of_gpio_n_cells = 2; gc->ngpio = 32; gc->direction_input = ppc4xx_gpio_dir_in; gc->direction_output = ppc4xx_gpio_dir_out; diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c index 32e9440010a1..36bf845df127 100644 --- a/arch/powerpc/sysdev/qe_lib/gpio.c +++ b/arch/powerpc/sysdev/qe_lib/gpio.c @@ -321,7 +321,6 @@ static int __init qe_add_gpiochips(void) gc = &mm_gc->gc; mm_gc->save_regs = qe_gpio_save_regs; - gc->of_gpio_n_cells = 2; gc->ngpio = QE_PIO_PINS; gc->direction_input = qe_gpio_dir_in; gc->direction_output = qe_gpio_dir_out; diff --git a/arch/powerpc/sysdev/simple_gpio.c b/arch/powerpc/sysdev/simple_gpio.c index b7559aa0c165..b6defda5ccc9 100644 --- a/arch/powerpc/sysdev/simple_gpio.c +++ b/arch/powerpc/sysdev/simple_gpio.c @@ -103,7 +103,6 @@ static int __init u8_simple_gpiochip_add(struct device_node *np) gc = &mm_gc->gc; mm_gc->save_regs = u8_gpio_save_regs; - gc->of_gpio_n_cells = 2; gc->ngpio = 8; gc->direction_input = u8_gpio_dir_in; gc->direction_output = u8_gpio_dir_out; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 73fd328f6fe4..83cbc34e3a76 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -1099,6 +1100,8 @@ int gpiochip_add(struct gpio_chip *chip) } } + of_gpiochip_add(chip); + unlock: spin_unlock_irqrestore(&gpio_lock, flags); @@ -1133,6 +1136,8 @@ int gpiochip_remove(struct gpio_chip *chip) spin_lock_irqsave(&gpio_lock, flags); + of_gpiochip_remove(chip); + for (id = chip->base; id < chip->base + chip->ngpio; id++) { if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) { status = -EBUSY; diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c index 2993c40b48e1..709690995d0d 100644 --- a/drivers/gpio/xilinx_gpio.c +++ b/drivers/gpio/xilinx_gpio.c @@ -190,7 +190,6 @@ static int __devinit xgpio_of_probe(struct device_node *np) spin_lock_init(&chip->gpio_lock); - chip->mmchip.gc.of_gpio_n_cells = 2; chip->mmchip.gc.direction_input = xgpio_dir_in; chip->mmchip.gc.direction_output = xgpio_dir_out; chip->mmchip.gc.get = xgpio_get; diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index c8618d3282cf..09f05a178668 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -125,8 +125,8 @@ EXPORT_SYMBOL(of_gpio_count); * gpio chips. This function performs only one sanity check: whether gpio * is less than ngpios (that is specified in the gpio_chip). */ -int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np, - const void *gpio_spec, u32 *flags) +static int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np, + const void *gpio_spec, u32 *flags) { const __be32 *gpio = gpio_spec; const u32 n = be32_to_cpup(gpio); @@ -150,7 +150,6 @@ int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np, return n; } -EXPORT_SYMBOL(of_gpio_simple_xlate); /** * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank) @@ -187,9 +186,6 @@ int of_mm_gpiochip_add(struct device_node *np, gc->base = -1; - if (!gc->of_xlate) - gc->of_xlate = of_gpio_simple_xlate; - if (mm_gc->save_regs) mm_gc->save_regs(mm_gc); @@ -199,9 +195,6 @@ int of_mm_gpiochip_add(struct device_node *np, if (ret) goto err2; - /* We don't want to lose the node and its ->data */ - of_node_get(np); - pr_debug("%s: registered as generic GPIO chip, base is %d\n", np->full_name, gc->base); return 0; @@ -216,6 +209,28 @@ err0: } EXPORT_SYMBOL(of_mm_gpiochip_add); +void of_gpiochip_add(struct gpio_chip *chip) +{ + if ((!chip->of_node) && (chip->dev)) + chip->of_node = chip->dev->of_node; + + if (!chip->of_node) + return; + + if (!chip->of_xlate) { + chip->of_gpio_n_cells = 2; + chip->of_xlate = of_gpio_simple_xlate; + } + + of_node_get(chip->of_node); +} + +void of_gpiochip_remove(struct gpio_chip *chip) +{ + if (chip->of_node) + of_node_put(chip->of_node); +} + /* Private function for resolving node pointer to gpio_chip */ static int of_gpiochip_is_match(struct gpio_chip *chip, void *data) { diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 1020587efed1..6598c04dab01 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -52,9 +52,9 @@ extern unsigned int of_gpio_count(struct device_node *np); extern int of_mm_gpiochip_add(struct device_node *np, struct of_mm_gpio_chip *mm_gc); -extern int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np, - const void *gpio_spec, u32 *flags); +extern void of_gpiochip_add(struct gpio_chip *gc); +extern void of_gpiochip_remove(struct gpio_chip *gc); extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np); #else /* CONFIG_OF_GPIO */ @@ -71,6 +71,9 @@ static inline unsigned int of_gpio_count(struct device_node *np) return 0; } +static inline void of_gpiochip_add(struct gpio_chip *gc) { } +static inline void of_gpiochip_remove(struct gpio_chip *gc) { } + #endif /* CONFIG_OF_GPIO */ /** -- cgit v1.2.3 From 2ffe8c5f323c3b9749bf7bc2375d909d20bdbb15 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:19 -0600 Subject: of: refactor of_modalias_node() and remove explicit match table. This patch tightens up the behaviour of of_modalias_node() to be more predicatable and to eliminate the explicit of_modalias_tablep[] that is currently used to override the first entry in the compatible list of a device. The override table was needed originally because spi and i2c drivers had no way to do of-style matching. Now that all devices can have an of_node pointer, and all drivers can have an of_match_table, the explicit override table is no longer needed because each driver can specify its own OF-style match data. The mpc8349emitx-mcu driver is modified to explicitly specify the correct device to bind against. Signed-off-by: Grant Likely --- arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c | 6 +++ drivers/mmc/host/mmc_spi.c | 8 ++++ drivers/of/base.c | 64 ++++---------------------- 3 files changed, 23 insertions(+), 55 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index 59b0ed1a56b1..70798ac911ef 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -160,10 +160,16 @@ static const struct i2c_device_id mcu_ids[] = { }; MODULE_DEVICE_TABLE(i2c, mcu_ids); +static struct of_device_id mcu_of_match_table[] __devinitdata = { + { .compatible = "fsl,mcu-mpc8349emitx", }, + { }, +}; + static struct i2c_driver mcu_driver = { .driver = { .name = "mcu-mpc8349emitx", .owner = THIS_MODULE, + .of_match_table = mcu_of_match_table, }, .probe = mcu_probe, .remove = __devexit_p(mcu_remove), diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index ad847a24a675..7b0f3ef50f96 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1533,12 +1533,20 @@ static int __devexit mmc_spi_remove(struct spi_device *spi) return 0; } +#if defined(CONFIG_OF) +static struct of_device_id mmc_spi_of_match_table[] __devinitdata = { + { .compatible = "mmc-spi-slot", }, +}; +#endif static struct spi_driver mmc_spi_driver = { .driver = { .name = "mmc_spi", .bus = &spi_bus_type, .owner = THIS_MODULE, +#if defined(CONFIG_OF) + .of_match_table = mmc_spi_of_match_table, +#endif }, .probe = mmc_spi_probe, .remove = __devexit_p(mmc_spi_remove), diff --git a/drivers/of/base.c b/drivers/of/base.c index b5ad9740d8b2..e3f7af882e45 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -544,75 +544,29 @@ struct device_node *of_find_matching_node(struct device_node *from, } EXPORT_SYMBOL(of_find_matching_node); -/** - * of_modalias_table: Table of explicit compatible ==> modalias mappings - * - * This table allows particulare compatible property values to be mapped - * to modalias strings. This is useful for busses which do not directly - * understand the OF device tree but are populated based on data contained - * within the device tree. SPI and I2C are the two current users of this - * table. - * - * In most cases, devices do not need to be listed in this table because - * the modalias value can be derived directly from the compatible table. - * However, if for any reason a value cannot be derived, then this table - * provides a method to override the implicit derivation. - * - * At the moment, a single table is used for all bus types because it is - * assumed that the data size is small and that the compatible values - * should already be distinct enough to differentiate between SPI, I2C - * and other devices. - */ -struct of_modalias_table { - char *of_device; - char *modalias; -}; -static struct of_modalias_table of_modalias_table[] = { - { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" }, - { "mmc-spi-slot", "mmc_spi" }, -}; - /** * of_modalias_node - Lookup appropriate modalias for a device node * @node: pointer to a device tree node * @modalias: Pointer to buffer that modalias value will be copied into * @len: Length of modalias value * - * Based on the value of the compatible property, this routine will determine - * an appropriate modalias value for a particular device tree node. Two - * separate methods are attempted to derive a modalias value. + * Based on the value of the compatible property, this routine will attempt + * to choose an appropriate modalias value for a particular device tree node. + * It does this by stripping the manufacturer prefix (as delimited by a ',') + * from the first entry in the compatible list property. * - * First method is to lookup the compatible value in of_modalias_table. - * Second is to strip off the manufacturer prefix from the first - * compatible entry and use the remainder as modalias - * - * This routine returns 0 on success + * This routine returns 0 on success, <0 on failure. */ int of_modalias_node(struct device_node *node, char *modalias, int len) { - int i, cplen; - const char *compatible; - const char *p; - - /* 1. search for exception list entry */ - for (i = 0; i < ARRAY_SIZE(of_modalias_table); i++) { - compatible = of_modalias_table[i].of_device; - if (!of_device_is_compatible(node, compatible)) - continue; - strlcpy(modalias, of_modalias_table[i].modalias, len); - return 0; - } + const char *compatible, *p; + int cplen; compatible = of_get_property(node, "compatible", &cplen); - if (!compatible) + if (!compatible || strlen(compatible) > cplen) return -ENODEV; - - /* 2. take first compatible entry and strip manufacturer */ p = strchr(compatible, ','); - if (!p) - return -ENODEV; - p++; - strlcpy(modalias, p, len); + strlcpy(modalias, p ? p + 1 : compatible, len); return 0; } EXPORT_SYMBOL_GPL(of_modalias_node); -- cgit v1.2.3 From 10f85f43ef134014da72d2bcc1bff1abb9b0640c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 29 Jun 2010 12:43:34 +1000 Subject: powerpc: turn CONFIG_OF into a select so that we can make CONFIG_OF global and remove it from the architecture Kconfig files later. Signed-off-by: Stephen Rothwell Signed-off-by: Grant Likely --- arch/powerpc/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 328774bd41ee..369723183002 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -120,6 +120,8 @@ config ARCH_NO_VIRT_TO_BUS config PPC bool default y + select OF + select OF_FLATTREE select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_TRACER @@ -173,8 +175,7 @@ config PPC_OF def_bool y config OF - def_bool y - select OF_FLATTREE + bool config PPC_UDBG_16550 bool -- cgit v1.2.3 From dd5e73794c9af30d6491963e13436d9f05ee6df6 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 29 Jun 2010 12:47:01 +1000 Subject: of: remove architecture CONFIG_OF definitions now that CONFIG_OF is defined globally Signed-off-by: Stephen Rothwell Acked-by: Michal Simek Signed-off-by: Grant Likely --- arch/microblaze/Kconfig | 3 --- arch/powerpc/Kconfig | 3 --- arch/sparc/Kconfig | 3 --- 3 files changed, 9 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 2b37820555bc..1a8f682248ce 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -126,9 +126,6 @@ config CMDLINE_FORCE Set this to have arguments from the default kernel command string override those passed by the boot loader. -config OF - bool - config PROC_DEVICETREE bool "Support for device tree in /proc" depends on PROC_FS diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 369723183002..402f4c028eb8 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -174,9 +174,6 @@ config ARCH_MAY_HAVE_PC_FDC config PPC_OF def_bool y -config OF - bool - config PPC_UDBG_16550 bool default n diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index d02e8ac7aa10..13a9f2f8738c 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -149,9 +149,6 @@ config GENERIC_GPIO config ARCH_NO_VIRT_TO_BUS def_bool y -config OF - bool - config ARCH_SUPPORTS_DEBUG_PAGEALLOC def_bool y if SPARC64 -- cgit v1.2.3 From 5ab5fc7e35705cf1a8a506d8e8b71acc27feec75 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 5 Jul 2010 12:02:13 -0600 Subject: of: Put all CONFIG_OF dependencies into a Kconfig menu block All of the options in drivers/of/Kconfig depend on CONFIG_OF. Putting all of them inside a menu block simplifies the dependency statements. It also creates a logical group for adding user selectable OF options. This patch also changes (PPC_OF || MICROBLAZE) statements to (!SPARC) so that those options are available to other architectures (and in fact the !SPARC conditions should probably be re-evalutated since the code is more generic now) This patch also moves the definition of CONFIG_DTC from arch/* to drivers/of/Kconfig Signed-off-by: Grant Likely --- arch/microblaze/Kconfig | 3 --- arch/powerpc/Kconfig | 4 ---- drivers/of/Kconfig | 25 ++++++++++++++++--------- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 1a8f682248ce..971f86760d83 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -77,9 +77,6 @@ config LOCKDEP_SUPPORT config HAVE_LATENCYTOP_SUPPORT def_bool y -config DTC - def_bool y - source "init/Kconfig" source "kernel/Kconfig.freezer" diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 402f4c028eb8..9b8e479c39da 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -196,10 +196,6 @@ config SYS_SUPPORTS_APM_EMULATION default y if PMAC_APM_EMU bool -config DTC - bool - default y - config DEFAULT_UIMAGE bool help diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index d836b47d0be5..ae2d4ad67bd0 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -1,46 +1,53 @@ +config DTC + bool + config OF bool +menu "Flattened Device Tree and Open Firmware support" + depends on OF + config OF_FLATTREE bool - depends on OF + select DTC config OF_DYNAMIC def_bool y - depends on OF && PPC_OF + depends on PPC_OF config OF_ADDRESS def_bool y - depends on OF && !SPARC + depends on !SPARC config OF_IRQ def_bool y - depends on OF && !SPARC + depends on !SPARC config OF_DEVICE def_bool y - depends on OF && (SPARC || PPC_OF || MICROBLAZE) config OF_GPIO def_bool y - depends on OF && (PPC_OF || MICROBLAZE) && GPIOLIB + depends on GPIOLIB && !SPARC help OpenFirmware GPIO accessors config OF_I2C def_tristate I2C - depends on OF && !SPARC && I2C + depends on I2C && !SPARC help OpenFirmware I2C accessors config OF_SPI def_tristate SPI - depends on OF && (PPC_OF || MICROBLAZE) && SPI + depends on SPI && !SPARC help OpenFirmware SPI accessors config OF_MDIO def_tristate PHYLIB - depends on OF && PHYLIB + depends on PHYLIB help OpenFirmware MDIO bus (Ethernet PHY) accessors + +endmenu # OF -- cgit v1.2.3 From ef2a4524d6e776bbce819eeccbdcaeee5ce74027 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 28 Jun 2010 22:00:48 -0400 Subject: proc: unify PROC_DEVICETREE config Microblaze and PPC both use PROC_DEVICETREE, and OLPC will as well.. put the Kconfig option into fs/ rather than in arch/*/Kconfig. Signed-off-by: Andres Salomon [grant.likely@secretlab.ca: changed depends to PROC_FS && !SPARC] [grant.likely@secretlab.ca: moved to drivers/of/Kconfig] Signed-off-by: Grant Likely --- arch/microblaze/Kconfig | 8 -------- arch/powerpc/Kconfig | 8 -------- drivers/of/Kconfig | 8 ++++++++ 3 files changed, 8 insertions(+), 16 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 971f86760d83..6c4fee5eaf0b 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -123,14 +123,6 @@ config CMDLINE_FORCE Set this to have arguments from the default kernel command string override those passed by the boot loader. -config PROC_DEVICETREE - bool "Support for device tree in /proc" - depends on PROC_FS - help - This option adds a device-tree directory under /proc which contains - an image of the device tree that the kernel copies from Open - Firmware or other boot firmware. If unsure, say Y here. - endmenu menu "Advanced setup" diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 9b8e479c39da..c9ae321a06f9 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -572,14 +572,6 @@ config SCHED_SMT when dealing with POWER5 cpus at a cost of slightly increased overhead in some places. If unsure say N here. -config PROC_DEVICETREE - bool "Support for device tree in /proc" - depends on PROC_FS - help - This option adds a device-tree directory under /proc which contains - an image of the device tree that the kernel copies from Open - Firmware or other boot firmware. If unsure, say Y here. - config CMDLINE_BOOL bool "Default bootloader kernel arguments" diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index ae2d4ad67bd0..6acbff389ab6 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -7,6 +7,14 @@ config OF menu "Flattened Device Tree and Open Firmware support" depends on OF +config PROC_DEVICETREE + bool "Support for device tree in /proc" + depends on PROC_FS && !SPARC + help + This option adds a device-tree directory under /proc which contains + an image of the device tree that the kernel copies from Open + Firmware or other boot firmware. If unsure, say Y here. + config OF_FLATTREE bool select DTC -- cgit v1.2.3 From 8fd63a9ea7528463211a6c88d500c51851d960c8 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 20 Jun 2010 19:03:08 +0000 Subject: powerpc: Rework VDSO gettimeofday to prevent time going backwards Currently it is possible for userspace to see the result of gettimeofday() going backwards by 1 microsecond, assuming that userspace is using the gettimeofday() in the VDSO. The VDSO gettimeofday() algorithm computes the time in "xsecs", which are units of 2^-20 seconds, or approximately 0.954 microseconds, using the algorithm now = (timebase - tb_orig_stamp) * tb_to_xs + stamp_xsec and then converts the time in xsecs to seconds and microseconds. The kernel updates the tb_orig_stamp and stamp_xsec values every tick in update_vsyscall(). If the length of the tick is not an integer number of xsecs, then some precision is lost in converting the current time to xsecs. For example, with CONFIG_HZ=1000, the tick is 1ms long, which is 1048.576 xsecs. That means that stamp_xsec will advance by either 1048 or 1049 on each tick. With the right conditions, it is possible for userspace to get (timebase - tb_orig_stamp) * tb_to_xs being 1049 if the kernel is slightly late in updating the vdso_datapage, and then for stamp_xsec to advance by 1048 when the kernel does update it, and for userspace to then see (timebase - tb_orig_stamp) * tb_to_xs being zero due to integer truncation. The result is that time appears to go backwards by 1 microsecond. To fix this we change the VDSO gettimeofday to use a new field in the VDSO datapage which stores the nanoseconds part of the time as a fractional number of seconds in a 0.32 binary fraction format. (Or put another way, as a 32-bit number in units of 0.23283 ns.) This is convenient because we can use the mulhwu instruction to convert it to either microseconds or nanoseconds. Since it turns out that computing the time of day using this new field is simpler than either using stamp_xsec (as gettimeofday does) or stamp_xtime.tv_nsec (as clock_gettime does), this converts both gettimeofday and clock_gettime to use the new field. The existing __do_get_tspec function is converted to use the new field and take a parameter in r7 that indicates the desired resolution, 1,000,000 for microseconds or 1,000,000,000 for nanoseconds. The __do_get_xsec function is then unused and is deleted. The new algorithm is now = ((timebase - tb_orig_stamp) << 12) * tb_to_xs + (stamp_xtime_seconds << 32) + stamp_sec_fraction with 'now' in units of 2^-32 seconds. That is then converted to seconds and either microseconds or nanoseconds with seconds = now >> 32 partseconds = ((now & 0xffffffff) * resolution) >> 32 The 32-bit VDSO code also makes a further simplification: it ignores the bottom 32 bits of the tb_to_xs value, which is a 0.64 format binary fraction. Doing so gets rid of 4 multiply instructions. Assuming a timebase frequency of 1GHz or less and an update interval of no more than 10ms, the upper 32 bits of tb_to_xs will be at least 4503599, so the error from ignoring the low 32 bits will be at most 2.2ns, which is more than an order of magnitude less than the time taken to do gettimeofday or clock_gettime on our fastest processors, so there is no possibility of seeing inconsistent values due to this. This also moves update_gtod() down next to its only caller, and makes update_vsyscall use the time passed in via the wall_time argument rather than accessing xtime directly. At present, wall_time always points to xtime, but that could change in future. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/vdso_datapage.h | 2 + arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kernel/time.c | 61 +++++----- arch/powerpc/kernel/vdso32/gettimeofday.S | 184 +++++++----------------------- arch/powerpc/kernel/vdso64/gettimeofday.S | 88 ++++---------- 5 files changed, 99 insertions(+), 237 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/vdso_datapage.h b/arch/powerpc/include/asm/vdso_datapage.h index 13c2c283e178..08679c5319b8 100644 --- a/arch/powerpc/include/asm/vdso_datapage.h +++ b/arch/powerpc/include/asm/vdso_datapage.h @@ -85,6 +85,7 @@ struct vdso_data { __s32 wtom_clock_sec; /* Wall to monotonic clock */ __s32 wtom_clock_nsec; struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */ + __u32 stamp_sec_fraction; /* fractional seconds of stamp_xtime */ __u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls */ __u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */ }; @@ -105,6 +106,7 @@ struct vdso_data { __s32 wtom_clock_sec; /* Wall to monotonic clock */ __s32 wtom_clock_nsec; struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */ + __u32 stamp_sec_fraction; /* fractional seconds of stamp_xtime */ __u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */ __u32 dcache_block_size; /* L1 d-cache block size */ __u32 icache_block_size; /* L1 i-cache block size */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 496cc5b3984f..acbbac6aaa22 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -342,6 +342,7 @@ int main(void) DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec)); DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); DEFINE(STAMP_XTIME, offsetof(struct vdso_data, stamp_xtime)); + DEFINE(STAMP_SEC_FRAC, offsetof(struct vdso_data, stamp_sec_fraction)); DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size)); DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size)); DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size)); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 0441bbdadbd1..5adebaf47f13 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -423,30 +423,6 @@ void udelay(unsigned long usecs) } EXPORT_SYMBOL(udelay); -static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, - u64 new_tb_to_xs) -{ - /* - * tb_update_count is used to allow the userspace gettimeofday code - * to assure itself that it sees a consistent view of the tb_to_xs and - * stamp_xsec variables. It reads the tb_update_count, then reads - * tb_to_xs and stamp_xsec and then reads tb_update_count again. If - * the two values of tb_update_count match and are even then the - * tb_to_xs and stamp_xsec values are consistent. If not, then it - * loops back and reads them again until this criteria is met. - * We expect the caller to have done the first increment of - * vdso_data->tb_update_count already. - */ - vdso_data->tb_orig_stamp = new_tb_stamp; - vdso_data->stamp_xsec = new_stamp_xsec; - vdso_data->tb_to_xs = new_tb_to_xs; - vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; - vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; - vdso_data->stamp_xtime = xtime; - smp_wmb(); - ++(vdso_data->tb_update_count); -} - #ifdef CONFIG_SMP unsigned long profile_pc(struct pt_regs *regs) { @@ -873,10 +849,37 @@ static cycle_t timebase_read(struct clocksource *cs) return (cycle_t)get_tb(); } +static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, + u64 new_tb_to_xs, struct timespec *now, + u32 frac_sec) +{ + /* + * tb_update_count is used to allow the userspace gettimeofday code + * to assure itself that it sees a consistent view of the tb_to_xs and + * stamp_xsec variables. It reads the tb_update_count, then reads + * tb_to_xs and stamp_xsec and then reads tb_update_count again. If + * the two values of tb_update_count match and are even then the + * tb_to_xs and stamp_xsec values are consistent. If not, then it + * loops back and reads them again until this criteria is met. + * We expect the caller to have done the first increment of + * vdso_data->tb_update_count already. + */ + vdso_data->tb_orig_stamp = new_tb_stamp; + vdso_data->stamp_xsec = new_stamp_xsec; + vdso_data->tb_to_xs = new_tb_to_xs; + vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; + vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; + vdso_data->stamp_xtime = *now; + vdso_data->stamp_sec_fraction = frac_sec; + smp_wmb(); + ++(vdso_data->tb_update_count); +} + void update_vsyscall(struct timespec *wall_time, struct clocksource *clock, u32 mult) { u64 t2x, stamp_xsec; + u32 frac_sec; if (clock != &clocksource_timebase) return; @@ -888,10 +891,14 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock, /* XXX this assumes clock->shift == 22 */ /* 4611686018 ~= 2^(20+64-22) / 1e9 */ t2x = (u64) mult * 4611686018ULL; - stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC; + stamp_xsec = (u64) wall_time->tv_nsec * XSEC_PER_SEC; do_div(stamp_xsec, 1000000000); - stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC; - update_gtod(clock->cycle_last, stamp_xsec, t2x); + stamp_xsec += (u64) wall_time->tv_sec * XSEC_PER_SEC; + + BUG_ON(wall_time->tv_nsec >= NSEC_PER_SEC); + /* this is tv_nsec / 1e9 as a 0.32 fraction */ + frac_sec = ((u64) wall_time->tv_nsec * 18446744073ULL) >> 32; + update_gtod(clock->cycle_last, stamp_xsec, t2x, wall_time, frac_sec); } void update_vsyscall_tz(void) diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S index ee038d4bf252..4ee09ee2e836 100644 --- a/arch/powerpc/kernel/vdso32/gettimeofday.S +++ b/arch/powerpc/kernel/vdso32/gettimeofday.S @@ -19,8 +19,10 @@ /* Offset for the low 32-bit part of a field of long type */ #ifdef CONFIG_PPC64 #define LOPART 4 +#define TSPEC_TV_SEC TSPC64_TV_SEC+LOPART #else #define LOPART 0 +#define TSPEC_TV_SEC TSPC32_TV_SEC #endif .text @@ -41,23 +43,11 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday) mr r9, r3 /* datapage ptr in r9 */ cmplwi r10,0 /* check if tv is NULL */ beq 3f - bl __do_get_xsec@local /* get xsec from tb & kernel */ - bne- 2f /* out of line -> do syscall */ - - /* seconds are xsec >> 20 */ - rlwinm r5,r4,12,20,31 - rlwimi r5,r3,12,0,19 - stw r5,TVAL32_TV_SEC(r10) - - /* get remaining xsec and convert to usec. we scale - * up remaining xsec by 12 bits and get the top 32 bits - * of the multiplication - */ - rlwinm r5,r4,12,0,19 - lis r6,1000000@h - ori r6,r6,1000000@l - mulhwu r5,r5,r6 - stw r5,TVAL32_TV_USEC(r10) + lis r7,1000000@ha /* load up USEC_PER_SEC */ + addi r7,r7,1000000@l /* so we get microseconds in r4 */ + bl __do_get_tspec@local /* get sec/usec from tb & kernel */ + stw r3,TVAL32_TV_SEC(r10) + stw r4,TVAL32_TV_USEC(r10) 3: cmplwi r11,0 /* check if tz is NULL */ beq 1f @@ -70,14 +60,6 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday) crclr cr0*4+so li r3,0 blr - -2: - mtlr r12 - mr r3,r10 - mr r4,r11 - li r0,__NR_gettimeofday - sc - blr .cfi_endproc V_FUNCTION_END(__kernel_gettimeofday) @@ -100,7 +82,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) mr r11,r4 /* r11 saves tp */ bl __get_datapage@local /* get data page */ mr r9,r3 /* datapage ptr in r9 */ - + lis r7,NSEC_PER_SEC@h /* want nanoseconds */ + ori r7,r7,NSEC_PER_SEC@l 50: bl __do_get_tspec@local /* get sec/nsec from tb & kernel */ bne cr1,80f /* not monotonic -> all done */ @@ -198,83 +181,12 @@ V_FUNCTION_END(__kernel_clock_getres) /* - * This is the core of gettimeofday() & friends, it returns the xsec - * value in r3 & r4 and expects the datapage ptr (non clobbered) - * in r9. clobbers r0,r4,r5,r6,r7,r8. - * When returning, r8 contains the counter value that can be reused - * by the monotonic clock implementation - */ -__do_get_xsec: - .cfi_startproc - /* Check for update count & load values. We use the low - * order 32 bits of the update count - */ -1: lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9) - andi. r0,r8,1 /* pending update ? loop */ - bne- 1b - xor r0,r8,r8 /* create dependency */ - add r9,r9,r0 - - /* Load orig stamp (offset to TB) */ - lwz r5,CFG_TB_ORIG_STAMP(r9) - lwz r6,(CFG_TB_ORIG_STAMP+4)(r9) - - /* Get a stable TB value */ -2: mftbu r3 - mftbl r4 - mftbu r0 - cmpl cr0,r3,r0 - bne- 2b - - /* Substract tb orig stamp. If the high part is non-zero, we jump to - * the slow path which call the syscall. - * If it's ok, then we have our 32 bits tb_ticks value in r7 - */ - subfc r7,r6,r4 - subfe. r0,r5,r3 - bne- 3f - - /* Load scale factor & do multiplication */ - lwz r5,CFG_TB_TO_XS(r9) /* load values */ - lwz r6,(CFG_TB_TO_XS+4)(r9) - mulhwu r4,r7,r5 - mulhwu r6,r7,r6 - mullw r0,r7,r5 - addc r6,r6,r0 - - /* At this point, we have the scaled xsec value in r4 + XER:CA - * we load & add the stamp since epoch - */ - lwz r5,CFG_STAMP_XSEC(r9) - lwz r6,(CFG_STAMP_XSEC+4)(r9) - adde r4,r4,r6 - addze r3,r5 - - /* We now have our result in r3,r4. We create a fake dependency - * on that result and re-check the counter - */ - or r6,r4,r3 - xor r0,r6,r6 - add r9,r9,r0 - lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) - cmpl cr0,r8,r0 /* check if updated */ - bne- 1b - - /* Warning ! The caller expects CR:EQ to be set to indicate a - * successful calculation (so it won't fallback to the syscall - * method). We have overriden that CR bit in the counter check, - * but fortunately, the loop exit condition _is_ CR:EQ set, so - * we can exit safely here. If you change this code, be careful - * of that side effect. - */ -3: blr - .cfi_endproc - -/* - * This is the core of clock_gettime(), it returns the current - * time in seconds and nanoseconds in r3 and r4. + * This is the core of clock_gettime() and gettimeofday(), + * it returns the current time in r3 (seconds) and r4. + * On entry, r7 gives the resolution of r4, either USEC_PER_SEC + * or NSEC_PER_SEC, giving r4 in microseconds or nanoseconds. * It expects the datapage ptr in r9 and doesn't clobber it. - * It clobbers r0, r5, r6, r10 and returns NSEC_PER_SEC in r7. + * It clobbers r0, r5 and r6. * On return, r8 contains the counter value that can be reused. * This clobbers cr0 but not any other cr field. */ @@ -297,70 +209,58 @@ __do_get_tspec: 2: mftbu r3 mftbl r4 mftbu r0 - cmpl cr0,r3,r0 + cmplw cr0,r3,r0 bne- 2b /* Subtract tb orig stamp and shift left 12 bits. */ - subfc r7,r6,r4 + subfc r4,r6,r4 subfe r0,r5,r3 slwi r0,r0,12 - rlwimi. r0,r7,12,20,31 - slwi r7,r7,12 + rlwimi. r0,r4,12,20,31 + slwi r4,r4,12 - /* Load scale factor & do multiplication */ + /* + * Load scale factor & do multiplication. + * We only use the high 32 bits of the tb_to_xs value. + * Even with a 1GHz timebase clock, the high 32 bits of + * tb_to_xs will be at least 4 million, so the error from + * ignoring the low 32 bits will be no more than 0.25ppm. + * The error will just make the clock run very very slightly + * slow until the next time the kernel updates the VDSO data, + * at which point the clock will catch up to the kernel's value, + * so there is no long-term error accumulation. + */ lwz r5,CFG_TB_TO_XS(r9) /* load values */ - lwz r6,(CFG_TB_TO_XS+4)(r9) - mulhwu r3,r7,r6 - mullw r10,r7,r5 - mulhwu r4,r7,r5 - addc r10,r3,r10 + mulhwu r4,r4,r5 li r3,0 beq+ 4f /* skip high part computation if 0 */ mulhwu r3,r0,r5 - mullw r7,r0,r5 - mulhwu r5,r0,r6 - mullw r6,r0,r6 - adde r4,r4,r7 - addze r3,r3 + mullw r5,r0,r5 addc r4,r4,r5 addze r3,r3 - addc r10,r10,r6 - -4: addze r4,r4 /* add in carry */ - lis r7,NSEC_PER_SEC@h - ori r7,r7,NSEC_PER_SEC@l - mulhwu r4,r4,r7 /* convert to nanoseconds */ - - /* At this point, we have seconds & nanoseconds since the xtime - * stamp in r3+CA and r4. Load & add the xtime stamp. +4: + /* At this point, we have seconds since the xtime stamp + * as a 32.32 fixed-point number in r3 and r4. + * Load & add the xtime stamp. */ -#ifdef CONFIG_PPC64 - lwz r5,STAMP_XTIME+TSPC64_TV_SEC+LOPART(r9) - lwz r6,STAMP_XTIME+TSPC64_TV_NSEC+LOPART(r9) -#else - lwz r5,STAMP_XTIME+TSPC32_TV_SEC(r9) - lwz r6,STAMP_XTIME+TSPC32_TV_NSEC(r9) -#endif - add r4,r4,r6 + lwz r5,STAMP_XTIME+TSPEC_TV_SEC(r9) + lwz r6,STAMP_SEC_FRAC(r9) + addc r4,r4,r6 adde r3,r3,r5 - /* We now have our result in r3,r4. We create a fake dependency - * on that result and re-check the counter + /* We create a fake dependency on the result in r3/r4 + * and re-check the counter */ or r6,r4,r3 xor r0,r6,r6 add r9,r9,r0 lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) - cmpl cr0,r8,r0 /* check if updated */ + cmplw cr0,r8,r0 /* check if updated */ bne- 1b - /* check for nanosecond overflow and adjust if necessary */ - cmpw r4,r7 - bltlr /* all done if no overflow */ - subf r4,r7,r4 /* adjust if overflow */ - addi r3,r3,1 + mulhwu r4,r4,r7 /* convert to micro or nanoseconds */ blr .cfi_endproc diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S index 262cd5857a56..e97a9a0dc4ac 100644 --- a/arch/powerpc/kernel/vdso64/gettimeofday.S +++ b/arch/powerpc/kernel/vdso64/gettimeofday.S @@ -33,18 +33,11 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday) bl V_LOCAL_FUNC(__get_datapage) /* get data page */ cmpldi r11,0 /* check if tv is NULL */ beq 2f - bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ - lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ - ori r7,r7,16960 - rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ - rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ - std r5,TVAL64_TV_SEC(r11) /* store sec in tv */ - subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */ - mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) / - * XSEC_PER_SEC - */ - rldicl r0,r0,44,20 - std r0,TVAL64_TV_USEC(r11) /* store usec in tv */ + lis r7,1000000@ha /* load up USEC_PER_SEC */ + addi r7,r7,1000000@l + bl V_LOCAL_FUNC(__do_get_tspec) /* get sec/us from tb & kernel */ + std r4,TVAL64_TV_SEC(r11) /* store sec in tv */ + std r5,TVAL64_TV_USEC(r11) /* store usec in tv */ 2: cmpldi r10,0 /* check if tz is NULL */ beq 1f lwz r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */ @@ -77,6 +70,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) .cfi_register lr,r12 mr r11,r4 /* r11 saves tp */ bl V_LOCAL_FUNC(__get_datapage) /* get data page */ + lis r7,NSEC_PER_SEC@h /* want nanoseconds */ + ori r7,r7,NSEC_PER_SEC@l 50: bl V_LOCAL_FUNC(__do_get_tspec) /* get time from tb & kernel */ bne cr1,80f /* if not monotonic, all done */ @@ -171,49 +166,12 @@ V_FUNCTION_END(__kernel_clock_getres) /* - * This is the core of gettimeofday(), it returns the xsec - * value in r4 and expects the datapage ptr (non clobbered) - * in r3. clobbers r0,r4,r5,r6,r7,r8 - * When returning, r8 contains the counter value that can be reused - */ -V_FUNCTION_BEGIN(__do_get_xsec) - .cfi_startproc - /* check for update count & load values */ -1: ld r8,CFG_TB_UPDATE_COUNT(r3) - andi. r0,r8,1 /* pending update ? loop */ - bne- 1b - xor r0,r8,r8 /* create dependency */ - add r3,r3,r0 - - /* Get TB & offset it. We use the MFTB macro which will generate - * workaround code for Cell. - */ - MFTB(r7) - ld r9,CFG_TB_ORIG_STAMP(r3) - subf r7,r9,r7 - - /* Scale result */ - ld r5,CFG_TB_TO_XS(r3) - mulhdu r7,r7,r5 - - /* Add stamp since epoch */ - ld r6,CFG_STAMP_XSEC(r3) - add r4,r6,r7 - - xor r0,r4,r4 - add r3,r3,r0 - ld r0,CFG_TB_UPDATE_COUNT(r3) - cmpld cr0,r0,r8 /* check if updated */ - bne- 1b - blr - .cfi_endproc -V_FUNCTION_END(__do_get_xsec) - -/* - * This is the core of clock_gettime(), it returns the current - * time in seconds and nanoseconds in r4 and r5. + * This is the core of clock_gettime() and gettimeofday(), + * it returns the current time in r4 (seconds) and r5. + * On entry, r7 gives the resolution of r5, either USEC_PER_SEC + * or NSEC_PER_SEC, giving r5 in microseconds or nanoseconds. * It expects the datapage ptr in r3 and doesn't clobber it. - * It clobbers r0 and r6 and returns NSEC_PER_SEC in r7. + * It clobbers r0, r6 and r9. * On return, r8 contains the counter value that can be reused. * This clobbers cr0 but not any other cr field. */ @@ -229,18 +187,18 @@ V_FUNCTION_BEGIN(__do_get_tspec) /* Get TB & offset it. We use the MFTB macro which will generate * workaround code for Cell. */ - MFTB(r7) + MFTB(r6) ld r9,CFG_TB_ORIG_STAMP(r3) - subf r7,r9,r7 + subf r6,r9,r6 /* Scale result */ ld r5,CFG_TB_TO_XS(r3) - sldi r7,r7,12 /* compute time since stamp_xtime */ - mulhdu r6,r7,r5 /* in units of 2^-32 seconds */ + sldi r6,r6,12 /* compute time since stamp_xtime */ + mulhdu r6,r6,r5 /* in units of 2^-32 seconds */ /* Add stamp since epoch */ ld r4,STAMP_XTIME+TSPC64_TV_SEC(r3) - ld r5,STAMP_XTIME+TSPC64_TV_NSEC(r3) + lwz r5,STAMP_SEC_FRAC(r3) or r0,r4,r5 or r0,r0,r6 xor r0,r0,r0 @@ -250,17 +208,11 @@ V_FUNCTION_BEGIN(__do_get_tspec) bne- 1b /* reload if so */ /* convert to seconds & nanoseconds and add to stamp */ - lis r7,NSEC_PER_SEC@h - ori r7,r7,NSEC_PER_SEC@l - mulhwu r0,r6,r7 /* compute nanoseconds and */ + add r6,r6,r5 /* add on fractional seconds of xtime */ + mulhwu r5,r6,r7 /* compute micro or nanoseconds and */ srdi r6,r6,32 /* seconds since stamp_xtime */ - clrldi r0,r0,32 - add r5,r5,r0 /* add nanoseconds together */ - cmpd r5,r7 /* overflow? */ + clrldi r5,r5,32 add r4,r4,r6 - bltlr /* all done if no overflow */ - subf r5,r7,r5 /* if overflow, adjust */ - addi r4,r4,1 blr .cfi_endproc V_FUNCTION_END(__do_get_tspec) -- cgit v1.2.3 From c1aa687d499a8bce55cb8cf962f0b72c0f933f14 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 20 Jun 2010 19:04:14 +0000 Subject: powerpc: Clean up obsolete code relating to decrementer and timebase Since the decrementer and timekeeping code was moved over to using the generic clockevents and timekeeping infrastructure, several variables and functions have been obsolete and effectively unused. This deletes them. In particular, wakeup_decrementer() is no longer needed since the generic code reprograms the decrementer as part of the process of resuming the timekeeping code, which happens during sysdev resume. Thus the wakeup_decrementer calls in the suspend_enter methods for 52xx platforms have been removed. The call in the powermac cpu frequency change code has been replaced by set_dec(1), which will cause a timer interrupt as soon as interrupts are enabled, and the generic code will then reprogram the decrementer with the correct value. This also simplifies the generic_suspend_en/disable_irqs functions and makes them static since they are not referenced outside time.c. The preempt_enable/disable calls are removed because the generic code has disabled all but the boot cpu at the point where these functions are called, so we can't be moved to another cpu. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/machdep.h | 3 - arch/powerpc/include/asm/time.h | 7 -- arch/powerpc/kernel/smp.c | 2 - arch/powerpc/kernel/time.c | 136 +-------------------------- arch/powerpc/platforms/52xx/lite5200_pm.c | 3 - arch/powerpc/platforms/52xx/mpc52xx_pm.c | 3 - arch/powerpc/platforms/powermac/cpufreq_32.c | 8 +- 7 files changed, 9 insertions(+), 153 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 9f0fc9e6ce0d..7716e68f7b18 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -366,8 +366,5 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal) #define machine_late_initcall(mach,fn) __define_machine_initcall(mach,"7",fn,7) #define machine_late_initcall_sync(mach,fn) __define_machine_initcall(mach,"7s",fn,7s) -void generic_suspend_disable_irqs(void); -void generic_suspend_enable_irqs(void); - #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_MACHDEP_H */ diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h index 27ccb764fdab..dc779dfcf258 100644 --- a/arch/powerpc/include/asm/time.h +++ b/arch/powerpc/include/asm/time.h @@ -28,16 +28,12 @@ extern unsigned long tb_ticks_per_jiffy; extern unsigned long tb_ticks_per_usec; extern unsigned long tb_ticks_per_sec; -extern u64 tb_to_xs; -extern unsigned tb_to_us; struct rtc_time; extern void to_tm(int tim, struct rtc_time * tm); extern void GregorianDay(struct rtc_time *tm); -extern time_t last_rtc_update; extern void generic_calibrate_decr(void); -extern void wakeup_decrementer(void); extern void snapshot_timebase(void); extern void set_dec_cpu6(unsigned int val); @@ -204,9 +200,6 @@ static inline unsigned long tb_ticks_since(unsigned long tstamp) extern u64 mulhdu(u64, u64); #endif -extern void smp_space_timers(unsigned int); - -extern unsigned mulhwu_scale_factor(unsigned, unsigned); extern void div128_by_32(u64 dividend_high, u64 dividend_low, unsigned divisor, struct div_result *dr); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 5c196d1086d9..8764daad309b 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -288,8 +288,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) max_cpus = NR_CPUS; else max_cpus = 1; - - smp_space_timers(max_cpus); for_each_possible_cpu(cpu) if (cpu != boot_cpuid) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 5adebaf47f13..ccb8759c8532 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -149,16 +149,6 @@ unsigned long tb_ticks_per_usec = 100; /* sane default */ EXPORT_SYMBOL(tb_ticks_per_usec); unsigned long tb_ticks_per_sec; EXPORT_SYMBOL(tb_ticks_per_sec); /* for cputime_t conversions */ -u64 tb_to_xs; -unsigned tb_to_us; - -#define TICKLEN_SCALE NTP_SCALE_SHIFT -static u64 last_tick_len; /* units are ns / 2^TICKLEN_SCALE */ -static u64 ticklen_to_xs; /* 0.64 fraction */ - -/* If last_tick_len corresponds to about 1/HZ seconds, then - last_tick_len << TICKLEN_SHIFT will be about 2^63. */ -#define TICKLEN_SHIFT (63 - 30 - TICKLEN_SCALE + SHIFT_HZ) DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL_GPL(rtc_lock); @@ -174,7 +164,6 @@ unsigned long ppc_proc_freq; EXPORT_SYMBOL(ppc_proc_freq); unsigned long ppc_tb_freq; -static u64 tb_last_jiffy __cacheline_aligned_in_smp; static DEFINE_PER_CPU(u64, last_jiffy); #ifdef CONFIG_VIRT_CPU_ACCOUNTING @@ -446,7 +435,6 @@ EXPORT_SYMBOL(profile_pc); static int __init iSeries_tb_recal(void) { - struct div_result divres; unsigned long titan, tb; /* Make sure we only run on iSeries */ @@ -477,10 +465,7 @@ static int __init iSeries_tb_recal(void) tb_ticks_per_jiffy = new_tb_ticks_per_jiffy; tb_ticks_per_sec = new_tb_ticks_per_sec; calc_cputime_factors(); - div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres ); - tb_to_xs = divres.result_low; vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; - vdso_data->tb_to_xs = tb_to_xs; setup_cputime_one_jiffy(); } else { @@ -643,27 +628,9 @@ void timer_interrupt(struct pt_regs * regs) trace_timer_interrupt_exit(regs); } -void wakeup_decrementer(void) -{ - unsigned long ticks; - - /* - * The timebase gets saved on sleep and restored on wakeup, - * so all we need to do is to reset the decrementer. - */ - ticks = tb_ticks_since(__get_cpu_var(last_jiffy)); - if (ticks < tb_ticks_per_jiffy) - ticks = tb_ticks_per_jiffy - ticks; - else - ticks = 1; - set_dec(ticks); -} - #ifdef CONFIG_SUSPEND -void generic_suspend_disable_irqs(void) +static void generic_suspend_disable_irqs(void) { - preempt_disable(); - /* Disable the decrementer, so that it doesn't interfere * with suspending. */ @@ -673,12 +640,9 @@ void generic_suspend_disable_irqs(void) set_dec(0x7fffffff); } -void generic_suspend_enable_irqs(void) +static void generic_suspend_enable_irqs(void) { - wakeup_decrementer(); - local_irq_enable(); - preempt_enable(); } /* Overrides the weak version in kernel/power/main.c */ @@ -698,23 +662,6 @@ void arch_suspend_enable_irqs(void) } #endif -#ifdef CONFIG_SMP -void __init smp_space_timers(unsigned int max_cpus) -{ - int i; - u64 previous_tb = per_cpu(last_jiffy, boot_cpuid); - - /* make sure tb > per_cpu(last_jiffy, cpu) for all cpus always */ - previous_tb -= tb_ticks_per_jiffy; - - for_each_possible_cpu(i) { - if (i == boot_cpuid) - continue; - per_cpu(last_jiffy, i) = previous_tb; - } -} -#endif - /* * Scheduler clock - returns current time in nanosec units. * @@ -1014,15 +961,13 @@ void secondary_cpu_time_init(void) /* This function is only called on the boot processor */ void __init time_init(void) { - unsigned long flags; struct div_result res; - u64 scale, x; + u64 scale; unsigned shift; if (__USE_RTC()) { /* 601 processor: dec counts down by 128 every 128ns */ ppc_tb_freq = 1000000000; - tb_last_jiffy = get_rtcl(); } else { /* Normal PowerPC with timebase register */ ppc_md.calibrate_decr(); @@ -1030,49 +975,14 @@ void __init time_init(void) ppc_tb_freq / 1000000, ppc_tb_freq % 1000000); printk(KERN_DEBUG "time_init: processor frequency = %lu.%.6lu MHz\n", ppc_proc_freq / 1000000, ppc_proc_freq % 1000000); - tb_last_jiffy = get_tb(); } tb_ticks_per_jiffy = ppc_tb_freq / HZ; tb_ticks_per_sec = ppc_tb_freq; tb_ticks_per_usec = ppc_tb_freq / 1000000; - tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); calc_cputime_factors(); setup_cputime_one_jiffy(); - /* - * Calculate the length of each tick in ns. It will not be - * exactly 1e9/HZ unless ppc_tb_freq is divisible by HZ. - * We compute 1e9 * tb_ticks_per_jiffy / ppc_tb_freq, - * rounded up. - */ - x = (u64) NSEC_PER_SEC * tb_ticks_per_jiffy + ppc_tb_freq - 1; - do_div(x, ppc_tb_freq); - tick_nsec = x; - last_tick_len = x << TICKLEN_SCALE; - - /* - * Compute ticklen_to_xs, which is a factor which gets multiplied - * by (last_tick_len << TICKLEN_SHIFT) to get a tb_to_xs value. - * It is computed as: - * ticklen_to_xs = 2^N / (tb_ticks_per_jiffy * 1e9) - * where N = 64 + 20 - TICKLEN_SCALE - TICKLEN_SHIFT - * which turns out to be N = 51 - SHIFT_HZ. - * This gives the result as a 0.64 fixed-point fraction. - * That value is reduced by an offset amounting to 1 xsec per - * 2^31 timebase ticks to avoid problems with time going backwards - * by 1 xsec when we do timer_recalc_offset due to losing the - * fractional xsec. That offset is equal to ppc_tb_freq/2^51 - * since there are 2^20 xsec in a second. - */ - div128_by_32((1ULL << 51) - ppc_tb_freq, 0, - tb_ticks_per_jiffy << SHIFT_HZ, &res); - div128_by_32(res.result_high, res.result_low, NSEC_PER_SEC, &res); - ticklen_to_xs = res.result_low; - - /* Compute tb_to_xs from tick_nsec */ - tb_to_xs = mulhdu(last_tick_len << TICKLEN_SHIFT, ticklen_to_xs); - /* * Compute scale factor for sched_clock. * The calibrate_decr() function has set tb_ticks_per_sec, @@ -1094,21 +1004,14 @@ void __init time_init(void) /* Save the current timebase to pretty up CONFIG_PRINTK_TIME */ boot_tb = get_tb_or_rtc(); - write_seqlock_irqsave(&xtime_lock, flags); - /* If platform provided a timezone (pmac), we correct the time */ if (timezone_offset) { sys_tz.tz_minuteswest = -timezone_offset / 60; sys_tz.tz_dsttime = 0; } - vdso_data->tb_orig_stamp = tb_last_jiffy; vdso_data->tb_update_count = 0; vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; - vdso_data->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC; - vdso_data->tb_to_xs = tb_to_xs; - - write_sequnlock_irqrestore(&xtime_lock, flags); /* Start the decrementer on CPUs that have manual control * such as BookE @@ -1202,39 +1105,6 @@ void to_tm(int tim, struct rtc_time * tm) GregorianDay(tm); } -/* Auxiliary function to compute scaling factors */ -/* Actually the choice of a timebase running at 1/4 the of the bus - * frequency giving resolution of a few tens of nanoseconds is quite nice. - * It makes this computation very precise (27-28 bits typically) which - * is optimistic considering the stability of most processor clock - * oscillators and the precision with which the timebase frequency - * is measured but does not harm. - */ -unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) -{ - unsigned mlt=0, tmp, err; - /* No concern for performance, it's done once: use a stupid - * but safe and compact method to find the multiplier. - */ - - for (tmp = 1U<<31; tmp != 0; tmp >>= 1) { - if (mulhwu(inscale, mlt|tmp) < outscale) - mlt |= tmp; - } - - /* We might still be off by 1 for the best approximation. - * A side effect of this is that if outscale is too large - * the returned value will be zero. - * Many corner cases have been checked and seem to work, - * some might have been forgotten in the test however. - */ - - err = inscale * (mlt+1); - if (err <= inscale/2) - mlt++; - return mlt; -} - /* * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit * result. diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c index b5c753db125e..80234e5921f5 100644 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -216,9 +216,6 @@ static int lite5200_pm_enter(suspend_state_t state) lite5200_restore_regs(); - /* restart jiffies */ - wakeup_decrementer(); - iounmap(mbar); return 0; } diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c index 76722532bd95..568cef636275 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c @@ -171,9 +171,6 @@ int mpc52xx_pm_enter(suspend_state_t state) /* restore SRAM */ memcpy(sram, saved_sram, sram_size); - /* restart jiffies */ - wakeup_decrementer(); - /* reenable interrupts in PIC */ out_be32(&intr->main_mask, intr_main_mask); diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 1e9eba175ff0..415ca6d6b273 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -310,8 +310,12 @@ static int pmu_set_cpu_speed(int low_speed) /* Restore low level PMU operations */ pmu_unlock(); - /* Restore decrementer */ - wakeup_decrementer(); + /* + * Restore decrementer; we'll take a decrementer interrupt + * as soon as interrupts are re-enabled and the generic + * clockevents code will reprogram it with the right value. + */ + set_dec(1); /* Restore interrupts */ mpic_cpu_set_priority(pic_prio); -- cgit v1.2.3 From 8fe93f8d850a24581e9d47df5814b257fe451052 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 7 Jul 2010 12:31:01 +0000 Subject: powerpc/pseries: Migration code reorganization / hibernation prep Partition hibernation will use some of the same code as is currently used for Live Partition Migration. This function further abstracts this code such that code outside of rtas.c can utilize it. It also changes the error field in the suspend me data structure to be an atomic type, since it is set and checked on different cpus without any barriers or locking. Signed-off-by: Brian King Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/hvcall.h | 1 + arch/powerpc/include/asm/rtas.h | 10 ++++ arch/powerpc/kernel/rtas.c | 105 +++++++++++++++++++++++++------------- 3 files changed, 81 insertions(+), 35 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 5119b7db3142..de03ca58db5d 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -74,6 +74,7 @@ #define H_NOT_ENOUGH_RESOURCES -44 #define H_R_STATE -45 #define H_RESCINDEND -46 +#define H_MULTI_THREADS_ACTIVE -9005 /* Long Busy is a condition that can be returned by the firmware diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 20de73c36682..8941c54b30ea 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -63,6 +63,14 @@ struct rtas_t { struct device_node *dev; /* virtual address pointer */ }; +struct rtas_suspend_me_data { + atomic_t working; /* number of cpus accessing this struct */ + atomic_t done; + int token; /* ibm,suspend-me */ + atomic_t error; + struct completion *complete; /* wait on this until working == 0 */ +}; + /* RTAS event classes */ #define RTAS_INTERNAL_ERROR 0x80000000 /* set bit 0 */ #define RTAS_EPOW_WARNING 0x40000000 /* set bit 1 */ @@ -174,6 +182,8 @@ extern int rtas_set_indicator(int indicator, int index, int new_value); extern int rtas_set_indicator_fast(int indicator, int index, int new_value); extern void rtas_progress(char *s, unsigned short hex); extern void rtas_initialize(void); +extern int rtas_suspend_cpu(struct rtas_suspend_me_data *data); +extern int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data); struct rtc_time; extern unsigned long rtas_get_boot_time(void); diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 0e1ec6f746f6..41cfde0ca11b 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -47,14 +47,6 @@ struct rtas_t rtas = { }; EXPORT_SYMBOL(rtas); -struct rtas_suspend_me_data { - atomic_t working; /* number of cpus accessing this struct */ - atomic_t done; - int token; /* ibm,suspend-me */ - int error; - struct completion *complete; /* wait on this until working == 0 */ -}; - DEFINE_SPINLOCK(rtas_data_buf_lock); EXPORT_SYMBOL(rtas_data_buf_lock); @@ -714,14 +706,53 @@ void rtas_os_term(char *str) static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; #ifdef CONFIG_PPC_PSERIES -static void rtas_percpu_suspend_me(void *info) +static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_when_done) +{ + u16 slb_size = mmu_slb_size; + int rc = H_MULTI_THREADS_ACTIVE; + int cpu; + + slb_set_size(SLB_MIN_SIZE); + printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n", smp_processor_id()); + + while (rc == H_MULTI_THREADS_ACTIVE && !atomic_read(&data->done) && + !atomic_read(&data->error)) + rc = rtas_call(data->token, 0, 1, NULL); + + if (rc || atomic_read(&data->error)) { + printk(KERN_DEBUG "ibm,suspend-me returned %d\n", rc); + slb_set_size(slb_size); + } + + if (atomic_read(&data->error)) + rc = atomic_read(&data->error); + + atomic_set(&data->error, rc); + + if (wake_when_done) { + atomic_set(&data->done, 1); + + for_each_online_cpu(cpu) + plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu)); + } + + if (atomic_dec_return(&data->working) == 0) + complete(data->complete); + + return rc; +} + +int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data) +{ + atomic_inc(&data->working); + return __rtas_suspend_last_cpu(data, 0); +} + +static int __rtas_suspend_cpu(struct rtas_suspend_me_data *data, int wake_when_done) { long rc = H_SUCCESS; unsigned long msr_save; - u16 slb_size = mmu_slb_size; int cpu; - struct rtas_suspend_me_data *data = - (struct rtas_suspend_me_data *)info; atomic_inc(&data->working); @@ -729,7 +760,7 @@ static void rtas_percpu_suspend_me(void *info) msr_save = mfmsr(); mtmsr(msr_save & ~(MSR_EE)); - while (rc == H_SUCCESS && !atomic_read(&data->done)) + while (rc == H_SUCCESS && !atomic_read(&data->done) && !atomic_read(&data->error)) rc = plpar_hcall_norets(H_JOIN); mtmsr(msr_save); @@ -741,33 +772,37 @@ static void rtas_percpu_suspend_me(void *info) /* All other cpus are in H_JOIN, this cpu does * the suspend. */ - slb_set_size(SLB_MIN_SIZE); - printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n", - smp_processor_id()); - data->error = rtas_call(data->token, 0, 1, NULL); - - if (data->error) { - printk(KERN_DEBUG "ibm,suspend-me returned %d\n", - data->error); - slb_set_size(slb_size); - } + return __rtas_suspend_last_cpu(data, wake_when_done); } else { printk(KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n", smp_processor_id(), rc); - data->error = rc; + atomic_set(&data->error, rc); } - atomic_set(&data->done, 1); + if (wake_when_done) { + atomic_set(&data->done, 1); - /* This cpu did the suspend or got an error; in either case, - * we need to prod all other other cpus out of join state. - * Extra prods are harmless. - */ - for_each_online_cpu(cpu) - plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu)); + /* This cpu did the suspend or got an error; in either case, + * we need to prod all other other cpus out of join state. + * Extra prods are harmless. + */ + for_each_online_cpu(cpu) + plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu)); + } out: if (atomic_dec_return(&data->working) == 0) complete(data->complete); + return rc; +} + +int rtas_suspend_cpu(struct rtas_suspend_me_data *data) +{ + return __rtas_suspend_cpu(data, 0); +} + +static void rtas_percpu_suspend_me(void *info) +{ + __rtas_suspend_cpu((struct rtas_suspend_me_data *)info, 1); } static int rtas_ibm_suspend_me(struct rtas_args *args) @@ -802,22 +837,22 @@ static int rtas_ibm_suspend_me(struct rtas_args *args) atomic_set(&data.working, 0); atomic_set(&data.done, 0); + atomic_set(&data.error, 0); data.token = rtas_token("ibm,suspend-me"); - data.error = 0; data.complete = &done; /* Call function on all CPUs. One of us will make the * rtas call */ if (on_each_cpu(rtas_percpu_suspend_me, &data, 0)) - data.error = -EINVAL; + atomic_set(&data.error, -EINVAL); wait_for_completion(&done); - if (data.error != 0) + if (atomic_read(&data.error) != 0) printk(KERN_ERR "Error doing global join\n"); - return data.error; + return atomic_read(&data.error); } #else /* CONFIG_PPC_PSERIES */ static int rtas_ibm_suspend_me(struct rtas_args *args) -- cgit v1.2.3 From 32d8ad4e621d6620e925cf540ef1d35aa6fa5a7b Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 7 Jul 2010 12:31:02 +0000 Subject: powerpc/pseries: Partition hibernation support Enables support for HMC initiated partition hibernation. This is a firmware assisted hibernation, since the firmware handles writing the memory out to disk, along with other partition information, so we just mimic suspend to ram. Signed-off-by: Brian King Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/machdep.h | 1 + arch/powerpc/platforms/pseries/Makefile | 4 + arch/powerpc/platforms/pseries/hotplug-cpu.c | 3 + arch/powerpc/platforms/pseries/suspend.c | 214 +++++++++++++++++++++++++++ 5 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/pseries/suspend.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 89bc2e895390..25b28fdc6767 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -219,7 +219,7 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - PPC_85xx || PPC_86xx + PPC_85xx || PPC_86xx || PPC_PSERIES config PPC_DCR_NATIVE bool diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 7716e68f7b18..2bad6e5855ad 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -266,6 +266,7 @@ struct machdep_calls { void (*suspend_disable_irqs)(void); void (*suspend_enable_irqs)(void); #endif + int (*suspend_disable_cpu)(void); #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE ssize_t (*cpu_probe)(const char *, size_t); diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 3dbef309bc8d..046ace9c4381 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -26,3 +26,7 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_DTL) += dtl.o + +ifeq ($(CONFIG_PPC_PSERIES),y) +obj-$(CONFIG_SUSPEND) += suspend.o +endif diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 8f85f399ab9f..bbe507635364 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -116,6 +116,9 @@ static void pseries_mach_cpu_die(void) if (get_preferred_offline_state(cpu) == CPU_STATE_INACTIVE) { set_cpu_current_state(cpu, CPU_STATE_INACTIVE); + if (ppc_md.suspend_disable_cpu) + ppc_md.suspend_disable_cpu(); + cede_latency_hint = 2; get_lppaca()->idle = 1; diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c new file mode 100644 index 000000000000..ed72098bb4e3 --- /dev/null +++ b/arch/powerpc/platforms/pseries/suspend.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2010 Brian King IBM Corporation + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +static u64 stream_id; +static struct sys_device suspend_sysdev; +static DECLARE_COMPLETION(suspend_work); +static struct rtas_suspend_me_data suspend_data; +static atomic_t suspending; + +/** + * pseries_suspend_begin - First phase of hibernation + * + * Check to ensure we are in a valid state to hibernate + * + * Return value: + * 0 on success / other on failure + **/ +static int pseries_suspend_begin(suspend_state_t state) +{ + long vasi_state, rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + /* Make sure the state is valid */ + rc = plpar_hcall(H_VASI_STATE, retbuf, stream_id); + + vasi_state = retbuf[0]; + + if (rc) { + pr_err("pseries_suspend_begin: vasi_state returned %ld\n",rc); + return rc; + } else if (vasi_state == H_VASI_ENABLED) { + return -EAGAIN; + } else if (vasi_state != H_VASI_SUSPENDING) { + pr_err("pseries_suspend_begin: vasi_state returned state %ld\n", + vasi_state); + return -EIO; + } + + return 0; +} + +/** + * pseries_suspend_cpu - Suspend a single CPU + * + * Makes the H_JOIN call to suspend the CPU + * + **/ +static int pseries_suspend_cpu(void) +{ + if (atomic_read(&suspending)) + return rtas_suspend_cpu(&suspend_data); + return 0; +} + +/** + * pseries_suspend_enter - Final phase of hibernation + * + * Return value: + * 0 on success / other on failure + **/ +static int pseries_suspend_enter(suspend_state_t state) +{ + int rc = rtas_suspend_last_cpu(&suspend_data); + + atomic_set(&suspending, 0); + atomic_set(&suspend_data.done, 1); + return rc; +} + +/** + * pseries_prepare_late - Prepare to suspend all other CPUs + * + * Return value: + * 0 on success / other on failure + **/ +static int pseries_prepare_late(void) +{ + atomic_set(&suspending, 1); + atomic_set(&suspend_data.working, 0); + atomic_set(&suspend_data.done, 0); + atomic_set(&suspend_data.error, 0); + suspend_data.complete = &suspend_work; + INIT_COMPLETION(suspend_work); + return 0; +} + +/** + * store_hibernate - Initiate partition hibernation + * @classdev: sysdev class struct + * @attr: class device attribute struct + * @buf: buffer + * @count: buffer size + * + * Write the stream ID received from the HMC to this file + * to trigger hibernating the partition + * + * Return value: + * number of bytes printed to buffer / other on failure + **/ +static ssize_t store_hibernate(struct sysdev_class *classdev, + struct sysdev_class_attribute *attr, + const char *buf, size_t count) +{ + int rc; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + stream_id = simple_strtoul(buf, NULL, 16); + + do { + rc = pseries_suspend_begin(PM_SUSPEND_MEM); + if (rc == -EAGAIN) + ssleep(1); + } while (rc == -EAGAIN); + + if (!rc) + rc = pm_suspend(PM_SUSPEND_MEM); + + stream_id = 0; + + if (!rc) + rc = count; + return rc; +} + +static SYSDEV_CLASS_ATTR(hibernate, S_IWUSR, NULL, store_hibernate); + +static struct sysdev_class suspend_sysdev_class = { + .name = "power", +}; + +static struct platform_suspend_ops pseries_suspend_ops = { + .valid = suspend_valid_only_mem, + .begin = pseries_suspend_begin, + .prepare_late = pseries_prepare_late, + .enter = pseries_suspend_enter, +}; + +/** + * pseries_suspend_sysfs_register - Register with sysfs + * + * Return value: + * 0 on success / other on failure + **/ +static int pseries_suspend_sysfs_register(struct sys_device *sysdev) +{ + int rc; + + if ((rc = sysdev_class_register(&suspend_sysdev_class))) + return rc; + + sysdev->id = 0; + sysdev->cls = &suspend_sysdev_class; + + if ((rc = sysdev_class_create_file(&suspend_sysdev_class, &attr_hibernate))) + goto class_unregister; + + return 0; + +class_unregister: + sysdev_class_unregister(&suspend_sysdev_class); + return rc; +} + +/** + * pseries_suspend_init - initcall for pSeries suspend + * + * Return value: + * 0 on success / other on failure + **/ +static int __init pseries_suspend_init(void) +{ + int rc; + + if (!machine_is(pseries) || !firmware_has_feature(FW_FEATURE_LPAR)) + return 0; + + suspend_data.token = rtas_token("ibm,suspend-me"); + if (suspend_data.token == RTAS_UNKNOWN_SERVICE) + return 0; + + if ((rc = pseries_suspend_sysfs_register(&suspend_sysdev))) + return rc; + + ppc_md.suspend_disable_cpu = pseries_suspend_cpu; + suspend_set_ops(&pseries_suspend_ops); + return 0; +} + +__initcall(pseries_suspend_init); -- cgit v1.2.3 From 6901c6cca1271d1724fc15e9937e0820e2d2fbd5 Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Sat, 3 Jul 2010 06:03:48 +0000 Subject: powerpc/pseries/eeh: Use for_each_pci_dev() Use for_each_pci_dev() to simplify the code. Signed-off-by: Kulikov Vasiliy Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/eeh_cache.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index 30b987b73c20..8ed0d2d0e1b5 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -288,8 +288,7 @@ void __init pci_addr_cache_build(void) spin_lock_init(&pci_io_addr_cache_root.piar_lock); - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - + for_each_pci_dev(dev) { pci_addr_cache_insert_device(dev); dn = pci_device_to_OF_node(dev); -- cgit v1.2.3 From d10ac3734d07bee675384d22d06883b3c57b1524 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Wed, 30 Jun 2010 10:23:31 +0000 Subject: powerpc/fsl-booke: Fix comments in mmu code that mention BATS There are no BATS on BookE - we have the TLBCAM instead. Also correct the page size information to included extended sizes. We don't actually allow a 4G page size to be used, so comment on that as well. Signed-off-by: Becky Bruce Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/fsl_booke_mmu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index cdc7526e9c93..4b66a1ece6d8 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -104,9 +104,10 @@ unsigned long p_mapped_by_tlbcam(phys_addr_t pa) } /* - * Set up one of the I/D BAT (block address translation) register pairs. - * The parameters are not checked; in particular size must be a power - * of 4 between 4k and 256M. + * Set up a variable-size TLB entry (tlbcam). The parameters are not checked; + * in particular size must be a power of 4 between 4k and 256M (or 1G, for cpus + * that support extended page sizes). Note that while some cpus support a + * page size of 4G, we don't allow its use here. */ static void settlbcam(int index, unsigned long virt, phys_addr_t phys, unsigned long size, unsigned long flags, unsigned int pid) -- cgit v1.2.3 From 66953ebef60ffe94650a735b445f1495d989c523 Mon Sep 17 00:00:00 2001 From: Matthew McClintock Date: Tue, 29 Jun 2010 09:42:26 +0000 Subject: powerpc/mpic: Add ability to reset a core via MPIC We need the ability to reset cores for use with kexec/kdump for SMP systems. Calling this function with the specific core you want to reset will cause the CPU to spin in reset. Signed-off-by: Matthew McClintock Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 18 ++++++++++++++++++ arch/powerpc/sysdev/mpic.h | 1 + 2 files changed, 19 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 20b73c025a45..7c1342618a30 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1636,6 +1636,24 @@ void __devinit smp_mpic_setup_cpu(int cpu) { mpic_setup_this_cpu(); } + +void mpic_reset_core(int cpu) +{ + struct mpic *mpic = mpic_primary; + u32 pir; + int cpuid = get_hard_smp_processor_id(cpu); + + /* Set target bit for core reset */ + pir = mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); + pir |= (1 << cpuid); + mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir); + mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); + + /* Restore target bit after reset complete */ + pir &= ~(1 << cpuid); + mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir); + mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); +} #endif /* CONFIG_SMP */ #ifdef CONFIG_PM diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h index eff433c322a0..e4a6df77b8d7 100644 --- a/arch/powerpc/sysdev/mpic.h +++ b/arch/powerpc/sysdev/mpic.h @@ -37,5 +37,6 @@ static inline int mpic_pasemi_msi_init(struct mpic *mpic) extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); extern void mpic_set_vector(unsigned int virq, unsigned int vector); extern int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask); +extern void mpic_reset_core(int cpu); #endif /* _POWERPC_SYSDEV_MPIC_H */ -- cgit v1.2.3 From 51c7fdba40e741dfe18455b5e4240b70c422bf2e Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Wed, 16 Jun 2010 04:34:44 +0000 Subject: powerpc/iseries: Fix constant warning Fix smatch warning: constant 0x8000000000000000 is so big it is unsigned long Signed-off-by: Denis Kirjanov Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/abs_addr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/abs_addr.h b/arch/powerpc/include/asm/abs_addr.h index 98324c5a8286..c3bffc3fa1de 100644 --- a/arch/powerpc/include/asm/abs_addr.h +++ b/arch/powerpc/include/asm/abs_addr.h @@ -69,7 +69,7 @@ static inline unsigned long phys_to_abs(unsigned long pa) * Legacy iSeries Hypervisor calls */ #define iseries_hv_addr(virtaddr) \ - (0x8000000000000000 | virt_to_abs(virtaddr)) + (0x8000000000000000UL | virt_to_abs(virtaddr)) #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_ABS_ADDR_H */ -- cgit v1.2.3 From ae01f84b93b274e2f215bdf6d0b46435679b5f9a Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 31 May 2010 18:45:11 +0000 Subject: powerpc: Optimise per cpu accesses on 64bit Now we dynamically allocate the paca array, it takes an extra load whenever we want to access another cpu's paca. One place we do that a lot is per cpu variables. A simple example: DEFINE_PER_CPU(unsigned long, vara); unsigned long test4(int cpu) { return per_cpu(vara, cpu); } This takes 4 loads, 5 if you include the actual load of the per cpu variable: ld r11,-32760(r30) # load address of paca pointer ld r9,-32768(r30) # load link address of percpu variable sldi r3,r29,9 # get offset into paca (each entry is 512 bytes) ld r0,0(r11) # load paca pointer add r3,r0,r3 # paca + offset ld r11,64(r3) # load paca[cpu].data_offset ldx r3,r9,r11 # load per cpu variable If we remove the ppc64 specific per_cpu_offset(), we get the generic one which indexes into a statically allocated array. This removes one load and one add: ld r11,-32760(r30) # load address of __per_cpu_offset ld r9,-32768(r30) # load link address of percpu variable sldi r3,r29,3 # get offset into __per_cpu_offset (each entry 8 bytes) ldx r11,r11,r3 # load __per_cpu_offset[cpu] ldx r3,r9,r11 # load per cpu variable Having all the offsets in one array also helps when iterating over a per cpu variable across a number of cpus, such as in the scheduler. Before we would need to load one paca cacheline when calculating each per cpu offset. Now we have 16 (128 / sizeof(long)) per cpu offsets in each cacheline. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/percpu.h | 3 --- arch/powerpc/kernel/asm-offsets.c | 1 - arch/powerpc/kernel/setup_64.c | 9 +++++++-- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/percpu.h b/arch/powerpc/include/asm/percpu.h index f879252b7ea6..2cedefddba37 100644 --- a/arch/powerpc/include/asm/percpu.h +++ b/arch/powerpc/include/asm/percpu.h @@ -1,7 +1,6 @@ #ifndef _ASM_POWERPC_PERCPU_H_ #define _ASM_POWERPC_PERCPU_H_ #ifdef __powerpc64__ -#include /* * Same as asm-generic/percpu.h, except that we store the per cpu offset @@ -12,9 +11,7 @@ #include -#define __per_cpu_offset(cpu) (paca[cpu].data_offset) #define __my_cpu_offset local_paca->data_offset -#define per_cpu_offset(x) (__per_cpu_offset(x)) #endif /* CONFIG_SMP */ #endif /* __powerpc64__ */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index acbbac6aaa22..1c0607ddccc0 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -194,7 +194,6 @@ int main(void) DEFINE(PACA_STARTSPURR, offsetof(struct paca_struct, startspurr)); DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time)); DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); - DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset)); DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); #ifdef CONFIG_KVM_BOOK3S_64_HANDLER DEFINE(PACA_KVM_SVCPU, offsetof(struct paca_struct, shadow_vcpu)); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 643dcac40fcb..c352f322dbdd 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -600,6 +600,9 @@ static int pcpu_cpu_distance(unsigned int from, unsigned int to) return REMOTE_DISTANCE; } +unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; +EXPORT_SYMBOL(__per_cpu_offset); + void __init setup_per_cpu_areas(void) { const size_t dyn_size = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE; @@ -624,8 +627,10 @@ void __init setup_per_cpu_areas(void) panic("cannot initialize percpu area (err=%d)", rc); delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; - for_each_possible_cpu(cpu) - paca[cpu].data_offset = delta + pcpu_unit_offsets[cpu]; + for_each_possible_cpu(cpu) { + __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu]; + paca[cpu].data_offset = __per_cpu_offset[cpu]; + } } #endif -- cgit v1.2.3 From b08e281b5ae681abcbc1815c13d4a3eb3df4ff1b Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 26 May 2010 21:40:39 +0000 Subject: powerpc/pseries: Rename RAS_VECTOR_OFFSET to RTAS_VECTOR_EXTERNAL_INTERRUPT and move to rtas.h The RAS code has a #define, RAS_VECTOR_OFFSET, that's used in the check-exception RTAS call for the vector offset of the exception. We'll be using this same vector offset for the upcoming IO Event interrupts code (0x500) so let's move it to include/asm/rtas.h and call it RTAS_VECTOR_EXTERNAL_INTERRUPT. Signed-off-by: Mark Nelson Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/rtas.h | 3 +++ arch/powerpc/platforms/pseries/ras.c | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 8941c54b30ea..3d35f8ae377e 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -145,6 +145,9 @@ struct rtas_suspend_me_data { #define RTAS_TYPE_PMGM_CONFIG_CHANGE 0x70 #define RTAS_TYPE_PMGM_SERVICE_PROC 0x71 +/* RTAS check-exception vector offset */ +#define RTAS_VECTOR_EXTERNAL_INTERRUPT 0x500 + struct rtas_error_log { unsigned long version:8; /* Architectural version */ unsigned long severity:3; /* Severity level of error */ diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 41a3e9a039ed..a4fc6da87c2e 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -61,7 +61,6 @@ static int ras_check_exception_token; #define EPOW_SENSOR_TOKEN 9 #define EPOW_SENSOR_INDEX 0 -#define RAS_VECTOR_OFFSET 0x500 static irqreturn_t ras_epow_interrupt(int irq, void *dev_id); static irqreturn_t ras_error_interrupt(int irq, void *dev_id); @@ -121,7 +120,7 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id) spin_lock(&ras_log_buf_lock); status = rtas_call(ras_check_exception_token, 6, 1, NULL, - RAS_VECTOR_OFFSET, + RTAS_VECTOR_EXTERNAL_INTERRUPT, irq_map[irq].hwirq, RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, critical, __pa(&ras_log_buf), @@ -156,7 +155,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id) spin_lock(&ras_log_buf_lock); status = rtas_call(ras_check_exception_token, 6, 1, NULL, - RAS_VECTOR_OFFSET, + RTAS_VECTOR_EXTERNAL_INTERRUPT, irq_map[irq].hwirq, RTAS_INTERNAL_ERROR, 1 /*Time Critical */, __pa(&ras_log_buf), -- cgit v1.2.3 From 68581e9350506dcf0160c3a29dcd21e5a848cda7 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 26 May 2010 20:56:04 +0000 Subject: powerpc/pseries: Add WARN_ON() to request_event_sources_irqs() on irq allocation/request failure At the moment if request_event_sources_irqs() can't allocate or request the interrupt, it just does a KERN_ERR printk. This may be fine for the existing RAS code where if we miss an EPOW event it just means that the event won't be logged and if we miss one of the RAS errors then we could miss an event that we perhaps should take action on. But, for the upcoming IO events code that will use event-sources if we can't allocate or request the interrupt it means we'd potentially miss an interrupt from the device. So, let's add a WARN_ON() in this error case so that we're a bit more vocal when something's amiss. While we're at it, also use pr_err() to neaten the code up a bit. Signed-off-by: Mark Nelson Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/event_sources.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/event_sources.c b/arch/powerpc/platforms/pseries/event_sources.c index e889c9d9586a..2605c310166a 100644 --- a/arch/powerpc/platforms/pseries/event_sources.c +++ b/arch/powerpc/platforms/pseries/event_sources.c @@ -41,9 +41,12 @@ void request_event_sources_irqs(struct device_node *np, if (count > 15) break; virqs[count] = irq_create_mapping(NULL, *(opicprop++)); - if (virqs[count] == NO_IRQ) - printk(KERN_ERR "Unable to allocate interrupt " - "number for %s\n", np->full_name); + if (virqs[count] == NO_IRQ) { + pr_err("event-sources: Unable to allocate " + "interrupt number for %s\n", + np->full_name); + WARN_ON(1); + } else count++; @@ -59,9 +62,12 @@ void request_event_sources_irqs(struct device_node *np, virqs[count] = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size); - if (virqs[count] == NO_IRQ) - printk(KERN_ERR "Unable to allocate interrupt " - "number for %s\n", np->full_name); + if (virqs[count] == NO_IRQ) { + pr_err("event-sources: Unable to allocate " + "interrupt number for %s\n", + np->full_name); + WARN_ON(1); + } else count++; } @@ -70,8 +76,9 @@ void request_event_sources_irqs(struct device_node *np, /* Now request them */ for (i = 0; i < count; i++) { if (request_irq(virqs[i], handler, 0, name, NULL)) { - printk(KERN_ERR "Unable to request interrupt %d for " - "%s\n", virqs[i], np->full_name); + pr_err("event-sources: Unable to request interrupt " + "%d for %s\n", virqs[i], np->full_name); + WARN_ON(1); return; } } -- cgit v1.2.3 From 540c6c392f01887dcc96bef0a41e63e6c1334f01 Mon Sep 17 00:00:00 2001 From: Martyn Welch Date: Mon, 24 May 2010 22:09:16 +0000 Subject: powerpc: Add i8042 keyboard and mouse irq parsing Currently the irqs for the i8042, which historically provides keyboard and mouse (aux) support, is hardwired in the driver rather than parsing the dts. This patch modifies the powerpc legacy IO code to attempt to parse the device tree for this information, failing back to the hardcoded values if it fails. Signed-off-by: Martyn Welch Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/setup-common.c | 13 +++++++++++++ drivers/input/serio/i8042-io.h | 5 +++++ 2 files changed, 18 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 5e4d852f640c..8b6ada66060b 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -94,6 +94,10 @@ struct screen_info screen_info = { .orig_video_points = 16 }; +/* Variables required to store legacy IO irq routing */ +int of_i8042_kbd_irq; +int of_i8042_aux_irq; + #ifdef __DO_IRQ_CANON /* XXX should go elsewhere eventually */ int ppc_do_canonicalize_irqs; @@ -575,6 +579,15 @@ int check_legacy_ioport(unsigned long base_port) np = of_find_compatible_node(NULL, NULL, "pnpPNP,f03"); if (np) { parent = of_get_parent(np); + + of_i8042_kbd_irq = irq_of_parse_and_map(parent, 0); + if (!of_i8042_kbd_irq) + of_i8042_kbd_irq = 1; + + of_i8042_aux_irq = irq_of_parse_and_map(parent, 1); + if (!of_i8042_aux_irq) + of_i8042_aux_irq = 12; + of_node_put(np); np = parent; break; diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index 847f4aad7ed5..5d48bb66aa73 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -27,6 +27,11 @@ #include #elif defined(CONFIG_SH_CAYMAN) #include +#elif defined(CONFIG_PPC) +extern int of_i8042_kbd_irq; +extern int of_i8042_aux_irq; +# define I8042_KBD_IRQ of_i8042_kbd_irq +# define I8042_AUX_IRQ of_i8042_aux_irq #else # define I8042_KBD_IRQ 1 # define I8042_AUX_IRQ 12 -- cgit v1.2.3 From a591f6b56d6fbd7d1951e352fe5b0acf6b91e497 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 18 May 2010 07:56:03 +0000 Subject: powerpc: Remove all rcu head initializations Remove all rcu head inits. We don't care about the RCU head state before passing it to call_rcu() anyway. Only leave the "on_stack" variants so debugobjects can keep track of objects on stack. Signed-off-by: Mathieu Desnoyers Signed-off-by: Paul E. McKenney Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/pgtable.c | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index ebc2f38eb381..2c7e801ab20b 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -92,7 +92,6 @@ static void pte_free_rcu_callback(struct rcu_head *head) static void pte_free_submit(struct pte_freelist_batch *batch) { - INIT_RCU_HEAD(&batch->rcu); call_rcu(&batch->rcu, pte_free_rcu_callback); } -- cgit v1.2.3 From 41eab6f88f24124df89e38067b3766b7bef06ddb Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 16 May 2010 20:22:31 +0000 Subject: powerpc/numa: Use form 1 affinity to setup node distance Form 1 affinity allows multiple entries in ibm,associativity-reference-points which represent affinity domains in decreasing order of importance. The Linux concept of a node is always the first entry, but using the other values as an input to node_distance() allows the memory allocator to make better decisions on which node to go first when local memory has been exhausted. We keep things simple and create an array indexed by NUMA node, capped at 4 entries. Each time we lookup an associativity property we initialise the array which is overkill, but since we should only hit this path during boot it didn't seem worth adding a per node valid bit. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/topology.h | 3 + arch/powerpc/mm/numa.c | 122 ++++++++++++++++++++++++++---------- 2 files changed, 92 insertions(+), 33 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 32adf7280720..3033c1b30745 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -87,6 +87,9 @@ static inline int pcibus_to_node(struct pci_bus *bus) .balance_interval = 1, \ } +extern int __node_distance(int, int); +#define node_distance(a, b) __node_distance(a, b) + extern void __init dump_numa_cpu_topology(void); extern int sysfs_add_device_to_node(struct sys_device *dev, int nid); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 80d110635d24..f78f19e0a2a4 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -42,6 +42,12 @@ EXPORT_SYMBOL(node_data); static int min_common_depth; static int n_mem_addr_cells, n_mem_size_cells; +static int form1_affinity; + +#define MAX_DISTANCE_REF_POINTS 4 +static int distance_ref_points_depth; +static const unsigned int *distance_ref_points; +static int distance_lookup_table[MAX_NUMNODES][MAX_DISTANCE_REF_POINTS]; /* * Allocate node_to_cpumask_map based on number of available nodes @@ -204,6 +210,39 @@ static const u32 *of_get_usable_memory(struct device_node *memory) return prop; } +int __node_distance(int a, int b) +{ + int i; + int distance = LOCAL_DISTANCE; + + if (!form1_affinity) + return distance; + + for (i = 0; i < distance_ref_points_depth; i++) { + if (distance_lookup_table[a][i] == distance_lookup_table[b][i]) + break; + + /* Double the distance for each NUMA level */ + distance *= 2; + } + + return distance; +} + +static void initialize_distance_lookup_table(int nid, + const unsigned int *associativity) +{ + int i; + + if (!form1_affinity) + return; + + for (i = 0; i < distance_ref_points_depth; i++) { + distance_lookup_table[nid][i] = + associativity[distance_ref_points[i]]; + } +} + /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa * info is found. */ @@ -225,6 +264,10 @@ static int of_node_to_nid_single(struct device_node *device) /* POWER4 LPAR uses 0xffff as invalid node */ if (nid == 0xffff || nid >= MAX_NUMNODES) nid = -1; + + if (nid > 0 && tmp[0] >= distance_ref_points_depth) + initialize_distance_lookup_table(nid, tmp); + out: return nid; } @@ -251,26 +294,10 @@ int of_node_to_nid(struct device_node *device) } EXPORT_SYMBOL_GPL(of_node_to_nid); -/* - * In theory, the "ibm,associativity" property may contain multiple - * associativity lists because a resource may be multiply connected - * into the machine. This resource then has different associativity - * characteristics relative to its multiple connections. We ignore - * this for now. We also assume that all cpu and memory sets have - * their distances represented at a common level. This won't be - * true for hierarchical NUMA. - * - * In any case the ibm,associativity-reference-points should give - * the correct depth for a normal NUMA system. - * - * - Dave Hansen - */ static int __init find_min_common_depth(void) { - int depth, index; - const unsigned int *ref_points; + int depth; struct device_node *rtas_root; - unsigned int len; struct device_node *chosen; const char *vec5; @@ -280,18 +307,28 @@ static int __init find_min_common_depth(void) return -1; /* - * this property is 2 32-bit integers, each representing a level of - * depth in the associativity nodes. The first is for an SMP - * configuration (should be all 0's) and the second is for a normal - * NUMA configuration. + * This property is a set of 32-bit integers, each representing + * an index into the ibm,associativity nodes. + * + * With form 0 affinity the first integer is for an SMP configuration + * (should be all 0's) and the second is for a normal NUMA + * configuration. We have only one level of NUMA. + * + * With form 1 affinity the first integer is the most significant + * NUMA boundary and the following are progressively less significant + * boundaries. There can be more than one level of NUMA. */ - index = 1; - ref_points = of_get_property(rtas_root, - "ibm,associativity-reference-points", &len); + distance_ref_points = of_get_property(rtas_root, + "ibm,associativity-reference-points", + &distance_ref_points_depth); + + if (!distance_ref_points) { + dbg("NUMA: ibm,associativity-reference-points not found.\n"); + goto err; + } + + distance_ref_points_depth /= sizeof(int); - /* - * For form 1 affinity information we want the first field - */ #define VEC5_AFFINITY_BYTE 5 #define VEC5_AFFINITY 0x80 chosen = of_find_node_by_path("/chosen"); @@ -299,19 +336,38 @@ static int __init find_min_common_depth(void) vec5 = of_get_property(chosen, "ibm,architecture-vec-5", NULL); if (vec5 && (vec5[VEC5_AFFINITY_BYTE] & VEC5_AFFINITY)) { dbg("Using form 1 affinity\n"); - index = 0; + form1_affinity = 1; } } - if ((len >= 2 * sizeof(unsigned int)) && ref_points) { - depth = ref_points[index]; + if (form1_affinity) { + depth = distance_ref_points[0]; } else { - dbg("NUMA: ibm,associativity-reference-points not found.\n"); - depth = -1; + if (distance_ref_points_depth < 2) { + printk(KERN_WARNING "NUMA: " + "short ibm,associativity-reference-points\n"); + goto err; + } + + depth = distance_ref_points[1]; } - of_node_put(rtas_root); + /* + * Warn and cap if the hardware supports more than + * MAX_DISTANCE_REF_POINTS domains. + */ + if (distance_ref_points_depth > MAX_DISTANCE_REF_POINTS) { + printk(KERN_WARNING "NUMA: distance array capped at " + "%d entries\n", MAX_DISTANCE_REF_POINTS); + distance_ref_points_depth = MAX_DISTANCE_REF_POINTS; + } + + of_node_put(rtas_root); return depth; + +err: + of_node_put(rtas_root); + return -1; } static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) -- cgit v1.2.3 From 307a54cc80ddc7e5d87c4862dd12f43a01355187 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 14 May 2010 09:31:26 +0000 Subject: powerpc/iseries: Use kstrdup Use kstrdup when the goal of an allocation is copy a string into the allocated region. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression from,to; expression flag,E1,E2; statement S; @@ - to = kmalloc(strlen(from) + 1,flag); + to = kstrdup(from, flag); ... when != \(from = E1 \| to = E1 \) if (to==NULL || ...) S ... when != \(from = E2 \| to = E2 \) - strcpy(to, from); // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/iseries/vio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index 00b6730bc48f..b6db7cef83b4 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c @@ -87,12 +87,11 @@ static struct device_node *new_node(const char *path, if (!np) return NULL; - np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL); + np->full_name = kstrdup(path, GFP_KERNEL); if (!np->full_name) { kfree(np); return NULL; } - strcpy(np->full_name, path); of_node_set_flag(np, OF_DYNAMIC); kref_init(&np->kref); np->parent = of_node_get(parent); -- cgit v1.2.3 From 74052173177b7f969d9cc0c8f136093e1d447a01 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 14 May 2010 09:30:13 +0000 Subject: powerpc/pseries: Use kstrdup Use kstrdup when the goal of an allocation is copy a string into the allocated region. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression from,to; expression flag,E1,E2; statement S; @@ - to = kmalloc(strlen(from) + 1,flag); + to = kstrdup(from, flag); ... when != \(from = E1 \| to = E1 \) if (to==NULL || ...) S ... when != \(from = E2 \| to = E2 \) - strcpy(to, from); // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/reconfig.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 1a58637bcea5..57ddbb43b33a 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -118,12 +118,10 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist if (!np) goto out_err; - np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL); + np->full_name = kstrdup(path, GFP_KERNEL); if (!np->full_name) goto out_err; - strcpy(np->full_name, path); - np->properties = proplist; of_node_set_flag(np, OF_DYNAMIC); kref_init(&np->kref); -- cgit v1.2.3 From cccd23428347251713b643d4bc5edb610308fd49 Mon Sep 17 00:00:00 2001 From: Christoph Egger Date: Thu, 10 Jun 2010 02:23:11 +0000 Subject: powerpc: Removing dead CONFIG_SMP_750 CONFIG_SMP_750 doesn't exist in Kconfig, therefore removing all references for it from the source code. Signed-off-by: Christoph Egger Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/tlb_hash32.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/mm/tlb_hash32.c b/arch/powerpc/mm/tlb_hash32.c index 8aaa8b7eb324..690566b66e8e 100644 --- a/arch/powerpc/mm/tlb_hash32.c +++ b/arch/powerpc/mm/tlb_hash32.c @@ -89,17 +89,6 @@ void tlb_flush(struct mmu_gather *tlb) * -- Cort */ -/* - * 750 SMP is a Bad Idea because the 750 doesn't broadcast all - * the cache operations on the bus. Hence we need to use an IPI - * to get the other CPU(s) to invalidate their TLBs. - */ -#ifdef CONFIG_SMP_750 -#define FINISH_FLUSH smp_send_tlb_invalidate(0) -#else -#define FINISH_FLUSH do { } while (0) -#endif - static void flush_range(struct mm_struct *mm, unsigned long start, unsigned long end) { @@ -138,7 +127,6 @@ static void flush_range(struct mm_struct *mm, unsigned long start, void flush_tlb_kernel_range(unsigned long start, unsigned long end) { flush_range(&init_mm, start, end); - FINISH_FLUSH; } EXPORT_SYMBOL(flush_tlb_kernel_range); @@ -162,7 +150,6 @@ void flush_tlb_mm(struct mm_struct *mm) */ for (mp = mm->mmap; mp != NULL; mp = mp->vm_next) flush_range(mp->vm_mm, mp->vm_start, mp->vm_end); - FINISH_FLUSH; } EXPORT_SYMBOL(flush_tlb_mm); @@ -179,7 +166,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr); if (!pmd_none(*pmd)) flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1); - FINISH_FLUSH; } EXPORT_SYMBOL(flush_tlb_page); @@ -192,6 +178,5 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { flush_range(vma->vm_mm, start, end); - FINISH_FLUSH; } EXPORT_SYMBOL(flush_tlb_range); -- cgit v1.2.3 From 0866eb99cc4d5951cb0ed6ddfa92d5a3d55216ae Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 9 Jul 2010 15:21:41 +1000 Subject: powerpc/book3e: mtmsr should not be mtmsrd on book3e 64-bit Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index d62fdf4e504b..d8be016d2ede 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -890,7 +890,7 @@ #ifndef __ASSEMBLY__ #define mfmsr() ({unsigned long rval; \ asm volatile("mfmsr %0" : "=r" (rval)); rval;}) -#ifdef CONFIG_PPC64 +#ifdef CONFIG_PPC_BOOK3S_64 #define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \ : : "r" (v) : "memory") #define mtmsrd(v) __mtmsrd((v), 0) -- cgit v1.2.3 From a2e198116f97bb1cd5b37ff33a8cfdfb4010cf5b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 9 Jul 2010 15:24:47 +1000 Subject: powerpc/book3e: Hack to get gdb moving along on Book3E 64-bit Our handling of debug interrupts on Book3E 64-bit is not quite the way it should be just yet. This is a workaround to let gdb work at least for now. We ensure that when context switching, we set the appropriate DBCR0 value for the new task. We also make sure that we turn off MSR[DE] within the kernel, and set it as part of the bits that get set when going back to userspace. In the long run, we will probably set the userspace DBCR0 on the exception exit code path and ensure we have some proper kernel value to set on the way into the kernel, a bit like ppc32 does, but that will take more work. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/reg_booke.h | 4 ++-- arch/powerpc/kernel/process.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 2360317179a9..66dc6f0d3ad8 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -29,8 +29,8 @@ #if defined(CONFIG_PPC_BOOK3E_64) #define MSR_ MSR_ME | MSR_CE #define MSR_KERNEL MSR_ | MSR_CM -#define MSR_USER32 MSR_ | MSR_PR | MSR_EE -#define MSR_USER64 MSR_USER32 | MSR_CM +#define MSR_USER32 MSR_ | MSR_PR | MSR_EE | MSR_DE +#define MSR_USER64 MSR_USER32 | MSR_CM | MSR_DE #elif defined (CONFIG_40x) #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE) #define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 1e78453645be..551f6713ff42 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -477,6 +477,28 @@ struct task_struct *__switch_to(struct task_struct *prev, new_thread = &new->thread; old_thread = ¤t->thread; +#if defined(CONFIG_PPC_BOOK3E_64) + /* XXX Current Book3E code doesn't deal with kernel side DBCR0, + * we always hold the user values, so we set it now. + * + * However, we ensure the kernel MSR:DE is appropriately cleared too + * to avoid spurrious single step exceptions in the kernel. + * + * This will have to change to merge with the ppc32 code at some point, + * but I don't like much what ppc32 is doing today so there's some + * thinking needed there + */ + if ((new_thread->dbcr0 | old_thread->dbcr0) & DBCR0_IDM) { + u32 dbcr0; + + mtmsr(mfmsr() & ~MSR_DE); + isync(); + dbcr0 = mfspr(SPRN_DBCR0); + dbcr0 = (dbcr0 & DBCR0_EDM) | new_thread->dbcr0; + mtspr(SPRN_DBCR0, dbcr0); + } +#endif /* CONFIG_PPC64_BOOK3E */ + #ifdef CONFIG_PPC64 /* * Collect processor utilization data per process -- cgit v1.2.3 From e3145b387a02d4bf8b8033b1354d413fc0864494 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 9 Jul 2010 15:25:18 +1000 Subject: powerpc/book3e: Move doorbell_exception from traps.c to dbell.c ... where it belongs Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/dbell.c | 22 +++++++++++++++++++++- arch/powerpc/kernel/traps.c | 21 --------------------- 2 files changed, 21 insertions(+), 22 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 1493734cd871..e3a717704fd6 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -41,4 +41,24 @@ void smp_dbell_message_pass(int target, int msg) ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0); } } -#endif + +void doorbell_exception(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int msg; + + if (num_online_cpus() < 2) + return; + + for (msg = 0; msg < 4; msg++) + if (test_and_clear_bit(msg, &dbell_smp_message[cpu])) + smp_message_recv(msg); +} + +#else /* CONFIG_SMP */ +void doorbell_exception(struct pt_regs *regs) +{ + printk(KERN_WARNING "Received doorbell on non-smp system\n"); +} +#endif /* CONFIG_SMP */ + diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index e5fe5a8522a6..a45a63c3a0c7 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -55,9 +55,6 @@ #endif #include #include -#ifdef CONFIG_FSL_BOOKE -#include -#endif #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) int (*__debugger)(struct pt_regs *regs) __read_mostly; @@ -1342,24 +1339,6 @@ void vsx_assist_exception(struct pt_regs *regs) #endif /* CONFIG_VSX */ #ifdef CONFIG_FSL_BOOKE - -void doorbell_exception(struct pt_regs *regs) -{ -#ifdef CONFIG_SMP - int cpu = smp_processor_id(); - int msg; - - if (num_online_cpus() < 2) - return; - - for (msg = 0; msg < 4; msg++) - if (test_and_clear_bit(msg, &dbell_smp_message[cpu])) - smp_message_recv(msg); -#else - printk(KERN_WARNING "Received doorbell on non-smp system\n"); -#endif -} - void CacheLockingException(struct pt_regs *regs, unsigned long address, unsigned long error_code) { -- cgit v1.2.3 From b9f1cd71dbf21a91fb7e2336a1d1ff18b97771e5 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 9 Jul 2010 15:29:53 +1000 Subject: powerpc/book3e: More doorbell cleanups. Sample the PIR register The doorbells use the content of the PIR register to match messages from other CPUs. This may or may not be the same as our linux CPU number, so using that as the "target" is no right. Instead, we sample the PIR register at boot on every processor and use that value subsequently when sending IPIs. We also use a per-cpu message mask rather than a global array which should limit cache line contention. Note: We could use the CPU number in the device-tree instead of the PIR register, as they are supposed to be equivalent. This might prove useful if doorbells are to be used to kick CPUs out of FW at boot time, thus before we can sample the PIR. This is however not the case now and using the PIR just works. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/dbell.h | 7 +++--- arch/powerpc/kernel/dbell.c | 47 ++++++++++++++++++++++++++++----------- arch/powerpc/platforms/85xx/smp.c | 4 +++- 3 files changed, 40 insertions(+), 18 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h index 501189a543d1..ced7e487ca27 100644 --- a/arch/powerpc/include/asm/dbell.h +++ b/arch/powerpc/include/asm/dbell.h @@ -27,10 +27,9 @@ enum ppc_dbell { PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */ }; -#ifdef CONFIG_SMP -extern unsigned long dbell_smp_message[NR_CPUS]; -extern void smp_dbell_message_pass(int target, int msg); -#endif +extern void doorbell_message_pass(int target, int msg); +extern void doorbell_exception(struct pt_regs *regs); +extern void doorbell_setup_this_cpu(void); static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag) { diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index e3a717704fd6..1c7a94580c3f 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -13,45 +13,66 @@ #include #include #include +#include #include #ifdef CONFIG_SMP -unsigned long dbell_smp_message[NR_CPUS]; +struct doorbell_cpu_info { + unsigned long messages; /* current messages bits */ + unsigned int tag; /* tag value */ +}; -void smp_dbell_message_pass(int target, int msg) +static DEFINE_PER_CPU(struct doorbell_cpu_info, doorbell_cpu_info); + +void doorbell_setup_this_cpu(void) +{ + struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); + + info->messages = 0; + info->tag = mfspr(SPRN_PIR) & 0x3fff; +} + +void doorbell_message_pass(int target, int msg) { + struct doorbell_cpu_info *info; int i; - if(target < NR_CPUS) { - set_bit(msg, &dbell_smp_message[target]); - ppc_msgsnd(PPC_DBELL, 0, target); + if (target < NR_CPUS) { + info = &per_cpu(doorbell_cpu_info, target); + set_bit(msg, &info->messages); + ppc_msgsnd(PPC_DBELL, 0, info->tag); } - else if(target == MSG_ALL_BUT_SELF) { + else if (target == MSG_ALL_BUT_SELF) { for_each_online_cpu(i) { if (i == smp_processor_id()) continue; - set_bit(msg, &dbell_smp_message[i]); - ppc_msgsnd(PPC_DBELL, 0, i); + info = &per_cpu(doorbell_cpu_info, i); + set_bit(msg, &info->messages); + ppc_msgsnd(PPC_DBELL, 0, info->tag); } } else { /* target == MSG_ALL */ - for_each_online_cpu(i) - set_bit(msg, &dbell_smp_message[i]); + for_each_online_cpu(i) { + info = &per_cpu(doorbell_cpu_info, i); + set_bit(msg, &info->messages); + } ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0); } } void doorbell_exception(struct pt_regs *regs) { - int cpu = smp_processor_id(); + struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); int msg; - if (num_online_cpus() < 2) + /* Warning: regs can be NULL when called from irq enable */ + + if (!info->messages || (num_online_cpus() < 2)) return; for (msg = 0; msg < 4; msg++) - if (test_and_clear_bit(msg, &dbell_smp_message[cpu])) + if (test_and_clear_bit(msg, &info->messages)) smp_message_recv(msg); } diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index a15f582300d8..4c3cde911c71 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -99,6 +99,8 @@ static void __init smp_85xx_setup_cpu(int cpu_nr) { mpic_setup_this_cpu(); + if (cpu_has_feature(CPU_FTR_DBELL)) + doorbell_setup_this_cpu(); } struct smp_ops_t smp_85xx_ops = { @@ -117,7 +119,7 @@ void __init mpc85xx_smp_init(void) } if (cpu_has_feature(CPU_FTR_DBELL)) - smp_85xx_ops.message_pass = smp_dbell_message_pass; + smp_85xx_ops.message_pass = doorbell_message_pass; BUG_ON(!smp_85xx_ops.message_pass); -- cgit v1.2.3 From e8775d4aa17d70d123814e68a6a51bbea50e5c16 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 9 Jul 2010 15:30:22 +1000 Subject: powerpc/book3e: Don't re-trigger decrementer on lazy irq restore The decrementer on BookE acts as a level interrupt and doesn't need to be re-triggered when going negative. It doesn't go negative anyways (unless programmed to auto-reload with a negative value) as it stops when reaching 0. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/irq.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 77be3d058a65..fa6f38525801 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -159,8 +159,17 @@ notrace void raw_local_irq_restore(unsigned long en) * use local_paca instead of get_paca() to avoid preemption checking. */ local_paca->hard_enabled = en; + +#ifndef CONFIG_BOOKE + /* On server, re-trigger the decrementer if it went negative since + * some processors only trigger on edge transitions of the sign bit. + * + * BookE has a level sensitive decrementer (latches in TSR) so we + * don't need that + */ if ((int)mfspr(SPRN_DEC) < 0) mtspr(SPRN_DEC, 1); +#endif /* CONFIG_BOOKE */ /* * Force the delivery of pending soft-disabled interrupts on PS3. -- cgit v1.2.3 From 89c81797d4a0779a957f4ea1f0c676cda203615b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 9 Jul 2010 15:31:28 +1000 Subject: powerpc/book3e: Hookup doorbells exceptions on 64-bit Book3E Note that critical doorbells are an unimplemented stub just like other critical or machine check handlers, since we haven't done support for "levelled" exceptions yet. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/Makefile | 1 + arch/powerpc/kernel/exceptions-64e.S | 21 +++++++++++++++++---- arch/powerpc/kernel/irq.c | 7 +++++++ 3 files changed, 25 insertions(+), 4 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 01006040f59e..8a33318fa46b 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -68,6 +68,7 @@ obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_44x) += cpu_setup_44x.o obj-$(CONFIG_FSL_BOOKE) += cpu_setup_fsl_booke.o dbell.o +obj-$(CONFIG_PPC_BOOK3E_64) += dbell.o extra-y := head_$(CONFIG_WORD_SIZE).o extra-$(CONFIG_PPC_BOOK3E_32) := head_new_booke.o diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 24dcc0ecf246..a42637c3a72d 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -246,11 +246,9 @@ interrupt_base_book3e: /* fake trap */ EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */ EXCEPTION_STUB(0x1c0, data_tlb_miss) EXCEPTION_STUB(0x1e0, instruction_tlb_miss) + EXCEPTION_STUB(0x280, doorbell) + EXCEPTION_STUB(0x2a0, doorbell_crit) -#if 0 - EXCEPTION_STUB(0x280, processor_doorbell) - EXCEPTION_STUB(0x220, processor_doorbell_crit) -#endif .globl interrupt_end_book3e interrupt_end_book3e: @@ -428,6 +426,19 @@ interrupt_end_book3e: kernel_dbg_exc: b . /* NYI */ +/* Doorbell interrupt */ + MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) + +/* Doorbell critical Interrupt */ + START_EXCEPTION(doorbell_crit); + CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE) +// EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL) +// bl special_reg_save_crit +// addi r3,r1,STACK_FRAME_OVERHEAD +// bl .doorbell_critical_exception +// b ret_from_crit_except + b . + /* * An interrupt came in while soft-disabled; clear EE in SRR1, @@ -563,6 +574,8 @@ BAD_STACK_TRAMPOLINE(0xd00) BAD_STACK_TRAMPOLINE(0xe00) BAD_STACK_TRAMPOLINE(0xf00) BAD_STACK_TRAMPOLINE(0xf20) +BAD_STACK_TRAMPOLINE(0x2070) +BAD_STACK_TRAMPOLINE(0x2080) .globl bad_stack_book3e bad_stack_book3e: diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index fa6f38525801..2f6dc7faf6de 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -64,6 +64,8 @@ #include #include #include +#include + #ifdef CONFIG_PPC64 #include #include @@ -153,6 +155,11 @@ notrace void raw_local_irq_restore(unsigned long en) if (get_hard_enabled()) return; +#if defined(CONFIG_BOOKE) && defined(CONFIG_SMP) + /* Check for pending doorbell interrupts on SMP */ + doorbell_exception(NULL); +#endif + /* * Need to hard-enable interrupts here. Since currently disabled, * no need to take further asm precautions against preemption; but -- cgit v1.2.3 From 0e37d25950f4fd5a7d74723e6ce608aaa972d24c Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 9 Jul 2010 15:32:30 +1000 Subject: powerpc/book3e: Use set_irq_regs() in the msgsnd/msgrcv IPI path include/asm-generic/irq_regs.h declares per-cpu irq_regs variables and get_irq_regs() and set_irq_regs() helper functions to maintain them. These can be used to access the proper pt_regs structure related to the current interrupt entry (if any). In the powerpc arch code, this is used to maintain irq regs on decrementer and external interrupt exceptions. However, for the doorbell exceptions used by the msgsnd/msgrcv IPI mechanism of newer BookE CPUs, the irq_regs are not kept up to date. In particular this means that xmon will not work properly on SMP, because the secondary xmon instances started by IPI will blow up when they cannot retrieve the irq regs. This patch fixes the problem by adding calls to maintain the irq regs across doorbell exceptions. Signed-off-by: David Gibson Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/dbell.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 1c7a94580c3f..f7b518894c80 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -16,6 +16,7 @@ #include #include +#include #ifdef CONFIG_SMP struct doorbell_cpu_info { @@ -63,17 +64,21 @@ void doorbell_message_pass(int target, int msg) void doorbell_exception(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); int msg; /* Warning: regs can be NULL when called from irq enable */ if (!info->messages || (num_online_cpus() < 2)) - return; + goto out; for (msg = 0; msg < 4; msg++) if (test_and_clear_bit(msg, &info->messages)) smp_message_recv(msg); + +out: + set_irq_regs(old_regs); } #else /* CONFIG_SMP */ -- cgit v1.2.3 From 850f22d5688941ea51628f3f8f8dcf3baff409ff Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 9 Jul 2010 15:34:00 +1000 Subject: powerpc/book3e: Resend doorbell exceptions to ourself If we are soft disabled and receive a doorbell exception we don't process it immediately. This means we need to check on the way out of irq restore if there are any doorbell exceptions to process. The problem is at that point we don't know what our regs are, and that in turn makes xmon unhappy. To workaround the problem, instead of checking for and processing doorbells, we check for any doorbells and if there were any we send ourselves another. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/dbell.h | 1 + arch/powerpc/kernel/dbell.c | 10 ++++++++++ arch/powerpc/kernel/irq.c | 4 ++-- 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h index ced7e487ca27..0893ab9343a6 100644 --- a/arch/powerpc/include/asm/dbell.h +++ b/arch/powerpc/include/asm/dbell.h @@ -29,6 +29,7 @@ enum ppc_dbell { extern void doorbell_message_pass(int target, int msg); extern void doorbell_exception(struct pt_regs *regs); +extern void doorbell_check_self(void); extern void doorbell_setup_this_cpu(void); static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag) diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index f7b518894c80..3307a52d797f 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -81,6 +81,16 @@ out: set_irq_regs(old_regs); } +void doorbell_check_self(void) +{ + struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); + + if (!info->messages) + return; + + ppc_msgsnd(PPC_DBELL, 0, info->tag); +} + #else /* CONFIG_SMP */ void doorbell_exception(struct pt_regs *regs) { diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 2f6dc7faf6de..8f96d3198905 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -156,8 +156,8 @@ notrace void raw_local_irq_restore(unsigned long en) return; #if defined(CONFIG_BOOKE) && defined(CONFIG_SMP) - /* Check for pending doorbell interrupts on SMP */ - doorbell_exception(NULL); + /* Check for pending doorbell interrupts and resend to ourself */ + doorbell_check_self(); #endif /* -- cgit v1.2.3 From 34d97e07cc81ab6f1e63696127cc7a5d2c4fce4b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 14 Jul 2010 14:12:16 +1000 Subject: powerpc/book3e: Add generic 64-bit idle powersave support We use a similar technique to ppc32: We set a thread local flag to indicate that we are about to enter or have entered the stop state, and have fixup code in the async interrupt entry code that reacts to this flag to make us return to a different location (sets NIP to LINK in our case). Signed-off-by: Benjamin Herrenschmidt -- v2. Fix lockdep bug Re-mask interrupts when coming back from idle --- arch/powerpc/include/asm/machdep.h | 1 + arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/exceptions-64e.S | 23 ++++++++++ arch/powerpc/kernel/idle_book3e.S | 86 ++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/kernel/idle_book3e.S (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 2bad6e5855ad..adc8e6cdf339 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -278,6 +278,7 @@ extern void e500_idle(void); extern void power4_idle(void); extern void power4_cpu_offline_powersave(void); extern void ppc6xx_idle(void); +extern void book3e_idle(void); /* * ppc_md contains a copy of the machine description structure for the diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 8a33318fa46b..77d831a1cc32 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -37,7 +37,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o -obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o +obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o obj-$(CONFIG_PPC_970_NAP) += idle_power4.o diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index a42637c3a72d..316465a32a9c 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -204,11 +204,30 @@ exc_##n##_bad_stack: \ lis r,TSR_FIS@h; \ mtspr SPRN_TSR,r +/* Used by asynchronous interrupt that may happen in the idle loop. + * + * This check if the thread was in the idle loop, and if yes, returns + * to the caller rather than the PC. This is to avoid a race if + * interrupts happen before the wait instruction. + */ +#define CHECK_NAPPING() \ + clrrdi r11,r1,THREAD_SHIFT; \ + ld r10,TI_LOCAL_FLAGS(r11); \ + andi. r9,r10,_TLF_NAPPING; \ + beq+ 1f; \ + ld r8,_LINK(r1); \ + rlwinm r7,r10,0,~_TLF_NAPPING; \ + std r8,_NIP(r1); \ + std r7,TI_LOCAL_FLAGS(r11); \ +1: + + #define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \ START_EXCEPTION(label); \ NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \ EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \ ack(r8); \ + CHECK_NAPPING(); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ bl hdlr; \ b .ret_from_except_lite; @@ -257,6 +276,7 @@ interrupt_end_book3e: CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE) // EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL) // bl special_reg_save_crit +// CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD // bl .critical_exception // b ret_from_crit_except @@ -268,6 +288,7 @@ interrupt_end_book3e: // EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL) // bl special_reg_save_mc // addi r3,r1,STACK_FRAME_OVERHEAD +// CHECK_NAPPING(); // bl .machine_check_exception // b ret_from_mc_except b . @@ -338,6 +359,7 @@ interrupt_end_book3e: CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE) // EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL) // bl special_reg_save_crit +// CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD // bl .unknown_exception // b ret_from_crit_except @@ -434,6 +456,7 @@ kernel_dbg_exc: CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE) // EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL) // bl special_reg_save_crit +// CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD // bl .doorbell_critical_exception // b ret_from_crit_except diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S new file mode 100644 index 000000000000..16c002d6bdf1 --- /dev/null +++ b/arch/powerpc/kernel/idle_book3e.S @@ -0,0 +1,86 @@ +/* + * Copyright 2010 IBM Corp, Benjamin Herrenschmidt + * + * Generic idle routine for Book3E processors + * + * 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 + +/* 64-bit version only for now */ +#ifdef CONFIG_PPC64 + +_GLOBAL(book3e_idle) + /* Save LR for later */ + mflr r0 + std r0,16(r1) + + /* Hard disable interrupts */ + wrteei 0 + + /* Now check if an interrupt came in while we were soft disabled + * since we may otherwise lose it (doorbells etc...). We know + * that since PACAHARDIRQEN will have been cleared in that case. + */ + lbz r3,PACAHARDIRQEN(r13) + cmpwi cr0,r3,0 + beqlr + + /* Now we are going to mark ourselves as soft and hard enables in + * order to be able to take interrupts while asleep. We inform lockdep + * of that. We don't actually turn interrupts on just yet tho. + */ +#ifdef CONFIG_TRACE_IRQFLAGS + stdu r1,-128(r1) + bl .trace_hardirqs_on +#endif + li r0,1 + stb r0,PACASOFTIRQEN(r13) + stb r0,PACAHARDIRQEN(r13) + + /* Interrupts will make use return to LR, so get something we want + * in there + */ + bl 1f + + /* Hard disable interrupts again */ + wrteei 0 + + /* Mark them off again in the PACA as well */ + li r0,0 + stb r0,PACASOFTIRQEN(r13) + stb r0,PACAHARDIRQEN(r13) + + /* Tell lockdep about it */ +#ifdef CONFIG_TRACE_IRQFLAGS + bl .trace_hardirqs_off + addi r1,r1,128 +#endif + ld r0,16(r1) + mtlr r0 + blr + +1: /* Let's set the _TLF_NAPPING flag so interrupts make us return + * to the right spot + */ + clrrdi r11,r1,THREAD_SHIFT + ld r10,TI_LOCAL_FLAGS(r11) + ori r10,r10,_TLF_NAPPING + std r10,TI_LOCAL_FLAGS(r11) + + /* We can now re-enable hard interrupts and go to sleep */ + wrteei 1 +1: PPC_WAIT(0) + b 1b + +#endif /* CONFIG_PPC64 */ -- cgit v1.2.3 From ff82c319e6327b12cd94c5c57754abff243ab3e4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 8 Jun 2010 10:58:58 +1000 Subject: powerpc/book3e: Fix single step when using HW page tables We patch the TLB miss exception vectors to point to alternate functions when using HW page table on BookE. However, we were patching in a new branch in the first instruction of the exception handler instead of the second one, thus overriding the nop that is in the first instruction. This cause problems when single stepping as we rely on that nop for the single step to stop properly within the exception vector range rather than on the target of the branch. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/exceptions-64e.S | 6 ++++++ arch/powerpc/mm/tlb_nohash.c | 13 +++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 316465a32a9c..5c43063d2506 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -191,6 +191,12 @@ exc_##n##_bad_stack: \ sth r1,PACA_TRAP_SAVE(r13); /* store trap */ \ b bad_stack_book3e; /* bad stack error */ +/* WARNING: If you change the layout of this stub, make sure you chcek + * the debug exception handler which handles single stepping + * into exceptions from userspace, and the MM code in + * arch/powerpc/mm/tlb_nohash.c which patches the branch here + * and would need to be updated if that branch is moved + */ #define EXCEPTION_STUB(loc, label) \ . = interrupt_base_book3e + loc; \ nop; /* To make debug interrupts happy */ \ diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index e81d5d67f834..2ce42bf1f67e 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -391,10 +391,15 @@ static void __early_init_mmu(int boot_cpu) /* Check if HW loader is supported */ if ((tlb0cfg & TLBnCFG_IND) && (tlb0cfg & TLBnCFG_PT)) { - patch_branch(ibase + (0x1c0 / 4), - (unsigned long)&exc_data_tlb_miss_htw_book3e, 0); - patch_branch(ibase + (0x1e0 / 4), - (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0); + /* Our exceptions vectors start with a NOP and -then- a branch + * to deal with single stepping from userspace which stops on + * the second instruction. Thus we need to patch the second + * instruction of the exception, not the first one + */ + patch_branch(ibase + (0x1c0 / 4) + 1, + (unsigned long)&exc_data_tlb_miss_htw_book3e, 0); + patch_branch(ibase + (0x1e0 / 4) + 1, + (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0); book3e_htw_enabled = 1; } pr_info("MMU: Book3E Page Tables %s\n", -- cgit v1.2.3 From 03247157f73912c98baa918cf46b98ee5483d7f8 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 9 Jul 2010 15:34:50 +1000 Subject: powerpc/book3e: Add TLB dump in xmon for Book3E Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/xmon/xmon.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 8bad7d5f32af..0554445200bf 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -155,6 +155,9 @@ static int do_spu_cmd(void); #ifdef CONFIG_44x static void dump_tlb_44x(void); #endif +#ifdef CONFIG_PPC_BOOK3E +static void dump_tlb_book3e(void); +#endif static int xmon_no_auto_backtrace; @@ -887,6 +890,11 @@ cmds(struct pt_regs *excp) case 'u': dump_tlb_44x(); break; +#endif +#ifdef CONFIG_PPC_BOOK3E + case 'u': + dump_tlb_book3e(); + break; #endif default: printf("Unrecognized command: "); @@ -2701,6 +2709,150 @@ static void dump_tlb_44x(void) } #endif /* CONFIG_44x */ +#ifdef CONFIG_PPC_BOOK3E +static void dump_tlb_book3e(void) +{ + u32 mmucfg, pidmask, lpidmask; + u64 ramask; + int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0; + int mmu_version; + static const char *pgsz_names[] = { + " 1K", + " 2K", + " 4K", + " 8K", + " 16K", + " 32K", + " 64K", + "128K", + "256K", + "512K", + " 1M", + " 2M", + " 4M", + " 8M", + " 16M", + " 32M", + " 64M", + "128M", + "256M", + "512M", + " 1G", + " 2G", + " 4G", + " 8G", + " 16G", + " 32G", + " 64G", + "128G", + "256G", + "512G", + " 1T", + " 2T", + }; + + /* Gather some infos about the MMU */ + mmucfg = mfspr(SPRN_MMUCFG); + mmu_version = (mmucfg & 3) + 1; + ntlbs = ((mmucfg >> 2) & 3) + 1; + pidsz = ((mmucfg >> 6) & 0x1f) + 1; + lpidsz = (mmucfg >> 24) & 0xf; + rasz = (mmucfg >> 16) & 0x7f; + if ((mmu_version > 1) && (mmucfg & 0x10000)) + lrat = 1; + printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n", + mmu_version, ntlbs, pidsz, lpidsz, rasz); + pidmask = (1ul << pidsz) - 1; + lpidmask = (1ul << lpidsz) - 1; + ramask = (1ull << rasz) - 1; + + for (tlb = 0; tlb < ntlbs; tlb++) { + u32 tlbcfg; + int nent, assoc, new_cc = 1; + printf("TLB %d:\n------\n", tlb); + switch(tlb) { + case 0: + tlbcfg = mfspr(SPRN_TLB0CFG); + break; + case 1: + tlbcfg = mfspr(SPRN_TLB1CFG); + break; + case 2: + tlbcfg = mfspr(SPRN_TLB2CFG); + break; + case 3: + tlbcfg = mfspr(SPRN_TLB3CFG); + break; + default: + printf("Unsupported TLB number !\n"); + continue; + } + nent = tlbcfg & 0xfff; + assoc = (tlbcfg >> 24) & 0xff; + for (i = 0; i < nent; i++) { + u32 mas0 = MAS0_TLBSEL(tlb); + u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K); + u64 mas2 = 0; + u64 mas7_mas3; + int esel = i, cc = i; + + if (assoc != 0) { + cc = i / assoc; + esel = i % assoc; + mas2 = cc * 0x1000; + } + + mas0 |= MAS0_ESEL(esel); + mtspr(SPRN_MAS0, mas0); + mtspr(SPRN_MAS1, mas1); + mtspr(SPRN_MAS2, mas2); + asm volatile("tlbre 0,0,0" : : : "memory"); + mas1 = mfspr(SPRN_MAS1); + mas2 = mfspr(SPRN_MAS2); + mas7_mas3 = mfspr(SPRN_MAS7_MAS3); + if (assoc && (i % assoc) == 0) + new_cc = 1; + if (!(mas1 & MAS1_VALID)) + continue; + if (assoc == 0) + printf("%04x- ", i); + else if (new_cc) + printf("%04x-%c", cc, 'A' + esel); + else + printf(" |%c", 'A' + esel); + new_cc = 0; + printf(" %016llx %04x %s %c%c AS%c", + mas2 & ~0x3ffull, + (mas1 >> 16) & 0x3fff, + pgsz_names[(mas1 >> 7) & 0x1f], + mas1 & MAS1_IND ? 'I' : ' ', + mas1 & MAS1_IPROT ? 'P' : ' ', + mas1 & MAS1_TS ? '1' : '0'); + printf(" %c%c%c%c%c%c%c", + mas2 & MAS2_X0 ? 'a' : ' ', + mas2 & MAS2_X1 ? 'v' : ' ', + mas2 & MAS2_W ? 'w' : ' ', + mas2 & MAS2_I ? 'i' : ' ', + mas2 & MAS2_M ? 'm' : ' ', + mas2 & MAS2_G ? 'g' : ' ', + mas2 & MAS2_E ? 'e' : ' '); + printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull); + if (mas1 & MAS1_IND) + printf(" %s\n", + pgsz_names[(mas7_mas3 >> 1) & 0x1f]); + else + printf(" U%c%c%c S%c%c%c\n", + mas7_mas3 & MAS3_UX ? 'x' : ' ', + mas7_mas3 & MAS3_UW ? 'w' : ' ', + mas7_mas3 & MAS3_UR ? 'r' : ' ', + mas7_mas3 & MAS3_SX ? 'x' : ' ', + mas7_mas3 & MAS3_SW ? 'w' : ' ', + mas7_mas3 & MAS3_SR ? 'r' : ' '); + } + } +} +#endif /* CONFIG_PPC_BOOK3E */ + static void xmon_init(int enable) { #ifdef CONFIG_PPC_ISERIES -- cgit v1.2.3 From f2b26c923518e03959142715a2b7615cb161cd16 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 9 Jul 2010 14:57:43 +1000 Subject: powerpc/book3e: Adjust the page sizes list based on MMU config Use the MMU config registers to scan for available direct and indirect page sizes and print out the result. Will be needed for future hugetlbfs implementation. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/mmu-book3e.h | 4 + arch/powerpc/include/asm/reg_booke.h | 1 + arch/powerpc/mm/tlb_nohash.c | 136 ++++++++++++++++++++++++++-------- 3 files changed, 109 insertions(+), 32 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index 74695816205c..87a1d787c5b6 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h @@ -193,6 +193,10 @@ struct mmu_psize_def { unsigned int shift; /* number of bits */ unsigned int enc; /* PTE encoding */ + unsigned int ind; /* Corresponding indirect page size shift */ + unsigned int flags; +#define MMU_PAGE_SIZE_DIRECT 0x1 /* Supported as a direct size */ +#define MMU_PAGE_SIZE_INDIRECT 0x2 /* Supported as an indirect size */ }; extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 66dc6f0d3ad8..667a498eaee1 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -62,6 +62,7 @@ #define SPRN_TLB0PS 0x158 /* TLB 0 Page Size Register */ #define SPRN_MAS5_MAS6 0x15c /* MMU Assist Register 5 || 6 */ #define SPRN_MAS8_MAS1 0x15d /* MMU Assist Register 8 || 1 */ +#define SPRN_EPTCFG 0x15e /* Embedded Page Table Config */ #define SPRN_MAS7_MAS3 0x174 /* MMU Assist Register 7 || 3 */ #define SPRN_MAS0_MAS1 0x175 /* MMU Assist Register 0 || 1 */ #define SPRN_IVOR0 0x190 /* Interrupt Vector Offset Register 0 */ diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index 2ce42bf1f67e..3b10f804b735 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -46,6 +46,7 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { [MMU_PAGE_4K] = { .shift = 12, + .ind = 20, .enc = BOOK3E_PAGESZ_4K, }, [MMU_PAGE_16K] = { @@ -54,6 +55,7 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { }, [MMU_PAGE_64K] = { .shift = 16, + .ind = 28, .enc = BOOK3E_PAGESZ_64K, }, [MMU_PAGE_1M] = { @@ -62,6 +64,7 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { }, [MMU_PAGE_16M] = { .shift = 24, + .ind = 36, .enc = BOOK3E_PAGESZ_16M, }, [MMU_PAGE_256M] = { @@ -344,16 +347,108 @@ void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address) } } -/* - * Early initialization of the MMU TLB code - */ -static void __early_init_mmu(int boot_cpu) +static void setup_page_sizes(void) +{ + unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG); + unsigned int tlb0ps = mfspr(SPRN_TLB0PS); + unsigned int eptcfg = mfspr(SPRN_EPTCFG); + int i, psize; + + /* Look for supported direct sizes */ + for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { + struct mmu_psize_def *def = &mmu_psize_defs[psize]; + + if (tlb0ps & (1U << (def->shift - 10))) + def->flags |= MMU_PAGE_SIZE_DIRECT; + } + + /* Indirect page sizes supported ? */ + if ((tlb0cfg & TLBnCFG_IND) == 0) + goto no_indirect; + + /* Now, we only deal with one IND page size for each + * direct size. Hopefully all implementations today are + * unambiguous, but we might want to be careful in the + * future. + */ + for (i = 0; i < 3; i++) { + unsigned int ps, sps; + + sps = eptcfg & 0x1f; + eptcfg >>= 5; + ps = eptcfg & 0x1f; + eptcfg >>= 5; + if (!ps || !sps) + continue; + for (psize = 0; psize < MMU_PAGE_COUNT; psize++) { + struct mmu_psize_def *def = &mmu_psize_defs[psize]; + + if (ps == (def->shift - 10)) + def->flags |= MMU_PAGE_SIZE_INDIRECT; + if (sps == (def->shift - 10)) + def->ind = ps + 10; + } + } + no_indirect: + + /* Cleanup array and print summary */ + pr_info("MMU: Supported page sizes\n"); + for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { + struct mmu_psize_def *def = &mmu_psize_defs[psize]; + const char *__page_type_names[] = { + "unsupported", + "direct", + "indirect", + "direct & indirect" + }; + if (def->flags == 0) { + def->shift = 0; + continue; + } + pr_info(" %8ld KB as %s\n", 1ul << (def->shift - 10), + __page_type_names[def->flags & 0x3]); + } +} + +static void setup_mmu_htw(void) { extern unsigned int interrupt_base_book3e; extern unsigned int exc_data_tlb_miss_htw_book3e; extern unsigned int exc_instruction_tlb_miss_htw_book3e; unsigned int *ibase = &interrupt_base_book3e; + + /* Check if HW tablewalk is present, and if yes, enable it by: + * + * - patching the TLB miss handlers to branch to the + * one dedicates to it + * + * - setting the global book3e_htw_enabled + */ + unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG); + + if ((tlb0cfg & TLBnCFG_IND) && + (tlb0cfg & TLBnCFG_PT)) { + /* Our exceptions vectors start with a NOP and -then- a branch + * to deal with single stepping from userspace which stops on + * the second instruction. Thus we need to patch the second + * instruction of the exception, not the first one + */ + patch_branch(ibase + (0x1c0 / 4) + 1, + (unsigned long)&exc_data_tlb_miss_htw_book3e, 0); + patch_branch(ibase + (0x1e0 / 4) + 1, + (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0); + book3e_htw_enabled = 1; + } + pr_info("MMU: Book3E Page Tables %s\n", + book3e_htw_enabled ? "Enabled" : "Disabled"); +} + +/* + * Early initialization of the MMU TLB code + */ +static void __early_init_mmu(int boot_cpu) +{ unsigned int mas4; /* XXX This will have to be decided at runtime, but right @@ -370,40 +465,17 @@ static void __early_init_mmu(int boot_cpu) */ mmu_vmemmap_psize = MMU_PAGE_16M; - /* Check if HW tablewalk is present, and if yes, enable it by: - * - * - patching the TLB miss handlers to branch to the - * one dedicates to it - * - * - setting the global book3e_htw_enabled - * - * - Set MAS4:INDD and default page size - */ - /* XXX This code only checks for TLB 0 capabilities and doesn't * check what page size combos are supported by the HW. It * also doesn't handle the case where a separate array holds * the IND entries from the array loaded by the PT. */ if (boot_cpu) { - unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG); - - /* Check if HW loader is supported */ - if ((tlb0cfg & TLBnCFG_IND) && - (tlb0cfg & TLBnCFG_PT)) { - /* Our exceptions vectors start with a NOP and -then- a branch - * to deal with single stepping from userspace which stops on - * the second instruction. Thus we need to patch the second - * instruction of the exception, not the first one - */ - patch_branch(ibase + (0x1c0 / 4) + 1, - (unsigned long)&exc_data_tlb_miss_htw_book3e, 0); - patch_branch(ibase + (0x1e0 / 4) + 1, - (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0); - book3e_htw_enabled = 1; - } - pr_info("MMU: Book3E Page Tables %s\n", - book3e_htw_enabled ? "Enabled" : "Disabled"); + /* Look for supported page sizes */ + setup_page_sizes(); + + /* Look for HW tablewalk support */ + setup_mmu_htw(); } /* Set MAS4 based on page table setting */ -- cgit v1.2.3 From 1caca371e80b0d40352512806368f6ff43e2cf52 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 9 Jul 2010 15:18:44 +1000 Subject: powerpc/oprofile: Don't build server oprofile drivers on 64-bit BookE They will fail to build due to the lack of mtmsrd, and wouldn't be useful anyways Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/oprofile/Makefile | 2 +- arch/powerpc/oprofile/common.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile index 73e1c2ca0552..e219ca43962d 100644 --- a/arch/powerpc/oprofile/Makefile +++ b/arch/powerpc/oprofile/Makefile @@ -16,6 +16,6 @@ oprofile-y := $(DRIVER_OBJS) common.o backtrace.o oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \ cell/spu_profiler.o cell/vma_map.o \ cell/spu_task_sync.o -oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o +oprofile-$(CONFIG_PPC_BOOK3S_64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o oprofile-$(CONFIG_FSL_EMB_PERFMON) += op_model_fsl_emb.o oprofile-$(CONFIG_6xx) += op_model_7450.o diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index 21f16edf6c8d..d65e68f3cb25 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -199,7 +199,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) return -ENODEV; switch (cur_cpu_spec->oprofile_type) { -#ifdef CONFIG_PPC64 +#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_OPROFILE_CELL case PPC_OPROFILE_CELL: if (firmware_has_feature(FW_FEATURE_LPAR)) -- cgit v1.2.3 From c5f5849bffb36478dd8a1e350860ff18b654bc44 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 29 Jun 2010 09:19:30 -0700 Subject: of: Remove unused of_find_device_by_phandle() Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt --- arch/microblaze/include/asm/of_platform.h | 2 -- arch/microblaze/kernel/of_platform.c | 18 ------------------ arch/powerpc/include/asm/of_platform.h | 2 -- arch/powerpc/kernel/of_platform.c | 19 ------------------- 4 files changed, 41 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/of_platform.h b/arch/microblaze/include/asm/of_platform.h index 625003f70888..353d8f651e30 100644 --- a/arch/microblaze/include/asm/of_platform.h +++ b/arch/microblaze/include/asm/of_platform.h @@ -14,8 +14,6 @@ /* This is just here during the transition */ #include -extern struct of_device *of_find_device_by_phandle(phandle ph); - extern void of_instantiate_rtc(void); #endif /* _ASM_MICROBLAZE_OF_PLATFORM_H */ diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c index a07abdd6859b..da79edf45420 100644 --- a/arch/microblaze/kernel/of_platform.c +++ b/arch/microblaze/kernel/of_platform.c @@ -75,21 +75,3 @@ struct of_device *of_find_device_by_node(struct device_node *np) return NULL; } EXPORT_SYMBOL(of_find_device_by_node); - -static int of_dev_phandle_match(struct device *dev, void *data) -{ - phandle *ph = data; - return to_of_device(dev)->dev.of_node->phandle == *ph; -} - -struct of_device *of_find_device_by_phandle(phandle ph) -{ - struct device *dev; - - dev = bus_find_device(&of_platform_bus_type, - NULL, &ph, of_dev_phandle_match); - if (dev) - return to_of_device(dev); - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_phandle); diff --git a/arch/powerpc/include/asm/of_platform.h b/arch/powerpc/include/asm/of_platform.h index b37d2dcddb97..d506aa61db83 100644 --- a/arch/powerpc/include/asm/of_platform.h +++ b/arch/powerpc/include/asm/of_platform.h @@ -11,8 +11,6 @@ * */ -extern struct of_device *of_find_device_by_phandle(phandle ph); - extern void of_instantiate_rtc(void); #endif /* _ASM_POWERPC_OF_PLATFORM_H */ diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 0b5cc6d892a7..4e0a2f7c1dd3 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -81,25 +81,6 @@ struct of_device *of_find_device_by_node(struct device_node *np) } EXPORT_SYMBOL(of_find_device_by_node); -static int of_dev_phandle_match(struct device *dev, void *data) -{ - phandle *ph = data; - return to_of_device(dev)->dev.of_node->phandle == *ph; -} - -struct of_device *of_find_device_by_phandle(phandle ph) -{ - struct device *dev; - - dev = bus_find_device(&of_platform_bus_type, - NULL, &ph, of_dev_phandle_match); - if (dev) - return to_of_device(dev); - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_phandle); - - #ifdef CONFIG_PPC_OF_PLATFORM_PCI /* The probing of PCI controllers from of_platform is currently -- cgit v1.2.3 From eca3930163ba8884060ce9d9ff5ef0d9b7c7b00f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 8 Jun 2010 07:48:21 -0600 Subject: of: Merge of_platform_bus_type with platform_bus_type of_platform_bus was being used in the same manner as the platform_bus. The only difference being that of_platform_bus devices are generated from data in the device tree, and platform_bus devices are usually statically allocated in platform code. Having them separate causes the problem of device drivers having to be registered twice if it was possible for the same device to appear on either bus. This patch removes of_platform_bus_type and registers all of_platform bus devices and drivers on the platform bus instead. A previous patch made the of_device structure an alias for the platform_device structure, and a shim is used to adapt of_platform_drivers to the platform bus. After all of of_platform_bus drivers are converted to be normal platform drivers, the shim code can be removed. Signed-off-by: Grant Likely Acked-by: David S. Miller --- arch/microblaze/kernel/of_platform.c | 11 ------ arch/microblaze/kernel/setup.c | 6 --- arch/powerpc/kernel/dma-swiotlb.c | 8 ---- arch/powerpc/kernel/of_platform.c | 12 ------ arch/powerpc/kernel/setup-common.c | 7 ---- arch/powerpc/platforms/cell/beat_iommu.c | 2 +- arch/powerpc/platforms/cell/iommu.c | 2 +- arch/powerpc/sysdev/mv64x60_dev.c | 7 +--- arch/sparc/kernel/of_device_32.c | 21 +++------- arch/sparc/kernel/of_device_64.c | 21 +++------- arch/sparc/kernel/of_device_common.c | 3 -- drivers/base/platform.c | 6 +++ drivers/of/device.c | 5 +++ drivers/of/platform.c | 67 ++++++++++++++++++++++++++++++-- include/linux/of_device.h | 6 +++ include/linux/of_platform.h | 21 ++++------ 16 files changed, 102 insertions(+), 103 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c index da79edf45420..fb2866104331 100644 --- a/arch/microblaze/kernel/of_platform.c +++ b/arch/microblaze/kernel/of_platform.c @@ -26,17 +26,6 @@ #include #include -struct bus_type of_platform_bus_type = { - .uevent = of_device_uevent, -}; -EXPORT_SYMBOL(of_platform_bus_type); - -static int __init of_bus_driver_init(void) -{ - return of_bus_type_init(&of_platform_bus_type, "of_platform"); -} -postcore_initcall(of_bus_driver_init); - /* * The list of OF IDs below is used for matching bus types in the * system whose devices are to be exposed as of_platform_devices. diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 17c98dbcec88..f5f768842354 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -213,15 +213,9 @@ static struct notifier_block dflt_plat_bus_notifier = { .priority = INT_MAX, }; -static struct notifier_block dflt_of_bus_notifier = { - .notifier_call = dflt_bus_notify, - .priority = INT_MAX, -}; - static int __init setup_bus_notifier(void) { bus_register_notifier(&platform_bus_type, &dflt_plat_bus_notifier); - bus_register_notifier(&of_platform_bus_type, &dflt_of_bus_notifier); return 0; } diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c index 02f724f36753..4295e0b94b2d 100644 --- a/arch/powerpc/kernel/dma-swiotlb.c +++ b/arch/powerpc/kernel/dma-swiotlb.c @@ -82,17 +82,9 @@ static struct notifier_block ppc_swiotlb_plat_bus_notifier = { .priority = 0, }; -static struct notifier_block ppc_swiotlb_of_bus_notifier = { - .notifier_call = ppc_swiotlb_bus_notify, - .priority = 0, -}; - int __init swiotlb_setup_bus_notifier(void) { bus_register_notifier(&platform_bus_type, &ppc_swiotlb_plat_bus_notifier); - bus_register_notifier(&of_platform_bus_type, - &ppc_swiotlb_of_bus_notifier); - return 0; } diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 4e0a2f7c1dd3..d3497cd81e8a 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -52,18 +52,6 @@ const struct of_device_id of_default_bus_ids[] = { {}, }; -struct bus_type of_platform_bus_type = { - .uevent = of_device_uevent, -}; -EXPORT_SYMBOL(of_platform_bus_type); - -static int __init of_bus_driver_init(void) -{ - return of_bus_type_init(&of_platform_bus_type, "of_platform"); -} - -postcore_initcall(of_bus_driver_init); - static int of_dev_node_match(struct device *dev, void *data) { return to_of_device(dev)->dev.of_node == data; diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index b7e6c7e193ae..d1a5304b3ddd 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -701,16 +701,9 @@ static struct notifier_block ppc_dflt_plat_bus_notifier = { .priority = INT_MAX, }; -static struct notifier_block ppc_dflt_of_bus_notifier = { - .notifier_call = ppc_dflt_bus_notify, - .priority = INT_MAX, -}; - static int __init setup_bus_notifier(void) { bus_register_notifier(&platform_bus_type, &ppc_dflt_plat_bus_notifier); - bus_register_notifier(&of_platform_bus_type, &ppc_dflt_of_bus_notifier); - return 0; } diff --git a/arch/powerpc/platforms/cell/beat_iommu.c b/arch/powerpc/platforms/cell/beat_iommu.c index 39d361c5c6d2..beec405eb6f8 100644 --- a/arch/powerpc/platforms/cell/beat_iommu.c +++ b/arch/powerpc/platforms/cell/beat_iommu.c @@ -108,7 +108,7 @@ static int __init celleb_init_iommu(void) celleb_init_direct_mapping(); set_pci_dma_ops(&dma_direct_ops); ppc_md.pci_dma_dev_setup = celleb_pci_dma_dev_setup; - bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier); + bus_register_notifier(&platform_bus_type, &celleb_of_bus_notifier); return 0; } diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 3712900471ba..58b13ce3847e 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -1204,7 +1204,7 @@ static int __init cell_iommu_init(void) /* Register callbacks on OF platform device addition/removal * to handle linking them to the right DMA operations */ - bus_register_notifier(&of_platform_bus_type, &cell_of_bus_notifier); + bus_register_notifier(&platform_bus_type, &cell_of_bus_notifier); return 0; } diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c index 31acd3b1718b..1398bc454999 100644 --- a/arch/powerpc/sysdev/mv64x60_dev.c +++ b/arch/powerpc/sysdev/mv64x60_dev.c @@ -20,12 +20,7 @@ #include -/* - * These functions provide the necessary setup for the mv64x60 drivers. - * These drivers are unusual in that they work on both the MIPS and PowerPC - * architectures. Because of that, the drivers do not support the normal - * PowerPC of_platform_bus_type. They support platform_bus_type instead. - */ +/* These functions provide the necessary setup for the mv64x60 drivers. */ static struct of_device_id __initdata of_mv64x60_devices[] = { { .compatible = "marvell,mv64306-devctrl", }, diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c index 331de91ad2bc..75fc9d5cd7e6 100644 --- a/arch/sparc/kernel/of_device_32.c +++ b/arch/sparc/kernel/of_device_32.c @@ -424,7 +424,7 @@ build_resources: build_device_resources(op, parent); op->dev.parent = parent; - op->dev.bus = &of_platform_bus_type; + op->dev.bus = &platform_bus_type; if (!parent) dev_set_name(&op->dev, "root"); else @@ -452,30 +452,19 @@ static void __init scan_tree(struct device_node *dp, struct device *parent) } } -static void __init scan_of_devices(void) +static int __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; + return 0; scan_tree(root->child, &parent->dev); + return 0; } - -static int __init of_bus_driver_init(void) -{ - int err; - - err = of_bus_type_init(&of_platform_bus_type, "of"); - if (!err) - scan_of_devices(); - - return err; -} - -postcore_initcall(of_bus_driver_init); +postcore_initcall(scan_of_devices); static int __init of_debug(char *str) { diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c index 5e8cbb942d3d..9743d1d9fa03 100644 --- a/arch/sparc/kernel/of_device_64.c +++ b/arch/sparc/kernel/of_device_64.c @@ -667,7 +667,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, op->archdata.irqs[i] = build_one_device_irq(op, parent, op->archdata.irqs[i]); op->dev.parent = parent; - op->dev.bus = &of_platform_bus_type; + op->dev.bus = &platform_bus_type; if (!parent) dev_set_name(&op->dev, "root"); else @@ -695,30 +695,19 @@ static void __init scan_tree(struct device_node *dp, struct device *parent) } } -static void __init scan_of_devices(void) +static int __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; + return 0; scan_tree(root->child, &parent->dev); + return 0; } - -static int __init of_bus_driver_init(void) -{ - int err; - - err = of_bus_type_init(&of_platform_bus_type, "of"); - if (!err) - scan_of_devices(); - - return err; -} - -postcore_initcall(of_bus_driver_init); +postcore_initcall(scan_of_devices); static int __init of_debug(char *str) { diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c index 016c947d4cae..01f380c7995c 100644 --- a/arch/sparc/kernel/of_device_common.c +++ b/arch/sparc/kernel/of_device_common.c @@ -64,9 +64,6 @@ void of_propagate_archdata(struct of_device *bus) } } -struct bus_type of_platform_bus_type; -EXPORT_SYMBOL(of_platform_bus_type); - static void get_cells(struct device_node *dp, int *addrc, int *sizec) { if (addrc) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index fac3633c7223..f699fabf403b 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -636,6 +636,12 @@ static struct device_attribute platform_dev_attrs[] = { static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) { struct platform_device *pdev = to_platform_device(dev); + int rc; + + /* Some devices have extra OF data and an OF-style MODALIAS */ + rc = of_device_uevent(dev,env); + if (rc != -ENODEV) + return rc; add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, (pdev->id_entry) ? pdev->id_entry->name : pdev->name); diff --git a/drivers/of/device.c b/drivers/of/device.c index 5282a202f5a9..12a44b493511 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -104,6 +104,11 @@ int of_device_register(struct of_device *ofdev) device_initialize(&ofdev->dev); + /* name and id have to be set so that the platform bus doesn't get + * confused on matching */ + ofdev->name = dev_name(&ofdev->dev); + ofdev->id = -1; + /* device_add will assume that this device is on the same node as * the parent. If there is no parent defined, set the node * explicitly */ diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 9d3d932bcb6f..712dfd866df0 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -20,6 +20,54 @@ #include #include #include +#include + +static int platform_driver_probe_shim(struct platform_device *pdev) +{ + struct platform_driver *pdrv; + struct of_platform_driver *ofpdrv; + const struct of_device_id *match; + + pdrv = container_of(pdev->dev.driver, struct platform_driver, driver); + ofpdrv = container_of(pdrv, struct of_platform_driver, platform_driver); + match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); + return ofpdrv->probe(pdev, match); +} + +static void platform_driver_shutdown_shim(struct platform_device *pdev) +{ + struct platform_driver *pdrv; + struct of_platform_driver *ofpdrv; + + pdrv = container_of(pdev->dev.driver, struct platform_driver, driver); + ofpdrv = container_of(pdrv, struct of_platform_driver, platform_driver); + ofpdrv->shutdown(pdev); +} + +/** + * of_register_platform_driver + */ +int of_register_platform_driver(struct of_platform_driver *drv) +{ + /* setup of_platform_driver to platform_driver adaptors */ + drv->platform_driver.driver = drv->driver; + if (drv->probe) + drv->platform_driver.probe = platform_driver_probe_shim; + drv->platform_driver.remove = drv->remove; + if (drv->shutdown) + drv->platform_driver.shutdown = platform_driver_shutdown_shim; + drv->platform_driver.suspend = drv->suspend; + drv->platform_driver.resume = drv->resume; + + return platform_driver_register(&drv->platform_driver); +} +EXPORT_SYMBOL(of_register_platform_driver); + +void of_unregister_platform_driver(struct of_platform_driver *drv) +{ + platform_driver_unregister(&drv->platform_driver); +} +EXPORT_SYMBOL(of_unregister_platform_driver); #if defined(CONFIG_PPC_DCR) #include @@ -392,16 +440,29 @@ int of_bus_type_init(struct bus_type *bus, const char *name) int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) { - drv->driver.bus = bus; + /* + * Temporary: of_platform_bus used to be distinct from the platform + * bus. It isn't anymore, and so drivers on the platform bus need + * to be registered in a special way. + * + * After all of_platform_bus_type drivers are converted to + * platform_drivers, this exception can be removed. + */ + if (bus == &platform_bus_type) + return of_register_platform_driver(drv); /* register with core */ + drv->driver.bus = bus; return driver_register(&drv->driver); } EXPORT_SYMBOL(of_register_driver); void of_unregister_driver(struct of_platform_driver *drv) { - driver_unregister(&drv->driver); + if (drv->driver.bus == &platform_bus_type) + of_unregister_platform_driver(drv); + else + driver_unregister(&drv->driver); } EXPORT_SYMBOL(of_unregister_driver); @@ -548,7 +609,7 @@ struct of_device *of_platform_device_create(struct device_node *np, dev->archdata.dma_mask = 0xffffffffUL; #endif dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - dev->dev.bus = &of_platform_bus_type; + dev->dev.bus = &platform_bus_type; /* We do not fill the DMA ops for platform devices by default. * This is currently the responsibility of the platform code diff --git a/include/linux/of_device.h b/include/linux/of_device.h index 7d27f5a878f6..8cd1fe7864e3 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -65,6 +65,12 @@ static inline int of_driver_match_device(struct device *dev, return 0; } +static inline int of_device_uevent(struct device *dev, + struct kobj_uevent_env *env) +{ + return -ENODEV; +} + #endif /* CONFIG_OF_DEVICE */ #endif /* _LINUX_OF_DEVICE_H */ diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index a51fd30176aa..133ecf31a60f 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -17,19 +17,19 @@ #include #include #include +#include /* - * The of_platform_bus_type is a bus type used by drivers that do not - * attach to a macio or similar bus but still use OF probing - * mechanism + * of_platform_bus_type isn't it's own bus anymore. It's now just an alias + * for the platform bus. */ -extern struct bus_type of_platform_bus_type; +#define of_platform_bus_type platform_bus_type extern const struct of_device_id of_default_bus_ids[]; /* * An of_platform_driver driver is attached to a basic of_device on - * the "platform bus" (of_platform_bus_type). + * the "platform bus" (platform_bus_type). */ struct of_platform_driver { @@ -42,6 +42,7 @@ struct of_platform_driver int (*shutdown)(struct of_device* dev); struct device_driver driver; + struct platform_driver platform_driver; }; #define to_of_platform_driver(drv) \ container_of(drv,struct of_platform_driver, driver) @@ -51,14 +52,8 @@ extern int of_register_driver(struct of_platform_driver *drv, extern void of_unregister_driver(struct of_platform_driver *drv); /* Platform drivers register/unregister */ -static inline int of_register_platform_driver(struct of_platform_driver *drv) -{ - return of_register_driver(drv, &of_platform_bus_type); -} -static inline void of_unregister_platform_driver(struct of_platform_driver *drv) -{ - of_unregister_driver(drv); -} +extern int of_register_platform_driver(struct of_platform_driver *drv); +extern void of_unregister_platform_driver(struct of_platform_driver *drv); extern struct of_device *of_device_alloc(struct device_node *np, const char *bus_id, -- cgit v1.2.3 From 1ab1d63a85cee2545272f63a7644e9f855cb65d0 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 24 Jun 2010 15:14:37 -0600 Subject: of/platform: remove all of_bus_type and of_platform_bus_type references Both of_bus_type and of_platform_bus_type are just #define aliases for the platform bus. This patch removes all references to them and switches to the of_register_platform_driver()/of_unregister_platform_driver() API for registering. Subsequent patches will convert each user of of_register_platform_driver() into plain platform_drivers without the of_platform_driver shim. At which point the of_register_platform_driver()/of_unregister_platform_driver() functions can be removed. Signed-off-by: Grant Likely Acked-by: David S. Miller --- arch/microblaze/kernel/of_platform.c | 3 +-- arch/powerpc/kernel/of_platform.c | 3 +-- arch/sparc/include/asm/of_platform.h | 2 -- arch/sparc/include/asm/parport.h | 4 +--- arch/sparc/kernel/apc.c | 2 +- arch/sparc/kernel/auxio_64.c | 2 +- arch/sparc/kernel/central.c | 4 ++-- arch/sparc/kernel/chmc.c | 4 ++-- arch/sparc/kernel/of_device_common.c | 2 +- arch/sparc/kernel/pci_fire.c | 2 +- arch/sparc/kernel/pci_psycho.c | 2 +- arch/sparc/kernel/pci_sabre.c | 2 +- arch/sparc/kernel/pci_schizo.c | 2 +- arch/sparc/kernel/pci_sun4v.c | 2 +- arch/sparc/kernel/pmc.c | 2 +- arch/sparc/kernel/power.c | 2 +- arch/sparc/kernel/time_32.c | 2 +- arch/sparc/kernel/time_64.c | 6 +++--- drivers/atm/fore200e.c | 6 +++--- drivers/char/hw_random/n2-drv.c | 4 ++-- drivers/crypto/n2_core.c | 10 +++++----- drivers/hwmon/ultra45_env.c | 4 ++-- drivers/input/misc/sparcspkr.c | 12 +++++------- drivers/input/serio/i8042-sparcio.h | 5 ++--- drivers/mtd/maps/sun_uflash.c | 4 ++-- drivers/net/ibm_newemac/core.c | 4 ++-- drivers/net/myri_sbus.c | 4 ++-- drivers/net/niu.c | 6 +++--- drivers/net/sunbmac.c | 4 ++-- drivers/net/sunhme.c | 4 ++-- drivers/net/sunlance.c | 4 ++-- drivers/net/sunqe.c | 4 ++-- drivers/parport/parport_sunbpp.c | 4 ++-- drivers/sbus/char/bbc_i2c.c | 4 ++-- drivers/sbus/char/display7seg.c | 4 ++-- drivers/sbus/char/envctrl.c | 4 ++-- drivers/sbus/char/flash.c | 4 ++-- drivers/sbus/char/uctrl.c | 4 ++-- drivers/scsi/qlogicpti.c | 4 ++-- drivers/scsi/sun_esp.c | 4 ++-- drivers/serial/sunhv.c | 4 ++-- drivers/serial/sunsab.c | 4 ++-- drivers/serial/sunsu.c | 2 +- drivers/serial/sunzilog.c | 6 +++--- drivers/video/bw2.c | 4 ++-- drivers/video/cg14.c | 4 ++-- drivers/video/cg3.c | 4 ++-- drivers/video/cg6.c | 4 ++-- drivers/video/ffb.c | 4 ++-- drivers/video/leo.c | 4 ++-- drivers/video/p9100.c | 4 ++-- drivers/video/sunxvr1000.c | 4 ++-- drivers/video/tcx.c | 4 ++-- drivers/watchdog/cpwd.c | 4 ++-- drivers/watchdog/riowd.c | 4 ++-- include/linux/of_platform.h | 6 ------ sound/sparc/amd7930.c | 4 ++-- sound/sparc/cs4231.c | 4 ++-- sound/sparc/dbri.c | 4 ++-- 59 files changed, 109 insertions(+), 124 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c index fb2866104331..80c9c493cb25 100644 --- a/arch/microblaze/kernel/of_platform.c +++ b/arch/microblaze/kernel/of_platform.c @@ -57,8 +57,7 @@ struct of_device *of_find_device_by_node(struct device_node *np) { struct device *dev; - dev = bus_find_device(&of_platform_bus_type, - NULL, np, of_dev_node_match); + dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); if (dev) return to_of_device(dev); return NULL; diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index d3497cd81e8a..b093d4b1f09c 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -61,8 +61,7 @@ struct of_device *of_find_device_by_node(struct device_node *np) { struct device *dev; - dev = bus_find_device(&of_platform_bus_type, - NULL, np, of_dev_node_match); + dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); if (dev) return to_of_device(dev); return NULL; diff --git a/arch/sparc/include/asm/of_platform.h b/arch/sparc/include/asm/of_platform.h index 90da99059f83..26540ddfc511 100644 --- a/arch/sparc/include/asm/of_platform.h +++ b/arch/sparc/include/asm/of_platform.h @@ -13,6 +13,4 @@ * */ -#define of_bus_type of_platform_bus_type /* for compatibility */ - #endif diff --git a/arch/sparc/include/asm/parport.h b/arch/sparc/include/asm/parport.h index 0c34a8792fc7..4891fbce1114 100644 --- a/arch/sparc/include/asm/parport.h +++ b/arch/sparc/include/asm/parport.h @@ -243,9 +243,7 @@ static struct of_platform_driver ecpp_driver = { static int parport_pc_find_nonpci_ports(int autoirq, int autodma) { - of_register_driver(&ecpp_driver, &of_bus_type); - - return 0; + return of_register_platform_driver(&ecpp_driver); } #endif /* !(_ASM_SPARC64_PARPORT_H */ diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index b27476caa133..c471251cd3f1 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c @@ -184,7 +184,7 @@ static struct of_platform_driver apc_driver = { static int __init apc_init(void) { - return of_register_driver(&apc_driver, &of_bus_type); + return of_register_platform_driver(&apc_driver); } /* This driver is not critical to the boot process diff --git a/arch/sparc/kernel/auxio_64.c b/arch/sparc/kernel/auxio_64.c index ddc84128b3c2..46ba58a8510f 100644 --- a/arch/sparc/kernel/auxio_64.c +++ b/arch/sparc/kernel/auxio_64.c @@ -142,7 +142,7 @@ static struct of_platform_driver auxio_driver = { static int __init auxio_init(void) { - return of_register_driver(&auxio_driver, &of_platform_bus_type); + return of_register_platform_driver(&auxio_driver); } /* Must be after subsys_initcall() so that busses are probed. Must diff --git a/arch/sparc/kernel/central.c b/arch/sparc/kernel/central.c index 434335f65823..b6080c39ed4b 100644 --- a/arch/sparc/kernel/central.c +++ b/arch/sparc/kernel/central.c @@ -265,8 +265,8 @@ static struct of_platform_driver fhc_driver = { static int __init sunfire_init(void) { - (void) of_register_driver(&fhc_driver, &of_platform_bus_type); - (void) of_register_driver(&clock_board_driver, &of_platform_bus_type); + (void) of_register_platform_driver(&fhc_driver); + (void) of_register_platform_driver(&clock_board_driver); return 0; } diff --git a/arch/sparc/kernel/chmc.c b/arch/sparc/kernel/chmc.c index 870cb65b3f21..04bb7df9f716 100644 --- a/arch/sparc/kernel/chmc.c +++ b/arch/sparc/kernel/chmc.c @@ -848,7 +848,7 @@ static int __init us3mc_init(void) ret = register_dimm_printer(us3mc_dimm_printer); if (!ret) { - ret = of_register_driver(&us3mc_driver, &of_bus_type); + ret = of_register_platform_driver(&us3mc_driver); if (ret) unregister_dimm_printer(us3mc_dimm_printer); } @@ -859,7 +859,7 @@ static void __exit us3mc_cleanup(void) { if (us3mc_platform()) { unregister_dimm_printer(us3mc_dimm_printer); - of_unregister_driver(&us3mc_driver); + of_unregister_platform_driver(&us3mc_driver); } } diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c index 01f380c7995c..2a5c639e4c3f 100644 --- a/arch/sparc/kernel/of_device_common.c +++ b/arch/sparc/kernel/of_device_common.c @@ -21,7 +21,7 @@ static int node_match(struct device *dev, void *data) struct of_device *of_find_device_by_node(struct device_node *dp) { - struct device *dev = bus_find_device(&of_platform_bus_type, NULL, + struct device *dev = bus_find_device(&platform_bus_type, NULL, dp, node_match); if (dev) diff --git a/arch/sparc/kernel/pci_fire.c b/arch/sparc/kernel/pci_fire.c index 51cfa09e392a..885f10b742e2 100644 --- a/arch/sparc/kernel/pci_fire.c +++ b/arch/sparc/kernel/pci_fire.c @@ -518,7 +518,7 @@ static struct of_platform_driver fire_driver = { static int __init fire_init(void) { - return of_register_driver(&fire_driver, &of_bus_type); + return of_register_platform_driver(&fire_driver); } subsys_initcall(fire_init); diff --git a/arch/sparc/kernel/pci_psycho.c b/arch/sparc/kernel/pci_psycho.c index 93011e6e7ddc..71550a7aacd8 100644 --- a/arch/sparc/kernel/pci_psycho.c +++ b/arch/sparc/kernel/pci_psycho.c @@ -612,7 +612,7 @@ static struct of_platform_driver psycho_driver = { static int __init psycho_init(void) { - return of_register_driver(&psycho_driver, &of_bus_type); + return of_register_platform_driver(&psycho_driver); } subsys_initcall(psycho_init); diff --git a/arch/sparc/kernel/pci_sabre.c b/arch/sparc/kernel/pci_sabre.c index 99c6dba7d4fd..2d7bf30552dd 100644 --- a/arch/sparc/kernel/pci_sabre.c +++ b/arch/sparc/kernel/pci_sabre.c @@ -606,7 +606,7 @@ static struct of_platform_driver sabre_driver = { static int __init sabre_init(void) { - return of_register_driver(&sabre_driver, &of_bus_type); + return of_register_platform_driver(&sabre_driver); } subsys_initcall(sabre_init); diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c index 9041dae7aaca..04f29c46bfa0 100644 --- a/arch/sparc/kernel/pci_schizo.c +++ b/arch/sparc/kernel/pci_schizo.c @@ -1501,7 +1501,7 @@ static struct of_platform_driver schizo_driver = { static int __init schizo_init(void) { - return of_register_driver(&schizo_driver, &of_bus_type); + return of_register_platform_driver(&schizo_driver); } subsys_initcall(schizo_init); diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index a24af6f7e17f..18ee8b6f4036 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -1019,7 +1019,7 @@ static struct of_platform_driver pci_sun4v_driver = { static int __init pci_sun4v_init(void) { - return of_register_driver(&pci_sun4v_driver, &of_bus_type); + return of_register_platform_driver(&pci_sun4v_driver); } subsys_initcall(pci_sun4v_init); diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c index 9589d8b9b0c1..a4c73edc8975 100644 --- a/arch/sparc/kernel/pmc.c +++ b/arch/sparc/kernel/pmc.c @@ -89,7 +89,7 @@ static struct of_platform_driver pmc_driver = { static int __init pmc_init(void) { - return of_register_driver(&pmc_driver, &of_bus_type); + return of_register_platform_driver(&pmc_driver); } /* This driver is not critical to the boot process diff --git a/arch/sparc/kernel/power.c b/arch/sparc/kernel/power.c index 1cfee577f6b5..abc194ed5a78 100644 --- a/arch/sparc/kernel/power.c +++ b/arch/sparc/kernel/power.c @@ -70,7 +70,7 @@ static struct of_platform_driver power_driver = { static int __init power_init(void) { - return of_register_driver(&power_driver, &of_platform_bus_type); + return of_register_platform_driver(&power_driver); } device_initcall(power_init); diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c index e404b063be2c..5dc20216952e 100644 --- a/arch/sparc/kernel/time_32.c +++ b/arch/sparc/kernel/time_32.c @@ -189,7 +189,7 @@ static struct of_platform_driver clock_driver = { /* Probe for the mostek real time clock chip. */ static int __init clock_init(void) { - return of_register_driver(&clock_driver, &of_platform_bus_type); + return of_register_platform_driver(&clock_driver); } /* Must be after subsys_initcall() so that busses are probed. Must * be before device_initcall() because things like the RTC driver diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 21e9fcae0668..2423b336a717 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -586,9 +586,9 @@ static int __init clock_init(void) if (tlb_type == hypervisor) return platform_device_register(&rtc_sun4v_device); - (void) of_register_driver(&rtc_driver, &of_platform_bus_type); - (void) of_register_driver(&mostek_driver, &of_platform_bus_type); - (void) of_register_driver(&bq4802_driver, &of_platform_bus_type); + (void) of_register_platform_driver(&rtc_driver); + (void) of_register_platform_driver(&mostek_driver); + (void) of_register_platform_driver(&bq4802_driver); return 0; } diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 38df87b198d5..b7385e077717 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2795,7 +2795,7 @@ static int __init fore200e_module_init(void) printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n"); #ifdef CONFIG_SBUS - err = of_register_driver(&fore200e_sba_driver, &of_bus_type); + err = of_register_platform_driver(&fore200e_sba_driver); if (err) return err; #endif @@ -2806,7 +2806,7 @@ static int __init fore200e_module_init(void) #ifdef CONFIG_SBUS if (err) - of_unregister_driver(&fore200e_sba_driver); + of_unregister_platform_driver(&fore200e_sba_driver); #endif return err; @@ -2818,7 +2818,7 @@ static void __exit fore200e_module_cleanup(void) pci_unregister_driver(&fore200e_pca_driver); #endif #ifdef CONFIG_SBUS - of_unregister_driver(&fore200e_sba_driver); + of_unregister_platform_driver(&fore200e_sba_driver); #endif } diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 0f9cbf1aaf15..d8a4ca87987d 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -762,12 +762,12 @@ static struct of_platform_driver n2rng_driver = { static int __init n2rng_init(void) { - return of_register_driver(&n2rng_driver, &of_bus_type); + return of_register_platform_driver(&n2rng_driver); } static void __exit n2rng_exit(void) { - of_unregister_driver(&n2rng_driver); + of_unregister_platform_driver(&n2rng_driver); } module_init(n2rng_init); diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 23163fda5035..34ac8ac8aaec 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -2070,20 +2070,20 @@ static struct of_platform_driver n2_mau_driver = { static int __init n2_init(void) { - int err = of_register_driver(&n2_crypto_driver, &of_bus_type); + int err = of_register_platform_driver(&n2_crypto_driver); if (!err) { - err = of_register_driver(&n2_mau_driver, &of_bus_type); + err = of_register_platform_driver(&n2_mau_driver); if (err) - of_unregister_driver(&n2_crypto_driver); + of_unregister_platform_driver(&n2_crypto_driver); } return err; } static void __exit n2_exit(void) { - of_unregister_driver(&n2_mau_driver); - of_unregister_driver(&n2_crypto_driver); + of_unregister_platform_driver(&n2_mau_driver); + of_unregister_platform_driver(&n2_crypto_driver); } module_init(n2_init); diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 5da5942cf970..89643261ccdb 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -311,12 +311,12 @@ static struct of_platform_driver env_driver = { static int __init env_init(void) { - return of_register_driver(&env_driver, &of_bus_type); + return of_register_platform_driver(&env_driver); } static void __exit env_exit(void) { - of_unregister_driver(&env_driver); + of_unregister_platform_driver(&env_driver); } module_init(env_init); diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index 1dacae4b43f0..f3bb92e9755f 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -353,14 +353,12 @@ static struct of_platform_driver grover_beep_driver = { static int __init sparcspkr_init(void) { - int err = of_register_driver(&bbc_beep_driver, - &of_platform_bus_type); + int err = of_register_platform_driver(&bbc_beep_driver); if (!err) { - err = of_register_driver(&grover_beep_driver, - &of_platform_bus_type); + err = of_register_platform_driver(&grover_beep_driver); if (err) - of_unregister_driver(&bbc_beep_driver); + of_unregister_platform_driver(&bbc_beep_driver); } return err; @@ -368,8 +366,8 @@ static int __init sparcspkr_init(void) static void __exit sparcspkr_exit(void) { - of_unregister_driver(&bbc_beep_driver); - of_unregister_driver(&grover_beep_driver); + of_unregister_platform_driver(&bbc_beep_driver); + of_unregister_platform_driver(&grover_beep_driver); } module_init(sparcspkr_init); diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index c7d50ff43fca..cb2a24b94746 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -116,8 +116,7 @@ static int __init i8042_platform_init(void) if (!kbd_iobase) return -ENODEV; } else { - int err = of_register_driver(&sparc_i8042_driver, - &of_bus_type); + int err = of_register_platform_driver(&sparc_i8042_driver); if (err) return err; @@ -141,7 +140,7 @@ static inline void i8042_platform_exit(void) struct device_node *root = of_find_node_by_path("/"); if (strcmp(root->name, "SUNW,JavaStation-1")) - of_unregister_driver(&sparc_i8042_driver); + of_unregister_platform_driver(&sparc_i8042_driver); } #else /* !CONFIG_PCI */ diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 0391c2527bd7..8984236a8d0a 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -160,12 +160,12 @@ static struct of_platform_driver uflash_driver = { static int __init uflash_init(void) { - return of_register_driver(&uflash_driver, &of_bus_type); + return of_register_platform_driver(&uflash_driver); } static void __exit uflash_exit(void) { - of_unregister_driver(&uflash_driver); + of_unregister_platform_driver(&uflash_driver); } module_init(uflash_init); diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index b150c102ca5a..f10476fb2623 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2339,11 +2339,11 @@ static int __devinit emac_wait_deps(struct emac_instance *dev) deps[EMAC_DEP_MDIO_IDX].phandle = dev->mdio_ph; if (dev->blist && dev->blist > emac_boot_list) deps[EMAC_DEP_PREV_IDX].phandle = 0xffffffffu; - bus_register_notifier(&of_platform_bus_type, &emac_of_bus_notifier); + bus_register_notifier(&platform_bus_type, &emac_of_bus_notifier); wait_event_timeout(emac_probe_wait, emac_check_deps(dev, deps), EMAC_PROBE_DEP_TIMEOUT); - bus_unregister_notifier(&of_platform_bus_type, &emac_of_bus_notifier); + bus_unregister_notifier(&platform_bus_type, &emac_of_bus_notifier); err = emac_check_deps(dev, deps) ? 0 : -ENODEV; for (i = 0; i < EMAC_DEP_COUNT; i++) { if (deps[i].node) diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 370d3c17f24c..04e552aa14ec 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -1172,12 +1172,12 @@ static struct of_platform_driver myri_sbus_driver = { static int __init myri_sbus_init(void) { - return of_register_driver(&myri_sbus_driver, &of_bus_type); + return of_register_platform_driver(&myri_sbus_driver); } static void __exit myri_sbus_exit(void) { - of_unregister_driver(&myri_sbus_driver); + of_unregister_platform_driver(&myri_sbus_driver); } module_init(myri_sbus_init); diff --git a/drivers/net/niu.c b/drivers/net/niu.c index f6ecf6180f72..8cb2b30eccae 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -10251,14 +10251,14 @@ static int __init niu_init(void) niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT); #ifdef CONFIG_SPARC64 - err = of_register_driver(&niu_of_driver, &of_bus_type); + err = of_register_platform_driver(&niu_of_driver); #endif if (!err) { err = pci_register_driver(&niu_pci_driver); #ifdef CONFIG_SPARC64 if (err) - of_unregister_driver(&niu_of_driver); + of_unregister_platform_driver(&niu_of_driver); #endif } @@ -10269,7 +10269,7 @@ static void __exit niu_exit(void) { pci_unregister_driver(&niu_pci_driver); #ifdef CONFIG_SPARC64 - of_unregister_driver(&niu_of_driver); + of_unregister_platform_driver(&niu_of_driver); #endif } diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 0b10d24de051..09c071bd6ad4 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1301,12 +1301,12 @@ static struct of_platform_driver bigmac_sbus_driver = { static int __init bigmac_init(void) { - return of_register_driver(&bigmac_sbus_driver, &of_bus_type); + return of_register_platform_driver(&bigmac_sbus_driver); } static void __exit bigmac_exit(void) { - of_unregister_driver(&bigmac_sbus_driver); + of_unregister_platform_driver(&bigmac_sbus_driver); } module_init(bigmac_init); diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 0a63ebef86a0..eec443f64079 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -3304,7 +3304,7 @@ static int __init happy_meal_sbus_init(void) { int err; - err = of_register_driver(&hme_sbus_driver, &of_bus_type); + err = of_register_platform_driver(&hme_sbus_driver); if (!err) err = quattro_sbus_register_irqs(); @@ -3313,7 +3313,7 @@ static int __init happy_meal_sbus_init(void) static void happy_meal_sbus_exit(void) { - of_unregister_driver(&hme_sbus_driver); + of_unregister_platform_driver(&hme_sbus_driver); quattro_sbus_free_irqs(); while (qfe_sbus_list) { diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index c6bfdad6c0c8..ee364fa75634 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1558,12 +1558,12 @@ static struct of_platform_driver sunlance_sbus_driver = { /* Find all the lance cards on the system and initialize them */ static int __init sparc_lance_init(void) { - return of_register_driver(&sunlance_sbus_driver, &of_bus_type); + return of_register_platform_driver(&sunlance_sbus_driver); } static void __exit sparc_lance_exit(void) { - of_unregister_driver(&sunlance_sbus_driver); + of_unregister_platform_driver(&sunlance_sbus_driver); } module_init(sparc_lance_init); diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 446517487084..5f84a5dadedd 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -988,12 +988,12 @@ static struct of_platform_driver qec_sbus_driver = { static int __init qec_init(void) { - return of_register_driver(&qec_sbus_driver, &of_bus_type); + return of_register_platform_driver(&qec_sbus_driver); } static void __exit qec_exit(void) { - of_unregister_driver(&qec_sbus_driver); + of_unregister_platform_driver(&qec_sbus_driver); while (root_qec_dev) { struct sunqec *next = root_qec_dev->next_module; diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 3cdfe96e8999..210a6441a066 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -393,12 +393,12 @@ static struct of_platform_driver bpp_sbus_driver = { static int __init parport_sunbpp_init(void) { - return of_register_driver(&bpp_sbus_driver, &of_bus_type); + return of_register_platform_driver(&bpp_sbus_driver); } static void __exit parport_sunbpp_exit(void) { - of_unregister_driver(&bpp_sbus_driver); + of_unregister_platform_driver(&bpp_sbus_driver); } MODULE_AUTHOR("Derrick J Brashear"); diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 40d7a1fc69af..3e89c313e98d 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -425,12 +425,12 @@ static struct of_platform_driver bbc_i2c_driver = { static int __init bbc_i2c_init(void) { - return of_register_driver(&bbc_i2c_driver, &of_bus_type); + return of_register_platform_driver(&bbc_i2c_driver); } static void __exit bbc_i2c_exit(void) { - of_unregister_driver(&bbc_i2c_driver); + of_unregister_platform_driver(&bbc_i2c_driver); } module_init(bbc_i2c_init); diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 7baf1b644039..8fd362e7fa65 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -277,12 +277,12 @@ static struct of_platform_driver d7s_driver = { static int __init d7s_init(void) { - return of_register_driver(&d7s_driver, &of_bus_type); + return of_register_platform_driver(&d7s_driver); } static void __exit d7s_exit(void) { - of_unregister_driver(&d7s_driver); + of_unregister_platform_driver(&d7s_driver); } module_init(d7s_init); diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index c8166ecf5276..2c76f700265b 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1142,12 +1142,12 @@ static struct of_platform_driver envctrl_driver = { static int __init envctrl_init(void) { - return of_register_driver(&envctrl_driver, &of_bus_type); + return of_register_platform_driver(&envctrl_driver); } static void __exit envctrl_exit(void) { - of_unregister_driver(&envctrl_driver); + of_unregister_platform_driver(&envctrl_driver); } module_init(envctrl_init); diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 368d66294d83..d79f386c3486 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -218,12 +218,12 @@ static struct of_platform_driver flash_driver = { static int __init flash_init(void) { - return of_register_driver(&flash_driver, &of_bus_type); + return of_register_platform_driver(&flash_driver); } static void __exit flash_cleanup(void) { - of_unregister_driver(&flash_driver); + of_unregister_platform_driver(&flash_driver); } module_init(flash_init); diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index b8b40e9eca79..57f0612bb013 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -437,12 +437,12 @@ static struct of_platform_driver uctrl_driver = { static int __init uctrl_init(void) { - return of_register_driver(&uctrl_driver, &of_bus_type); + return of_register_platform_driver(&uctrl_driver); } static void __exit uctrl_exit(void) { - of_unregister_driver(&uctrl_driver); + of_unregister_platform_driver(&uctrl_driver); } module_init(uctrl_init); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 3f5b5411e6bc..53d7ed0dc169 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1467,12 +1467,12 @@ static struct of_platform_driver qpti_sbus_driver = { static int __init qpti_init(void) { - return of_register_driver(&qpti_sbus_driver, &of_bus_type); + return of_register_platform_driver(&qpti_sbus_driver); } static void __exit qpti_exit(void) { - of_unregister_driver(&qpti_sbus_driver); + of_unregister_platform_driver(&qpti_sbus_driver); } MODULE_DESCRIPTION("QlogicISP SBUS driver"); diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index ddc221acd14c..89ba6fe02f80 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -644,12 +644,12 @@ static struct of_platform_driver esp_sbus_driver = { static int __init sunesp_init(void) { - return of_register_driver(&esp_sbus_driver, &of_bus_type); + return of_register_platform_driver(&esp_sbus_driver); } static void __exit sunesp_exit(void) { - of_unregister_driver(&esp_sbus_driver); + of_unregister_platform_driver(&esp_sbus_driver); } MODULE_DESCRIPTION("Sun ESP SCSI driver"); diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index 36e244867dd8..a779e22d213e 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -644,12 +644,12 @@ static int __init sunhv_init(void) if (tlb_type != hypervisor) return -ENODEV; - return of_register_driver(&hv_driver, &of_bus_type); + return of_register_platform_driver(&hv_driver); } static void __exit sunhv_exit(void) { - of_unregister_driver(&hv_driver); + of_unregister_platform_driver(&hv_driver); } module_init(sunhv_init); diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 0a7dd6841ff8..9845fb1cfb1f 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -1130,12 +1130,12 @@ static int __init sunsab_init(void) } } - return of_register_driver(&sab_driver, &of_bus_type); + return of_register_platform_driver(&sab_driver); } static void __exit sunsab_exit(void) { - of_unregister_driver(&sab_driver); + of_unregister_platform_driver(&sab_driver); if (sunsab_reg.nr) { sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr); } diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 5deafc8180b5..3cdf74822db5 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1586,7 +1586,7 @@ static int __init sunsu_init(void) return err; } - err = of_register_driver(&su_driver, &of_bus_type); + err = of_register_platform_driver(&su_driver); if (err && num_uart) sunserial_unregister_minors(&sunsu_reg, num_uart); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index fcbe20d48039..d1e6bcb59546 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1576,7 +1576,7 @@ static int __init sunzilog_init(void) goto out_free_tables; } - err = of_register_driver(&zs_driver, &of_bus_type); + err = of_register_platform_driver(&zs_driver); if (err) goto out_unregister_uart; @@ -1604,7 +1604,7 @@ out: return err; out_unregister_driver: - of_unregister_driver(&zs_driver); + of_unregister_platform_driver(&zs_driver); out_unregister_uart: if (num_sunzilog) { @@ -1619,7 +1619,7 @@ out_free_tables: static void __exit sunzilog_exit(void) { - of_unregister_driver(&zs_driver); + of_unregister_platform_driver(&zs_driver); if (zilog_irq != -1) { struct uart_sunzilog_port *up = sunzilog_irq_chain; diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 09f1b9b462f4..c7796637bafd 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -390,12 +390,12 @@ static int __init bw2_init(void) if (fb_get_options("bw2fb", NULL)) return -ENODEV; - return of_register_driver(&bw2_driver, &of_bus_type); + return of_register_platform_driver(&bw2_driver); } static void __exit bw2_exit(void) { - of_unregister_driver(&bw2_driver); + of_unregister_platform_driver(&bw2_driver); } module_init(bw2_init); diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index e5dc2241194f..d09fde8beb69 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -610,12 +610,12 @@ static int __init cg14_init(void) if (fb_get_options("cg14fb", NULL)) return -ENODEV; - return of_register_driver(&cg14_driver, &of_bus_type); + return of_register_platform_driver(&cg14_driver); } static void __exit cg14_exit(void) { - of_unregister_driver(&cg14_driver); + of_unregister_platform_driver(&cg14_driver); } module_init(cg14_init); diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 558d73a948a0..64aa29809fb9 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -477,12 +477,12 @@ static int __init cg3_init(void) if (fb_get_options("cg3fb", NULL)) return -ENODEV; - return of_register_driver(&cg3_driver, &of_bus_type); + return of_register_platform_driver(&cg3_driver); } static void __exit cg3_exit(void) { - of_unregister_driver(&cg3_driver); + of_unregister_platform_driver(&cg3_driver); } module_init(cg3_init); diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 480d761a27a8..2389a719dcc7 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -870,12 +870,12 @@ static int __init cg6_init(void) if (fb_get_options("cg6fb", NULL)) return -ENODEV; - return of_register_driver(&cg6_driver, &of_bus_type); + return of_register_platform_driver(&cg6_driver); } static void __exit cg6_exit(void) { - of_unregister_driver(&cg6_driver); + of_unregister_platform_driver(&cg6_driver); } module_init(cg6_init); diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 95c0227f47fc..f6ecfab296d3 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -1067,12 +1067,12 @@ static int __init ffb_init(void) if (fb_get_options("ffb", NULL)) return -ENODEV; - return of_register_driver(&ffb_driver, &of_bus_type); + return of_register_platform_driver(&ffb_driver); } static void __exit ffb_exit(void) { - of_unregister_driver(&ffb_driver); + of_unregister_platform_driver(&ffb_driver); } module_init(ffb_init); diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 9e8bf7d5e249..ad677637ffbb 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -677,12 +677,12 @@ static int __init leo_init(void) if (fb_get_options("leofb", NULL)) return -ENODEV; - return of_register_driver(&leo_driver, &of_bus_type); + return of_register_platform_driver(&leo_driver); } static void __exit leo_exit(void) { - of_unregister_driver(&leo_driver); + of_unregister_platform_driver(&leo_driver); } module_init(leo_init); diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 6552751e81aa..688b055abab2 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -367,12 +367,12 @@ static int __init p9100_init(void) if (fb_get_options("p9100fb", NULL)) return -ENODEV; - return of_register_driver(&p9100_driver, &of_bus_type); + return of_register_platform_driver(&p9100_driver); } static void __exit p9100_exit(void) { - of_unregister_driver(&p9100_driver); + of_unregister_platform_driver(&p9100_driver); } module_init(p9100_init); diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c index 489b44e8db81..7288934c0d49 100644 --- a/drivers/video/sunxvr1000.c +++ b/drivers/video/sunxvr1000.c @@ -213,12 +213,12 @@ static int __init gfb_init(void) if (fb_get_options("gfb", NULL)) return -ENODEV; - return of_register_driver(&gfb_driver, &of_bus_type); + return of_register_platform_driver(&gfb_driver); } static void __exit gfb_exit(void) { - of_unregister_driver(&gfb_driver); + of_unregister_platform_driver(&gfb_driver); } module_init(gfb_init); diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index cc039b33d2d8..f375e0db6776 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -526,12 +526,12 @@ static int __init tcx_init(void) if (fb_get_options("tcxfb", NULL)) return -ENODEV; - return of_register_driver(&tcx_driver, &of_bus_type); + return of_register_platform_driver(&tcx_driver); } static void __exit tcx_exit(void) { - of_unregister_driver(&tcx_driver); + of_unregister_platform_driver(&tcx_driver); } module_init(tcx_init); diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index 8c03fd71693e..30a2512fd52e 100644 --- a/drivers/watchdog/cpwd.c +++ b/drivers/watchdog/cpwd.c @@ -688,12 +688,12 @@ static struct of_platform_driver cpwd_driver = { static int __init cpwd_init(void) { - return of_register_driver(&cpwd_driver, &of_bus_type); + return of_register_platform_driver(&cpwd_driver); } static void __exit cpwd_exit(void) { - of_unregister_driver(&cpwd_driver); + of_unregister_platform_driver(&cpwd_driver); } module_init(cpwd_init); diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c index 5dceeddc8859..4082b4ace1fc 100644 --- a/drivers/watchdog/riowd.c +++ b/drivers/watchdog/riowd.c @@ -250,12 +250,12 @@ static struct of_platform_driver riowd_driver = { static int __init riowd_init(void) { - return of_register_driver(&riowd_driver, &of_bus_type); + return of_register_platform_driver(&riowd_driver); } static void __exit riowd_exit(void) { - of_unregister_driver(&riowd_driver); + of_unregister_platform_driver(&riowd_driver); } module_init(riowd_init); diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 133ecf31a60f..429513ae8f6e 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -19,12 +19,6 @@ #include #include -/* - * of_platform_bus_type isn't it's own bus anymore. It's now just an alias - * for the platform bus. - */ -#define of_platform_bus_type platform_bus_type - extern const struct of_device_id of_default_bus_ids[]; /* diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 43c63d441087..9eb1a4e0363b 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -1075,7 +1075,7 @@ static struct of_platform_driver amd7930_sbus_driver = { static int __init amd7930_init(void) { - return of_register_driver(&amd7930_sbus_driver, &of_bus_type); + return of_register_platform_driver(&amd7930_sbus_driver); } static void __exit amd7930_exit(void) @@ -1092,7 +1092,7 @@ static void __exit amd7930_exit(void) amd7930_list = NULL; - of_unregister_driver(&amd7930_sbus_driver); + of_unregister_platform_driver(&amd7930_sbus_driver); } module_init(amd7930_init); diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index f7f05c246303..68570ee2c9bb 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -2120,12 +2120,12 @@ static struct of_platform_driver cs4231_driver = { static int __init cs4231_init(void) { - return of_register_driver(&cs4231_driver, &of_bus_type); + return of_register_platform_driver(&cs4231_driver); } static void __exit cs4231_exit(void) { - of_unregister_driver(&cs4231_driver); + of_unregister_platform_driver(&cs4231_driver); } module_init(cs4231_init); diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 491ce71c84b6..c421901c48d0 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2699,12 +2699,12 @@ static struct of_platform_driver dbri_sbus_driver = { /* Probe for the dbri chip and then attach the driver. */ static int __init dbri_init(void) { - return of_register_driver(&dbri_sbus_driver, &of_bus_type); + return of_register_platform_driver(&dbri_sbus_driver); } static void __exit dbri_exit(void) { - of_unregister_driver(&dbri_sbus_driver); + of_unregister_platform_driver(&dbri_sbus_driver); } module_init(dbri_init); -- cgit v1.2.3 From 129ac799ad627b1e08382739f9e8cd75d7477fa3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 29 Jun 2010 09:26:53 -0700 Subject: of: remove asm/of_platform.h Only thing left in it is of_instantiate_rtc() which can be moved to asm/prom.h on PowerPC and is unused in microblaze. Signed-off-by: Grant Likely Acked-by: David S. Miller --- arch/microblaze/include/asm/of_platform.h | 19 ------------------- arch/powerpc/include/asm/of_platform.h | 16 ---------------- arch/powerpc/include/asm/prom.h | 2 ++ arch/sparc/include/asm/of_platform.h | 16 ---------------- include/linux/of_platform.h | 2 -- 5 files changed, 2 insertions(+), 53 deletions(-) delete mode 100644 arch/microblaze/include/asm/of_platform.h delete mode 100644 arch/powerpc/include/asm/of_platform.h delete mode 100644 arch/sparc/include/asm/of_platform.h (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/of_platform.h b/arch/microblaze/include/asm/of_platform.h deleted file mode 100644 index 353d8f651e30..000000000000 --- a/arch/microblaze/include/asm/of_platform.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. - * - * - * 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. - */ - -#ifndef _ASM_MICROBLAZE_OF_PLATFORM_H -#define _ASM_MICROBLAZE_OF_PLATFORM_H - -/* This is just here during the transition */ -#include - -extern void of_instantiate_rtc(void); - -#endif /* _ASM_MICROBLAZE_OF_PLATFORM_H */ diff --git a/arch/powerpc/include/asm/of_platform.h b/arch/powerpc/include/asm/of_platform.h deleted file mode 100644 index d506aa61db83..000000000000 --- a/arch/powerpc/include/asm/of_platform.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _ASM_POWERPC_OF_PLATFORM_H -#define _ASM_POWERPC_OF_PLATFORM_H -/* - * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. - * - * - * 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. - * - */ - -extern void of_instantiate_rtc(void); - -#endif /* _ASM_POWERPC_OF_PLATFORM_H */ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index f864722679e8..da7dd634e7ce 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -117,5 +117,7 @@ extern const void *of_get_mac_address(struct device_node *np); struct pci_dev; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); +extern void of_instantiate_rtc(void); + #endif /* __KERNEL__ */ #endif /* _POWERPC_PROM_H */ diff --git a/arch/sparc/include/asm/of_platform.h b/arch/sparc/include/asm/of_platform.h deleted file mode 100644 index 26540ddfc511..000000000000 --- a/arch/sparc/include/asm/of_platform.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ___ASM_SPARC_OF_PLATFORM_H -#define ___ASM_SPARC_OF_PLATFORM_H -/* - * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. - * - * Modified for Sparc by merging parts of asm/of_device.h - * by Stephen Rothwell - * - * 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. - * - */ - -#endif diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 429513ae8f6e..a79f59bf61a0 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -52,8 +52,6 @@ extern void of_unregister_platform_driver(struct of_platform_driver *drv); extern struct of_device *of_device_alloc(struct device_node *np, const char *bus_id, struct device *parent); -#include - extern struct of_device *of_find_device_by_node(struct device_node *np); extern int of_bus_type_init(struct bus_type *bus, const char *name); -- cgit v1.2.3 From 295960429675e17ec658320ebb24385727032bed Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 29 Jun 2010 11:15:54 -0600 Subject: of: remove asm/of_device.h It is mostly unused now. Sparc has a few defines left in it, but they can be moved to other headers. Removing this header means that new architectures adding CONFIG_OF support don't need to also add this header file. Signed-off-by: Grant Likely Acked-by: David S. Miller --- arch/microblaze/include/asm/of_device.h | 13 ------------- arch/powerpc/include/asm/of_device.h | 3 --- arch/sparc/include/asm/device.h | 2 ++ arch/sparc/include/asm/of_device.h | 19 ------------------- arch/sparc/include/asm/prom.h | 4 ++++ include/linux/of_device.h | 2 +- 6 files changed, 7 insertions(+), 36 deletions(-) delete mode 100644 arch/microblaze/include/asm/of_device.h delete mode 100644 arch/powerpc/include/asm/of_device.h delete mode 100644 arch/sparc/include/asm/of_device.h (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/of_device.h b/arch/microblaze/include/asm/of_device.h deleted file mode 100644 index 47e8d42aee8f..000000000000 --- a/arch/microblaze/include/asm/of_device.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) 2007-2008 Michal Simek - * - * based on PowerPC of_device.h - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#ifndef _ASM_MICROBLAZE_OF_DEVICE_H -#define _ASM_MICROBLAZE_OF_DEVICE_H -#endif /* _ASM_MICROBLAZE_OF_DEVICE_H */ diff --git a/arch/powerpc/include/asm/of_device.h b/arch/powerpc/include/asm/of_device.h deleted file mode 100644 index 04f76717f82c..000000000000 --- a/arch/powerpc/include/asm/of_device.h +++ /dev/null @@ -1,3 +0,0 @@ -#ifndef _ASM_POWERPC_OF_DEVICE_H -#define _ASM_POWERPC_OF_DEVICE_H -#endif /* _ASM_POWERPC_OF_DEVICE_H */ diff --git a/arch/sparc/include/asm/device.h b/arch/sparc/include/asm/device.h index fb220e482039..daa6a8a5e9cd 100644 --- a/arch/sparc/include/asm/device.h +++ b/arch/sparc/include/asm/device.h @@ -19,6 +19,8 @@ struct dev_archdata { int numa_node; }; +extern void of_propagate_archdata(struct platform_device *bus); + struct pdev_archdata { struct resource resource[PROMREG_MAX]; unsigned int irqs[PROMINTR_MAX]; diff --git a/arch/sparc/include/asm/of_device.h b/arch/sparc/include/asm/of_device.h deleted file mode 100644 index 22b9828fe693..000000000000 --- a/arch/sparc/include/asm/of_device.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _ASM_SPARC_OF_DEVICE_H -#define _ASM_SPARC_OF_DEVICE_H -#ifdef __KERNEL__ - -#include -#include -#include -#include - -extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); -extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size); - -extern void of_propagate_archdata(struct of_device *bus); - -/* This is just here during the transition */ -#include - -#endif /* __KERNEL__ */ -#endif /* _ASM_SPARC_OF_DEVICE_H */ diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index ac695742df85..d35df5ace18a 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -51,6 +51,10 @@ extern void prom_build_devicetree(void); extern void of_populate_present_mask(void); extern void of_fill_in_cpu_data(void); +struct resource; +extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); +extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size); + /* These routines are here to provide compatibility with how powerpc * handles IRQ mapping for OF device nodes. We precompute and permanently * register them in the of_device objects, whereas powerpc computes them diff --git a/include/linux/of_device.h b/include/linux/of_device.h index 8cd1fe7864e3..0f1911994559 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -16,12 +16,12 @@ */ #define of_device platform_device #include +#include /* temporary until merge */ #ifdef CONFIG_OF_DEVICE #include #include #include -#include #define to_of_device(d) container_of(d, struct of_device, dev) -- cgit v1.2.3 From 94a0cb1fc61ab7a0d47d268a7764374efeb2160b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 22 Jul 2010 13:59:23 -0600 Subject: of/device: Replace of_device with platform_device in includes and core code of_device is currently just an #define alias to platform_device until it gets removed entirely. This patch removes references to it from the include directories and the core drivers/of code. Signed-off-by: Grant Likely Acked-by: David S. Miller --- arch/powerpc/include/asm/macio.h | 2 +- arch/sparc/include/asm/floppy_64.h | 6 +++--- arch/sparc/include/asm/parport.h | 4 ++-- drivers/of/device.c | 22 +++++++++++----------- drivers/of/platform.c | 24 ++++++++++++------------ include/linux/of_device.h | 10 +++++----- include/linux/of_platform.h | 16 ++++++++-------- 7 files changed, 42 insertions(+), 42 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/macio.h b/arch/powerpc/include/asm/macio.h index 675e159b5ef4..7ab82c825a03 100644 --- a/arch/powerpc/include/asm/macio.h +++ b/arch/powerpc/include/asm/macio.h @@ -38,7 +38,7 @@ struct macio_dev { struct macio_bus *bus; /* macio bus this device is on */ struct macio_dev *media_bay; /* Device is part of a media bay */ - struct of_device ofdev; + struct platform_device ofdev; struct device_dma_parameters dma_parms; /* ide needs that */ int n_resources; struct resource resource[MACIO_DEV_COUNT_RESOURCES]; diff --git a/arch/sparc/include/asm/floppy_64.h b/arch/sparc/include/asm/floppy_64.h index 4f5bde638f72..6597ce874d78 100644 --- a/arch/sparc/include/asm/floppy_64.h +++ b/arch/sparc/include/asm/floppy_64.h @@ -43,7 +43,7 @@ struct sun_flpy_controller { /* You'll only ever find one controller on an Ultra anyways. */ static struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1; unsigned long fdc_status; -static struct of_device *floppy_op = NULL; +static struct platform_device *floppy_op = NULL; struct sun_floppy_ops { unsigned char (*fd_inb) (unsigned long port); @@ -548,7 +548,7 @@ static unsigned long __init sun_floppy_init(void) { static int initialized = 0; struct device_node *dp; - struct of_device *op; + struct platform_device *op; const char *prop; char state[128]; @@ -661,7 +661,7 @@ static unsigned long __init sun_floppy_init(void) config = 0; for (dp = ebus_dp->child; dp; dp = dp->sibling) { if (!strcmp(dp->name, "ecpp")) { - struct of_device *ecpp_op; + struct platform_device *ecpp_op; ecpp_op = of_find_device_by_node(dp); if (ecpp_op) diff --git a/arch/sparc/include/asm/parport.h b/arch/sparc/include/asm/parport.h index 4891fbce1114..4f7afa01b2ae 100644 --- a/arch/sparc/include/asm/parport.h +++ b/arch/sparc/include/asm/parport.h @@ -103,7 +103,7 @@ static inline unsigned int get_dma_residue(unsigned int dmanr) return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info); } -static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit ecpp_probe(struct platform_device *op, const struct of_device_id *match) { unsigned long base = op->resource[0].start; unsigned long config = op->resource[1].start; @@ -192,7 +192,7 @@ out_err: return err; } -static int __devexit ecpp_remove(struct of_device *op) +static int __devexit ecpp_remove(struct platform_device *op) { struct parport *p = dev_get_drvdata(&op->dev); int slot = p->dma; diff --git a/drivers/of/device.c b/drivers/of/device.c index 12a44b493511..0d8a0644f540 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -26,7 +26,7 @@ const struct of_device_id *of_match_device(const struct of_device_id *matches, } EXPORT_SYMBOL(of_match_device); -struct of_device *of_dev_get(struct of_device *dev) +struct platform_device *of_dev_get(struct platform_device *dev) { struct device *tmp; @@ -34,13 +34,13 @@ struct of_device *of_dev_get(struct of_device *dev) return NULL; tmp = get_device(&dev->dev); if (tmp) - return to_of_device(tmp); + return to_platform_device(tmp); else return NULL; } EXPORT_SYMBOL(of_dev_get); -void of_dev_put(struct of_device *dev) +void of_dev_put(struct platform_device *dev) { if (dev) put_device(&dev->dev); @@ -50,18 +50,18 @@ EXPORT_SYMBOL(of_dev_put); static ssize_t devspec_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct of_device *ofdev; + struct platform_device *ofdev; - ofdev = to_of_device(dev); + ofdev = to_platform_device(dev); return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name); } static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct of_device *ofdev; + struct platform_device *ofdev; - ofdev = to_of_device(dev); + ofdev = to_platform_device(dev); return sprintf(buf, "%s\n", ofdev->dev.of_node->name); } @@ -90,15 +90,15 @@ struct device_attribute of_platform_device_attrs[] = { */ void of_release_dev(struct device *dev) { - struct of_device *ofdev; + struct platform_device *ofdev; - ofdev = to_of_device(dev); + ofdev = to_platform_device(dev); of_node_put(ofdev->dev.of_node); kfree(ofdev); } EXPORT_SYMBOL(of_release_dev); -int of_device_register(struct of_device *ofdev) +int of_device_register(struct platform_device *ofdev) { BUG_ON(ofdev->dev.of_node == NULL); @@ -119,7 +119,7 @@ int of_device_register(struct of_device *ofdev) } EXPORT_SYMBOL(of_device_register); -void of_device_unregister(struct of_device *ofdev) +void of_device_unregister(struct platform_device *ofdev) { device_unregister(&ofdev->dev); } diff --git a/drivers/of/platform.c b/drivers/of/platform.c index f3f1ec81ef48..9f3840cdcde5 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -94,11 +94,11 @@ static int of_platform_device_probe(struct device *dev) { int error = -ENODEV; struct of_platform_driver *drv; - struct of_device *of_dev; + struct platform_device *of_dev; const struct of_device_id *match; drv = to_of_platform_driver(dev->driver); - of_dev = to_of_device(dev); + of_dev = to_platform_device(dev); if (!drv->probe) return error; @@ -116,7 +116,7 @@ static int of_platform_device_probe(struct device *dev) static int of_platform_device_remove(struct device *dev) { - struct of_device *of_dev = to_of_device(dev); + struct platform_device *of_dev = to_platform_device(dev); struct of_platform_driver *drv = to_of_platform_driver(dev->driver); if (dev->driver && drv->remove) @@ -126,7 +126,7 @@ static int of_platform_device_remove(struct device *dev) static void of_platform_device_shutdown(struct device *dev) { - struct of_device *of_dev = to_of_device(dev); + struct platform_device *of_dev = to_platform_device(dev); struct of_platform_driver *drv = to_of_platform_driver(dev->driver); if (dev->driver && drv->shutdown) @@ -137,7 +137,7 @@ static void of_platform_device_shutdown(struct device *dev) static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg) { - struct of_device *of_dev = to_of_device(dev); + struct platform_device *of_dev = to_platform_device(dev); struct of_platform_driver *drv = to_of_platform_driver(dev->driver); int ret = 0; @@ -148,7 +148,7 @@ static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg) static int of_platform_legacy_resume(struct device *dev) { - struct of_device *of_dev = to_of_device(dev); + struct platform_device *of_dev = to_platform_device(dev); struct of_platform_driver *drv = to_of_platform_driver(dev->driver); int ret = 0; @@ -543,11 +543,11 @@ static void of_device_make_bus_id(struct device *dev) * @bus_id: Name to assign to the device. May be null to use default name. * @parent: Parent device. */ -struct of_device *of_device_alloc(struct device_node *np, +struct platform_device *of_device_alloc(struct device_node *np, const char *bus_id, struct device *parent) { - struct of_device *dev; + struct platform_device *dev; int rc, i, num_reg = 0, num_irq = 0; struct resource *res, temp_res; @@ -600,11 +600,11 @@ EXPORT_SYMBOL(of_device_alloc); * @bus_id: name to assign device * @parent: Linux device model parent device. */ -struct of_device *of_platform_device_create(struct device_node *np, +struct platform_device *of_platform_device_create(struct device_node *np, const char *bus_id, struct device *parent) { - struct of_device *dev; + struct platform_device *dev; dev = of_device_alloc(np, bus_id, parent); if (!dev) @@ -642,7 +642,7 @@ static int of_platform_bus_create(const struct device_node *bus, struct device *parent) { struct device_node *child; - struct of_device *dev; + struct platform_device *dev; int rc = 0; for_each_child_of_node(bus, child) { @@ -678,7 +678,7 @@ int of_platform_bus_probe(struct device_node *root, struct device *parent) { struct device_node *child; - struct of_device *dev; + struct platform_device *dev; int rc = 0; if (matches == NULL) diff --git a/include/linux/of_device.h b/include/linux/of_device.h index 0f1911994559..e11a0be7893a 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -39,14 +39,14 @@ static inline int of_driver_match_device(const struct device *dev, return of_match_device(drv->of_match_table, dev) != NULL; } -extern struct of_device *of_dev_get(struct of_device *dev); -extern void of_dev_put(struct of_device *dev); +extern struct platform_device *of_dev_get(struct platform_device *dev); +extern void of_dev_put(struct platform_device *dev); -extern int of_device_register(struct of_device *ofdev); -extern void of_device_unregister(struct of_device *ofdev); +extern int of_device_register(struct platform_device *ofdev); +extern void of_device_unregister(struct platform_device *ofdev); extern void of_release_dev(struct device *dev); -static inline void of_device_free(struct of_device *dev) +static inline void of_device_free(struct platform_device *dev) { of_release_dev(&dev->dev); } diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index a79f59bf61a0..b24c5a5b0426 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -27,13 +27,13 @@ extern const struct of_device_id of_default_bus_ids[]; */ struct of_platform_driver { - int (*probe)(struct of_device* dev, + int (*probe)(struct platform_device* dev, const struct of_device_id *match); - int (*remove)(struct of_device* dev); + int (*remove)(struct platform_device* dev); - int (*suspend)(struct of_device* dev, pm_message_t state); - int (*resume)(struct of_device* dev); - int (*shutdown)(struct of_device* dev); + int (*suspend)(struct platform_device* dev, pm_message_t state); + int (*resume)(struct platform_device* dev); + int (*shutdown)(struct platform_device* dev); struct device_driver driver; struct platform_driver platform_driver; @@ -49,16 +49,16 @@ extern void of_unregister_driver(struct of_platform_driver *drv); extern int of_register_platform_driver(struct of_platform_driver *drv); extern void of_unregister_platform_driver(struct of_platform_driver *drv); -extern struct of_device *of_device_alloc(struct device_node *np, +extern struct platform_device *of_device_alloc(struct device_node *np, const char *bus_id, struct device *parent); -extern struct of_device *of_find_device_by_node(struct device_node *np); +extern struct platform_device *of_find_device_by_node(struct device_node *np); extern int of_bus_type_init(struct bus_type *bus, const char *name); #if !defined(CONFIG_SPARC) /* SPARC has its own device registration method */ /* Platform devices and busses creation */ -extern struct of_device *of_platform_device_create(struct device_node *np, +extern struct platform_device *of_platform_device_create(struct device_node *np, const char *bus_id, struct device *parent); -- cgit v1.2.3 From a454dc50590c6d758abba016a303a221f2f1b4b8 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 22 Jul 2010 15:52:34 -0600 Subject: powerpc: remove references to of_device and to_of_device of_device is just a #define alias to platform_device. This patch replaces all references to it with platform_device. Signed-off-by: Grant Likely --- arch/powerpc/kernel/ibmebus.c | 8 ++++---- arch/powerpc/kernel/of_platform.c | 8 ++++---- arch/powerpc/platforms/512x/clock.c | 2 +- arch/powerpc/platforms/52xx/mpc52xx_gpio.c | 6 +++--- arch/powerpc/platforms/52xx/mpc52xx_gpt.c | 4 ++-- arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c | 6 +++--- arch/powerpc/platforms/82xx/ep8248e.c | 4 ++-- arch/powerpc/platforms/83xx/suspend.c | 6 +++--- arch/powerpc/platforms/cell/axon_msi.c | 4 ++-- arch/powerpc/platforms/pasemi/gpio_mdio.c | 4 ++-- arch/powerpc/sysdev/axonram.c | 12 ++++++------ arch/powerpc/sysdev/bestcomm/bestcomm.c | 7 +++---- arch/powerpc/sysdev/fsl_msi.c | 4 ++-- arch/powerpc/sysdev/fsl_pmc.c | 3 ++- arch/powerpc/sysdev/fsl_rio.c | 4 ++-- arch/powerpc/sysdev/pmi.c | 6 +++--- arch/powerpc/sysdev/qe_lib/qe.c | 5 +++-- 17 files changed, 47 insertions(+), 46 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 21266abfbda6..9b626cfffce1 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -140,19 +140,19 @@ static struct dma_map_ops ibmebus_dma_ops = { static int ibmebus_match_path(struct device *dev, void *data) { - struct device_node *dn = to_of_device(dev)->dev.of_node; + struct device_node *dn = to_platform_device(dev)->dev.of_node; return (dn->full_name && (strcasecmp((char *)data, dn->full_name) == 0)); } static int ibmebus_match_node(struct device *dev, void *data) { - return to_of_device(dev)->dev.of_node == data; + return to_platform_device(dev)->dev.of_node == data; } static int ibmebus_create_device(struct device_node *dn) { - struct of_device *dev; + struct platform_device *dev; int ret; dev = of_device_alloc(dn, NULL, &ibmebus_bus_device); @@ -298,7 +298,7 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus, if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path, ibmebus_match_path))) { - of_device_unregister(to_of_device(dev)); + of_device_unregister(to_platform_device(dev)); kfree(path); return count; diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index b093d4b1f09c..84439d1b7cb3 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -54,16 +54,16 @@ const struct of_device_id of_default_bus_ids[] = { static int of_dev_node_match(struct device *dev, void *data) { - return to_of_device(dev)->dev.of_node == data; + return to_platform_device(dev)->dev.of_node == data; } -struct of_device *of_find_device_by_node(struct device_node *np) +struct platform_device *of_find_device_by_node(struct device_node *np) { struct device *dev; dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); if (dev) - return to_of_device(dev); + return to_platform_device(dev); return NULL; } EXPORT_SYMBOL(of_find_device_by_node); @@ -76,7 +76,7 @@ EXPORT_SYMBOL(of_find_device_by_node); * lacking some bits needed here. */ -static int __devinit of_pci_phb_probe(struct of_device *dev, +static int __devinit of_pci_phb_probe(struct platform_device *dev, const struct of_device_id *match) { struct pci_controller *phb; diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c index 4c42246b86a7..65e2d6729c1b 100644 --- a/arch/powerpc/platforms/512x/clock.c +++ b/arch/powerpc/platforms/512x/clock.c @@ -660,7 +660,7 @@ static void psc_clks_init(void) { struct device_node *np; const u32 *cell_index; - struct of_device *ofdev; + struct platform_device *ofdev; for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") { cell_index = of_get_property(np, "cell-index", NULL); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c index 0855e804fc0d..0dad9a935eb5 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c @@ -147,7 +147,7 @@ mpc52xx_wkup_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } -static int __devinit mpc52xx_wkup_gpiochip_probe(struct of_device *ofdev, +static int __devinit mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct mpc52xx_gpiochip *chip; @@ -179,7 +179,7 @@ static int __devinit mpc52xx_wkup_gpiochip_probe(struct of_device *ofdev, return 0; } -static int mpc52xx_gpiochip_remove(struct of_device *ofdev) +static int mpc52xx_gpiochip_remove(struct platform_device *ofdev) { return -EBUSY; } @@ -310,7 +310,7 @@ mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } -static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev, +static int __devinit mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct mpc52xx_gpiochip *chip; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index 5d7d607617cd..fea833e18ad5 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -720,7 +720,7 @@ static inline int mpc52xx_gpt_wdt_setup(struct mpc52xx_gpt_priv *gpt, /* --------------------------------------------------------------------- * of_platform bus binding code */ -static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev, +static int __devinit mpc52xx_gpt_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct mpc52xx_gpt_priv *gpt; @@ -766,7 +766,7 @@ static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev, return 0; } -static int mpc52xx_gpt_remove(struct of_device *ofdev) +static int mpc52xx_gpt_remove(struct platform_device *ofdev) { return -EBUSY; } diff --git a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c index e86aec644501..f4ac213c89c0 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c @@ -436,8 +436,8 @@ void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req) } EXPORT_SYMBOL(mpc52xx_lpbfifo_abort); -static int __devinit -mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit mpc52xx_lpbfifo_probe(struct platform_device *op, + const struct of_device_id *match) { struct resource res; int rc = -ENOMEM; @@ -507,7 +507,7 @@ mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match) } -static int __devexit mpc52xx_lpbfifo_remove(struct of_device *op) +static int __devexit mpc52xx_lpbfifo_remove(struct platform_device *op) { if (lpbfifo.dev != &op->dev) return 0; diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c index 9f2e52b36f91..1565e0446dc8 100644 --- a/arch/powerpc/platforms/82xx/ep8248e.c +++ b/arch/powerpc/platforms/82xx/ep8248e.c @@ -111,7 +111,7 @@ static struct mdiobb_ctrl ep8248e_mdio_ctrl = { .ops = &ep8248e_mdio_ops, }; -static int __devinit ep8248e_mdio_probe(struct of_device *ofdev, +static int __devinit ep8248e_mdio_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct mii_bus *bus; @@ -154,7 +154,7 @@ err_free_bus: return ret; } -static int ep8248e_mdio_remove(struct of_device *ofdev) +static int ep8248e_mdio_remove(struct platform_device *ofdev) { BUG(); return 0; diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index ebe6c3537209..75ae77f1af6a 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -99,7 +99,7 @@ struct pmc_type { int has_deep_sleep; }; -static struct of_device *pmc_dev; +static struct platform_device *pmc_dev; static int has_deep_sleep, deep_sleeping; static int pmc_irq; static struct mpc83xx_pmc __iomem *pmc_regs; @@ -318,7 +318,7 @@ static struct platform_suspend_ops mpc83xx_suspend_ops = { .end = mpc83xx_suspend_end, }; -static int pmc_probe(struct of_device *ofdev, +static int pmc_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct device_node *np = ofdev->dev.of_node; @@ -396,7 +396,7 @@ out: return ret; } -static int pmc_remove(struct of_device *ofdev) +static int pmc_remove(struct platform_device *ofdev) { return -EPERM; }; diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 6257e5378615..97085530aa63 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -328,7 +328,7 @@ static struct irq_host_ops msic_host_ops = { .map = msic_host_map, }; -static int axon_msi_shutdown(struct of_device *device) +static int axon_msi_shutdown(struct platform_device *device) { struct axon_msic *msic = dev_get_drvdata(&device->dev); u32 tmp; @@ -342,7 +342,7 @@ static int axon_msi_shutdown(struct of_device *device) return 0; } -static int axon_msi_probe(struct of_device *device, +static int axon_msi_probe(struct platform_device *device, const struct of_device_id *device_id) { struct device_node *dn = device->dev.of_node; diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index 627ee089e75d..a5d907b5a4c2 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -216,7 +216,7 @@ static int gpio_mdio_reset(struct mii_bus *bus) } -static int __devinit gpio_mdio_probe(struct of_device *ofdev, +static int __devinit gpio_mdio_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct device *dev = &ofdev->dev; @@ -275,7 +275,7 @@ out: } -static int gpio_mdio_remove(struct of_device *dev) +static int gpio_mdio_remove(struct platform_device *dev) { struct mii_bus *bus = dev_get_drvdata(&dev->dev); diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 402d2212162f..2659a60bd7b8 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -60,7 +60,7 @@ static int azfs_major, azfs_minor; struct axon_ram_bank { - struct of_device *device; + struct platform_device *device; struct gendisk *disk; unsigned int irq_id; unsigned long ph_addr; @@ -72,7 +72,7 @@ struct axon_ram_bank { static ssize_t axon_ram_sysfs_ecc(struct device *dev, struct device_attribute *attr, char *buf) { - struct of_device *device = to_of_device(dev); + struct platform_device *device = to_platform_device(dev); struct axon_ram_bank *bank = device->dev.platform_data; BUG_ON(!bank); @@ -90,7 +90,7 @@ static DEVICE_ATTR(ecc, S_IRUGO, axon_ram_sysfs_ecc, NULL); static irqreturn_t axon_ram_irq_handler(int irq, void *dev) { - struct of_device *device = dev; + struct platform_device *device = dev; struct axon_ram_bank *bank = device->dev.platform_data; BUG_ON(!bank); @@ -174,8 +174,8 @@ static const struct block_device_operations axon_ram_devops = { * axon_ram_probe - probe() method for platform driver * @device, @device_id: see of_platform_driver method */ -static int -axon_ram_probe(struct of_device *device, const struct of_device_id *device_id) +static int axon_ram_probe(struct platform_device *device, + const struct of_device_id *device_id) { static int axon_ram_bank_id = -1; struct axon_ram_bank *bank; @@ -304,7 +304,7 @@ failed: * @device: see of_platform_driver method */ static int -axon_ram_remove(struct of_device *device) +axon_ram_remove(struct platform_device *device) { struct axon_ram_bank *bank = device->dev.platform_data; diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c index a7c5c470af14..650256115064 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.c +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c @@ -365,8 +365,8 @@ bcom_engine_cleanup(void) /* OF platform driver */ /* ======================================================================== */ -static int __devinit -mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit mpc52xx_bcom_probe(struct platform_device *op, + const struct of_device_id *match) { struct device_node *ofn_sram; struct resource res_bcom; @@ -461,8 +461,7 @@ error_ofput: } -static int -mpc52xx_bcom_remove(struct of_device *op) +static int mpc52xx_bcom_remove(struct platform_device *op) { /* Clean up the engine */ bcom_engine_cleanup(); diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 962c2d8dd8d9..87991d3abbab 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -250,7 +250,7 @@ unlock: raw_spin_unlock(&desc->lock); } -static int fsl_of_msi_remove(struct of_device *ofdev) +static int fsl_of_msi_remove(struct platform_device *ofdev) { struct fsl_msi *msi = ofdev->dev.platform_data; int virq, i; @@ -274,7 +274,7 @@ static int fsl_of_msi_remove(struct of_device *ofdev) return 0; } -static int __devinit fsl_of_msi_probe(struct of_device *dev, +static int __devinit fsl_of_msi_probe(struct platform_device *dev, const struct of_device_id *match) { struct fsl_msi *msi; diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c index 9082eb921ad9..44de8559c975 100644 --- a/arch/powerpc/sysdev/fsl_pmc.c +++ b/arch/powerpc/sysdev/fsl_pmc.c @@ -58,7 +58,8 @@ static struct platform_suspend_ops pmc_suspend_ops = { .enter = pmc_suspend_enter, }; -static int pmc_probe(struct of_device *ofdev, const struct of_device_id *id) +static int pmc_probe(struct platform_device *ofdev, + const struct of_device_id *id) { pmc_regs = of_iomap(ofdev->dev.of_node, 0); if (!pmc_regs) diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index 30e1626b2e85..8bd86530ee25 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -1338,7 +1338,7 @@ static inline void fsl_rio_info(struct device *dev, u32 ccsr) * master port with system-specific info, and registers the * master port with the RapidIO subsystem. */ -int fsl_rio_setup(struct of_device *dev) +int fsl_rio_setup(struct platform_device *dev) { struct rio_ops *ops; struct rio_mport *port; @@ -1536,7 +1536,7 @@ err_ops: /* The probe function for RapidIO peer-to-peer network. */ -static int __devinit fsl_of_rio_rpn_probe(struct of_device *dev, +static int __devinit fsl_of_rio_rpn_probe(struct platform_device *dev, const struct of_device_id *match) { int rc; diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c index d07137a07d75..24a0bb955b18 100644 --- a/arch/powerpc/sysdev/pmi.c +++ b/arch/powerpc/sysdev/pmi.c @@ -43,7 +43,7 @@ struct pmi_data { struct mutex msg_mutex; pmi_message_t msg; struct completion *completion; - struct of_device *dev; + struct platform_device *dev; int irq; u8 __iomem *pmi_reg; struct work_struct work; @@ -121,7 +121,7 @@ static void pmi_notify_handlers(struct work_struct *work) spin_unlock(&data->handler_spinlock); } -static int pmi_of_probe(struct of_device *dev, +static int pmi_of_probe(struct platform_device *dev, const struct of_device_id *match) { struct device_node *np = dev->dev.of_node; @@ -185,7 +185,7 @@ out: return rc; } -static int pmi_of_remove(struct of_device *dev) +static int pmi_of_remove(struct platform_device *dev) { struct pmi_handler *handler, *tmp; diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 093e0ae1a941..3da8014931c9 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -651,14 +651,15 @@ unsigned int qe_get_num_of_snums(void) EXPORT_SYMBOL(qe_get_num_of_snums); #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) -static int qe_resume(struct of_device *ofdev) +static int qe_resume(struct platform_device *ofdev) { if (!qe_alive_during_sleep()) qe_reset(); return 0; } -static int qe_probe(struct of_device *ofdev, const struct of_device_id *id) +static int qe_probe(struct platform_device *ofdev, + const struct of_device_id *id) { return 0; } -- cgit v1.2.3 From c608558407aa64d2b98d58bfc116e95c0afb357e Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Fri, 23 Jul 2010 19:19:35 +0200 Subject: of: make of_find_device_by_node generic There's no need for this function to be architecture specific and all four architectures defining it had the same definition. The function has been moved to drivers/of/platform.c. Signed-off-by: Jonas Bonn [grant.likely@secretlab.ca: moved to drivers/of/platform.c, simplified code, and added kerneldoc comment] Signed-off-by: Grant Likely Acked-by: David S. Miller --- arch/microblaze/kernel/of_platform.c | 16 ---------------- arch/powerpc/kernel/of_platform.c | 16 ---------------- arch/sparc/kernel/of_device_common.c | 20 -------------------- drivers/of/platform.c | 20 ++++++++++++++++++++ 4 files changed, 20 insertions(+), 52 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c index c664b275a5fa..6cffadbe2fcd 100644 --- a/arch/microblaze/kernel/of_platform.c +++ b/arch/microblaze/kernel/of_platform.c @@ -47,19 +47,3 @@ const struct of_device_id of_default_bus_ids[] = { { .type = "simple", }, {}, }; - -static int of_dev_node_match(struct device *dev, void *data) -{ - return to_platform_device(dev)->dev.of_node == data; -} - -struct platform_device *of_find_device_by_node(struct device_node *np) -{ - struct device *dev; - - dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); - if (dev) - return to_platform_device(dev); - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_node); diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 84439d1b7cb3..760a7af7fdb5 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -52,22 +52,6 @@ const struct of_device_id of_default_bus_ids[] = { {}, }; -static int of_dev_node_match(struct device *dev, void *data) -{ - return to_platform_device(dev)->dev.of_node == data; -} - -struct platform_device *of_find_device_by_node(struct device_node *np) -{ - struct device *dev; - - dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); - if (dev) - return to_platform_device(dev); - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_node); - #ifdef CONFIG_PPC_OF_PLATFORM_PCI /* The probing of PCI controllers from of_platform is currently diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c index e80729bba028..49ddff56cb04 100644 --- a/arch/sparc/kernel/of_device_common.c +++ b/arch/sparc/kernel/of_device_common.c @@ -11,26 +11,6 @@ #include "of_device_common.h" -static int node_match(struct device *dev, void *data) -{ - struct platform_device *op = to_platform_device(dev); - struct device_node *dp = data; - - return (op->dev.of_node == dp); -} - -struct platform_device *of_find_device_by_node(struct device_node *dp) -{ - struct device *dev = bus_find_device(&platform_bus_type, NULL, - dp, node_match); - - if (dev) - return to_platform_device(dev); - - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_node); - unsigned int irq_of_parse_and_map(struct device_node *node, int index) { struct platform_device *op = of_find_device_by_node(node); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 9f3840cdcde5..f79f40b516c6 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -22,6 +22,26 @@ #include #include +static int of_dev_node_match(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +/** + * of_find_device_by_node - Find the platform_device associated with a node + * @np: Pointer to device tree node + * + * Returns platform_device pointer, or NULL if not found + */ +struct platform_device *of_find_device_by_node(struct device_node *np) +{ + struct device *dev; + + dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); + return dev ? to_platform_device(dev) : NULL; +} +EXPORT_SYMBOL(of_find_device_by_node); + static int platform_driver_probe_shim(struct platform_device *pdev) { struct platform_driver *pdrv; -- cgit v1.2.3 From c0dd394ca5e78649b7013c3ce2d6338af9f228f0 Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Fri, 23 Jul 2010 20:19:24 +0200 Subject: of: remove of_default_bus_ids This list used was by only two platforms with all other platforms defining an own list of valid bus id's to pass to of_platform_bus_probe. This patch: i) copies the default list to the two platforms that depended on it (powerpc) ii) remove the usage of of_default_bus_ids in of_platform_bus_probe iii) removes the definition of the list from all architectures that defined it Passing a NULL 'matches' parameter to of_platform_bus_probe is still valid; the function returns no error in that case as the NULL value is equivalent to an empty list. Signed-off-by: Jonas Bonn [grant.likely@secretlab.ca: added __initdata annotations, warn on and return error on missing match table, and fix whitespace errors] Signed-off-by: Grant Likely --- arch/microblaze/kernel/Makefile | 2 +- arch/microblaze/kernel/of_platform.c | 49 ------------------------------- arch/powerpc/kernel/of_platform.c | 24 --------------- arch/powerpc/platforms/cell/qpace_setup.c | 14 ++++++++- arch/powerpc/platforms/cell/setup.c | 14 ++++++++- drivers/of/platform.c | 4 +-- include/linux/of_platform.h | 2 -- 7 files changed, 28 insertions(+), 81 deletions(-) delete mode 100644 arch/microblaze/kernel/of_platform.c (limited to 'arch/powerpc') diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index 727e2cbff9c6..7fcc5f7b5a46 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile @@ -16,7 +16,7 @@ extra-y := head.o vmlinux.lds obj-y += dma.o exceptions.o \ hw_exception_handler.o init_task.o intc.o irq.o \ - of_platform.o process.o prom.o prom_parse.o ptrace.o \ + process.o prom.o prom_parse.o ptrace.o \ setup.o signal.o sys_microblaze.o timer.o traps.o reset.o obj-y += cpu/ diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c deleted file mode 100644 index 6cffadbe2fcd..000000000000 --- a/arch/microblaze/kernel/of_platform.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. - * - * and Arnd Bergmann, IBM Corp. - * - * 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. - * - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * The list of OF IDs below is used for matching bus types in the - * system whose devices are to be exposed as of_platform_devices. - * - * This is the default list valid for most platforms. This file provides - * functions who can take an explicit list if necessary though - * - * The search is always performed recursively looking for children of - * the provided device_node and recursively if such a children matches - * a bus type in the list - */ - -const struct of_device_id of_default_bus_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .type = "plb5", }, - { .type = "plb4", }, - { .type = "opb", }, - { .type = "simple", }, - {}, -}; diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 760a7af7fdb5..b2c363ef38ad 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -28,30 +28,6 @@ #include #include -/* - * The list of OF IDs below is used for matching bus types in the - * system whose devices are to be exposed as of_platform_devices. - * - * This is the default list valid for most platforms. This file provides - * functions who can take an explicit list if necessary though - * - * The search is always performed recursively looking for children of - * the provided device_node and recursively if such a children matches - * a bus type in the list - */ - -const struct of_device_id of_default_bus_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .type = "spider", }, - { .type = "axon", }, - { .type = "plb5", }, - { .type = "plb4", }, - { .type = "opb", }, - { .type = "ebc", }, - {}, -}; - #ifdef CONFIG_PPC_OF_PLATFORM_PCI /* The probing of PCI controllers from of_platform is currently diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c index c5ce02e84c8e..1b5749042756 100644 --- a/arch/powerpc/platforms/cell/qpace_setup.c +++ b/arch/powerpc/platforms/cell/qpace_setup.c @@ -61,12 +61,24 @@ static void qpace_progress(char *s, unsigned short hex) printk("*** %04x : %s\n", hex, s ? s : ""); } +static const struct of_device_id qpace_bus_ids[] __initdata = { + { .type = "soc", }, + { .compatible = "soc", }, + { .type = "spider", }, + { .type = "axon", }, + { .type = "plb5", }, + { .type = "plb4", }, + { .type = "opb", }, + { .type = "ebc", }, + {}, +}; + static int __init qpace_publish_devices(void) { int node; /* Publish OF platform devices for southbridge IOs */ - of_platform_bus_probe(NULL, NULL, NULL); + of_platform_bus_probe(NULL, qpace_bus_ids, NULL); /* There is no device for the MIC memory controller, thus we create * a platform device for it to attach the EDAC driver to. diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 50385db586bd..691995761b3d 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -141,6 +141,18 @@ static int __devinit cell_setup_phb(struct pci_controller *phb) return 0; } +static const struct of_device_id cell_bus_ids[] __initdata = { + { .type = "soc", }, + { .compatible = "soc", }, + { .type = "spider", }, + { .type = "axon", }, + { .type = "plb5", }, + { .type = "plb4", }, + { .type = "opb", }, + { .type = "ebc", }, + {}, +}; + static int __init cell_publish_devices(void) { struct device_node *root = of_find_node_by_path("/"); @@ -148,7 +160,7 @@ static int __init cell_publish_devices(void) int node; /* Publish OF platform devices for southbridge IOs */ - of_platform_bus_probe(NULL, NULL, NULL); + of_platform_bus_probe(NULL, cell_bus_ids, NULL); /* On spider based blades, we need to manually create the OF * platform devices for the PCI host bridges diff --git a/drivers/of/platform.c b/drivers/of/platform.c index f79f40b516c6..033a224a9fda 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -701,9 +701,7 @@ int of_platform_bus_probe(struct device_node *root, struct platform_device *dev; int rc = 0; - if (matches == NULL) - matches = of_default_bus_ids; - if (matches == OF_NO_DEEP_PROBE) + if (WARN_ON(!matches || matches == OF_NO_DEEP_PROBE)) return -EINVAL; if (root == NULL) root = of_find_node_by_path("/"); diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index b24c5a5b0426..4e6d989c06df 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -19,8 +19,6 @@ #include #include -extern const struct of_device_id of_default_bus_ids[]; - /* * An of_platform_driver driver is attached to a basic of_device on * the "platform bus" (platform_bus_type). -- cgit v1.2.3 From c76986cca8379db619de4b6c6b7359125df0e341 Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Fri, 16 Jul 2010 02:29:02 +0000 Subject: Remove REDWOOD_[456] config options and conditional code The config options for REDWOOD_[456] were commented out in the powerpc Kconfig. The ifdefs referencing this options therefore are dead and all references to this can be removed (Also dependencies in other KConfig files). Signed-off-by: Christian Dietrich Signed-off-by: Christoph Egger Acked-by: David S. Miller Acked-by: Benjamin Herrenschmidt Signed-off-by: Josh Boyer --- arch/powerpc/platforms/40x/Kconfig | 16 -------------- drivers/mtd/maps/Kconfig | 2 +- drivers/mtd/maps/redwood.c | 43 -------------------------------------- drivers/net/Kconfig | 2 +- drivers/net/smc91x.h | 37 -------------------------------- 5 files changed, 2 insertions(+), 98 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index ec64264f7a50..b72176434ebe 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -71,22 +71,6 @@ config MAKALU help This option enables support for the AMCC PPC405EX board. -#config REDWOOD_5 -# bool "Redwood-5" -# depends on 40x -# default n -# select STB03xxx -# help -# This option enables support for the IBM STB04 evaluation board. - -#config REDWOOD_6 -# bool "Redwood-6" -# depends on 40x -# default n -# select STB03xxx -# help -# This option enables support for the IBM STBx25xx evaluation board. - #config SYCAMORE # bool "Sycamore" # depends on 40x diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index f22bc9f05ddb..6629d09f3b38 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -321,7 +321,7 @@ config MTD_CFI_FLAGADM config MTD_REDWOOD tristate "CFI Flash devices mapped on IBM Redwood" - depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) + depends on MTD_CFI help This enables access routines for the flash chips on the IBM Redwood board. If you have one of these boards and would like to diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index 933c0b63b016..d2c9db00db0c 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c @@ -22,8 +22,6 @@ #include -#if !defined (CONFIG_REDWOOD_6) - #define WINDOW_ADDR 0xffc00000 #define WINDOW_SIZE 0x00400000 @@ -69,47 +67,6 @@ static struct mtd_partition redwood_flash_partitions[] = { } }; -#else /* CONFIG_REDWOOD_6 */ -/* FIXME: the window is bigger - armin */ -#define WINDOW_ADDR 0xff800000 -#define WINDOW_SIZE 0x00800000 - -#define RW_PART0_OF 0 -#define RW_PART0_SZ 0x400000 /* 4 MiB data */ -#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ -#define RW_PART1_SZ 0x10000 /* 64K VPD */ -#define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ -#define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) -#define RW_PART3_OF RW_PART2_OF + RW_PART2_SZ -#define RW_PART3_SZ 0x20000 - -static struct mtd_partition redwood_flash_partitions[] = { - { - .name = "Redwood filesystem", - .offset = RW_PART0_OF, - .size = RW_PART0_SZ - }, - { - .name = "Redwood OpenBIOS Vital Product Data", - .offset = RW_PART1_OF, - .size = RW_PART1_SZ, - .mask_flags = MTD_WRITEABLE /* force read-only */ - }, - { - .name = "Redwood kernel", - .offset = RW_PART2_OF, - .size = RW_PART2_SZ - }, - { - .name = "Redwood OpenBIOS", - .offset = RW_PART3_OF, - .size = RW_PART3_SZ, - .mask_flags = MTD_WRITEABLE /* force read-only */ - } -}; - -#endif /* CONFIG_REDWOOD_6 */ - struct map_info redwood_flash_map = { .name = "IBM Redwood", .size = WINDOW_SIZE, diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ce2fcdd4ab90..313d3060fc1d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -913,7 +913,7 @@ config SMC91X tristate "SMC 91C9x/91C1xxx support" select CRC32 select MII - depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || \ + depends on ARM || M32R || SUPERH || \ MIPS || BLACKFIN || MN10300 || COLDFIRE help This is a driver for SMC's 91x series of Ethernet chipsets, diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 8d2772cc42f2..ee747919a766 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -83,43 +83,6 @@ static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg) } } -#elif defined(CONFIG_REDWOOD_5) || defined(CONFIG_REDWOOD_6) - -/* We can only do 16-bit reads and writes in the static memory space. */ -#define SMC_CAN_USE_8BIT 0 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 -#define SMC_NOWAIT 1 - -#define SMC_IO_SHIFT 0 - -#define SMC_inw(a, r) in_be16((volatile u16 *)((a) + (r))) -#define SMC_outw(v, a, r) out_be16((volatile u16 *)((a) + (r)), v) -#define SMC_insw(a, r, p, l) \ - do { \ - unsigned long __port = (a) + (r); \ - u16 *__p = (u16 *)(p); \ - int __l = (l); \ - insw(__port, __p, __l); \ - while (__l > 0) { \ - *__p = swab16(*__p); \ - __p++; \ - __l--; \ - } \ - } while (0) -#define SMC_outsw(a, r, p, l) \ - do { \ - unsigned long __port = (a) + (r); \ - u16 *__p = (u16 *)(p); \ - int __l = (l); \ - while (__l > 0) { \ - /* Believe it or not, the swab isn't needed. */ \ - outw( /* swab16 */ (*__p++), __port); \ - __l--; \ - } \ - } while (0) -#define SMC_IRQ_FLAGS (0) - #elif defined(CONFIG_SA1100_PLEB) /* We can only do 16-bit reads and writes in the static memory space. */ #define SMC_CAN_USE_8BIT 1 -- cgit v1.2.3 From 9a52e392bd053f1d282488517125c6c1ab77006a Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 3 Jun 2010 22:29:59 +0000 Subject: powerpc/44x: Fix UART2/3 interrupt assignment in PPC460EX/GT dts files UART2 and UART3 on 460EX/GT have incorrect interrupt mappings right now. UART2 should be 28 (0x1c) and UART3 29 (0x1d). This patch fixes this and switches to using decimal number instead of hex, since the AppliedMicro (AMCC) users manuals describe their inerrupt numbers in decimal. Thanks to Fabien Proriol for pointing this out. Signed-off-by: Stefan Roese Cc: Fabien Proriol Cc: Josh Boyer Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/canyonlands.dts | 4 ++-- arch/powerpc/boot/dts/glacier.dts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts index cd56bb5b347b..5806ef0b860b 100644 --- a/arch/powerpc/boot/dts/canyonlands.dts +++ b/arch/powerpc/boot/dts/canyonlands.dts @@ -270,7 +270,7 @@ clock-frequency = <0>; /* Filled in by U-Boot */ current-speed = <0>; /* Filled in by U-Boot */ interrupt-parent = <&UIC1>; - interrupts = <0x1d 0x4>; + interrupts = <28 0x4>; }; UART3: serial@ef600600 { @@ -281,7 +281,7 @@ clock-frequency = <0>; /* Filled in by U-Boot */ current-speed = <0>; /* Filled in by U-Boot */ interrupt-parent = <&UIC1>; - interrupts = <0x1e 0x4>; + interrupts = <29 0x4>; }; IIC0: i2c@ef600700 { diff --git a/arch/powerpc/boot/dts/glacier.dts b/arch/powerpc/boot/dts/glacier.dts index d62a4fb6f93c..e618fc4cbc9e 100644 --- a/arch/powerpc/boot/dts/glacier.dts +++ b/arch/powerpc/boot/dts/glacier.dts @@ -259,7 +259,7 @@ clock-frequency = <0>; /* Filled in by U-Boot */ current-speed = <0>; /* Filled in by U-Boot */ interrupt-parent = <&UIC1>; - interrupts = <0x1d 0x4>; + interrupts = <28 0x4>; }; UART3: serial@ef600600 { @@ -270,7 +270,7 @@ clock-frequency = <0>; /* Filled in by U-Boot */ current-speed = <0>; /* Filled in by U-Boot */ interrupt-parent = <&UIC1>; - interrupts = <0x1e 0x4>; + interrupts = <29 0x4>; }; IIC0: i2c@ef600700 { -- cgit v1.2.3 From ff349103964d43c28b7b80bdecf7ace0113b3dda Mon Sep 17 00:00:00 2001 From: Lee Nipper Date: Fri, 9 Jul 2010 01:17:16 +0000 Subject: powerpc/40x: Distinguish AMCC PowerPC 405EX and 405EXr correctly The recent AMCC 405EX Rev D without Security uses a PVR value that matches the old 405EXr Rev A/B with Security. The 405EX Rev D without Security would be shown incorrectly as an 405EXr. The pvr_mask of 0xffff0004 is no longer sufficient to distinguish the 405EX from 405EXr. This patch replaces 2 entries in the cpu_specs table and adds 8 more, each using pvr_mask of 0xffff000f and appropriate pvr_value to distinguish the AMCC PowerPC 405EX and 405EXr instances. The cpu_name for these entries now includes the Rev, in similar fashion to the 440GX. Signed-off-by: Lee Nipper Signed-off-by: Josh Boyer --- arch/powerpc/kernel/cputable.c | 118 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 7 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 87aa0f3c6047..65e2b4e10f97 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1364,10 +1364,10 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check = machine_check_4xx, .platform = "ppc405", }, - { /* 405EX */ - .pvr_mask = 0xffff0004, - .pvr_value = 0x12910004, - .cpu_name = "405EX", + { /* 405EX Rev. A/B with Security */ + .pvr_mask = 0xffff000f, + .pvr_value = 0x12910007, + .cpu_name = "405EX Rev. A/B", .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, @@ -1377,10 +1377,114 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check = machine_check_4xx, .platform = "ppc405", }, - { /* 405EXr */ - .pvr_mask = 0xffff0004, + { /* 405EX Rev. C without Security */ + .pvr_mask = 0xffff000f, + .pvr_value = 0x1291000d, + .cpu_name = "405EX Rev. C", + .cpu_features = CPU_FTRS_40X, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, + .icache_bsize = 32, + .dcache_bsize = 32, + .machine_check = machine_check_4xx, + .platform = "ppc405", + }, + { /* 405EX Rev. C with Security */ + .pvr_mask = 0xffff000f, + .pvr_value = 0x1291000f, + .cpu_name = "405EX Rev. C", + .cpu_features = CPU_FTRS_40X, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, + .icache_bsize = 32, + .dcache_bsize = 32, + .machine_check = machine_check_4xx, + .platform = "ppc405", + }, + { /* 405EX Rev. D without Security */ + .pvr_mask = 0xffff000f, + .pvr_value = 0x12910003, + .cpu_name = "405EX Rev. D", + .cpu_features = CPU_FTRS_40X, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, + .icache_bsize = 32, + .dcache_bsize = 32, + .machine_check = machine_check_4xx, + .platform = "ppc405", + }, + { /* 405EX Rev. D with Security */ + .pvr_mask = 0xffff000f, + .pvr_value = 0x12910005, + .cpu_name = "405EX Rev. D", + .cpu_features = CPU_FTRS_40X, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, + .icache_bsize = 32, + .dcache_bsize = 32, + .machine_check = machine_check_4xx, + .platform = "ppc405", + }, + { /* 405EXr Rev. A/B without Security */ + .pvr_mask = 0xffff000f, + .pvr_value = 0x12910001, + .cpu_name = "405EXr Rev. A/B", + .cpu_features = CPU_FTRS_40X, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, + .icache_bsize = 32, + .dcache_bsize = 32, + .machine_check = machine_check_4xx, + .platform = "ppc405", + }, + { /* 405EXr Rev. C without Security */ + .pvr_mask = 0xffff000f, + .pvr_value = 0x12910009, + .cpu_name = "405EXr Rev. C", + .cpu_features = CPU_FTRS_40X, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, + .icache_bsize = 32, + .dcache_bsize = 32, + .machine_check = machine_check_4xx, + .platform = "ppc405", + }, + { /* 405EXr Rev. C with Security */ + .pvr_mask = 0xffff000f, + .pvr_value = 0x1291000b, + .cpu_name = "405EXr Rev. C", + .cpu_features = CPU_FTRS_40X, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, + .icache_bsize = 32, + .dcache_bsize = 32, + .machine_check = machine_check_4xx, + .platform = "ppc405", + }, + { /* 405EXr Rev. D without Security */ + .pvr_mask = 0xffff000f, .pvr_value = 0x12910000, - .cpu_name = "405EXr", + .cpu_name = "405EXr Rev. D", + .cpu_features = CPU_FTRS_40X, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .mmu_features = MMU_FTR_TYPE_40x, + .icache_bsize = 32, + .dcache_bsize = 32, + .machine_check = machine_check_4xx, + .platform = "ppc405", + }, + { /* 405EXr Rev. D with Security */ + .pvr_mask = 0xffff000f, + .pvr_value = 0x12910002, + .cpu_name = "405EXr Rev. D", .cpu_features = CPU_FTRS_40X, .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, -- cgit v1.2.3 From 559e2b7ee7a1c7753d534abcb2742a4775339293 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 23 Jul 2010 20:11:18 -0600 Subject: of: Provide default of_node_to_nid() implementation. of_node_to_nid() is only relevant in a few architectures. Don't force everyone to implement it anyway. Signed-off-by: Grant Likely --- arch/microblaze/include/asm/topology.h | 10 ---------- arch/powerpc/include/asm/prom.h | 7 +++++++ arch/powerpc/include/asm/topology.h | 7 ------- arch/sparc/include/asm/prom.h | 3 +-- include/linux/of.h | 5 +++++ 5 files changed, 13 insertions(+), 19 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/topology.h b/arch/microblaze/include/asm/topology.h index 96bcea5a9920..5428f333a02c 100644 --- a/arch/microblaze/include/asm/topology.h +++ b/arch/microblaze/include/asm/topology.h @@ -1,11 +1 @@ #include - -#ifndef _ASM_MICROBLAZE_TOPOLOGY_H -#define _ASM_MICROBLAZE_TOPOLOGY_H - -struct device_node; -static inline int of_node_to_nid(struct device_node *device) -{ - return 0; -} -#endif /* _ASM_MICROBLAZE_TOPOLOGY_H */ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index da7dd634e7ce..55bccc0a21c3 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -103,6 +103,13 @@ struct device_node *of_find_next_cache_node(struct device_node *np); /* Get the MAC address */ extern const void *of_get_mac_address(struct device_node *np); +#ifdef CONFIG_NUMA +extern int of_node_to_nid(struct device_node *device); +#else +static inline int of_node_to_nid(struct device_node *device) { return 0; } +#endif +#define of_node_to_nid of_node_to_nid + /** * of_irq_map_pci - Resolve the interrupt for a PCI device * @pdev: the device whose interrupt is to be resolved diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 32adf7280720..09dd38c8882c 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -41,8 +41,6 @@ static inline int cpu_to_node(int cpu) cpu_all_mask : \ node_to_cpumask_map[node]) -int of_node_to_nid(struct device_node *device); - struct pci_bus; #ifdef CONFIG_PCI extern int pcibus_to_node(struct pci_bus *bus); @@ -94,11 +92,6 @@ extern void sysfs_remove_device_from_node(struct sys_device *dev, int nid); #else -static inline int of_node_to_nid(struct device_node *device) -{ - return 0; -} - static inline void dump_numa_cpu_topology(void) {} static inline int sysfs_add_device_to_node(struct sys_device *dev, int nid) diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index c82a7da25f9f..291f12575edd 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -43,8 +43,7 @@ extern int of_getintprop_default(struct device_node *np, extern int of_find_in_proplist(const char *list, const char *match, int len); #ifdef CONFIG_NUMA extern int of_node_to_nid(struct device_node *dp); -#else -#define of_node_to_nid(dp) (-1) +#define of_node_to_nid of_node_to_nid #endif extern void prom_build_devicetree(void); diff --git a/include/linux/of.h b/include/linux/of.h index b0756f33249e..cad7cf0ab278 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -146,6 +146,11 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size) #define OF_BAD_ADDR ((u64)-1) +#ifndef of_node_to_nid +static inline int of_node_to_nid(struct device_node *np) { return -1; } +#define of_node_to_nid of_node_to_nid +#endif + extern struct device_node *of_find_node_by_name(struct device_node *from, const char *name); #define for_each_node_by_name(dn, name) \ -- cgit v1.2.3 From fc53b4202e61c7e9008c241933ae282aab8a6082 Mon Sep 17 00:00:00 2001 From: Matt Evans Date: Wed, 7 Jul 2010 21:55:37 +0000 Subject: powerpc/kexec: Switch to a static PACA on the way out With dynamic PACAs, the kexecing CPU's PACA won't lie within the kernel static data and there is a chance that something may stomp it when preparing to kexec. This patch switches this final CPU to a static PACA just before we pull the switch. Signed-off-by: Matt Evans Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/paca.h | 2 +- arch/powerpc/kernel/machine_kexec_64.c | 20 ++++++++++++++++++++ arch/powerpc/kernel/paca.c | 10 ++++++++++ arch/powerpc/kernel/setup_64.c | 10 ---------- 4 files changed, 31 insertions(+), 11 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 8ce7963ad41d..1ff6662f7faf 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -146,7 +146,7 @@ struct paca_struct { extern struct paca_struct *paca; extern __initdata struct paca_struct boot_paca; extern void initialise_paca(struct paca_struct *new_paca, int cpu); - +extern void setup_paca(struct paca_struct *new_paca); extern void allocate_pacas(void); extern void free_unused_pacas(void); diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index de6b70eac51d..022d2f613b7b 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -260,6 +260,12 @@ static void kexec_prepare_cpus(void) static union thread_union kexec_stack __init_task_data = { }; +/* + * For similar reasons to the stack above, the kexecing CPU needs to be on a + * static PACA; we switch to kexec_paca. + */ +struct paca_struct kexec_paca; + /* Our assembly helper, in kexec_stub.S */ extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start, void *image, void *control, @@ -287,6 +293,20 @@ void default_machine_kexec(struct kimage *image) kexec_stack.thread_info.task = current_thread_info()->task; kexec_stack.thread_info.flags = 0; + /* We need a static PACA, too; copy this CPU's PACA over and switch to + * it. Also poison per_cpu_offset to catch anyone using non-static + * data. + */ + memcpy(&kexec_paca, get_paca(), sizeof(struct paca_struct)); + kexec_paca.data_offset = 0xedeaddeadeeeeeeeUL; + paca = (struct paca_struct *)RELOC_HIDE(&kexec_paca, 0) - + kexec_paca.paca_index; + setup_paca(&kexec_paca); + + /* XXX: If anyone does 'dynamic lppacas' this will also need to be + * switched to a static version! + */ + /* Some things are best done in assembly. Finding globals with * a toc is easier in C, so pass in what we can. */ diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index f88acf0218db..3db8d64f40e1 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -105,6 +105,16 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) #endif /* CONFIG_PPC_STD_MMU_64 */ } +/* Put the paca pointer into r13 and SPRG_PACA */ +void setup_paca(struct paca_struct *new_paca) +{ + local_paca = new_paca; + mtspr(SPRN_SPRG_PACA, local_paca); +#ifdef CONFIG_PPC_BOOK3E + mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); +#endif +} + static int __initdata paca_size; void __init allocate_pacas(void) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index c352f322dbdd..96e662c1d46b 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -142,16 +142,6 @@ early_param("smt-enabled", early_smt_enabled); #define check_smt_enabled() #endif /* CONFIG_SMP */ -/* Put the paca pointer into r13 and SPRG_PACA */ -static void __init setup_paca(struct paca_struct *new_paca) -{ - local_paca = new_paca; - mtspr(SPRN_SPRG_PACA, local_paca); -#ifdef CONFIG_PPC_BOOK3E - mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); -#endif -} - /* * Early initialization entry point. This is called by head.S * with MMU translation disabled. We rely on the "feature" of -- cgit v1.2.3 From bbc8e30f17077f83fdeeeca0cf70e0f179279282 Mon Sep 17 00:00:00 2001 From: Matthew McClintock Date: Wed, 21 Jul 2010 11:14:54 +0000 Subject: powerpc/crashdump: Fix issues with kexec and 36bit physical addr Fix sizes of variables so correct values are exported via /proc. Cast variable in comparison to avoid compiler error. Signed-off-by: Matthew McClintock Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/crash_dump.c | 4 ++-- arch/powerpc/kernel/machine_kexec.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 5fb667a60894..d254132f08f6 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -128,9 +128,9 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, if (!csize) return 0; - csize = min(csize, PAGE_SIZE); + csize = min_t(size_t, csize, PAGE_SIZE); - if (pfn < max_pfn) { + if ((min_low_pfn < pfn) && (pfn < max_pfn)) { vaddr = __va(pfn << PAGE_SHIFT); csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); } else { diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index bb3d893a8353..6ff15f03dcc4 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -144,24 +144,24 @@ int overlaps_crashkernel(unsigned long start, unsigned long size) } /* Values we need to export to the second kernel via the device tree. */ -static unsigned long kernel_end; -static unsigned long crashk_size; +static phys_addr_t kernel_end; +static phys_addr_t crashk_size; static struct property kernel_end_prop = { .name = "linux,kernel-end", - .length = sizeof(unsigned long), + .length = sizeof(phys_addr_t), .value = &kernel_end, }; static struct property crashk_base_prop = { .name = "linux,crashkernel-base", - .length = sizeof(unsigned long), + .length = sizeof(phys_addr_t), .value = &crashk_res.start, }; static struct property crashk_size_prop = { .name = "linux,crashkernel-size", - .length = sizeof(unsigned long), + .length = sizeof(phys_addr_t), .value = &crashk_size, }; -- cgit v1.2.3 From ea01c6b487d53571e2e5f15a0fd41700c1e0486d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 12 Jul 2010 10:49:55 +0000 Subject: powerpc: Remove unnecessary casts of private_data Signed-off-by: Joe Perches Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kvm/timing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kvm/timing.c b/arch/powerpc/kvm/timing.c index 70378551c0cc..46fa04f12a9b 100644 --- a/arch/powerpc/kvm/timing.c +++ b/arch/powerpc/kvm/timing.c @@ -182,7 +182,7 @@ static ssize_t kvmppc_exit_timing_write(struct file *file, } if (c == 'c') { - struct seq_file *seqf = (struct seq_file *)file->private_data; + struct seq_file *seqf = file->private_data; struct kvm_vcpu *vcpu = seqf->private; /* Write does not affect our buffers previously generated with * show. seq_file is locked here to prevent races of init with -- cgit v1.2.3 From 67238fb721639046b5d76488317522af4ece9d61 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 13 Jul 2010 03:46:09 +0000 Subject: powerpc: Add vmcoreinfo symbols to allow makdumpfile to filter core files properly Signed-off-by: Neil Horman machine_kexec.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) Reviewed-by: WANG Cong Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/machine_kexec.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index 6ff15f03dcc4..47905c092861 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -45,6 +45,18 @@ void machine_kexec_cleanup(struct kimage *image) ppc_md.machine_kexec_cleanup(image); } +void arch_crash_save_vmcoreinfo(void) +{ + +#ifdef CONFIG_NEED_MULTIPLE_NODES + VMCOREINFO_SYMBOL(node_data); + VMCOREINFO_LENGTH(node_data, MAX_NUMNODES); +#endif +#ifndef CONFIG_NEED_MULTIPLE_NODES + VMCOREINFO_SYMBOL(contig_page_data); +#endif +} + /* * Do not allocate memory (or fail in any way) in machine_kexec(). * We are past the point of no return, committed to rebooting now. -- cgit v1.2.3 From e9ae9dabfc1df26d5eff0102c4d359f534e11087 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 14 Jul 2010 08:48:13 +0000 Subject: powerpc: Remove redundant xics badness warning While testing cpu offlining, we are regularly seeing the WARN_ON go off in xics_ipi_dispatch. It can occur when an IPI gets sent to the CPU while it is going offline. There is already a similar WARN_ON in the handlers for PPC_MSG_CALL_FUNCTION and PPC_MSG_CALL_FUNC_SINGLE, so the warning is not needed in that path. The debugger handler handles this case by simply ignoring IPIs for offline CPUs, so no warning is needed there. And the reschedule IPI, which is what is occurring in our test environment, can be safely ignored, so we can simply remove the WARN_ON from xics_ipi_dispatch. Signed-off-by: Brian King Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/xics.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index f19d19468393..5b22b07c8f67 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -549,8 +549,6 @@ static irqreturn_t xics_ipi_dispatch(int cpu) { unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); - WARN_ON(cpu_is_offline(cpu)); - mb(); /* order mmio clearing qirr */ while (*tgt) { if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) { -- cgit v1.2.3 From 1927445a7376e183072e6147a9641088b9b6a30e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 15 Jul 2010 07:38:16 +0000 Subject: powerpc: Fix GENERIC_ISA_DMA dependency On PowerPC we should always use generic ISA DMA API implementation as there is simply no other implementation exist. Without this patch, the following build error pops up: sound/built-in.o: In function 'snd_dma_pointer': (.text+0x74ae): undefined reference to 'dma_spin_lock' ... make: *** [.tmp_vmlinux1] Error 1 This is PPC_85xx, SMP and some sound drivers set to =y. Signed-off-by: Anton Vorontsov Acked-by: Dave Liu Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 25b28fdc6767..4fa420381044 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -669,7 +669,7 @@ config NEED_SG_DMA_LENGTH config GENERIC_ISA_DMA bool - depends on PPC64 || POWER4 || 6xx && !CPM2 + depends on ISA_DMA_API default y config PPC_INDIRECT_PCI -- cgit v1.2.3 From d77cb21b578a5428482bc0fd187f7c0518a0b32a Mon Sep 17 00:00:00 2001 From: Tiejun Chen Date: Thu, 15 Jul 2010 20:17:11 +0000 Subject: powerpc/smp: remove the incorrect decrementer initial codes for AP We already defined start_cpu_decrementer() to invoke decrementer for AP as the following path: start_secondary() -> secondary_cpu_time_init() -> start_cpu_decrementer() So remove these incorrect codes introduced from commit: e7f75ad0 powerpc/47x: Base ppc476 support And actually we really should not enable decrementer before calling set_dec(). Signed-off-by: Tiejun Chen Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/smp.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 8764daad309b..a61b3ddd7bb3 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -499,14 +499,6 @@ int __devinit start_secondary(void *unused) current->active_mm = &init_mm; smp_store_cpu_info(cpu); - -#if defined(CONFIG_BOOKE) || defined(CONFIG_40x) - /* Clear any pending timer interrupts */ - mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); - - /* Enable decrementer interrupt */ - mtspr(SPRN_TCR, TCR_DIE); -#endif set_dec(tb_ticks_per_jiffy); preempt_disable(); cpu_callin_map[cpu] = 1; -- cgit v1.2.3 From 940ce422a367c8e65404a5ef1ff5969527a06410 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 31 Jul 2010 15:04:15 +1000 Subject: powerpc/pseries: Increase cpu die timeout In testing SMT disable, we have been regularly seeing the following message: Querying DEAD? cpu %i (%i) shows %i This indicates the current delay in pseries_cpu_die where we wait for the specified CPU to die, is insufficient. Usually, this does not cause a problem, but we've seen this result in BUG_ON's going off in the timer code when we try to migrate the timers off the dead cpu while a timer is still running. Increasing this delay, as is done in this patch, seems to resolve this issue. Signed-off-by: Brian King Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/hotplug-cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index bbe507635364..fd50ccd4bac1 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -193,12 +193,12 @@ static void pseries_cpu_die(unsigned int cpu) if (get_preferred_offline_state(cpu) == CPU_STATE_INACTIVE) { cpu_status = 1; - for (tries = 0; tries < 1000; tries++) { + for (tries = 0; tries < 5000; tries++) { if (get_cpu_current_state(cpu) == CPU_STATE_INACTIVE) { cpu_status = 0; break; } - cpu_relax(); + msleep(1); } } else if (get_preferred_offline_state(cpu) == CPU_STATE_OFFLINE) { -- cgit v1.2.3 From ff4bb7cb9feea3d8851c0e7837dce15822acf11b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 31 Jul 2010 15:05:15 +1000 Subject: powerpc/powermac: Add PowerMac10,2 machine descriptor This adds support for the Mac Mini's that were quietly rolled out in 2005. Work still needs to be done to support suspend and WakeOnLan. Signed-off-by: Mark Crichton Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powermac/feature.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 9e1b9fd75206..79bd3e89dbaf 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2191,7 +2191,11 @@ static struct pmac_mb_def pmac_mb_defs[] = { PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, PMAC_MB_MAY_SLEEP, }, - { "iMac,1", "iMac (first generation)", + { "PowerMac10,2", "Mac mini (Late 2005)", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_MAY_SLEEP, + }, + { "iMac,1", "iMac (first generation)", PMAC_TYPE_ORIG_IMAC, paddington_features, 0 }, -- cgit v1.2.3 From ceddee23be9fda04b928aa309fd95931bc4efb96 Mon Sep 17 00:00:00 2001 From: Robert Jennings Date: Thu, 22 Jul 2010 16:43:44 +0000 Subject: powerpc: ONLINE to OFFLINE CPU state transition during removal If a CPU remove is attempted using the 'release' interface on hardware which supports extended cede, the CPU will be put in the INACTIVE state rather than the OFFLINE state due to the default preferred_offline_state in that situation. In the INACTIVE state it will fail to be removed. This patch changes the preferred offline state to OFFLINE when an CPU is in the ONLINE state. After cpu_down() is called in dlpar_offline_cpu() the CPU will be OFFLINE and CPU removal can continue. Signed-off-by: Robert Jennings Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/dlpar.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index d71e58584086..227c1c3d585e 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -463,6 +463,7 @@ static int dlpar_offline_cpu(struct device_node *dn) break; if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) { + set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); cpu_maps_update_done(); rc = cpu_down(cpu); if (rc) -- cgit v1.2.3 From 2c48a7d615b82e030196e8b61ab0c7933be16dff Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 27 Jul 2010 18:26:21 +0000 Subject: powerpc: Print decimal values in prom_init.c Currently we look pretty stupid when printing out a bunch of things in prom_init.c. eg. Max number of cores passed to firmware: 0x0000000000000080 So I've change this to print in decimal: Max number of cores passed to firmware: 128 (NR_CPUS = 256) This required adding a prom_print_dec() function and changing some prom_printk() calls from %x to %lu. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/prom_init.c | 44 ++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 3b6f8ae9b8cc..941ff4dbc567 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -311,6 +311,24 @@ static void __init prom_print_hex(unsigned long val) call_prom("write", 3, 1, _prom->stdout, buf, nibbles); } +/* max number of decimal digits in an unsigned long */ +#define UL_DIGITS 21 +static void __init prom_print_dec(unsigned long val) +{ + int i, size; + char buf[UL_DIGITS+1]; + struct prom_t *_prom = &RELOC(prom); + + for (i = UL_DIGITS-1; i >= 0; i--) { + buf[i] = (val % 10) + '0'; + val = val/10; + if (val == 0) + break; + } + /* shift stuff down */ + size = UL_DIGITS - i; + call_prom("write", 3, 1, _prom->stdout, buf+i, size); +} static void __init prom_printf(const char *format, ...) { @@ -350,6 +368,14 @@ static void __init prom_printf(const char *format, ...) v = va_arg(args, unsigned long); prom_print_hex(v); break; + case 'l': + ++q; + if (*q == 'u') { /* '%lu' */ + ++q; + v = va_arg(args, unsigned long); + prom_print_dec(v); + } + break; } } } @@ -835,11 +861,11 @@ static int __init prom_count_smt_threads(void) if (plen == PROM_ERROR) break; plen >>= 2; - prom_debug("Found 0x%x smt threads per core\n", (unsigned long)plen); + prom_debug("Found %lu smt threads per core\n", (unsigned long)plen); /* Sanity check */ if (plen < 1 || plen > 64) { - prom_printf("Threads per core 0x%x out of bounds, assuming 1\n", + prom_printf("Threads per core %lu out of bounds, assuming 1\n", (unsigned long)plen); return 1; } @@ -869,12 +895,12 @@ static void __init prom_send_capabilities(void) cores = (u32 *)PTRRELOC(&ibm_architecture_vec[IBM_ARCH_VEC_NRCORES_OFFSET]); if (*cores != NR_CPUS) { prom_printf("WARNING ! " - "ibm_architecture_vec structure inconsistent: 0x%x !\n", + "ibm_architecture_vec structure inconsistent: %lu!\n", *cores); } else { *cores = DIV_ROUND_UP(NR_CPUS, prom_count_smt_threads()); - prom_printf("Max number of cores passed to firmware: 0x%x\n", - (unsigned long)*cores); + prom_printf("Max number of cores passed to firmware: %lu (NR_CPUS = %lu)\n", + *cores, NR_CPUS); } /* try calling the ibm,client-architecture-support method */ @@ -1482,7 +1508,7 @@ static void __init prom_hold_cpus(void) reg = -1; prom_getprop(node, "reg", ®, sizeof(reg)); - prom_debug("cpu hw idx = 0x%x\n", reg); + prom_debug("cpu hw idx = %lu\n", reg); /* Init the acknowledge var which will be reset by * the secondary cpu when it awakens from its OF @@ -1492,7 +1518,7 @@ static void __init prom_hold_cpus(void) if (reg != _prom->cpu) { /* Primary Thread of non-boot cpu */ - prom_printf("starting cpu hw idx %x... ", reg); + prom_printf("starting cpu hw idx %lu... ", reg); call_prom("start-cpu", 3, 0, node, secondary_hold, reg); @@ -1507,7 +1533,7 @@ static void __init prom_hold_cpus(void) } #ifdef CONFIG_SMP else - prom_printf("boot cpu hw idx %x\n", reg); + prom_printf("boot cpu hw idx %lu\n", reg); #endif /* CONFIG_SMP */ } @@ -2420,7 +2446,7 @@ static void __init prom_find_boot_cpu(void) prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); _prom->cpu = getprop_rval; - prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); + prom_debug("Booting CPU hw index = %lu\n", _prom->cpu); } static void __init prom_check_initrd(unsigned long r3, unsigned long r4) -- cgit v1.2.3 From e2f7f73717c0a2927bbe7551d90b1ec47a094361 Mon Sep 17 00:00:00 2001 From: Matt Evans Date: Thu, 29 Jul 2010 18:47:17 +0000 Subject: powerpc/kexec: Add to and tidy debug/comments in machine_kexec64.c Tidies some typos, KERN_INFO-ise an info msg, and add a debug msg showing when the final sequence starts. Also adds a comment to kexec_prepare_cpus_wait() to make note of a possible problem; the need for kexec to deal with CPUs that failed to originally start up. Signed-off-by: Matt Evans Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/machine_kexec_64.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 022d2f613b7b..a0bcec3614e1 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -184,7 +185,20 @@ static void kexec_prepare_cpus_wait(int wait_state) hw_breakpoint_disable(); my_cpu = get_cpu(); - /* Make sure each CPU has atleast made it to the state we need */ + /* Make sure each CPU has at least made it to the state we need. + * + * FIXME: There is a (slim) chance of a problem if not all of the CPUs + * are correctly onlined. If somehow we start a CPU on boot with RTAS + * start-cpu, but somehow that CPU doesn't write callin_cpu_map[] in + * time, the boot CPU will timeout. If it does eventually execute + * stuff, the secondary will start up (paca[].cpu_start was written) and + * get into a peculiar state. If the platform supports + * smp_ops->take_timebase(), the secondary CPU will probably be spinning + * in there. If not (i.e. pseries), the secondary will continue on and + * try to online itself/idle/etc. If it survives that, we need to find + * these possible-but-not-online-but-should-be CPUs and chaperone them + * into kexec_smp_wait(). + */ for_each_online_cpu(i) { if (i == my_cpu) continue; @@ -192,9 +206,9 @@ static void kexec_prepare_cpus_wait(int wait_state) while (paca[i].kexec_state < wait_state) { barrier(); if (i != notified) { - printk( "kexec: waiting for cpu %d (physical" - " %d) to enter %i state\n", - i, paca[i].hw_cpu_id, wait_state); + printk(KERN_INFO "kexec: waiting for cpu %d " + "(physical %d) to enter %i state\n", + i, paca[i].hw_cpu_id, wait_state); notified = i; } } @@ -218,7 +232,10 @@ static void kexec_prepare_cpus(void) if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(0, 0); - /* Before removing MMU mapings make sure all CPUs have entered real mode */ + /* + * Before removing MMU mappings make sure all CPUs have entered real + * mode: + */ kexec_prepare_cpus_wait(KEXEC_STATE_REAL_MODE); put_cpu(); @@ -287,6 +304,8 @@ void default_machine_kexec(struct kimage *image) if (crashing_cpu == -1) kexec_prepare_cpus(); + pr_debug("kexec: Starting switchover sequence.\n"); + /* switch to a staticly allocated stack. Based on irq stack code. * XXX: the task struct will likely be invalid once we do the copy! */ -- cgit v1.2.3 From e8e5c2155b0035b6e04f29be67f6444bc914005b Mon Sep 17 00:00:00 2001 From: Matt Evans Date: Thu, 29 Jul 2010 18:49:08 +0000 Subject: powerpc/kexec: Fix orphaned offline CPUs across kexec When CPU hotplug is used, some CPUs may be offline at the time a kexec is performed. The subsequent kernel may expect these CPUs to be already running, and will declare them stuck. On pseries, there's also a soft-offline (cede) state that CPUs may be in; this can also cause problems as the kexeced kernel may ask RTAS if they're online -- and RTAS would say they are. The CPU will either appear stuck, or will cause a crash as we replace its cede loop beneath it. This patch kicks each present offline CPU awake before the kexec, so that none are forever lost to these assumptions in the subsequent kernel. Now, the behaviour is that all available CPUs that were offlined are now online & usable after the kexec. This mimics the behaviour of a full reboot (on which all CPUs will be restarted). Signed-off-by: Matt Evans Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/machine_kexec_64.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index a0bcec3614e1..583af70c4b14 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -216,9 +217,32 @@ static void kexec_prepare_cpus_wait(int wait_state) mb(); } -static void kexec_prepare_cpus(void) +/* + * We need to make sure each present CPU is online. The next kernel will scan + * the device tree and assume primary threads are online and query secondary + * threads via RTAS to online them if required. If we don't online primary + * threads, they will be stuck. However, we also online secondary threads as we + * may be using 'cede offline'. In this case RTAS doesn't see the secondary + * threads as offline -- and again, these CPUs will be stuck. + * + * So, we online all CPUs that should be running, including secondary threads. + */ +static void wake_offline_cpus(void) { + int cpu = 0; + + for_each_present_cpu(cpu) { + if (!cpu_online(cpu)) { + printk(KERN_INFO "kexec: Waking offline cpu %d.\n", + cpu); + cpu_up(cpu); + } + } +} +static void kexec_prepare_cpus(void) +{ + wake_offline_cpus(); smp_call_function(kexec_smp_down, NULL, /* wait */0); local_irq_disable(); mb(); /* make sure IRQs are disabled before we say they are */ -- cgit v1.2.3 From 22ae782f86b726f9cea752c0f269ff6dcdf2f6e1 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 29 Jul 2010 11:49:01 -0600 Subject: of/address: Clean up function declarations This patch moves the declaration of of_get_address(), of_get_pci_address(), and of_pci_address_to_resource() out of arch code and into the common linux/of_address header file. This patch also fixes some of the asm/prom.h ordering issues. It still includes some header files that it ideally shouldn't be, but at least the ordering is consistent now so that of_* overrides work. Signed-off-by: Grant Likely --- arch/microblaze/include/asm/prom.h | 33 +++++++-------------- arch/powerpc/include/asm/prom.h | 49 +++++++------------------------ arch/powerpc/kernel/legacy_serial.c | 1 + arch/powerpc/kernel/pci-common.c | 1 + arch/powerpc/platforms/52xx/lite5200.c | 1 + arch/powerpc/platforms/amigaone/setup.c | 3 +- arch/powerpc/platforms/iseries/mf.c | 1 + arch/powerpc/platforms/powermac/feature.c | 2 ++ arch/powerpc/sysdev/bestcomm/sram.c | 1 + arch/powerpc/sysdev/fsl_gtm.c | 1 + drivers/char/bsr.c | 1 + drivers/net/fsl_pq_mdio.c | 1 + drivers/net/xilinx_emaclite.c | 2 +- drivers/serial/uartlite.c | 1 + drivers/spi/mpc512x_psc_spi.c | 1 + drivers/spi/mpc52xx_psc_spi.c | 1 + drivers/spi/xilinx_spi_of.c | 1 + drivers/usb/gadget/fsl_qe_udc.c | 1 + drivers/video/controlfb.c | 2 ++ drivers/video/offb.c | 3 +- include/linux/of_address.h | 32 ++++++++++++++++++++ 21 files changed, 76 insertions(+), 63 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index cb9c3dd9a23b..101fa098f62a 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -20,11 +20,6 @@ #ifndef __ASSEMBLY__ #include -#include -#include -#include -#include -#include #include #include @@ -52,25 +47,9 @@ extern void pci_create_OF_bus_map(void); * OF address retreival & translation */ -/* Extract an address from a device, returns the region size and - * the address space flags too. The PCI version uses a BAR number - * instead of an absolute index - */ -extern const u32 *of_get_address(struct device_node *dev, int index, - u64 *size, unsigned int *flags); -extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no, - u64 *size, unsigned int *flags); - -extern int of_pci_address_to_resource(struct device_node *dev, int bar, - struct resource *r); - #ifdef CONFIG_PCI extern unsigned long pci_address_to_pio(phys_addr_t address); -#else -static inline unsigned long pci_address_to_pio(phys_addr_t address) -{ - return (unsigned long)-1; -} +#define pci_address_to_pio pci_address_to_pio #endif /* CONFIG_PCI */ /* Parse the ibm,dma-window property of an OF node into the busno, phys and @@ -99,8 +78,18 @@ extern const void *of_get_mac_address(struct device_node *np); * resolving using the OF tree walking. */ struct pci_dev; +struct of_irq; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ + +/* These includes are put at the bottom because they may contain things + * that are overridden by this file. Ideally they shouldn't be included + * by this file, but there are a bunch of .c files that currently depend + * on it. Eventually they will be cleaned up. */ +#include +#include +#include + #endif /* _ASM_MICROBLAZE_PROM_H */ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index 55bccc0a21c3..ae26f2efd089 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -17,11 +17,6 @@ * 2 of the License, or (at your option) any later version. */ #include -#include -#include -#include -#include -#include #include #include @@ -49,41 +44,9 @@ extern void pci_create_OF_bus_map(void); extern u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr); -/* Extract an address from a device, returns the region size and - * the address space flags too. The PCI version uses a BAR number - * instead of an absolute index - */ -extern const u32 *of_get_address(struct device_node *dev, int index, - u64 *size, unsigned int *flags); -#ifdef CONFIG_PCI -extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no, - u64 *size, unsigned int *flags); -#else -static inline const u32 *of_get_pci_address(struct device_node *dev, - int bar_no, u64 *size, unsigned int *flags) -{ - return NULL; -} -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_PCI -extern int of_pci_address_to_resource(struct device_node *dev, int bar, - struct resource *r); -#else -static inline int of_pci_address_to_resource(struct device_node *dev, int bar, - struct resource *r) -{ - return -ENOSYS; -} -#endif /* CONFIG_PCI */ - #ifdef CONFIG_PCI extern unsigned long pci_address_to_pio(phys_addr_t address); -#else -static inline unsigned long pci_address_to_pio(phys_addr_t address) -{ - return (unsigned long)-1; -} +#define pci_address_to_pio pci_address_to_pio #endif /* CONFIG_PCI */ /* Parse the ibm,dma-window property of an OF node into the busno, phys and @@ -122,9 +85,19 @@ static inline int of_node_to_nid(struct device_node *device) { return 0; } * resolving using the OF tree walking. */ struct pci_dev; +struct of_irq; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); extern void of_instantiate_rtc(void); +/* These includes are put at the bottom because they may contain things + * that are overridden by this file. Ideally they shouldn't be included + * by this file, but there are a bunch of .c files that currently depend + * on it. Eventually they will be cleaned up. */ +#include +#include +#include +#include + #endif /* __KERNEL__ */ #endif /* _POWERPC_PROM_H */ diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 035ada5443ee..c1fd0f9658fd 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 5b38f6ae2b29..9021c4ad4bbd 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 6d584f4e3c9a..de55bc0584b5 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/platforms/amigaone/setup.c b/arch/powerpc/platforms/amigaone/setup.c index fb4eb0df054c..03aabc0e16ac 100644 --- a/arch/powerpc/platforms/amigaone/setup.c +++ b/arch/powerpc/platforms/amigaone/setup.c @@ -13,12 +13,13 @@ */ #include +#include +#include #include #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index d2c1d497846e..33e5fc7334fc 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 9e1b9fd75206..75eec031e7a2 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/arch/powerpc/sysdev/bestcomm/sram.c b/arch/powerpc/sysdev/bestcomm/sram.c index 5d74ef7a651f..1225012a681a 100644 --- a/arch/powerpc/sysdev/bestcomm/sram.c +++ b/arch/powerpc/sysdev/bestcomm/sram.c @@ -11,6 +11,7 @@ * kind, whether express or implied. */ +#include #include #include #include diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c index eca4545dd52e..7dd2885321ad 100644 --- a/arch/powerpc/sysdev/fsl_gtm.c +++ b/arch/powerpc/sysdev/fsl_gtm.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 89d871ef8c2f..91917133ae0a 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c index b4c41d72c423..f53f850b6418 100644 --- a/drivers/net/fsl_pq_mdio.c +++ b/drivers/net/fsl_pq_mdio.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index d04c5b262050..b2c2f391b29d 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -20,7 +20,7 @@ #include #include #include - +#include #include #include #include diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 8acccd564378..caf085d3a76a 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -21,6 +21,7 @@ #include #if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) #include +#include #include #include diff --git a/drivers/spi/mpc512x_psc_spi.c b/drivers/spi/mpc512x_psc_spi.c index 1bb4315f5f84..10baac3f8ea5 100644 --- a/drivers/spi/mpc512x_psc_spi.c +++ b/drivers/spi/mpc512x_psc_spi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index bd81ff90cfb3..66d170147dcc 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c index 87cda0956a83..f53d3f6b9f61 100644 --- a/drivers/spi/xilinx_spi_of.c +++ b/drivers/spi/xilinx_spi_of.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 82506ca297d5..9648b75f0283 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 49fcbe8f18ac..c225dcce89e7 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 46dda7d8aaee..cb163a5397be 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -19,13 +19,14 @@ #include #include #include +#include +#include #include #include #include #include #include #include -#include #ifdef CONFIG_PPC64 #include diff --git a/include/linux/of_address.h b/include/linux/of_address.h index cc567df9a00d..8aea06f0564c 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -8,5 +8,37 @@ extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); extern void __iomem *of_iomap(struct device_node *device, int index); +/* Extract an address from a device, returns the region size and + * the address space flags too. The PCI version uses a BAR number + * instead of an absolute index + */ +extern const u32 *of_get_address(struct device_node *dev, int index, + u64 *size, unsigned int *flags); + +#ifndef pci_address_to_pio +static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } +#define pci_address_to_pio pci_address_to_pio +#endif + +#ifdef CONFIG_PCI +extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no, + u64 *size, unsigned int *flags); +extern int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r); +#else /* CONFIG_PCI */ +static inline int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r) +{ + return -ENOSYS; +} + +static inline const u32 *of_get_pci_address(struct device_node *dev, + int bar_no, u64 *size, unsigned int *flags) +{ + return NULL; +} +#endif /* CONFIG_PCI */ + + #endif /* __OF_ADDRESS_H */ -- cgit v1.2.3 From 1044ea8cfd67dc70f87999906bc2849eef7b053a Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 30 Apr 2010 10:30:47 +0000 Subject: powerpc/512x: Group mpc512x board's selection menu Allow board selection in a drop-down board sub-menu like many other platforms do. Before the patch: ... [ ] Freescale MPC5121E ADS [ ] Generic support for simple MPC5121 based boards [ ] 52xx-based boards ... Patched: ... [*] 512x-based boards [ ] Freescale MPC5121E ADS [ ] Generic support for simple MPC5121 based boards [ ] 52xx-based boards ... This is a cleanup before adding new board selection entry. Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- arch/powerpc/platforms/512x/Kconfig | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index 4dac9b0525a4..e9dca280a4d2 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig @@ -1,29 +1,24 @@ config PPC_MPC512x - bool + bool "512x-based boards" + depends on 6xx select FSL_SOC select IPIC select PPC_CLOCK select PPC_PCI_CHOICE select FSL_PCI if PCI -config PPC_MPC5121 - bool - select PPC_MPC512x - config MPC5121_ADS bool "Freescale MPC5121E ADS" - depends on 6xx + depends on PPC_MPC512x select DEFAULT_UIMAGE - select PPC_MPC5121 select MPC5121_ADS_CPLD help This option enables support for the MPC5121E ADS board. config MPC5121_GENERIC bool "Generic support for simple MPC5121 based boards" - depends on 6xx + depends on PPC_MPC512x select DEFAULT_UIMAGE - select PPC_MPC5121 help This option enables support for simple MPC5121 based boards which do not need custom platform specific setup. -- cgit v1.2.3 From 12fb0eb4c963452f727752aae03bbef192abed40 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Tue, 27 Jul 2010 11:26:02 +0000 Subject: powerpc/5121: add initial support for PDM360NG board Adds IFM PDM360NG device tree and platform code. Currently following is supported: - Spansion S29GL512P 256 MB NOR flash - ST Micro NAND 1 GiB flash - DIU, please use "fbcon=map:5 video=fslfb:800x480-32@60" at the kernel command line to enable PrimeView PM070WL3 Display support. - FEC - I2C - RTC, EEPROM - MSCAN - PSC UART, please pass "console=tty0 console=ttyPSC5,115200" on the kernel command line. - SPI, ADS7845 Touchscreen - USB0/1 Host - USB0 OTG Host/Device - VIU, Overlay/Capture support Signed-off-by: Markus Fischer Signed-off-by: Wolfgang Grandegger Signed-off-by: Michael Weiss Signed-off-by: Detlev Zundel Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- arch/powerpc/boot/dts/pdm360ng.dts | 410 +++++++++++++++++++++++++++++++++ arch/powerpc/platforms/512x/Kconfig | 7 + arch/powerpc/platforms/512x/Makefile | 1 + arch/powerpc/platforms/512x/pdm360ng.c | 129 +++++++++++ 4 files changed, 547 insertions(+) create mode 100644 arch/powerpc/boot/dts/pdm360ng.dts create mode 100644 arch/powerpc/platforms/512x/pdm360ng.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/pdm360ng.dts b/arch/powerpc/boot/dts/pdm360ng.dts new file mode 100644 index 000000000000..94dfa5c9a7f9 --- /dev/null +++ b/arch/powerpc/boot/dts/pdm360ng.dts @@ -0,0 +1,410 @@ +/* + * Device Tree Source for IFM PDM360NG. + * + * Copyright 2009 - 2010 DENX Software Engineering. + * Anatolij Gustschin + * + * Based on MPC5121E ADS dts. + * Copyright 2008 Freescale Semiconductor Inc. + * + * 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. + */ + +/dts-v1/; + +/ { + model = "pdm360ng"; + compatible = "ifm,pdm360ng"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&ipic>; + + aliases { + ethernet0 = ð0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,5121@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <0x20>; // 32 bytes + i-cache-line-size = <0x20>; // 32 bytes + d-cache-size = <0x8000>; // L1, 32K + i-cache-size = <0x8000>; // L1, 32K + timebase-frequency = <49500000>;// 49.5 MHz (csb/4) + bus-frequency = <198000000>; // 198 MHz csb bus + clock-frequency = <396000000>; // 396 MHz ppc core + }; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x20000000>; // 512MB at 0 + }; + + nfc@40000000 { + compatible = "fsl,mpc5121-nfc"; + reg = <0x40000000 0x100000>; + interrupts = <0x6 0x8>; + #address-cells = <0x1>; + #size-cells = <0x1>; + bank-width = <0x1>; + chips = <0x1>; + + partition@0 { + label = "nand0"; + reg = <0x0 0x40000000>; + }; + }; + + sram@50000000 { + compatible = "fsl,mpc5121-sram"; + reg = <0x50000000 0x20000>; // 128K at 0x50000000 + }; + + localbus@80000020 { + compatible = "fsl,mpc5121-localbus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x80000020 0x40>; + + ranges = <0x0 0x0 0xf0000000 0x10000000 /* Flash */ + 0x2 0x0 0x50040000 0x00020000>; /* CS2: MRAM */ + + flash@0,0 { + compatible = "amd,s29gl01gp", "cfi-flash"; + reg = <0 0x00000000 0x08000000 + 0 0x08000000 0x08000000>; + #address-cells = <1>; + #size-cells = <1>; + bank-width = <4>; + device-width = <2>; + + partition@0 { + label = "u-boot"; + reg = <0x00000000 0x00080000>; + read-only; + }; + partition@80000 { + label = "environment"; + reg = <0x00080000 0x00080000>; + read-only; + }; + partition@100000 { + label = "splash-image"; + reg = <0x00100000 0x00080000>; + read-only; + }; + partition@180000 { + label = "device-tree"; + reg = <0x00180000 0x00040000>; + }; + partition@1c0000 { + label = "kernel"; + reg = <0x001c0000 0x00500000>; + }; + partition@6c0000 { + label = "filesystem"; + reg = <0x006c0000 0x07940000>; + }; + }; + + mram0@2,0 { + compatible = "mtd-ram"; + reg = <2 0x00000 0x10000>; + bank-width = <2>; + }; + + mram1@2,10000 { + compatible = "mtd-ram"; + reg = <2 0x010000 0x10000>; + bank-width = <2>; + }; + }; + + soc@80000000 { + compatible = "fsl,mpc5121-immr"; + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + ranges = <0x0 0x80000000 0x400000>; + reg = <0x80000000 0x400000>; + bus-frequency = <66000000>; // 66 MHz ips bus + + // IPIC + // interrupts cell = + // sense values match linux IORESOURCE_IRQ_* defines: + // sense == 8: Level, low assertion + // sense == 2: Edge, high-to-low change + // + ipic: interrupt-controller@c00 { + compatible = "fsl,mpc5121-ipic", "fsl,ipic"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0xc00 0x100>; + }; + + rtc@a00 { // Real time clock + compatible = "fsl,mpc5121-rtc"; + reg = <0xa00 0x100>; + interrupts = <79 0x8 80 0x8>; + }; + + reset@e00 { // Reset module + compatible = "fsl,mpc5121-reset"; + reg = <0xe00 0x100>; + }; + + clock@f00 { // Clock control + compatible = "fsl,mpc5121-clock"; + reg = <0xf00 0x100>; + }; + + pmc@1000{ //Power Management Controller + compatible = "fsl,mpc5121-pmc"; + reg = <0x1000 0x100>; + interrupts = <83 0x2>; + }; + + gpio@1100 { + compatible = "fsl,mpc5121-gpio"; + reg = <0x1100 0x100>; + interrupts = <78 0x8>; + }; + + can@1300 { + compatible = "fsl,mpc5121-mscan"; + interrupts = <12 0x8>; + reg = <0x1300 0x80>; + }; + + can@1380 { + compatible = "fsl,mpc5121-mscan"; + interrupts = <13 0x8>; + reg = <0x1380 0x80>; + }; + + i2c@1700 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mpc5121-i2c"; + reg = <0x1700 0x20>; + interrupts = <0x9 0x8>; + fsl,preserve-clocking; + + eeprom@50 { + compatible = "at,24c01"; + reg = <0x50>; + }; + + rtc@68 { + compatible = "stm,m41t00"; + reg = <0x68>; + }; + }; + + i2c@1740 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mpc5121-i2c"; + reg = <0x1740 0x20>; + interrupts = <0xb 0x8>; + fsl,preserve-clocking; + }; + + i2ccontrol@1760 { + compatible = "fsl,mpc5121-i2c-ctrl"; + reg = <0x1760 0x8>; + }; + + axe@2000 { + compatible = "fsl,mpc5121-axe"; + reg = <0x2000 0x100>; + interrupts = <42 0x8>; + }; + + display@2100 { + compatible = "fsl,mpc5121-diu"; + reg = <0x2100 0x100>; + interrupts = <64 0x8>; + }; + + can@2300 { + compatible = "fsl,mpc5121-mscan"; + interrupts = <90 0x8>; + reg = <0x2300 0x80>; + }; + + can@2380 { + compatible = "fsl,mpc5121-mscan"; + interrupts = <91 0x8>; + reg = <0x2380 0x80>; + }; + + viu@2400 { + compatible = "fsl,mpc5121-viu"; + reg = <0x2400 0x400>; + interrupts = <67 0x8>; + }; + + mdio@2800 { + compatible = "fsl,mpc5121-fec-mdio"; + reg = <0x2800 0x200>; + #address-cells = <1>; + #size-cells = <0>; + phy: ethernet-phy@0 { + compatible = "smsc,lan8700"; + reg = <0x1f>; + }; + }; + + eth0: ethernet@2800 { + compatible = "fsl,mpc5121-fec"; + reg = <0x2800 0x200>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <4 0x8>; + phy-handle = < &phy >; + }; + + // USB1 using external ULPI PHY + usb@3000 { + compatible = "fsl,mpc5121-usb2-dr"; + reg = <0x3000 0x600>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <43 0x8>; + dr_mode = "host"; + phy_type = "ulpi"; + }; + + // USB0 using internal UTMI PHY + usb@4000 { + compatible = "fsl,mpc5121-usb2-dr"; + reg = <0x4000 0x600>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <44 0x8>; + dr_mode = "otg"; + phy_type = "utmi_wide"; + fsl,invert-pwr-fault; + }; + + // IO control + ioctl@a000 { + compatible = "fsl,mpc5121-ioctl"; + reg = <0xA000 0x1000>; + }; + + // 512x PSCs are not 52xx PSCs compatible + serial@11000 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <0>; + reg = <0x11000 0x100>; + interrupts = <40 0x8>; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; + }; + + serial@11100 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <1>; + reg = <0x11100 0x100>; + interrupts = <40 0x8>; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; + }; + + serial@11200 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <2>; + reg = <0x11200 0x100>; + interrupts = <40 0x8>; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; + }; + + serial@11300 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <3>; + reg = <0x11300 0x100>; + interrupts = <40 0x8>; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; + }; + + serial@11400 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <4>; + reg = <0x11400 0x100>; + interrupts = <40 0x8>; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; + }; + + serial@11600 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <6>; + reg = <0x11600 0x100>; + interrupts = <40 0x8>; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; + }; + + serial@11800 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <8>; + reg = <0x11800 0x100>; + interrupts = <40 0x8>; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; + }; + + serial@11B00 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <11>; + reg = <0x11B00 0x100>; + interrupts = <40 0x8>; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; + }; + + pscfifo@11f00 { + compatible = "fsl,mpc5121-psc-fifo"; + reg = <0x11f00 0x100>; + interrupts = <40 0x8>; + }; + + spi@11900 { + compatible = "fsl,mpc5121-psc-spi", "fsl,mpc5121-psc"; + cell-index = <9>; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11900 0x100>; + interrupts = <40 0x8>; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; + + // 7845 touch screen controller + ts@0 { + compatible = "ti,ads7846"; + reg = <0x0>; + spi-max-frequency = <3000000>; + // pen irq is GPIO25 + interrupts = <78 0x8>; + }; + }; + + dma@14000 { + compatible = "fsl,mpc5121-dma"; + reg = <0x14000 0x1800>; + interrupts = <65 0x8>; + }; + }; +}; diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index e9dca280a4d2..27b0651221d1 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig @@ -25,3 +25,10 @@ config MPC5121_GENERIC Compatible boards include: Protonic LVT base boards (ZANMCU and VICVT2). + +config PDM360NG + bool "ifm PDM360NG board" + depends on PPC_MPC512x + select DEFAULT_UIMAGE + help + This option enables support for the PDM360NG board. diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile index 90be2f5717e6..4efc1c4b6fb5 100644 --- a/arch/powerpc/platforms/512x/Makefile +++ b/arch/powerpc/platforms/512x/Makefile @@ -4,3 +4,4 @@ obj-y += clock.o mpc512x_shared.o obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o +obj-$(CONFIG_PDM360NG) += pdm360ng.o diff --git a/arch/powerpc/platforms/512x/pdm360ng.c b/arch/powerpc/platforms/512x/pdm360ng.c new file mode 100644 index 000000000000..0575e858291c --- /dev/null +++ b/arch/powerpc/platforms/512x/pdm360ng.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 DENX Software Engineering + * + * Anatolij Gustschin, + * + * PDM360NG board setup + * + * This 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 "mpc512x.h" + +#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \ + defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) +#include +#include +#include +#include + +static void *pdm360ng_gpio_base; + +static int pdm360ng_get_pendown_state(void) +{ + u32 reg; + + reg = in_be32(pdm360ng_gpio_base + 0xc); + if (reg & 0x40) + setbits32(pdm360ng_gpio_base + 0xc, 0x40); + + reg = in_be32(pdm360ng_gpio_base + 0x8); + + /* return 1 if pen is down */ + return (reg & 0x40) == 0; +} + +static struct ads7846_platform_data pdm360ng_ads7846_pdata = { + .model = 7845, + .get_pendown_state = pdm360ng_get_pendown_state, + .irq_flags = IRQF_TRIGGER_LOW, +}; + +static int __init pdm360ng_penirq_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-gpio"); + if (!np) { + pr_err("%s: Can't find 'mpc5121-gpio' node\n", __func__); + return -ENODEV; + } + + pdm360ng_gpio_base = of_iomap(np, 0); + of_node_put(np); + if (!pdm360ng_gpio_base) { + pr_err("%s: Can't map gpio regs.\n", __func__); + return -ENODEV; + } + out_be32(pdm360ng_gpio_base + 0xc, 0xffffffff); + setbits32(pdm360ng_gpio_base + 0x18, 0x2000); + setbits32(pdm360ng_gpio_base + 0x10, 0x40); + + return 0; +} + +static int pdm360ng_touchscreen_notifier_call(struct notifier_block *nb, + unsigned long event, void *__dev) +{ + struct device *dev = __dev; + + if ((event == BUS_NOTIFY_ADD_DEVICE) && + of_device_is_compatible(dev->of_node, "ti,ads7846")) { + dev->platform_data = &pdm360ng_ads7846_pdata; + return NOTIFY_OK; + } + return NOTIFY_DONE; +} + +static struct notifier_block pdm360ng_touchscreen_nb = { + .notifier_call = pdm360ng_touchscreen_notifier_call, +}; + +static void __init pdm360ng_touchscreen_init(void) +{ + if (pdm360ng_penirq_init()) + return; + + bus_register_notifier(&spi_bus_type, &pdm360ng_touchscreen_nb); +} +#else +static inline void __init pdm360ng_touchscreen_init(void) +{ +} +#endif /* CONFIG_TOUCHSCREEN_ADS7846 */ + +void __init pdm360ng_init(void) +{ + mpc512x_init(); + pdm360ng_touchscreen_init(); +} + +static int __init pdm360ng_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "ifm,pdm360ng"); +} + +define_machine(pdm360ng) { + .name = "PDM360NG", + .probe = pdm360ng_probe, + .setup_arch = mpc512x_setup_diu, + .init = pdm360ng_init, + .init_early = mpc512x_init_diu, + .init_IRQ = mpc512x_init_IRQ, + .get_irq = ipic_get_irq, + .calibrate_decr = generic_calibrate_decr, + .restart = mpc512x_restart, +}; -- cgit v1.2.3 From 9e2089cbed7441a21d72a510897f0336afb06492 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 23 Jul 2010 03:50:18 +0000 Subject: powerpc/512x: add clock structure for Video-IN (VIU) unit Allows using clk_get()/clk_enable()/clk_disable() for VIU clock in the v4l2 video driver. Signed-off-by: Hongjun Chen Signed-off-by: Anatolij Gustschin Signed-off-by: Grant Likely --- arch/powerpc/platforms/512x/clock.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c index 4c42246b86a7..e1c5cd6650b1 100644 --- a/arch/powerpc/platforms/512x/clock.c +++ b/arch/powerpc/platforms/512x/clock.c @@ -292,6 +292,15 @@ static void diu_clk_calc(struct clk *clk) clk->rate = rate; } +static void viu_clk_calc(struct clk *clk) +{ + unsigned long rate; + + rate = sys_clk.rate; + rate /= 2; + clk->rate = rate; +} + static void half_clk_calc(struct clk *clk) { clk->rate = clk->parent->rate / 2; @@ -412,6 +421,14 @@ static struct clk diu_clk = { .calc = diu_clk_calc, }; +static struct clk viu_clk = { + .name = "viu_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 18, + .calc = viu_clk_calc, +}; + static struct clk axe_clk = { .name = "axe_clk", .flags = CLK_HAS_CTRL, @@ -535,6 +552,7 @@ struct clk *rate_clks[] = { &ref_clk, &sys_clk, &diu_clk, + &viu_clk, &csb_clk, &e300_clk, &ips_clk, -- cgit v1.2.3 From 4b5006ec7bb73cd9d4c8a723d484b4c87fad4123 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 23 Jul 2010 04:00:37 +0000 Subject: powerpc/5121: shared DIU framebuffer support MPC5121 DIU configuration/setup as initialized by the boot loader currently will get lost while booting Linux. As a result displaying the boot splash is not possible through the boot process. To prevent this we reserve configured DIU frame buffer address range while booting and preserve AOI descriptor and gamma table so that DIU continues displaying through the whole boot process. On first open from user space DIU frame buffer driver releases the reserved frame buffer area and continues to operate as usual. Signed-off-by: John Rigby Signed-off-by: Anatolij Gustschin Acked-by: Timur Tabi Signed-off-by: Grant Likely --- arch/powerpc/include/asm/mpc5121.h | 32 +++ arch/powerpc/platforms/512x/mpc5121_ads.c | 2 + arch/powerpc/platforms/512x/mpc5121_generic.c | 2 + arch/powerpc/platforms/512x/mpc512x.h | 2 + arch/powerpc/platforms/512x/mpc512x_shared.c | 284 ++++++++++++++++++++++++++ arch/powerpc/sysdev/fsl_soc.h | 1 + drivers/video/fsl-diu-fb.c | 17 +- 7 files changed, 338 insertions(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h index e6a30bb1d16a..8c0ab2ca689c 100644 --- a/arch/powerpc/include/asm/mpc5121.h +++ b/arch/powerpc/include/asm/mpc5121.h @@ -21,4 +21,36 @@ struct mpc512x_reset_module { u32 rcer; /* Reset Control Enable Register */ }; +/* + * Clock Control Module + */ +struct mpc512x_ccm { + u32 spmr; /* System PLL Mode Register */ + u32 sccr1; /* System Clock Control Register 1 */ + u32 sccr2; /* System Clock Control Register 2 */ + u32 scfr1; /* System Clock Frequency Register 1 */ + u32 scfr2; /* System Clock Frequency Register 2 */ + u32 scfr2s; /* System Clock Frequency Shadow Register 2 */ + u32 bcr; /* Bread Crumb Register */ + u32 p0ccr; /* PSC0 Clock Control Register */ + u32 p1ccr; /* PSC1 CCR */ + u32 p2ccr; /* PSC2 CCR */ + u32 p3ccr; /* PSC3 CCR */ + u32 p4ccr; /* PSC4 CCR */ + u32 p5ccr; /* PSC5 CCR */ + u32 p6ccr; /* PSC6 CCR */ + u32 p7ccr; /* PSC7 CCR */ + u32 p8ccr; /* PSC8 CCR */ + u32 p9ccr; /* PSC9 CCR */ + u32 p10ccr; /* PSC10 CCR */ + u32 p11ccr; /* PSC11 CCR */ + u32 spccr; /* SPDIF Clock Control Register */ + u32 cccr; /* CFM Clock Control Register */ + u32 dccr; /* DIU Clock Control Register */ + u32 m1ccr; /* MSCAN1 CCR */ + u32 m2ccr; /* MSCAN2 CCR */ + u32 m3ccr; /* MSCAN3 CCR */ + u32 m4ccr; /* MSCAN4 CCR */ + u8 res[0x98]; /* Reserved */ +}; #endif /* __ASM_POWERPC_MPC5121_H__ */ diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c index ee6ae129c25c..dcef6ade48e1 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c @@ -42,6 +42,7 @@ static void __init mpc5121_ads_setup_arch(void) for_each_compatible_node(np, "pci", "fsl,mpc5121-pci") mpc83xx_add_bridge(np); #endif + mpc512x_setup_diu(); } static void __init mpc5121_ads_init_IRQ(void) @@ -65,6 +66,7 @@ define_machine(mpc5121_ads) { .probe = mpc5121_ads_probe, .setup_arch = mpc5121_ads_setup_arch, .init = mpc512x_init, + .init_early = mpc512x_init_diu, .init_IRQ = mpc5121_ads_init_IRQ, .get_irq = ipic_get_irq, .calibrate_decr = generic_calibrate_decr, diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c index a6c0e3a2615d..e487eb06ec6b 100644 --- a/arch/powerpc/platforms/512x/mpc5121_generic.c +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c @@ -52,6 +52,8 @@ define_machine(mpc5121_generic) { .name = "MPC5121 generic", .probe = mpc5121_generic_probe, .init = mpc512x_init, + .init_early = mpc512x_init_diu, + .setup_arch = mpc512x_setup_diu, .init_IRQ = mpc512x_init_IRQ, .get_irq = ipic_get_irq, .calibrate_decr = generic_calibrate_decr, diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h index b2daca0d1488..1ab6d11d0b19 100644 --- a/arch/powerpc/platforms/512x/mpc512x.h +++ b/arch/powerpc/platforms/512x/mpc512x.h @@ -16,4 +16,6 @@ extern void __init mpc512x_init(void); extern int __init mpc5121_clk_init(void); void __init mpc512x_declare_of_platform_devices(void); extern void mpc512x_restart(char *cmd); +extern void mpc512x_init_diu(void); +extern void mpc512x_setup_diu(void); #endif /* __MPC512X_H__ */ diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c index 707e572b7c40..e41ebbdb3e12 100644 --- a/arch/powerpc/platforms/512x/mpc512x_shared.c +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c @@ -16,7 +16,11 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -54,6 +58,286 @@ void mpc512x_restart(char *cmd) ; } +struct fsl_diu_shared_fb { + u8 gamma[0x300]; /* 32-bit aligned! */ + struct diu_ad ad0; /* 32-bit aligned! */ + phys_addr_t fb_phys; + size_t fb_len; + bool in_use; +}; + +unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel, + int monitor_port) +{ + switch (bits_per_pixel) { + case 32: + return 0x88883316; + case 24: + return 0x88082219; + case 16: + return 0x65053118; + } + return 0x00000400; +} + +void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base) +{ +} + +void mpc512x_set_monitor_port(int monitor_port) +{ +} + +#define DIU_DIV_MASK 0x000000ff +void mpc512x_set_pixel_clock(unsigned int pixclock) +{ + unsigned long bestval, bestfreq, speed, busfreq; + unsigned long minpixclock, maxpixclock, pixval; + struct mpc512x_ccm __iomem *ccm; + struct device_node *np; + u32 temp; + long err; + int i; + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock"); + if (!np) { + pr_err("Can't find clock control module.\n"); + return; + } + + ccm = of_iomap(np, 0); + of_node_put(np); + if (!ccm) { + pr_err("Can't map clock control module reg.\n"); + return; + } + + np = of_find_node_by_type(NULL, "cpu"); + if (np) { + const unsigned int *prop = + of_get_property(np, "bus-frequency", NULL); + + of_node_put(np); + if (prop) { + busfreq = *prop; + } else { + pr_err("Can't get bus-frequency property\n"); + return; + } + } else { + pr_err("Can't find 'cpu' node.\n"); + return; + } + + /* Pixel Clock configuration */ + pr_debug("DIU: Bus Frequency = %lu\n", busfreq); + speed = busfreq * 4; /* DIU_DIV ratio is 4 * CSB_CLK / DIU_CLK */ + + /* Calculate the pixel clock with the smallest error */ + /* calculate the following in steps to avoid overflow */ + pr_debug("DIU pixclock in ps - %d\n", pixclock); + temp = (1000000000 / pixclock) * 1000; + pixclock = temp; + pr_debug("DIU pixclock freq - %u\n", pixclock); + + temp = temp / 20; /* pixclock * 0.05 */ + pr_debug("deviation = %d\n", temp); + minpixclock = pixclock - temp; + maxpixclock = pixclock + temp; + pr_debug("DIU minpixclock - %lu\n", minpixclock); + pr_debug("DIU maxpixclock - %lu\n", maxpixclock); + pixval = speed/pixclock; + pr_debug("DIU pixval = %lu\n", pixval); + + err = LONG_MAX; + bestval = pixval; + pr_debug("DIU bestval = %lu\n", bestval); + + bestfreq = 0; + for (i = -1; i <= 1; i++) { + temp = speed / (pixval+i); + pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n", + i, pixval, temp); + if ((temp < minpixclock) || (temp > maxpixclock)) + pr_debug("DIU exceeds monitor range (%lu to %lu)\n", + minpixclock, maxpixclock); + else if (abs(temp - pixclock) < err) { + pr_debug("Entered the else if block %d\n", i); + err = abs(temp - pixclock); + bestval = pixval + i; + bestfreq = temp; + } + } + + pr_debug("DIU chose = %lx\n", bestval); + pr_debug("DIU error = %ld\n NomPixClk ", err); + pr_debug("DIU: Best Freq = %lx\n", bestfreq); + /* Modify DIU_DIV in CCM SCFR1 */ + temp = in_be32(&ccm->scfr1); + pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp); + temp &= ~DIU_DIV_MASK; + temp |= (bestval & DIU_DIV_MASK); + out_be32(&ccm->scfr1, temp); + pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp); + iounmap(ccm); +} + +ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf) +{ + return sprintf(buf, "0 - 5121 LCD\n"); +} + +int mpc512x_set_sysfs_monitor_port(int val) +{ + return 0; +} + +static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb; + +#if defined(CONFIG_FB_FSL_DIU) || \ + defined(CONFIG_FB_FSL_DIU_MODULE) +static inline void mpc512x_free_bootmem(struct page *page) +{ + __ClearPageReserved(page); + BUG_ON(PageTail(page)); + BUG_ON(atomic_read(&page->_count) > 1); + atomic_set(&page->_count, 1); + __free_page(page); + totalram_pages++; +} + +void mpc512x_release_bootmem(void) +{ + unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK; + unsigned long size = diu_shared_fb.fb_len; + unsigned long start, end; + + if (diu_shared_fb.in_use) { + start = PFN_UP(addr); + end = PFN_DOWN(addr + size); + + for (; start < end; start++) + mpc512x_free_bootmem(pfn_to_page(start)); + + diu_shared_fb.in_use = false; + } + diu_ops.release_bootmem = NULL; +} +#endif + +/* + * Check if DIU was pre-initialized. If so, perform steps + * needed to continue displaying through the whole boot process. + * Move area descriptor and gamma table elsewhere, they are + * destroyed by bootmem allocator otherwise. The frame buffer + * address range will be reserved in setup_arch() after bootmem + * allocator is up. + */ +void __init mpc512x_init_diu(void) +{ + struct device_node *np; + struct diu __iomem *diu_reg; + phys_addr_t desc; + void __iomem *vaddr; + unsigned long mode, pix_fmt, res, bpp; + unsigned long dst; + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu"); + if (!np) { + pr_err("No DIU node\n"); + return; + } + + diu_reg = of_iomap(np, 0); + of_node_put(np); + if (!diu_reg) { + pr_err("Can't map DIU\n"); + return; + } + + mode = in_be32(&diu_reg->diu_mode); + if (mode != MFB_MODE1) { + pr_info("%s: DIU OFF\n", __func__); + goto out; + } + + desc = in_be32(&diu_reg->desc[0]); + vaddr = ioremap(desc, sizeof(struct diu_ad)); + if (!vaddr) { + pr_err("Can't map DIU area desc.\n"); + goto out; + } + memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad)); + /* flush fb area descriptor */ + dst = (unsigned long)&diu_shared_fb.ad0; + flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1); + + res = in_be32(&diu_reg->disp_size); + pix_fmt = in_le32(vaddr); + bpp = ((pix_fmt >> 16) & 0x3) + 1; + diu_shared_fb.fb_phys = in_le32(vaddr + 4); + diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp; + diu_shared_fb.in_use = true; + iounmap(vaddr); + + desc = in_be32(&diu_reg->gamma); + vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma)); + if (!vaddr) { + pr_err("Can't map DIU area desc.\n"); + diu_shared_fb.in_use = false; + goto out; + } + memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma)); + /* flush gamma table */ + dst = (unsigned long)&diu_shared_fb.gamma; + flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1); + + iounmap(vaddr); + out_be32(&diu_reg->gamma, virt_to_phys(&diu_shared_fb.gamma)); + out_be32(&diu_reg->desc[1], 0); + out_be32(&diu_reg->desc[2], 0); + out_be32(&diu_reg->desc[0], virt_to_phys(&diu_shared_fb.ad0)); + +out: + iounmap(diu_reg); +} + +void __init mpc512x_setup_diu(void) +{ + int ret; + + /* + * We do not allocate and configure new area for bitmap buffer + * because it would requere copying bitmap data (splash image) + * and so negatively affect boot time. Instead we reserve the + * already configured frame buffer area so that it won't be + * destroyed. The starting address of the area to reserve and + * also it's length is passed to reserve_bootmem(). It will be + * freed later on first open of fbdev, when splash image is not + * needed any more. + */ + if (diu_shared_fb.in_use) { + ret = reserve_bootmem(diu_shared_fb.fb_phys, + diu_shared_fb.fb_len, + BOOTMEM_EXCLUSIVE); + if (ret) { + pr_err("%s: reserve bootmem failed\n", __func__); + diu_shared_fb.in_use = false; + } + } + +#if defined(CONFIG_FB_FSL_DIU) || \ + defined(CONFIG_FB_FSL_DIU_MODULE) + diu_ops.get_pixel_format = mpc512x_get_pixel_format; + diu_ops.set_gamma_table = mpc512x_set_gamma_table; + diu_ops.set_monitor_port = mpc512x_set_monitor_port; + diu_ops.set_pixel_clock = mpc512x_set_pixel_clock; + diu_ops.show_monitor_port = mpc512x_show_monitor_port; + diu_ops.set_sysfs_monitor_port = mpc512x_set_sysfs_monitor_port; + diu_ops.release_bootmem = mpc512x_release_bootmem; +#endif +} + void __init mpc512x_init_IRQ(void) { struct device_node *np; diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 42381bb6cd51..53609489a62b 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -30,6 +30,7 @@ struct platform_diu_data_ops { void (*set_pixel_clock) (unsigned int pixclock); ssize_t (*show_monitor_port) (int monitor_port, char *buf); int (*set_sysfs_monitor_port) (int val); + void (*release_bootmem) (void); }; extern struct platform_diu_data_ops diu_ops; diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 48905d5f4e8d..db3e360e6aad 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -1108,6 +1108,10 @@ static int fsl_diu_open(struct fb_info *info, int user) struct mfb_info *mfbi = info->par; int res = 0; + /* free boot splash memory on first /dev/fb0 open */ + if (!mfbi->index && diu_ops.release_bootmem) + diu_ops.release_bootmem(); + spin_lock(&diu_lock); mfbi->count++; if (mfbi->count == 1) { @@ -1435,6 +1439,7 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, int ret, i, error = 0; struct resource res; struct fsl_diu_data *machine_data; + int diu_mode; machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); if (!machine_data) @@ -1471,7 +1476,9 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, goto error2; } - out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/ + diu_mode = in_be32(&dr.diu_reg->diu_mode); + if (diu_mode != MFB_MODE1) + out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU */ /* Get the IRQ of the DIU */ machine_data->irq = irq_of_parse_and_map(np, 0); @@ -1519,7 +1526,13 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, machine_data->dummy_ad->offset_xyd = 0; machine_data->dummy_ad->next_ad = 0; - out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); + /* + * Let DIU display splash screen if it was pre-initialized + * by the bootloader, set dummy area descriptor otherwise. + */ + if (diu_mode != MFB_MODE1) + out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); + out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); -- cgit v1.2.3 From f933a41e419a954ef90605224e02c3ded78f3372 Mon Sep 17 00:00:00 2001 From: Matthew McClintock Date: Wed, 21 Jul 2010 16:14:53 -0500 Subject: powerpc/85xx: kexec for SMP 85xx BookE systems Adds support for kexec on 85xx machines for the BookE platform. Including support for SMP machines Based off work from Maxim Uvarov Signed-off-by: Matthew McClintock Signed-off-by: Kumar Gala --- arch/powerpc/Kconfig | 10 +++---- arch/powerpc/platforms/85xx/smp.c | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 4fa420381044..0e3fd3a489da 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -352,7 +352,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE config KEXEC bool "kexec system call (EXPERIMENTAL)" - depends on (PPC_BOOK3S || (FSL_BOOKE && !SMP)) && EXPERIMENTAL + depends on (PPC_BOOK3S || FSL_BOOKE) && EXPERIMENTAL help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot @@ -369,8 +369,8 @@ config KEXEC config CRASH_DUMP bool "Build a kdump crash kernel" - depends on PPC64 || 6xx - select RELOCATABLE if PPC64 + depends on PPC64 || 6xx || FSL_BOOKE + select RELOCATABLE if PPC64 || FSL_BOOKE help Build a kernel suitable for use as a kdump capture kernel. The same kernel binary can be used as production kernel and dump @@ -898,7 +898,7 @@ config KERNEL_START_BOOL config KERNEL_START hex "Virtual address of kernel base" if KERNEL_START_BOOL default PAGE_OFFSET if PAGE_OFFSET_BOOL - default "0xc2000000" if CRASH_DUMP + default "0xc2000000" if CRASH_DUMP && !RELOCATABLE default "0xc0000000" config PHYSICAL_START_BOOL @@ -911,7 +911,7 @@ config PHYSICAL_START_BOOL config PHYSICAL_START hex "Physical address where the kernel is loaded" if PHYSICAL_START_BOOL - default "0x02000000" if PPC_STD_MMU && CRASH_DUMP + default "0x02000000" if PPC_STD_MMU && CRASH_DUMP && !RELOCATABLE default "0x00000000" config PHYSICAL_ALIGN diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 4c3cde911c71..a6b106557be4 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,7 @@ #include #include +#include extern void __early_start(void); @@ -105,8 +107,64 @@ smp_85xx_setup_cpu(int cpu_nr) struct smp_ops_t smp_85xx_ops = { .kick_cpu = smp_85xx_kick_cpu, +#ifdef CONFIG_KEXEC + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, +#endif }; +#ifdef CONFIG_KEXEC +static int kexec_down_cpus = 0; + +void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary) +{ + mpic_teardown_this_cpu(1); + + /* When crashing, this gets called on all CPU's we only + * take down the non-boot cpus */ + if (smp_processor_id() != boot_cpuid) + { + local_irq_disable(); + kexec_down_cpus++; + + while (1); + } +} + +static void mpc85xx_smp_kexec_down(void *arg) +{ + if (ppc_md.kexec_cpu_down) + ppc_md.kexec_cpu_down(0,1); +} + +static void mpc85xx_smp_machine_kexec(struct kimage *image) +{ + int timeout = 2000; + int i; + + set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid)); + + smp_call_function(mpc85xx_smp_kexec_down, NULL, 0); + + while ( (kexec_down_cpus != (num_online_cpus() - 1)) && + ( timeout > 0 ) ) + { + timeout--; + } + + if ( !timeout ) + printk(KERN_ERR "Unable to bring down secondary cpu(s)"); + + for (i = 0; i < num_present_cpus(); i++) + { + if ( i == smp_processor_id() ) continue; + mpic_reset_core(i); + } + + default_machine_kexec(image); +} +#endif /* CONFIG_KEXEC */ + void __init mpc85xx_smp_init(void) { struct device_node *np; @@ -124,4 +182,9 @@ void __init mpc85xx_smp_init(void) BUG_ON(!smp_85xx_ops.message_pass); smp_ops = &smp_85xx_ops; + +#ifdef CONFIG_KEXEC + ppc_md.kexec_cpu_down = mpc85xx_smp_kexec_cpu_down; + ppc_md.machine_kexec = mpc85xx_smp_machine_kexec; +#endif } -- cgit v1.2.3 From 6588169d516560f68672e2928680b71c647b7806 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Wed, 28 Jul 2010 17:33:09 +0200 Subject: kbuild: allow assignment to {A,C,LD}FLAGS_MODULE on the command line It is now possible to assign options to AS, CC and LD on the command line - which is only used when building modules. {A,C,LD}FLAGS_MODULE was all used both in the top-level Makefile in the arch makefiles, thus users had no way to specify additional options to AS, CC, LD when building modules without overriding the original value. Introduce a new set of variables KBUILD_{A,C,LD}FLAGS_MODULE that is used by arch specific files and free up {A,C,LD}FLAGS_MODULE so they can be assigned on the command line. All arch Makefiles that used the old variables has been updated. Note: Previously we had a MODFLAGS variable for both AS and CC. But in favour of consistency this was dropped. So in some cases arch Makefile has one assignmnet replaced by two assignmnets. Note2: MODFLAGS was not documented and is dropped without any notice. I do not expect much/any breakage from this. Signed-off-by: Sam Ravnborg Cc: Denys Vlasenko Cc: Haavard Skinnemoen Cc: Mike Frysinger Cc: Tony Luck Cc: Geert Uytterhoeven Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Martin Schwidefsky Cc: Chen Liqin Acked-by: Mike Frysinger [blackfin] Acked-by: Haavard Skinnemoen [avr32] Signed-off-by: Michal Marek --- Documentation/kbuild/kbuild.txt | 16 ++++++++++++++-- Documentation/kbuild/makefiles.txt | 18 +++++++++++++++--- Makefile | 13 ++++++++----- arch/avr32/Makefile | 2 +- arch/blackfin/Makefile | 4 ++-- arch/ia64/Makefile | 2 +- arch/m32r/Makefile | 2 +- arch/m68k/Makefile | 2 +- arch/mips/Makefile | 6 ++++-- arch/powerpc/Makefile | 2 +- arch/s390/Makefile | 3 ++- arch/score/Makefile | 3 ++- scripts/Makefile.build | 9 ++++++--- scripts/Makefile.modpost | 7 ++++--- 14 files changed, 62 insertions(+), 27 deletions(-) (limited to 'arch/powerpc') diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt index 634c625da8ce..d9c655433ec6 100644 --- a/Documentation/kbuild/kbuild.txt +++ b/Documentation/kbuild/kbuild.txt @@ -22,11 +22,23 @@ building C files and assembler files. KAFLAGS -------------------------------------------------- -Additional options to the assembler. +Additional options to the assembler (for built-in and modules). + +AFLAGS_MODULE +-------------------------------------------------- +Addtional module specific options to use for $(AS). KCFLAGS -------------------------------------------------- -Additional options to the C compiler. +Additional options to the C compiler (for built-in and modules). + +CFLAGS_MODULE +-------------------------------------------------- +Addtional module specific options to use for $(CC). + +LDFLAGS_MODULE +-------------------------------------------------- +Additional options used for $(LD) when linking modules. KBUILD_VERBOSE -------------------------------------------------- diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 71c602d61680..802341abf702 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -928,11 +928,23 @@ When kbuild executes, the following steps are followed (roughly): $(CFLAGS_KERNEL) contains extra C compiler flags used to compile resident kernel code. - CFLAGS_MODULE $(CC) options specific for modules + KBUILD_AFLAGS_MODULE Options for $(AS) when building modules - $(CFLAGS_MODULE) contains extra C compiler flags used to compile code - for loadable kernel modules. + $(KBUILD_AFLAGS_MODULE) is used to add arch specific options that + are used for $(AS). + From commandline AFLAGS_MODULE shall be used (see kbuild.txt). + KBUILD_CFLAGS_MODULE Options for $(CC) when building modules + + $(KBUILD_CFLAGS_MODULE) is used to add arch specific options that + are used for $(CC). + From commandline CFLAGS_MODULE shall be used (see kbuild.txt). + + KBUILD_LDFLAGS_MODULE Options for $(LD) when linking modules + + $(KBUILD_LDFLAGS_MODULE) is used to add arch specific options + used when linking modules. This is often a linker script. + From commandline LDFLAGS_MODULE shall be used (see kbuild.txt). --- 6.2 Add prerequisites to archprepare: diff --git a/Makefile b/Makefile index e1dfb90c6092..3dbd62b0bcfe 100644 --- a/Makefile +++ b/Makefile @@ -332,10 +332,9 @@ CHECK = sparse CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ -Wbitwise -Wno-return-void $(CF) -MODFLAGS = -DMODULE -CFLAGS_MODULE = $(MODFLAGS) -AFLAGS_MODULE = $(MODFLAGS) -LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds +CFLAGS_MODULE = +AFLAGS_MODULE = +LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = CFLAGS_GCOV = -fprofile-arcs -ftest-coverage @@ -355,6 +354,9 @@ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -Wno-format-security \ -fno-delete-null-pointer-checks KBUILD_AFLAGS := -D__ASSEMBLY__ +KBUILD_AFLAGS_MODULE := -DMODULE +KBUILD_CFLAGS_MODULE := -DMODULE +KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds # Read KERNELRELEASE from include/config/kernel.release (if it exists) KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) @@ -369,6 +371,7 @@ export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE +export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE # When compiling out-of-tree modules, put MODVERDIR in the module # tree rather than in the kernel tree. The kernel tree might @@ -607,7 +610,7 @@ endif # Use --build-id when available. LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\ $(call cc-ldoption, -Wl$(comma)--build-id,)) -LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID) +KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID) LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID) ifeq ($(CONFIG_STRIP_ASM_SYMS),y) diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile index ead8a75203a9..22fb66590dcd 100644 --- a/arch/avr32/Makefile +++ b/arch/avr32/Makefile @@ -13,7 +13,7 @@ KBUILD_DEFCONFIG := atstk1002_defconfig KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic KBUILD_AFLAGS += -mrelax -mno-pic -CFLAGS_MODULE += -mno-relax +KBUILD_CFLAGS_MODULE += -mno-relax LDFLAGS_vmlinux += --relax cpuflags-$(CONFIG_PLATFORM_AT32AP) += -march=ap diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile index d4c7177e7656..f7ef923297fc 100644 --- a/arch/blackfin/Makefile +++ b/arch/blackfin/Makefile @@ -15,8 +15,8 @@ GZFLAGS := -9 KBUILD_CFLAGS += $(call cc-option,-mno-fdpic) KBUILD_AFLAGS += $(call cc-option,-mno-fdpic) -CFLAGS_MODULE += -mlong-calls -LDFLAGS_MODULE += -m elf32bfin +KBUILD_CFLAGS_MODULE += -mlong-calls +KBUILD_LDFLAGS_MODULE += -m elf32bfin KALLSYMS += --symbol-prefix=_ KBUILD_DEFCONFIG := BF537-STAMP_defconfig diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 475e2725fbde..5ab6af3361a8 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -22,7 +22,7 @@ CHECKFLAGS += -m64 -D__ia64=1 -D__ia64__=1 -D_LP64 -D__LP64__ OBJCOPYFLAGS := --strip-all LDFLAGS_vmlinux := -static -LDFLAGS_MODULE += -T $(srctree)/arch/ia64/module.lds +KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/ia64/module.lds AFLAGS_KERNEL := -mconstant-gp EXTRA := diff --git a/arch/m32r/Makefile b/arch/m32r/Makefile index 469766b24e22..14a3c2314fef 100644 --- a/arch/m32r/Makefile +++ b/arch/m32r/Makefile @@ -13,7 +13,7 @@ LDFLAGS_vmlinux := KBUILD_CFLAGS += -pipe -fno-schedule-insns CFLAGS_KERNEL += -mmodel=medium -CFLAGS_MODULE += -mmodel=large +KBUILD_CFLAGS_MODULE += -mmodel=large ifdef CONFIG_CHIP_VDEC2 cflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -Wa,-bitinst diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index 570d85c3f97f..b06a7e3cbcd6 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -18,7 +18,7 @@ KBUILD_DEFCONFIG := multi_defconfig # override top level makefile AS += -m68020 LDFLAGS := -m m68kelf -LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds +KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds ifneq ($(SUBARCH),$(ARCH)) ifeq ($(CROSS_COMPILE),) CROSS_COMPILE := $(call cc-cross-prefix, \ diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 1893efd43fca..a77dcf35c14e 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -93,7 +93,8 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz cflags-y += -G 0 -mno-abicalls -fno-pic -pipe cflags-y += -msoft-float LDFLAGS_vmlinux += -G 0 -static -n -nostdlib -MODFLAGS += -mlong-calls +KBUILD_AFLAGS_MODULE += -mlong-calls +KBUILD_CFLAGS_MODULE += -mlong-calls cflags-y += -ffreestanding @@ -172,7 +173,8 @@ cflags-$(CONFIG_CPU_DADDI_WORKAROUNDS) += $(call cc-option,-mno-daddi,) ifdef CONFIG_CPU_SB1 ifdef CONFIG_SB1_PASS_1_WORKAROUNDS -MODFLAGS += -msb1-pass1-workarounds +KBUILD_AFLAGS_MODULE += -msb1-pass1-workarounds +KBUILD_CFLAGS_MODULE += -msb1-pass1-workarounds endif endif diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 42dcd3f4ad7b..b68a83853e1c 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -93,7 +93,7 @@ else KBUILD_CFLAGS += $(call cc-option,-mtune=power4) endif else -LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o +KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o endif ifeq ($(CONFIG_TUNE_CELL),y) diff --git a/arch/s390/Makefile b/arch/s390/Makefile index fc8fb20e7fc0..83ef8724c833 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -22,7 +22,8 @@ STACK_SIZE := 8192 CHECKFLAGS += -D__s390__ -msize-long else LDFLAGS := -m elf64_s390 -MODFLAGS += -fpic -D__PIC__ +KBUILD_AFLAGS_MODULE += -fpic -D__PIC__ +KBUILD_CFLAGS_MODULE += -fpic -D__PIC__ KBUILD_CFLAGS += -m64 KBUILD_AFLAGS += -m64 UTS_MACHINE := s390x diff --git a/arch/score/Makefile b/arch/score/Makefile index 68e0cd06d5c9..d77dc639d8e3 100644 --- a/arch/score/Makefile +++ b/arch/score/Makefile @@ -20,7 +20,8 @@ cflags-y += -G0 -pipe -mel -mnhwloop -D__SCOREEL__ \ # KBUILD_AFLAGS += $(cflags-y) KBUILD_CFLAGS += $(cflags-y) -MODFLAGS += -mlong-calls +KBUILD_AFLAGS_MODULE += -mlong-calls +KBUILD_CFLAGS_MODULE += -mlong-calls LDFLAGS += --oformat elf32-littlescore LDFLAGS_vmlinux += -G0 -static -nostdlib diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 390aae4bb222..5e7c40e16545 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -115,7 +115,10 @@ endif # --------------------------------------------------------------------------- # Default is built-in, unless we know otherwise -modkern_cflags = $(if $(part-of-module), $(CFLAGS_MODULE), $(CFLAGS_KERNEL)) +modkern_cflags = \ + $(if $(part-of-module), \ + $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \ + $(CFLAGS_KERNEL)) quiet_modtag := $(empty) $(empty) $(real-objs-m) : part-of-module := y @@ -250,8 +253,8 @@ $(obj)/%.lst: $(src)/%.c FORCE modkern_aflags := $(AFLAGS_KERNEL) -$(real-objs-m) : modkern_aflags := $(AFLAGS_MODULE) -$(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE) +$(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) +$(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) quiet_cmd_as_s_S = CPP $(quiet_modtag) $@ cmd_as_s_S = $(CPP) $(a_flags) -o $@ $< diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 8f14c81abbc7..3e3f02409bbd 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -107,7 +107,7 @@ $(modules:.ko=.mod.c): __modpost ; modname = $(notdir $(@:.mod.o=)) quiet_cmd_cc_o_c = CC $@ - cmd_cc_o_c = $(CC) $(c_flags) $(CFLAGS_MODULE) \ + cmd_cc_o_c = $(CC) $(c_flags) $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE) \ -c -o $@ $< $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE @@ -117,8 +117,9 @@ targets += $(modules:.ko=.mod.o) # Step 6), final link of the modules quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = $(LD) -r $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \ - $(filter-out FORCE,$^) + cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ + -o $@ $(filter-out FORCE,$^) $(modules): %.ko :%.o %.mod.o FORCE $(call if_changed,ld_ko_o) -- cgit v1.2.3 From bb863e85a74f0222f4486ddb1945ed9eb431d6c9 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 8 Jun 2010 09:55:40 +0000 Subject: powerpc/85xx: Fix SWIOTLB initalization for MPC85xxMDS boards The code inside '#ifdef CONFIG_QUICC_ENGINE' makes the mpc85xx_mds_setup_arch() return early if no QE nodes present, and so SWIOTLB is never initialized. This patch fixes the issue by moving SWIOTLB code above QE. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 8fe87fc61485..35ab2b42d698 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -202,6 +202,14 @@ static void __init mpc85xx_mds_setup_arch(void) mpc85xx_smp_init(); #endif +#ifdef CONFIG_SWIOTLB + if (lmb_end_of_DRAM() > max) { + ppc_swiotlb_enable = 1; + set_pci_dma_ops(&swiotlb_dma_ops); + ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; + } +#endif + #ifdef CONFIG_QUICC_ENGINE np = of_find_compatible_node(NULL, NULL, "fsl,qe"); if (!np) { @@ -323,14 +331,6 @@ static void __init mpc85xx_mds_setup_arch(void) } #endif /* CONFIG_QUICC_ENGINE */ - -#ifdef CONFIG_SWIOTLB - if (lmb_end_of_DRAM() > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif } -- cgit v1.2.3 From dee9ad718b4f0009a4170c178f7171c7b1f06f92 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 8 Jun 2010 09:55:50 +0000 Subject: powerpc/85xx: Fix booting for P1021MDS boards P1021 processors have no dedicated ROM to store the QE microcode, so the fimrware is stored externally, and it is U-Boot responsibility to load it. It might be that the board is booting without QE, e.g. currently U-Boot doesn't support QE for P1021MDS boards, which means that QE isn't initialized, and so the board hangs early at boot. This patch fixes the issue by marking QE as disabled and checking the state in the probing code. U-Boot should fixup the state if it initialized the QE. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/p1021mds.dts | 1 + arch/powerpc/platforms/85xx/mpc85xx_mds.c | 43 ++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 6 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/p1021mds.dts b/arch/powerpc/boot/dts/p1021mds.dts index 7fad2df25981..ad5b85269004 100644 --- a/arch/powerpc/boot/dts/p1021mds.dts +++ b/arch/powerpc/boot/dts/p1021mds.dts @@ -617,6 +617,7 @@ bus-frequency = <0>; fsl,qe-num-riscs = <1>; fsl,qe-num-snums = <28>; + status = "disabled"; /* no firmware loaded */ qeic: interrupt-controller@80 { interrupt-controller; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 35ab2b42d698..9dadcffd9947 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -158,6 +158,29 @@ static int mpc8568_mds_phy_fixups(struct phy_device *phydev) extern void __init mpc85xx_smp_init(void); #endif +#ifdef CONFIG_QUICC_ENGINE +static struct of_device_id mpc85xx_qe_ids[] __initdata = { + { .type = "qe", }, + { .compatible = "fsl,qe", }, + { }, +}; + +static void __init mpc85xx_publish_qe_devices(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!of_device_is_available(np)) { + of_node_put(np); + return; + } + + of_platform_bus_probe(NULL, mpc85xx_qe_ids, NULL); +} +#else +static void __init mpc85xx_publish_qe_devices(void) { } +#endif /* CONFIG_QUICC_ENGINE */ + static void __init mpc85xx_mds_setup_arch(void) { struct device_node *np; @@ -218,6 +241,11 @@ static void __init mpc85xx_mds_setup_arch(void) return; } + if (!of_device_is_available(np)) { + of_node_put(np); + return; + } + qe_reset(); of_node_put(np); @@ -369,8 +397,6 @@ static struct of_device_id mpc85xx_ids[] = { { .type = "soc", }, { .compatible = "soc", }, { .compatible = "simple-bus", }, - { .type = "qe", }, - { .compatible = "fsl,qe", }, { .compatible = "gianfar", }, { .compatible = "fsl,rapidio-delta", }, { .compatible = "fsl,mpc8548-guts", }, @@ -382,8 +408,6 @@ static struct of_device_id p1021_ids[] = { { .type = "soc", }, { .compatible = "soc", }, { .compatible = "simple-bus", }, - { .type = "qe", }, - { .compatible = "fsl,qe", }, { .compatible = "gianfar", }, {}, }; @@ -395,16 +419,16 @@ static int __init mpc85xx_publish_devices(void) if (machine_is(mpc8569_mds)) simple_gpiochip_init("fsl,mpc8569mds-bcsr-gpio"); - /* Publish the QE devices */ of_platform_bus_probe(NULL, mpc85xx_ids, NULL); + mpc85xx_publish_qe_devices(); return 0; } static int __init p1021_publish_devices(void) { - /* Publish the QE devices */ of_platform_bus_probe(NULL, p1021_ids, NULL); + mpc85xx_publish_qe_devices(); return 0; } @@ -443,12 +467,19 @@ static void __init mpc85xx_mds_pic_init(void) mpic_init(mpic); #ifdef CONFIG_QUICC_ENGINE + np = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!of_device_is_available(np)) { + of_node_put(np); + return; + } + np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); if (!np) { np = of_find_node_by_type(NULL, "qeic"); if (!np) return; } + if (machine_is(p1021_mds)) qe_ic_init(np, 0, qe_ic_cascade_low_mpic, qe_ic_cascade_high_mpic); -- cgit v1.2.3 From 99d8238f5fb1dfe225042aea708337fcb7e8de55 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 8 Jun 2010 09:55:57 +0000 Subject: powerpc/85xx: Cleanup QE initialization for MPC85xxMDS boards The mpc85xx_mds_setup_arch() function is incomprehensible and unmaintainable. Factor out all QE specific stuff into mpc85xx_mds_qe_init() and mpc85xx_mds_reset_ucc_phys(). Also move QE stuff out of mpc85xx_mds_pic_init(). The diff is unreadable, but only because the code was so. ;-) It should be better now, and less indented. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 272 ++++++++++++++++-------------- 1 file changed, 143 insertions(+), 129 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 9dadcffd9947..c8be7b528bb0 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -177,63 +177,89 @@ static void __init mpc85xx_publish_qe_devices(void) of_platform_bus_probe(NULL, mpc85xx_qe_ids, NULL); } -#else -static void __init mpc85xx_publish_qe_devices(void) { } -#endif /* CONFIG_QUICC_ENGINE */ -static void __init mpc85xx_mds_setup_arch(void) +static void __init mpc85xx_mds_reset_ucc_phys(void) { struct device_node *np; - static u8 __iomem *bcsr_regs = NULL; -#ifdef CONFIG_PCI - struct pci_controller *hose; -#endif - dma_addr_t max = 0xffffffff; - - if (ppc_md.progress) - ppc_md.progress("mpc85xx_mds_setup_arch()", 0); + static u8 __iomem *bcsr_regs; /* Map BCSR area */ np = of_find_node_by_name(NULL, "bcsr"); - if (np != NULL) { - struct resource res; + if (!np) + return; - of_address_to_resource(np, 0, &res); - bcsr_regs = ioremap(res.start, res.end - res.start +1); - of_node_put(np); - } + bcsr_regs = of_iomap(np, 0); + of_node_put(np); + if (!bcsr_regs) + return; -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8540-pci") || - of_device_is_compatible(np, "fsl,mpc8548-pcie")) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); + if (machine_is(mpc8568_mds)) { +#define BCSR_UCC1_GETH_EN (0x1 << 7) +#define BCSR_UCC2_GETH_EN (0x1 << 7) +#define BCSR_UCC1_MODE_MSK (0x3 << 4) +#define BCSR_UCC2_MODE_MSK (0x3 << 0) - hose = pci_find_hose_for_OF_device(np); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); + /* Turn off UCC1 & UCC2 */ + clrbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); + clrbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); + + /* Mode is RGMII, all bits clear */ + clrbits8(&bcsr_regs[11], BCSR_UCC1_MODE_MSK | + BCSR_UCC2_MODE_MSK); + + /* Turn UCC1 & UCC2 on */ + setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); + setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); + } else if (machine_is(mpc8569_mds)) { +#define BCSR7_UCC12_GETHnRST (0x1 << 2) +#define BCSR8_UEM_MARVELL_RST (0x1 << 1) +#define BCSR_UCC_RGMII (0x1 << 6) +#define BCSR_UCC_RTBI (0x1 << 5) + /* + * U-Boot mangles interrupt polarity for Marvell PHYs, + * so reset built-in and UEM Marvell PHYs, this puts + * the PHYs into their normal state. + */ + clrbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST); + setbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST); + + setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST); + clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST); + + for (np = NULL; (np = of_find_compatible_node(np, + "network", + "ucc_geth")) != NULL;) { + const unsigned int *prop; + int ucc_num; + + prop = of_get_property(np, "cell-index", NULL); + if (prop == NULL) + continue; + + ucc_num = *prop - 1; + + prop = of_get_property(np, "phy-connection-type", NULL); + if (prop == NULL) + continue; + + if (strcmp("rtbi", (const char *)prop) == 0) + clrsetbits_8(&bcsr_regs[7 + ucc_num], + BCSR_UCC_RGMII, BCSR_UCC_RTBI); } + } else if (machine_is(p1021_mds)) { +#define BCSR11_ENET_MICRST (0x1 << 5) + /* Reset Micrel PHY */ + clrbits8(&bcsr_regs[11], BCSR11_ENET_MICRST); + setbits8(&bcsr_regs[11], BCSR11_ENET_MICRST); } -#endif -#ifdef CONFIG_SMP - mpc85xx_smp_init(); -#endif + iounmap(bcsr_regs); +} -#ifdef CONFIG_SWIOTLB - if (lmb_end_of_DRAM() > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif +static void __init mpc85xx_mds_qe_init(void) +{ + struct device_node *np; -#ifdef CONFIG_QUICC_ENGINE np = of_find_compatible_node(NULL, NULL, "fsl,qe"); if (!np) { np = of_find_node_by_name(NULL, "qe"); @@ -260,70 +286,7 @@ static void __init mpc85xx_mds_setup_arch(void) par_io_of_config(ucc); } - if (bcsr_regs) { - if (machine_is(mpc8568_mds)) { -#define BCSR_UCC1_GETH_EN (0x1 << 7) -#define BCSR_UCC2_GETH_EN (0x1 << 7) -#define BCSR_UCC1_MODE_MSK (0x3 << 4) -#define BCSR_UCC2_MODE_MSK (0x3 << 0) - - /* Turn off UCC1 & UCC2 */ - clrbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); - clrbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); - - /* Mode is RGMII, all bits clear */ - clrbits8(&bcsr_regs[11], BCSR_UCC1_MODE_MSK | - BCSR_UCC2_MODE_MSK); - - /* Turn UCC1 & UCC2 on */ - setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); - setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); - } else if (machine_is(mpc8569_mds)) { -#define BCSR7_UCC12_GETHnRST (0x1 << 2) -#define BCSR8_UEM_MARVELL_RST (0x1 << 1) -#define BCSR_UCC_RGMII (0x1 << 6) -#define BCSR_UCC_RTBI (0x1 << 5) - /* - * U-Boot mangles interrupt polarity for Marvell PHYs, - * so reset built-in and UEM Marvell PHYs, this puts - * the PHYs into their normal state. - */ - clrbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST); - setbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST); - - setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST); - clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST); - - for (np = NULL; (np = of_find_compatible_node(np, - "network", - "ucc_geth")) != NULL;) { - const unsigned int *prop; - int ucc_num; - - prop = of_get_property(np, "cell-index", NULL); - if (prop == NULL) - continue; - - ucc_num = *prop - 1; - - prop = of_get_property(np, "phy-connection-type", NULL); - if (prop == NULL) - continue; - - if (strcmp("rtbi", (const char *)prop) == 0) - clrsetbits_8(&bcsr_regs[7 + ucc_num], - BCSR_UCC_RGMII, BCSR_UCC_RTBI); - } - - } else if (machine_is(p1021_mds)) { -#define BCSR11_ENET_MICRST (0x1 << 5) - /* Reset Micrel PHY */ - clrbits8(&bcsr_regs[11], BCSR11_ENET_MICRST); - setbits8(&bcsr_regs[11], BCSR11_ENET_MICRST); - } - - iounmap(bcsr_regs); - } + mpc85xx_mds_reset_ucc_phys(); if (machine_is(p1021_mds)) { #define MPC85xx_PMUXCR_OFFSET 0x60 @@ -358,7 +321,79 @@ static void __init mpc85xx_mds_setup_arch(void) } } +} + +static void __init mpc85xx_mds_qeic_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!of_device_is_available(np)) { + of_node_put(np); + return; + } + + np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); + if (!np) { + np = of_find_node_by_type(NULL, "qeic"); + if (!np) + return; + } + + if (machine_is(p1021_mds)) + qe_ic_init(np, 0, qe_ic_cascade_low_mpic, + qe_ic_cascade_high_mpic); + else + qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL); + of_node_put(np); +} +#else +static void __init mpc85xx_publish_qe_devices(void) { } +static void __init mpc85xx_mds_qe_init(void) { } +static void __init mpc85xx_mds_qeic_init(void) { } #endif /* CONFIG_QUICC_ENGINE */ + +static void __init mpc85xx_mds_setup_arch(void) +{ +#ifdef CONFIG_PCI + struct pci_controller *hose; +#endif + dma_addr_t max = 0xffffffff; + + if (ppc_md.progress) + ppc_md.progress("mpc85xx_mds_setup_arch()", 0); + +#ifdef CONFIG_PCI + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == 0x8000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + + hose = pci_find_hose_for_OF_device(np); + max = min(max, hose->dma_window_base_cur + + hose->dma_window_size); + } + } +#endif + +#ifdef CONFIG_SMP + mpc85xx_smp_init(); +#endif + + mpc85xx_mds_qe_init(); + +#ifdef CONFIG_SWIOTLB + if (lmb_end_of_DRAM() > max) { + ppc_swiotlb_enable = 1; + set_pci_dma_ops(&swiotlb_dma_ops); + ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; + } +#endif } @@ -465,28 +500,7 @@ static void __init mpc85xx_mds_pic_init(void) of_node_put(np); mpic_init(mpic); - -#ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe"); - if (!of_device_is_available(np)) { - of_node_put(np); - return; - } - - np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); - if (!np) { - np = of_find_node_by_type(NULL, "qeic"); - if (!np) - return; - } - - if (machine_is(p1021_mds)) - qe_ic_init(np, 0, qe_ic_cascade_low_mpic, - qe_ic_cascade_high_mpic); - else - qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL); - of_node_put(np); -#endif /* CONFIG_QUICC_ENGINE */ + mpc85xx_mds_qeic_init(); } static int __init mpc85xx_mds_probe(void) -- cgit v1.2.3 From e3b5e0d552b34d65e15b20610273b200555eea53 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 8 Jul 2010 10:10:38 +0000 Subject: powerpc/fsl_pci: add quirk for mpc8308 pcie bridge This patch adds the quirk for PCIE controller found on Freescale MPC8308. The quirk is the same as for other MPC83xx processors. Signed-off-by: Ilya Yanok Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_pci.c | 1 + include/linux/pci_ids.h | 1 + 2 files changed, 2 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index a14760fe513a..7e900ec988f6 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -412,6 +412,7 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header); #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */ #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8308, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314E, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8315E, quirk_fsl_pcie_header); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3bedcc149c84..79bb11f35c4b 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2264,6 +2264,7 @@ #define PCI_DEVICE_ID_TDI_EHCI 0x0101 #define PCI_VENDOR_ID_FREESCALE 0x1957 +#define PCI_DEVICE_ID_MPC8308 0xc006 #define PCI_DEVICE_ID_MPC8315E 0x00b4 #define PCI_DEVICE_ID_MPC8315 0x00b5 #define PCI_DEVICE_ID_MPC8314E 0x00b6 -- cgit v1.2.3 From ba4d1275d1ad89a17cd529f7755e227ead52be4e Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 8 Jul 2010 10:10:39 +0000 Subject: powerpc/mpc8308rdb: support for MPC8308RDB board from Freescale This patch adds support for MPC8308RDB development board from Freescale. Supported devices: DUART Dual Ethernet NOR and NAND flashes I2C USB in peripheral mode PCIE support is broken by the commit 3da34aa ("powerpc/fsl: Support unique MSI addresses per PCIe Root Complex"). Works after revert. Signed-off-by: Ilya Yanok Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8308rdb.dts | 303 ++++++++++++++++++++++++++++++ arch/powerpc/platforms/83xx/Kconfig | 8 + arch/powerpc/platforms/83xx/Makefile | 1 + arch/powerpc/platforms/83xx/mpc830x_rdb.c | 94 +++++++++ 4 files changed, 406 insertions(+) create mode 100644 arch/powerpc/boot/dts/mpc8308rdb.dts create mode 100644 arch/powerpc/platforms/83xx/mpc830x_rdb.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/mpc8308rdb.dts b/arch/powerpc/boot/dts/mpc8308rdb.dts new file mode 100644 index 000000000000..a97eb2db5a18 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8308rdb.dts @@ -0,0 +1,303 @@ +/* + * MPC8308RDB Device Tree Source + * + * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2010 Ilya Yanok, Emcraft Systems, yanok@emcraft.com + * + * 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. + */ + +/dts-v1/; + +/ { + compatible = "fsl,mpc8308rdb"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + ethernet0 = &enet0; + ethernet1 = &enet1; + serial0 = &serial0; + serial1 = &serial1; + pci0 = &pci0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8308@0 { + device_type = "cpu"; + reg = <0x0>; + d-cache-line-size = <32>; + i-cache-line-size = <32>; + d-cache-size = <16384>; + i-cache-size = <16384>; + timebase-frequency = <0>; // from bootloader + bus-frequency = <0>; // from bootloader + clock-frequency = <0>; // from bootloader + }; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x08000000>; // 128MB at 0 + }; + + localbus@e0005000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "fsl,mpc8315-elbc", "fsl,elbc", "simple-bus"; + reg = <0xe0005000 0x1000>; + interrupts = <77 0x8>; + interrupt-parent = <&ipic>; + + // CS0 and CS1 are swapped when + // booting from nand, but the + // addresses are the same. + ranges = <0x0 0x0 0xfe000000 0x00800000 + 0x1 0x0 0xe0600000 0x00002000 + 0x2 0x0 0xf0000000 0x00020000 + 0x3 0x0 0xfa000000 0x00008000>; + + flash@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x800000>; + bank-width = <2>; + device-width = <1>; + + u-boot@0 { + reg = <0x0 0x60000>; + read-only; + }; + env@60000 { + reg = <0x60000 0x10000>; + }; + env1@70000 { + reg = <0x70000 0x10000>; + }; + kernel@80000 { + reg = <0x80000 0x200000>; + }; + dtb@280000 { + reg = <0x280000 0x10000>; + }; + ramdisk@290000 { + reg = <0x290000 0x570000>; + }; + }; + + nand@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8315-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x1 0x0 0x2000>; + + jffs2@0 { + reg = <0x0 0x2000000>; + }; + }; + }; + + immr@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "fsl,mpc8315-immr", "simple-bus"; + ranges = <0 0xe0000000 0x00100000>; + reg = <0xe0000000 0x00000200>; + bus-frequency = <0>; + + i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + compatible = "fsl-i2c"; + reg = <0x3000 0x100>; + interrupts = <14 0x8>; + interrupt-parent = <&ipic>; + dfsrr; + rtc@68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + }; + }; + + usb@23000 { + compatible = "fsl-usb2-dr"; + reg = <0x23000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&ipic>; + interrupts = <38 0x8>; + dr_mode = "peripheral"; + phy_type = "ulpi"; + }; + + enet0: ethernet@24000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x24000 0x1000>; + + cell-index = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x24000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <32 0x8 33 0x8 34 0x8>; + interrupt-parent = <&ipic>; + tbi-handle = < &tbi0 >; + phy-handle = < &phy2 >; + fsl,magic-packet; + + mdio@520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-mdio"; + reg = <0x520 0x20>; + phy2: ethernet-phy@2 { + interrupt-parent = <&ipic>; + interrupts = <17 0x8>; + reg = <0x2>; + device_type = "ethernet-phy"; + }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + }; + + enet1: ethernet@25000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x25000 0x1000>; + ranges = <0x0 0x25000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <35 0x8 36 0x8 37 0x8>; + interrupt-parent = <&ipic>; + tbi-handle = < &tbi1 >; + /* Vitesse 7385 isn't on the MDIO bus */ + fixed-link = <1 1 1000 0 0>; + fsl,magic-packet; + + mdio@520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + }; + + serial0: serial@4500 { + cell-index = <0>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4500 0x100>; + clock-frequency = <133333333>; + interrupts = <9 0x8>; + interrupt-parent = <&ipic>; + }; + + serial1: serial@4600 { + cell-index = <1>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4600 0x100>; + clock-frequency = <133333333>; + interrupts = <10 0x8>; + interrupt-parent = <&ipic>; + }; + + gpio@c00 { + #gpio-cells = <2>; + device_type = "gpio"; + compatible = "fsl,mpc8308-gpio", "fsl,mpc8349-gpio"; + reg = <0xc00 0x18>; + interrupts = <74 0x8>; + interrupt-parent = <&ipic>; + gpio-controller; + }; + + /* IPIC + * interrupts cell = + * sense values match linux IORESOURCE_IRQ_* defines: + * sense == 8: Level, low assertion + * sense == 2: Edge, high-to-low change + */ + ipic: interrupt-controller@700 { + compatible = "fsl,ipic"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x700 0x100>; + device_type = "ipic"; + }; + + ipic-msi@7c0 { + compatible = "fsl,ipic-msi"; + reg = <0x7c0 0x40>; + msi-available-ranges = <0x0 0x100>; + interrupts = < 0x43 0x8 + 0x4 0x8 + 0x51 0x8 + 0x52 0x8 + 0x56 0x8 + 0x57 0x8 + 0x58 0x8 + 0x59 0x8 >; + interrupt-parent = < &ipic >; + }; + + }; + + pci0: pcie@e0009000 { + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + compatible = "fsl,mpc8308-pcie", "fsl,mpc8314-pcie"; + reg = <0xe0009000 0x00001000 + 0xb0000000 0x01000000>; + ranges = <0x02000000 0 0xa0000000 0xa0000000 0 0x10000000 + 0x01000000 0 0x00000000 0xb1000000 0 0x00800000>; + bus-range = <0 0>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = <0 0 0 1 &ipic 1 8 + 0 0 0 2 &ipic 1 8 + 0 0 0 3 &ipic 1 8 + 0 0 0 4 &ipic 1 8>; + interrupts = <0x1 0x8>; + interrupt-parent = <&ipic>; + clock-frequency = <0>; + + pcie@0 { + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + reg = <0 0 0 0 0>; + ranges = <0x02000000 0 0xa0000000 + 0x02000000 0 0xa0000000 + 0 0x10000000 + 0x01000000 0 0x00000000 + 0x01000000 0 0x00000000 + 0 0x00800000>; + }; + }; +}; diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index f49a2548c5ff..021763a32c2f 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -9,6 +9,14 @@ menuconfig PPC_83xx if PPC_83xx +config MPC830x_RDB + bool "Freescale MPC830x RDB" + select DEFAULT_UIMAGE + select PPC_MPC831x + select FSL_GTM + help + This option enables support for the MPC8308 RDB board. + config MPC831x_RDB bool "Freescale MPC831x RDB" select DEFAULT_UIMAGE diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index e139c36572ec..6e8bbbbcfdf8 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile @@ -4,6 +4,7 @@ obj-y := misc.o usb.o obj-$(CONFIG_SUSPEND) += suspend.o suspend-asm.o obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o +obj-$(CONFIG_MPC830x_RDB) += mpc830x_rdb.o obj-$(CONFIG_MPC831x_RDB) += mpc831x_rdb.o obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c new file mode 100644 index 000000000000..ac102ee9abe8 --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c @@ -0,0 +1,94 @@ +/* + * arch/powerpc/platforms/83xx/mpc830x_rdb.c + * + * Description: MPC830x RDB board specific routines. + * This file is based on mpc831x_rdb.c + * + * Copyright (C) Freescale Semiconductor, Inc. 2009. All rights reserved. + * Copyright (C) 2010. Ilya Yanok, Emcraft Systems, yanok@emcraft.com + * + * 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 +#include "mpc83xx.h" + +/* + * Setup the architecture + */ +static void __init mpc830x_rdb_setup_arch(void) +{ +#ifdef CONFIG_PCI + struct device_node *np; +#endif + + if (ppc_md.progress) + ppc_md.progress("mpc830x_rdb_setup_arch()", 0); + +#ifdef CONFIG_PCI + for_each_compatible_node(np, "pci", "fsl,mpc8308-pcie") + mpc83xx_add_bridge(np); +#endif + mpc831x_usb_cfg(); +} + +static void __init mpc830x_rdb_init_IRQ(void) +{ + struct device_node *np; + + np = of_find_node_by_type(NULL, "ipic"); + if (!np) + return; + + ipic_init(np, 0); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc830x_rdb_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "MPC8308RDB") || + of_flat_dt_is_compatible(root, "fsl,mpc8308rdb"); +} + +static struct of_device_id __initdata of_bus_ids[] = { + { .compatible = "simple-bus" }, + { .compatible = "gianfar" }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + return 0; +} +machine_device_initcall(mpc830x_rdb, declare_of_platform_devices); + +define_machine(mpc830x_rdb) { + .name = "MPC830x RDB", + .probe = mpc830x_rdb_probe, + .setup_arch = mpc830x_rdb_setup_arch, + .init_IRQ = mpc830x_rdb_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; -- cgit v1.2.3 From 07c638398f490e63275ae23aa51b7c50df7d1a49 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 21 Jul 2010 10:33:23 +0000 Subject: powerpc/tqm85xx: update PCI interrupt-map attribute Update PCI IRQ mapping on TQM85xx platforms: include INTC and INTD on PCI-X slot and add INTA/INTB mapping for PCMCIA bridge. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/tqm8540.dts | 9 ++++++++- arch/powerpc/boot/dts/tqm8541.dts | 9 ++++++++- arch/powerpc/boot/dts/tqm8548-bigflash.dts | 9 ++++++++- arch/powerpc/boot/dts/tqm8548.dts | 9 ++++++++- arch/powerpc/boot/dts/tqm8555.dts | 9 ++++++++- arch/powerpc/boot/dts/tqm8560.dts | 9 ++++++++- 6 files changed, 48 insertions(+), 6 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/tqm8540.dts b/arch/powerpc/boot/dts/tqm8540.dts index 71347537b83e..15ca731bc24e 100644 --- a/arch/powerpc/boot/dts/tqm8540.dts +++ b/arch/powerpc/boot/dts/tqm8540.dts @@ -289,7 +289,14 @@ interrupt-map = < /* IDSEL 28 */ 0xe000 0 0 1 &mpic 2 1 - 0xe000 0 0 2 &mpic 3 1>; + 0xe000 0 0 2 &mpic 3 1 + 0xe000 0 0 3 &mpic 6 1 + 0xe000 0 0 4 &mpic 5 1 + + /* IDSEL 11 */ + 0x5800 0 0 1 &mpic 6 1 + 0x5800 0 0 2 &mpic 5 1 + >; interrupt-parent = <&mpic>; interrupts = <24 2>; diff --git a/arch/powerpc/boot/dts/tqm8541.dts b/arch/powerpc/boot/dts/tqm8541.dts index b30f63753d41..f49d09181312 100644 --- a/arch/powerpc/boot/dts/tqm8541.dts +++ b/arch/powerpc/boot/dts/tqm8541.dts @@ -311,7 +311,14 @@ interrupt-map = < /* IDSEL 28 */ 0xe000 0 0 1 &mpic 2 1 - 0xe000 0 0 2 &mpic 3 1>; + 0xe000 0 0 2 &mpic 3 1 + 0xe000 0 0 3 &mpic 6 1 + 0xe000 0 0 4 &mpic 5 1 + + /* IDSEL 11 */ + 0x5800 0 0 1 &mpic 6 1 + 0x5800 0 0 2 &mpic 5 1 + >; interrupt-parent = <&mpic>; interrupts = <24 2>; diff --git a/arch/powerpc/boot/dts/tqm8548-bigflash.dts b/arch/powerpc/boot/dts/tqm8548-bigflash.dts index 61f25e15fd66..5dbb36edb038 100644 --- a/arch/powerpc/boot/dts/tqm8548-bigflash.dts +++ b/arch/powerpc/boot/dts/tqm8548-bigflash.dts @@ -442,7 +442,14 @@ interrupt-map = < /* IDSEL 28 */ 0xe000 0 0 1 &mpic 2 1 - 0xe000 0 0 2 &mpic 3 1>; + 0xe000 0 0 2 &mpic 3 1 + 0xe000 0 0 3 &mpic 6 1 + 0xe000 0 0 4 &mpic 5 1 + + /* IDSEL 11 */ + 0x5800 0 0 1 &mpic 6 1 + 0x5800 0 0 2 &mpic 5 1 + >; interrupt-parent = <&mpic>; interrupts = <24 2>; diff --git a/arch/powerpc/boot/dts/tqm8548.dts b/arch/powerpc/boot/dts/tqm8548.dts index 025759c7c955..a050ae427108 100644 --- a/arch/powerpc/boot/dts/tqm8548.dts +++ b/arch/powerpc/boot/dts/tqm8548.dts @@ -442,7 +442,14 @@ interrupt-map = < /* IDSEL 28 */ 0xe000 0 0 1 &mpic 2 1 - 0xe000 0 0 2 &mpic 3 1>; + 0xe000 0 0 2 &mpic 3 1 + 0xe000 0 0 3 &mpic 6 1 + 0xe000 0 0 4 &mpic 5 1 + + /* IDSEL 11 */ + 0x5800 0 0 1 &mpic 6 1 + 0x5800 0 0 2 &mpic 5 1 + >; interrupt-parent = <&mpic>; interrupts = <24 2>; diff --git a/arch/powerpc/boot/dts/tqm8555.dts b/arch/powerpc/boot/dts/tqm8555.dts index 95e287381836..81bad8cd3756 100644 --- a/arch/powerpc/boot/dts/tqm8555.dts +++ b/arch/powerpc/boot/dts/tqm8555.dts @@ -311,7 +311,14 @@ interrupt-map = < /* IDSEL 28 */ 0xe000 0 0 1 &mpic 2 1 - 0xe000 0 0 2 &mpic 3 1>; + 0xe000 0 0 2 &mpic 3 1 + 0xe000 0 0 3 &mpic 6 1 + 0xe000 0 0 4 &mpic 5 1 + + /* IDSEL 11 */ + 0x5800 0 0 1 &mpic 6 1 + 0x5800 0 0 2 &mpic 5 1 + >; interrupt-parent = <&mpic>; interrupts = <24 2>; diff --git a/arch/powerpc/boot/dts/tqm8560.dts b/arch/powerpc/boot/dts/tqm8560.dts index ff70580a8f4c..22ec39b5beeb 100644 --- a/arch/powerpc/boot/dts/tqm8560.dts +++ b/arch/powerpc/boot/dts/tqm8560.dts @@ -382,7 +382,14 @@ interrupt-map = < /* IDSEL 28 */ 0xe000 0 0 1 &mpic 2 1 - 0xe000 0 0 2 &mpic 3 1>; + 0xe000 0 0 2 &mpic 3 1 + 0xe000 0 0 3 &mpic 6 1 + 0xe000 0 0 4 &mpic 5 1 + + /* IDSEL 11 */ + 0x5800 0 0 1 &mpic 6 1 + 0x5800 0 0 2 &mpic 5 1 + >; interrupt-parent = <&mpic>; interrupts = <24 2>; -- cgit v1.2.3 From e9502fbe2d1e754edfb70d5738f058853097c88c Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 21 Jul 2010 10:33:24 +0000 Subject: powerpc/tqm85xx: add a quirk for ti1520 PCMCIA bridge By default ti1520 bridge expects an input clock on CLOCK pin (to control power chip). However on this boards CLOCK should be generated by PCI1520 itself. Add a quirk that enables internal 16 KHz clock generation on this pin. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/tqm85xx.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index 5b0ab9966e90..8f29bbce5360 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -151,6 +151,27 @@ static void tqm85xx_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } +static void __init tqm85xx_ti1520_fixup(struct pci_dev *pdev) +{ + unsigned int val; + + /* Do not do the fixup on other platforms! */ + if (!machine_is(tqm85xx)) + return; + + dev_info(&pdev->dev, "Using TI 1520 fixup on TQM85xx\n"); + + /* + * Enable P2CCLK bit in system control register + * to enable CLOCK output to power chip + */ + pci_read_config_dword(pdev, 0x80, &val); + pci_write_config_dword(pdev, 0x80, val | (1 << 27)); + +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, + tqm85xx_ti1520_fixup); + static struct of_device_id __initdata of_bus_ids[] = { { .compatible = "simple-bus", }, { .compatible = "gianfar", }, -- cgit v1.2.3 From 8a4ab218ef7034660982931b3e1eb6bbc2bde0ea Mon Sep 17 00:00:00 2001 From: Bradley Hughes Date: Wed, 21 Jul 2010 12:04:06 +0000 Subject: powerpc/85xx: Change deprecated binding for 85xx-based boards The "fsl,85..." style compatible binding was to be deprecated some time ago. This patch corrects existing occurrences of the incorrect binding. The memory-controller and l2-cache-controller are the only affected nodes. Signed-off-by: Bradley Hughes Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8540ads.dts | 4 ++-- arch/powerpc/boot/dts/mpc8541cds.dts | 4 ++-- arch/powerpc/boot/dts/mpc8544ds.dts | 4 ++-- arch/powerpc/boot/dts/mpc8548cds.dts | 4 ++-- arch/powerpc/boot/dts/mpc8555cds.dts | 4 ++-- arch/powerpc/boot/dts/mpc8560ads.dts | 4 ++-- arch/powerpc/boot/dts/mpc8568mds.dts | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts index 9dc292962a9a..8d1bf0fd9268 100644 --- a/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/arch/powerpc/boot/dts/mpc8540ads.dts @@ -71,14 +71,14 @@ }; memory-controller@2000 { - compatible = "fsl,8540-memory-controller"; + compatible = "fsl,mpc8540-memory-controller"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <18 2>; }; L2: l2-cache-controller@20000 { - compatible = "fsl,8540-l2-cache-controller"; + compatible = "fsl,mpc8540-l2-cache-controller"; reg = <0x20000 0x1000>; cache-line-size = <32>; // 32 bytes cache-size = <0x40000>; // L2, 256K diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index 9a3ad311aedf..87ff96549fac 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts @@ -71,14 +71,14 @@ }; memory-controller@2000 { - compatible = "fsl,8541-memory-controller"; + compatible = "fsl,mpc8541-memory-controller"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <18 2>; }; L2: l2-cache-controller@20000 { - compatible = "fsl,8541-l2-cache-controller"; + compatible = "fsl,mpc8541-l2-cache-controller"; reg = <0x20000 0x1000>; cache-line-size = <32>; // 32 bytes cache-size = <0x40000>; // L2, 256K diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts index 98e94b465662..d793968743c9 100644 --- a/arch/powerpc/boot/dts/mpc8544ds.dts +++ b/arch/powerpc/boot/dts/mpc8544ds.dts @@ -73,14 +73,14 @@ }; memory-controller@2000 { - compatible = "fsl,8544-memory-controller"; + compatible = "fsl,mpc8544-memory-controller"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <18 2>; }; L2: l2-cache-controller@20000 { - compatible = "fsl,8544-l2-cache-controller"; + compatible = "fsl,mpc8544-l2-cache-controller"; reg = <0x20000 0x1000>; cache-line-size = <32>; // 32 bytes cache-size = <0x40000>; // L2, 256K diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts index 0f5262452682..a17a5572fb73 100644 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/arch/powerpc/boot/dts/mpc8548cds.dts @@ -74,14 +74,14 @@ }; memory-controller@2000 { - compatible = "fsl,8548-memory-controller"; + compatible = "fsl,mpc8548-memory-controller"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <18 2>; }; L2: l2-cache-controller@20000 { - compatible = "fsl,8548-l2-cache-controller"; + compatible = "fsl,mpc8548-l2-cache-controller"; reg = <0x20000 0x1000>; cache-line-size = <32>; // 32 bytes cache-size = <0x80000>; // L2, 512K diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index 065b2f093de2..5c5614f9eb17 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts @@ -71,14 +71,14 @@ }; memory-controller@2000 { - compatible = "fsl,8555-memory-controller"; + compatible = "fsl,mpc8555-memory-controller"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <18 2>; }; L2: l2-cache-controller@20000 { - compatible = "fsl,8555-l2-cache-controller"; + compatible = "fsl,mpc8555-l2-cache-controller"; reg = <0x20000 0x1000>; cache-line-size = <32>; // 32 bytes cache-size = <0x40000>; // L2, 256K diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index a5bb1ec70a5a..6e85e1ba0851 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -71,14 +71,14 @@ }; memory-controller@2000 { - compatible = "fsl,8540-memory-controller"; + compatible = "fsl,mpc8540-memory-controller"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <18 2>; }; L2: l2-cache-controller@20000 { - compatible = "fsl,8540-l2-cache-controller"; + compatible = "fsl,mpc8540-l2-cache-controller"; reg = <0x20000 0x1000>; cache-line-size = <32>; // 32 bytes cache-size = <0x40000>; // L2, 256K diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index 92fb17876e7d..30cf0e098bb9 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -124,14 +124,14 @@ }; memory-controller@2000 { - compatible = "fsl,8568-memory-controller"; + compatible = "fsl,mpc8568-memory-controller"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <18 2>; }; L2: l2-cache-controller@20000 { - compatible = "fsl,8568-l2-cache-controller"; + compatible = "fsl,mpc8568-l2-cache-controller"; reg = <0x20000 0x1000>; cache-line-size = <32>; // 32 bytes cache-size = <0x80000>; // L2, 512K -- cgit v1.2.3 From 51974d3162308695f888600b15c6f6009069dd0d Mon Sep 17 00:00:00 2001 From: Bradley Hughes Date: Wed, 21 Jul 2010 12:04:00 +0000 Subject: powerpc/85xx: Adding DTS for the STx GP3-SSA MPC8555 board This version uses "fsl,mpc8555..." instead of "fsl,85..." notation. There is also an 8541 version of this board so DTS for this board is specific to the 8555 processor. Another patch is coming to fix-up other DTS that use old notation. Signed-off-by: Bradley Hughes Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/stxssa8555.dts | 380 +++++++++++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 arch/powerpc/boot/dts/stxssa8555.dts (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/stxssa8555.dts b/arch/powerpc/boot/dts/stxssa8555.dts new file mode 100644 index 000000000000..49efd44057d7 --- /dev/null +++ b/arch/powerpc/boot/dts/stxssa8555.dts @@ -0,0 +1,380 @@ +/* + * MPC8555-based STx GP3 Device Tree Source + * + * Copyright 2006, 2008 Freescale Semiconductor Inc. + * + * Copyright 2010 Silicon Turnkey Express LLC. + * + * 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. + */ + +/dts-v1/; + +/ { + model = "stx,gp3"; + compatible = "stx,gp3-8560", "stx,gp3"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + ethernet0 = &enet0; + ethernet1 = &enet1; + serial0 = &serial0; + serial1 = &serial1; + pci0 = &pci0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8555@0 { + device_type = "cpu"; + reg = <0x0>; + d-cache-line-size = <32>; // 32 bytes + i-cache-line-size = <32>; // 32 bytes + d-cache-size = <0x8000>; // L1, 32K + i-cache-size = <0x8000>; // L1, 32K + timebase-frequency = <0>; // 33 MHz, from uboot + bus-frequency = <0>; // 166 MHz + clock-frequency = <0>; // 825 MHz, from uboot + next-level-cache = <&L2>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + soc8555@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "simple-bus"; + ranges = <0x0 0xe0000000 0x100000>; + bus-frequency = <0>; + + ecm-law@0 { + compatible = "fsl,ecm-law"; + reg = <0x0 0x1000>; + fsl,num-laws = <8>; + }; + + ecm@1000 { + compatible = "fsl,mpc8555-ecm", "fsl,ecm"; + reg = <0x1000 0x1000>; + interrupts = <17 2>; + interrupt-parent = <&mpic>; + }; + + memory-controller@2000 { + compatible = "fsl,mpc8555-memory-controller"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + }; + + L2: l2-cache-controller@20000 { + compatible = "fsl,mpc8555-l2-cache-controller"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x40000>; // L2, 256K + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + compatible = "fsl-i2c"; + reg = <0x3000 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + dma@21300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8555-dma", "fsl,eloplus-dma"; + reg = <0x21300 0x4>; + ranges = <0x0 0x21100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,mpc8555-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <20 2>; + }; + dma-channel@80 { + compatible = "fsl,mpc8555-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <21 2>; + }; + dma-channel@100 { + compatible = "fsl,mpc8555-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <22 2>; + }; + dma-channel@180 { + compatible = "fsl,mpc8555-dma-channel", + "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <23 2>; + }; + }; + + enet0: ethernet@24000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <0>; + device_type = "network"; + model = "TSEC"; + compatible = "gianfar"; + reg = <0x24000 0x1000>; + ranges = <0x0 0x24000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <29 2 30 2 34 2>; + interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; + phy-handle = <&phy0>; + + mdio@520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-mdio"; + reg = <0x520 0x20>; + + phy0: ethernet-phy@2 { + interrupt-parent = <&mpic>; + interrupts = <5 1>; + reg = <0x2>; + device_type = "ethernet-phy"; + }; + phy1: ethernet-phy@4 { + interrupt-parent = <&mpic>; + interrupts = <5 1>; + reg = <0x4>; + device_type = "ethernet-phy"; + }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + }; + + enet1: ethernet@25000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <1>; + device_type = "network"; + model = "TSEC"; + compatible = "gianfar"; + reg = <0x25000 0x1000>; + ranges = <0x0 0x25000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <35 2 36 2 40 2>; + interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; + phy-handle = <&phy1>; + + mdio@520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + }; + + serial0: serial@4500 { + cell-index = <0>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4500 0x100>; // reg base, size + clock-frequency = <0>; // should we fill in in uboot? + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + serial1: serial@4600 { + cell-index = <1>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4600 0x100>; // reg base, size + clock-frequency = <0>; // should we fill in in uboot? + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + crypto@30000 { + compatible = "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <45 2>; + interrupt-parent = <&mpic>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0x7e>; + fsl,descriptor-types-mask = <0x01010ebf>; + }; + + mpic: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x40000 0x40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + }; + + cpm@919c0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8555-cpm", "fsl,cpm2"; + reg = <0x919c0 0x30>; + ranges; + + muram@80000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x80000 0x10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0x0 0x2000 0x9000 0x1000>; + }; + }; + + brg@919f0 { + compatible = "fsl,mpc8555-brg", + "fsl,cpm2-brg", + "fsl,cpm-brg"; + reg = <0x919f0 0x10 0x915f0 0x10>; + }; + + cpmpic: pic@90c00 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupts = <46 2>; + interrupt-parent = <&mpic>; + reg = <0x90c00 0x80>; + compatible = "fsl,mpc8555-cpm-pic", "fsl,cpm2-pic"; + }; + }; + }; + + pci0: pci@e0008000 { + interrupt-map-mask = <0x1f800 0x0 0x0 0x7>; + interrupt-map = < + + /* IDSEL 0x10 */ + 0x8000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0x8000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0x8000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0x8000 0x0 0x0 0x4 &mpic 0x3 0x1 + + /* IDSEL 0x11 */ + 0x8800 0x0 0x0 0x1 &mpic 0x0 0x1 + 0x8800 0x0 0x0 0x2 &mpic 0x1 0x1 + 0x8800 0x0 0x0 0x3 &mpic 0x2 0x1 + 0x8800 0x0 0x0 0x4 &mpic 0x3 0x1 + + /* IDSEL 0x12 (Slot 1) */ + 0x9000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0x9000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0x9000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0x9000 0x0 0x0 0x4 &mpic 0x3 0x1 + + /* IDSEL 0x13 (Slot 2) */ + 0x9800 0x0 0x0 0x1 &mpic 0x1 0x1 + 0x9800 0x0 0x0 0x2 &mpic 0x2 0x1 + 0x9800 0x0 0x0 0x3 &mpic 0x3 0x1 + 0x9800 0x0 0x0 0x4 &mpic 0x0 0x1 + + /* IDSEL 0x14 (Slot 3) */ + 0xa000 0x0 0x0 0x1 &mpic 0x2 0x1 + 0xa000 0x0 0x0 0x2 &mpic 0x3 0x1 + 0xa000 0x0 0x0 0x3 &mpic 0x0 0x1 + 0xa000 0x0 0x0 0x4 &mpic 0x1 0x1 + + /* IDSEL 0x15 (Slot 4) */ + 0xa800 0x0 0x0 0x1 &mpic 0x3 0x1 + 0xa800 0x0 0x0 0x2 &mpic 0x0 0x1 + 0xa800 0x0 0x0 0x3 &mpic 0x1 0x1 + 0xa800 0x0 0x0 0x4 &mpic 0x2 0x1 + + /* Bus 1 (Tundra Bridge) */ + /* IDSEL 0x12 (ISA bridge) */ + 0x19000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0x19000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0x19000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0x19000 0x0 0x0 0x4 &mpic 0x3 0x1>; + interrupt-parent = <&mpic>; + interrupts = <24 2>; + bus-range = <0 0>; + ranges = <0x2000000 0x0 0x80000000 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x0 0xe2000000 0x0 0x100000>; + clock-frequency = <66666666>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xe0008000 0x1000>; + compatible = "fsl,mpc8540-pci"; + device_type = "pci"; + + i8259@19000 { + interrupt-controller; + device_type = "interrupt-controller"; + reg = <0x19000 0x0 0x0 0x0 0x1>; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <1>; + interrupt-parent = <&pci0>; + }; + }; + + pci1: pci@e0009000 { + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + + /* IDSEL 0x15 */ + 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 + 0xa800 0x0 0x0 0x2 &mpic 0xb 0x1 + 0xa800 0x0 0x0 0x3 &mpic 0xb 0x1 + 0xa800 0x0 0x0 0x4 &mpic 0xb 0x1>; + interrupt-parent = <&mpic>; + interrupts = <25 2>; + bus-range = <0 0>; + ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x0 0xe3000000 0x0 0x100000>; + clock-frequency = <66666666>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xe0009000 0x1000>; + compatible = "fsl,mpc8540-pci"; + device_type = "pci"; + }; +}; -- cgit v1.2.3 From 30be4c965c37418606006940f45919694693e3f9 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 2 Jul 2010 17:25:03 -0500 Subject: powerpc/85xx: Introduce support for the Freescale P1022DS reference board Introduce basic support for the Freescale P1022DS reference board, based on the Freescale BSP for this board. This patch excludes the DIU, SSI, and MMC/SD drivers. Only a 36-bit DTS is provided. Update mpc86xx_smp_defconfig and mpc85xx_defconfig to support the P1022DS. This means enabling 64-bit physical address support, increasing the maximum zone order to 12 (to allow the DIU driver to allocate large chunks), and clean up the audio options to disable the deprecated OSS support. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/p1022ds.dts | 633 +++++++++++++++++++++++++++++ arch/powerpc/configs/mpc85xx_defconfig | 34 +- arch/powerpc/configs/mpc85xx_smp_defconfig | 34 +- arch/powerpc/platforms/85xx/Kconfig | 8 + arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/p1022_ds.c | 148 +++++++ 6 files changed, 814 insertions(+), 44 deletions(-) create mode 100644 arch/powerpc/boot/dts/p1022ds.dts create mode 100644 arch/powerpc/platforms/85xx/p1022_ds.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts new file mode 100644 index 000000000000..8bcb10b92677 --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds.dts @@ -0,0 +1,633 @@ +/* + * P1022 DS 36Bit Physical Address Map Device Tree Source + * + * Copyright 2010 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/dts-v1/; +/ { + model = "fsl,P1022"; + compatible = "fsl,P1022DS"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&mpic>; + + aliases { + ethernet0 = &enet0; + ethernet1 = &enet1; + serial0 = &serial0; + serial1 = &serial1; + pci0 = &pci0; + pci1 = &pci1; + pci2 = &pci2; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,P1022@0 { + device_type = "cpu"; + reg = <0x0>; + next-level-cache = <&L2>; + }; + + PowerPC,P1022@1 { + device_type = "cpu"; + reg = <0x1>; + next-level-cache = <&L2>; + }; + }; + + memory { + device_type = "memory"; + }; + + localbus@fffe05000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus"; + reg = <0 0xffe05000 0 0x1000>; + interrupts = <19 2>; + + ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 + 0x1 0x0 0xf 0xe0000000 0x08000000 + 0x2 0x0 0x0 0xffa00000 0x00040000 + 0x3 0x0 0xf 0xffdf0000 0x00008000>; + + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x8000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + reg = <0x0 0x03000000>; + label = "ramdisk-nor"; + read-only; + }; + + partition@3000000 { + reg = <0x03000000 0x00e00000>; + label = "diagnostic-nor"; + read-only; + }; + + partition@3e00000 { + reg = <0x03e00000 0x00200000>; + label = "dink-nor"; + read-only; + }; + + partition@4000000 { + reg = <0x04000000 0x00400000>; + label = "kernel-nor"; + read-only; + }; + + partition@4400000 { + reg = <0x04400000 0x03b00000>; + label = "jffs2-nor"; + }; + + partition@7f00000 { + reg = <0x07f00000 0x00080000>; + label = "dtb-nor"; + read-only; + }; + + partition@7f80000 { + reg = <0x07f80000 0x00080000>; + label = "u-boot-nor"; + read-only; + }; + }; + + nand@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,elbc-fcm-nand"; + reg = <0x2 0x0 0x40000>; + + partition@0 { + reg = <0x0 0x02000000>; + label = "u-boot-nand"; + read-only; + }; + + partition@2000000 { + reg = <0x02000000 0x10000000>; + label = "jffs2-nand"; + }; + + partition@12000000 { + reg = <0x12000000 0x10000000>; + label = "ramdisk-nand"; + read-only; + }; + + partition@22000000 { + reg = <0x22000000 0x04000000>; + label = "kernel-nand"; + }; + + partition@26000000 { + reg = <0x26000000 0x01000000>; + label = "dtb-nand"; + read-only; + }; + + partition@27000000 { + reg = <0x27000000 0x19000000>; + label = "reserved-nand"; + }; + }; + }; + + soc@fffe00000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "fsl,p1022-immr", "simple-bus"; + ranges = <0x0 0xf 0xffe00000 0x100000>; + bus-frequency = <0>; // Filled out by uboot. + + ecm-law@0 { + compatible = "fsl,ecm-law"; + reg = <0x0 0x1000>; + fsl,num-laws = <12>; + }; + + ecm@1000 { + compatible = "fsl,p1022-ecm", "fsl,ecm"; + reg = <0x1000 0x1000>; + interrupts = <16 2>; + }; + + memory-controller@2000 { + compatible = "fsl,p1022-memory-controller"; + reg = <0x2000 0x1000>; + interrupts = <16 2>; + }; + + i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + compatible = "fsl-i2c"; + reg = <0x3000 0x100>; + interrupts = <43 2>; + dfsrr; + }; + + i2c@3100 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <1>; + compatible = "fsl-i2c"; + reg = <0x3100 0x100>; + interrupts = <43 2>; + dfsrr; + + wm8776:codec@1a { + compatible = "wlf,wm8776"; + reg = <0x1a>; + /* MCLK source is a stand-alone oscillator */ + clock-frequency = <12288000>; + }; + }; + + serial0: serial@4500 { + cell-index = <0>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4500 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + }; + + serial1: serial@4600 { + cell-index = <1>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4600 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + }; + + spi@7000 { + cell-index = <0>; + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,espi"; + reg = <0x7000 0x1000>; + interrupts = <59 0x2>; + espi,num-ss-bits = <4>; + mode = "cpu"; + + fsl_m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,espi-flash"; + reg = <0>; + linux,modalias = "fsl_m25p80"; + spi-max-frequency = <40000000>; /* input clock */ + partition@0 { + label = "u-boot-spi"; + reg = <0x00000000 0x00100000>; + read-only; + }; + partition@100000 { + label = "kernel-spi"; + reg = <0x00100000 0x00500000>; + read-only; + }; + partition@600000 { + label = "dtb-spi"; + reg = <0x00600000 0x00100000>; + read-only; + }; + partition@700000 { + label = "file system-spi"; + reg = <0x00700000 0x00900000>; + }; + }; + }; + + ssi@15000 { + compatible = "fsl,mpc8610-ssi"; + cell-index = <0>; + reg = <0x15000 0x100>; + interrupts = <75 2>; + fsl,mode = "i2s-slave"; + codec-handle = <&wm8776>; + fsl,playback-dma = <&dma00>; + fsl,capture-dma = <&dma01>; + fsl,fifo-depth = <16>; + }; + + dma@c300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eloplus-dma"; + reg = <0xc300 0x4>; + ranges = <0x0 0xc100 0x200>; + cell-index = <1>; + dma00: dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupts = <76 2>; + }; + dma01: dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupts = <77 2>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupts = <78 2>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupts = <79 2>; + }; + }; + + gpio: gpio-controller@f000 { + #gpio-cells = <2>; + compatible = "fsl,mpc8572-gpio"; + reg = <0xf000 0x100>; + interrupts = <47 0x2>; + gpio-controller; + }; + + L2: l2-cache-controller@20000 { + compatible = "fsl,p1022-l2-cache-controller"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x40000>; // L2, 256K + interrupts = <16 2>; + }; + + dma@21300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eloplus-dma"; + reg = <0x21300 0x4>; + ranges = <0x0 0x21100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupts = <20 2>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupts = <21 2>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupts = <22 2>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupts = <23 2>; + }; + }; + + usb@22000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl-usb2-dr"; + reg = <0x22000 0x1000>; + interrupts = <28 0x2>; + phy_type = "ulpi"; + }; + + mdio@24000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-mdio"; + reg = <0x24000 0x1000 0xb0030 0x4>; + + phy0: ethernet-phy@0 { + interrupts = <3 1>; + reg = <0x1>; + }; + phy1: ethernet-phy@1 { + interrupts = <9 1>; + reg = <0x2>; + }; + }; + + mdio@25000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-mdio"; + reg = <0x25000 0x1000 0xb1030 0x4>; + }; + + enet0: ethernet@B0000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + fsl,magic-packet; + fsl,wake-on-filer; + local-mac-address = [ 00 00 00 00 00 00 ]; + fixed-link = <1 1 1000 0 0>; + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + queue-group@0{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB0000 0x1000>; + interrupts = <29 2 30 2 34 2>; + }; + queue-group@1{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB4000 0x1000>; + interrupts = <17 2 18 2 24 2>; + }; + }; + + enet1: ethernet@B1000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + fixed-link = <1 1 1000 0 0>; + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + queue-group@0{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB1000 0x1000>; + interrupts = <35 2 36 2 40 2>; + }; + queue-group@1{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB5000 0x1000>; + interrupts = <51 2 52 2 67 2>; + }; + }; + + sdhci@2e000 { + compatible = "fsl,p1022-esdhc", "fsl,esdhc"; + reg = <0x2e000 0x1000>; + interrupts = <72 0x2>; + fsl,sdhci-auto-cmd12; + /* Filled in by U-Boot */ + clock-frequency = <0>; + }; + + crypto@30000 { + compatible = "fsl,sec3.3", "fsl,sec3.1", "fsl,sec3.0", + "fsl,sec2.4", "fsl,sec2.2", "fsl,sec2.1", + "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <45 2 58 2>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0x97c>; + fsl,descriptor-types-mask = <0x3a30abf>; + }; + + sata@18000 { + compatible = "fsl,mpc8536-sata", "fsl,pq-sata"; + reg = <0x18000 0x1000>; + cell-index = <1>; + interrupts = <74 0x2>; + }; + + sata@19000 { + compatible = "fsl,mpc8536-sata", "fsl,pq-sata"; + reg = <0x19000 0x1000>; + cell-index = <2>; + interrupts = <41 0x2>; + }; + + power@e0070{ + compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc"; + reg = <0xe0070 0x20>; + }; + + display@10000 { + compatible = "fsl,diu", "fsl,p1022-diu"; + reg = <0x10000 1000>; + interrupts = <64 2>; + }; + + timer@41100 { + compatible = "fsl,mpic-global-timer"; + reg = <0x41100 0x204>; + interrupts = <0xf7 0x2>; + }; + + mpic: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x40000 0x40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + }; + + msi@41600 { + compatible = "fsl,p1022-msi", "fsl,mpic-msi"; + reg = <0x41600 0x80>; + msi-available-ranges = <0 0x100>; + interrupts = < + 0xe0 0 + 0xe1 0 + 0xe2 0 + 0xe3 0 + 0xe4 0 + 0xe5 0 + 0xe6 0 + 0xe7 0>; + }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,p1022-guts"; + reg = <0xe0000 0x1000>; + fsl,has-rstcr; + }; + }; + + pci0: pcie@fffe09000 { + compatible = "fsl,p1022-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xf 0xffe09000 0 0x1000>; + bus-range = <0 255>; + ranges = <0x2000000 0x0 0xa0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + clock-frequency = <33333333>; + interrupts = <16 2>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 4 1 + 0000 0 0 2 &mpic 5 1 + 0000 0 0 3 &mpic 6 1 + 0000 0 0 4 &mpic 7 1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@fffe0a000 { + compatible = "fsl,p1022-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xf 0xffe0a000 0 0x1000>; + bus-range = <0 255>; + ranges = <0x2000000 0x0 0xc0000000 0xc 0x40000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>; + clock-frequency = <33333333>; + interrupts = <16 2>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 0 1 + 0000 0 0 2 &mpic 1 1 + 0000 0 0 3 &mpic 2 1 + 0000 0 0 4 &mpic 3 1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + + pci2: pcie@fffe0b000 { + compatible = "fsl,p1022-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xf 0xffe0b000 0 0x1000>; + bus-range = <0 255>; + ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; + clock-frequency = <33333333>; + interrupts = <16 2>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 8 1 + 0000 0 0 2 &mpic 9 1 + 0000 0 0 3 &mpic 10 1 + 0000 0 0 4 &mpic 11 1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index cfebef9f9123..d32f31a03f58 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -19,7 +19,8 @@ CONFIG_E500=y CONFIG_FSL_EMB_PERFMON=y CONFIG_BOOKE=y CONFIG_FSL_BOOKE=y -# CONFIG_PHYS_64BIT is not set +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y CONFIG_SPE=y CONFIG_PPC_MMU_NOHASH=y CONFIG_PPC_MMU_NOHASH_32=y @@ -28,7 +29,7 @@ CONFIG_PPC_BOOK3E_MMU=y # CONFIG_SMP is not set CONFIG_PPC32=y CONFIG_WORD_SIZE=32 -# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y CONFIG_MMU=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_TIME=y @@ -239,6 +240,7 @@ CONFIG_MPC85xx_MDS=y CONFIG_MPC8536_DS=y CONFIG_MPC85xx_DS=y CONFIG_MPC85xx_RDB=y +CONFIG_P1022_DS=y CONFIG_SOCRATES=y CONFIG_KSI8560=y CONFIG_XES_MPC85xx=y @@ -311,7 +313,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_PAGEFLAGS_EXTENDED=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MIGRATION=y -# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_PHYS_ADDR_T_64BIT=y CONFIG_ZONE_DMA_FLAG=1 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y @@ -321,7 +323,7 @@ CONFIG_PPC_4K_PAGES=y # CONFIG_PPC_16K_PAGES is not set # CONFIG_PPC_64K_PAGES is not set # CONFIG_PPC_256K_PAGES is not set -CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORCE_MAX_ZONEORDER=12 CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set CONFIG_EXTRA_TARGETS="" @@ -1122,16 +1124,13 @@ CONFIG_VGA_CONSOLE=y # CONFIG_VGACON_SOFT_SCROLLBACK is not set CONFIG_DUMMY_CONSOLE=y CONFIG_SOUND=y -CONFIG_SOUND_OSS_CORE=y -CONFIG_SOUND_OSS_CORE_PRECLAIM=y +# CONFIG_SOUND_OSS_CORE is not set CONFIG_SND=y CONFIG_SND_TIMER=y CONFIG_SND_PCM=y # CONFIG_SND_SEQUENCER is not set -CONFIG_SND_OSSEMUL=y -CONFIG_SND_MIXER_OSS=y -CONFIG_SND_PCM_OSS=y -CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set # CONFIG_SND_HRTIMER is not set # CONFIG_SND_DYNAMIC_MINORS is not set # CONFIG_SND_SUPPORT_OLD_API is not set @@ -1145,12 +1144,7 @@ CONFIG_SND_VMASTER=y # CONFIG_SND_SBAWE_SEQ is not set # CONFIG_SND_EMU10K1_SEQ is not set CONFIG_SND_AC97_CODEC=y -CONFIG_SND_DRIVERS=y -# CONFIG_SND_DUMMY is not set -# CONFIG_SND_MTPAV is not set -# CONFIG_SND_SERIAL_U16550 is not set -# CONFIG_SND_MPU401 is not set -# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_DRIVERS is not set CONFIG_SND_PCI=y # CONFIG_SND_AD1889 is not set # CONFIG_SND_ALS300 is not set @@ -1218,12 +1212,8 @@ CONFIG_SND_INTEL8X0=y # CONFIG_SND_VIRTUOSO is not set # CONFIG_SND_VX222 is not set # CONFIG_SND_YMFPCI is not set -CONFIG_SND_PPC=y -CONFIG_SND_USB=y -# CONFIG_SND_USB_AUDIO is not set -# CONFIG_SND_USB_UA101 is not set -# CONFIG_SND_USB_USX2Y is not set -# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_PPC is not set +# CONFIG_SND_USB is not set # CONFIG_SND_SOC is not set # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index f5451d80f19b..f93de10adcda 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -19,7 +19,8 @@ CONFIG_E500=y CONFIG_FSL_EMB_PERFMON=y CONFIG_BOOKE=y CONFIG_FSL_BOOKE=y -# CONFIG_PHYS_64BIT is not set +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y CONFIG_SPE=y CONFIG_PPC_MMU_NOHASH=y CONFIG_PPC_MMU_NOHASH_32=y @@ -29,7 +30,7 @@ CONFIG_SMP=y CONFIG_NR_CPUS=8 CONFIG_PPC32=y CONFIG_WORD_SIZE=32 -# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y CONFIG_MMU=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_TIME=y @@ -243,6 +244,7 @@ CONFIG_MPC85xx_MDS=y CONFIG_MPC8536_DS=y CONFIG_MPC85xx_DS=y CONFIG_MPC85xx_RDB=y +CONFIG_P1022_DS=y CONFIG_SOCRATES=y CONFIG_KSI8560=y CONFIG_XES_MPC85xx=y @@ -316,7 +318,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_PAGEFLAGS_EXTENDED=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MIGRATION=y -# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_PHYS_ADDR_T_64BIT=y CONFIG_ZONE_DMA_FLAG=1 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y @@ -326,7 +328,7 @@ CONFIG_PPC_4K_PAGES=y # CONFIG_PPC_16K_PAGES is not set # CONFIG_PPC_64K_PAGES is not set # CONFIG_PPC_256K_PAGES is not set -CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORCE_MAX_ZONEORDER=12 CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set CONFIG_EXTRA_TARGETS="" @@ -1127,16 +1129,13 @@ CONFIG_VGA_CONSOLE=y # CONFIG_VGACON_SOFT_SCROLLBACK is not set CONFIG_DUMMY_CONSOLE=y CONFIG_SOUND=y -CONFIG_SOUND_OSS_CORE=y -CONFIG_SOUND_OSS_CORE_PRECLAIM=y +# CONFIG_SOUND_OSS_CORE is not set CONFIG_SND=y CONFIG_SND_TIMER=y CONFIG_SND_PCM=y # CONFIG_SND_SEQUENCER is not set -CONFIG_SND_OSSEMUL=y -CONFIG_SND_MIXER_OSS=y -CONFIG_SND_PCM_OSS=y -CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set # CONFIG_SND_HRTIMER is not set # CONFIG_SND_DYNAMIC_MINORS is not set # CONFIG_SND_SUPPORT_OLD_API is not set @@ -1150,12 +1149,7 @@ CONFIG_SND_VMASTER=y # CONFIG_SND_SBAWE_SEQ is not set # CONFIG_SND_EMU10K1_SEQ is not set CONFIG_SND_AC97_CODEC=y -CONFIG_SND_DRIVERS=y -# CONFIG_SND_DUMMY is not set -# CONFIG_SND_MTPAV is not set -# CONFIG_SND_SERIAL_U16550 is not set -# CONFIG_SND_MPU401 is not set -# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_DRIVERS is not set CONFIG_SND_PCI=y # CONFIG_SND_AD1889 is not set # CONFIG_SND_ALS300 is not set @@ -1223,12 +1217,8 @@ CONFIG_SND_INTEL8X0=y # CONFIG_SND_VIRTUOSO is not set # CONFIG_SND_VX222 is not set # CONFIG_SND_YMFPCI is not set -CONFIG_SND_PPC=y -CONFIG_SND_USB=y -# CONFIG_SND_USB_AUDIO is not set -# CONFIG_SND_USB_UA101 is not set -# CONFIG_SND_USB_USX2Y is not set -# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_PPC is not set +# CONFIG_SND_USB is not set # CONFIG_SND_SOC is not set # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=y diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 3a2ade2e443f..bea1f5905ad4 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -65,6 +65,14 @@ config MPC85xx_RDB help This option enables support for the MPC85xx RDB (P2020 RDB) board +config P1022_DS + bool "Freescale P1022 DS" + select DEFAULT_UIMAGE + select CONFIG_PHYS_64BIT # The DTS has 36-bit addresses + select SWIOTLB + help + This option enables support for the Freescale P1022DS reference board. + config SOCRATES bool "Socrates" select DEFAULT_UIMAGE diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 387c128f2c8c..a2ec3f8f4d06 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MPC8536_DS) += mpc8536_ds.o obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o +obj-$(CONFIG_P1022_DS) += p1022_ds.o obj-$(CONFIG_P4080_DS) += p4080_ds.o corenet_ds.o obj-$(CONFIG_STX_GP3) += stx_gp3.o obj-$(CONFIG_TQM85xx) += tqm85xx.o diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c new file mode 100644 index 000000000000..e1467c937450 --- /dev/null +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -0,0 +1,148 @@ +/* + * P1022DS board specific routines + * + * Authors: Travis Wheatley + * Dave Liu + * Timur Tabi + * + * Copyright 2010 Freescale Semiconductor, Inc. + * + * This file is taken from the Freescale P1022DS BSP, with modifications: + * 1) No DIU support (pending rewrite of DIU code) + * 2) No AMP support + * 3) No PCI endpoint support + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include + +#include +#include + +#include +#include + +void __init p1022_ds_pic_init(void) +{ + struct mpic *mpic; + struct resource r; + struct device_node *np; + + np = of_find_node_by_type(NULL, "open-pic"); + if (!np) { + pr_err("Could not find open-pic node\n"); + return; + } + + if (of_address_to_resource(np, 0, &r)) { + pr_err("Failed to map mpic register space\n"); + of_node_put(np); + return; + } + + mpic = mpic_alloc(np, r.start, + MPIC_PRIMARY | MPIC_WANTS_RESET | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + MPIC_SINGLE_DEST_CPU, + 0, 256, " OpenPIC "); + + BUG_ON(mpic == NULL); + of_node_put(np); + + mpic_init(mpic); +} + +#ifdef CONFIG_SMP +void __init mpc85xx_smp_init(void); +#endif + +/* + * Setup the architecture + */ +static void __init p1022_ds_setup_arch(void) +{ +#ifdef CONFIG_PCI + struct device_node *np; +#endif + dma_addr_t max = 0xffffffff; + + if (ppc_md.progress) + ppc_md.progress("p1022_ds_setup_arch()", 0); + +#ifdef CONFIG_PCI + for_each_compatible_node(np, "pci", "fsl,p1022-pcie") { + struct resource rsrc; + struct pci_controller *hose; + + of_address_to_resource(np, 0, &rsrc); + + if ((rsrc.start & 0xfffff) == 0x8000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + + hose = pci_find_hose_for_OF_device(np); + max = min(max, hose->dma_window_base_cur + + hose->dma_window_size); + } +#endif + +#ifdef CONFIG_SMP + mpc85xx_smp_init(); +#endif + +#ifdef CONFIG_SWIOTLB + if (lmb_end_of_DRAM() > max) { + ppc_swiotlb_enable = 1; + set_pci_dma_ops(&swiotlb_dma_ops); + ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; + } +#endif + + pr_info("Freescale P1022 DS reference board\n"); +} + +static struct of_device_id __initdata p1022_ds_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .compatible = "simple-bus", }, + { .compatible = "gianfar", }, + {}, +}; + +static int __init p1022_ds_publish_devices(void) +{ + return of_platform_bus_probe(NULL, p1022_ds_ids, NULL); +} +machine_device_initcall(p1022_ds, p1022_ds_publish_devices); + +machine_arch_initcall(p1022_ds, swiotlb_setup_bus_notifier); + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init p1022_ds_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,p1022ds"); +} + +define_machine(p1022_ds) { + .name = "P1022 DS", + .probe = p1022_ds_probe, + .setup_arch = p1022_ds_setup_arch, + .init_IRQ = p1022_ds_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; -- cgit v1.2.3 From c4b6a77663f5879de20561144716cfb675815e82 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Tue, 23 Mar 2010 08:57:01 +0100 Subject: powerpc/8xx: Add support for the MPC8xx based boards from TQC Supported SMC1 (serial console), SCC1 Ethernet (10Mbps HD). FEC Ethernet, 8MB NOR CFI Flash. Tested on STK8xx with TQM860L (with FEC) and with TQM855M (without FEC). Signed-off-by: Heiko Schocher Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/tqm8xx.dts | 172 ++++++ arch/powerpc/configs/tqm8xx_defconfig | 934 ++++++++++++++++++++++++++++++ arch/powerpc/platforms/8xx/Kconfig | 6 + arch/powerpc/platforms/8xx/Makefile | 1 + arch/powerpc/platforms/8xx/tqm8xx_setup.c | 156 +++++ 5 files changed, 1269 insertions(+) create mode 100644 arch/powerpc/boot/dts/tqm8xx.dts create mode 100644 arch/powerpc/configs/tqm8xx_defconfig create mode 100644 arch/powerpc/platforms/8xx/tqm8xx_setup.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/tqm8xx.dts b/arch/powerpc/boot/dts/tqm8xx.dts new file mode 100644 index 000000000000..f6da7ec49a8e --- /dev/null +++ b/arch/powerpc/boot/dts/tqm8xx.dts @@ -0,0 +1,172 @@ +/* + * TQM8XX Device Tree Source + * + * Heiko Schocher + * 2010 DENX Software Engineering GmbH + * + * 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. + */ + +/dts-v1/; + +/ { + model = "TQM8xx"; + compatible = "tqc,tqm8xx"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + ethernet0 = ð0; + ethernet1 = ð1; + mdio1 = &phy1; + serial0 = &smc1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,860@0 { + device_type = "cpu"; + reg = <0x0>; + d-cache-line-size = <16>; // 16 bytes + i-cache-line-size = <16>; // 16 bytes + d-cache-size = <0x1000>; // L1, 4K + i-cache-size = <0x1000>; // L1, 4K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + interrupts = <15 2>; // decrementer interrupt + interrupt-parent = <&PIC>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x2000000>; + }; + + localbus@fff00100 { + compatible = "fsl,mpc860-localbus", "fsl,pq1-localbus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0xfff00100 0x40>; + + ranges = < + 0x0 0x0 0x40000000 0x800000 + >; + + flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + bank-width = <4>; + device-width = <2>; + }; + }; + + soc@fff00000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + ranges = <0x0 0xfff00000 0x00004000>; + + phy1: mdio@e00 { + compatible = "fsl,mpc866-fec-mdio", "fsl,pq1-fec-mdio"; + reg = <0xe00 0x188>; + #address-cells = <1>; + #size-cells = <0>; + PHY: ethernet-phy@f { + reg = <0xf>; + device_type = "ethernet-phy"; + }; + }; + + eth1: ethernet@e00 { + device_type = "network"; + compatible = "fsl,mpc866-fec-enet", + "fsl,pq1-fec-enet"; + reg = <0xe00 0x188>; + interrupts = <3 1>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY>; + linux,network-index = <1>; + }; + + PIC: pic@0 { + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x0 0x24>; + compatible = "fsl,mpc860-pic", "fsl,pq1-pic"; + }; + + cpm@9c0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc860-cpm", "fsl,cpm1"; + ranges; + reg = <0x9c0 0x40>; + brg-frequency = <0>; + interrupts = <0 2>; // cpm error interrupt + interrupt-parent = <&CPM_PIC>; + + muram@2000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x2000 0x2000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0x0 0x2000>; + }; + }; + + brg@9f0 { + compatible = "fsl,mpc860-brg", + "fsl,cpm1-brg", + "fsl,cpm-brg"; + reg = <0x9f0 0x10>; + clock-frequency = <0>; + }; + + CPM_PIC: pic@930 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupts = <5 2 0 2>; + interrupt-parent = <&PIC>; + reg = <0x930 0x20>; + compatible = "fsl,mpc860-cpm-pic", + "fsl,cpm1-pic"; + }; + + + smc1: serial@a80 { + device_type = "serial"; + compatible = "fsl,mpc860-smc-uart", + "fsl,cpm1-smc-uart"; + reg = <0xa80 0x10 0x3e80 0x40>; + interrupts = <4>; + interrupt-parent = <&CPM_PIC>; + fsl,cpm-brg = <1>; + fsl,cpm-command = <0x90>; + }; + + eth0: ethernet@a00 { + device_type = "network"; + compatible = "fsl,mpc860-scc-enet", + "fsl,cpm1-scc-enet"; + reg = <0xa00 0x18 0x3c00 0x100>; + interrupts = <30>; + interrupt-parent = <&CPM_PIC>; + fsl,cpm-command = <0000>; + linux,network-index = <0>; + fixed-link = <0 0 10 0 0>; + }; + }; + }; +}; diff --git a/arch/powerpc/configs/tqm8xx_defconfig b/arch/powerpc/configs/tqm8xx_defconfig new file mode 100644 index 000000000000..85e654b64874 --- /dev/null +++ b/arch/powerpc/configs/tqm8xx_defconfig @@ -0,0 +1,934 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.34-rc1 +# Tue Mar 23 08:22:15 2010 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_PPC_BOOK3S_32 is not set +# CONFIG_PPC_85xx is not set +CONFIG_PPC_8xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_8xx=y +CONFIG_PPC_MMU_NOHASH=y +CONFIG_PPC_MMU_NOHASH_32=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_WORD_SIZE=32 +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_MMU=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set +# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set +CONFIG_IRQ_PER_CPU=y +CONFIG_NR_IRQS=512 +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DTC=y +# CONFIG_DEFAULT_UIMAGE is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TINY_RCU is not set +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +# CONFIG_BASE_FULL is not set +# CONFIG_FUTEX is not set +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y + +# +# GCOV-based kernel profiling +# +# CONFIG_SLOW_WORK is not set +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_SLABINFO=y +CONFIG_BASE_SMALL=1 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_FREEZER is not set + +# +# Platform support +# +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +CONFIG_CPM1=y +# CONFIG_MPC8XXFADS is not set +# CONFIG_MPC86XADS is not set +# CONFIG_MPC885ADS is not set +# CONFIG_PPC_EP88XC is not set +# CONFIG_PPC_ADDER875 is not set +# CONFIG_PPC_MGSUVD is not set +CONFIG_TQM8XX=y + +# +# MPC8xx CPM Options +# + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_GPIO is not set +# CONFIG_8xx_CPU6 is not set +# CONFIG_8xx_CPU15 is not set +CONFIG_NO_UCODE_PATCH=y +# CONFIG_USB_SOF_UCODE_PATCH is not set +# CONFIG_I2C_SPI_UCODE_PATCH is not set +# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set +# CONFIG_PQ2ADS is not set +# CONFIG_IPIC is not set +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_QUICC_ENGINE is not set +# CONFIG_FSL_ULI1575 is not set +CONFIG_CPM=y +# CONFIG_SIMPLE_GPIO is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_8XX_MINIMAL_FPEMU=y +# CONFIG_IOMMU_HELPER is not set +# CONFIG_SWIOTLB is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_HAS_WALK_MEMORY=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_SPARSE_IRQ=y +CONFIG_MAX_ACTIVE_REGIONS=32 +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +CONFIG_EXTRA_TARGETS="" +# CONFIG_PM is not set +# CONFIG_SECCOMP is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_FSL_SOC=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set +# CONFIG_PCI_SYSCALL is not set +# CONFIG_PCI_QSPAN is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set +# CONFIG_HAS_RAPIDIO is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_PAGE_OFFSET=0xc0000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_PHYSICAL_START=0x00000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_CFI_FLAGADM is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_DEVICE=y +CONFIG_OF_MDIO=y +# CONFIG_PARPORT is not set +# CONFIG_BLK_DEV is not set +# CONFIG_MISC_DEVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +CONFIG_DAVICOM_PHY=y +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +CONFIG_FIXED_PHY=y +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_ETHOC is not set +# CONFIG_DNET is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_XILINX_EMACLITE is not set +CONFIG_FS_ENET=y +CONFIG_FS_ENET_HAS_SCC=y +CONFIG_FS_ENET_HAS_FEC=y +CONFIG_FS_ENET_MDIO_FEC=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_CPM=y +CONFIG_SERIAL_CPM_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set + +# +# PPS support +# +# CONFIG_PPS is not set +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_SOUND is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# TI VLYNQ +# +# CONFIG_STAGING is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_NLS is not set +# CONFIG_DLM is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC32 is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_HAVE_LMB=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +# CONFIG_BOOT_TRACER is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_PPC_DISABLE_WERROR is not set +CONFIG_PPC_WERROR=y +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_XMON is not set +# CONFIG_IRQSTACKS is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +# CONFIG_CRYPTO is not set +CONFIG_PPC_CLOCK=y +CONFIG_PPC_LIB_RHEAP=y +# CONFIG_VIRTUALIZATION is not set diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 48a920a98e7b..dd35ce081cff 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -55,6 +55,12 @@ config PPC_MGSUVD help This enables support for the Keymile MGSUVD board. +config TQM8XX + bool "TQM8XX" + select CPM1 + help + support for the mpc8xx based boards from TQM. + endchoice menu "Freescale Ethernet driver platform-specific options" diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile index bdbfd7496018..a491fe6b94fc 100644 --- a/arch/powerpc/platforms/8xx/Makefile +++ b/arch/powerpc/platforms/8xx/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o obj-$(CONFIG_PPC_EP88XC) += ep88xc.o obj-$(CONFIG_PPC_ADDER875) += adder875.o obj-$(CONFIG_PPC_MGSUVD) += mgsuvd.o +obj-$(CONFIG_TQM8XX) += tqm8xx_setup.o diff --git a/arch/powerpc/platforms/8xx/tqm8xx_setup.c b/arch/powerpc/platforms/8xx/tqm8xx_setup.c new file mode 100644 index 000000000000..b71c650fbb11 --- /dev/null +++ b/arch/powerpc/platforms/8xx/tqm8xx_setup.c @@ -0,0 +1,156 @@ +/* + * Platform setup for the MPC8xx based boards from TQM. + * + * Heiko Schocher + * Copyright 2010 DENX Software Engineering GmbH + * + * based on: + * Vitaly Bordug + * + * Copyright 2005 MontaVista Software Inc. + * + * Heavily modified by Scott Wood + * Copyright 2007 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpc8xx.h" + +struct cpm_pin { + int port, pin, flags; +}; + +static struct __initdata cpm_pin tqm8xx_pins[] = { + /* SMC1 */ + {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */ + {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ + + /* SCC1 */ + {CPM_PORTA, 5, CPM_PIN_INPUT}, /* CLK1 */ + {CPM_PORTA, 7, CPM_PIN_INPUT}, /* CLK2 */ + {CPM_PORTA, 14, CPM_PIN_INPUT}, /* TX */ + {CPM_PORTA, 15, CPM_PIN_INPUT}, /* RX */ + {CPM_PORTC, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TENA */ + {CPM_PORTC, 10, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, + {CPM_PORTC, 11, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, +}; + +static struct __initdata cpm_pin tqm8xx_fec_pins[] = { + /* MII */ + {CPM_PORTD, 3, CPM_PIN_OUTPUT}, + {CPM_PORTD, 4, CPM_PIN_OUTPUT}, + {CPM_PORTD, 5, CPM_PIN_OUTPUT}, + {CPM_PORTD, 6, CPM_PIN_OUTPUT}, + {CPM_PORTD, 7, CPM_PIN_OUTPUT}, + {CPM_PORTD, 8, CPM_PIN_OUTPUT}, + {CPM_PORTD, 9, CPM_PIN_OUTPUT}, + {CPM_PORTD, 10, CPM_PIN_OUTPUT}, + {CPM_PORTD, 11, CPM_PIN_OUTPUT}, + {CPM_PORTD, 12, CPM_PIN_OUTPUT}, + {CPM_PORTD, 13, CPM_PIN_OUTPUT}, + {CPM_PORTD, 14, CPM_PIN_OUTPUT}, + {CPM_PORTD, 15, CPM_PIN_OUTPUT}, +}; + +static void __init init_pins(int n, struct cpm_pin *pin) +{ + int i; + + for (i = 0; i < n; i++) { + cpm1_set_pin(pin->port, pin->pin, pin->flags); + pin++; + } +} + +static void __init init_ioports(void) +{ + struct device_node *dnode; + struct property *prop; + int len; + + init_pins(ARRAY_SIZE(tqm8xx_pins), &tqm8xx_pins[0]); + + cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX); + + dnode = of_find_node_by_name(NULL, "aliases"); + if (dnode == NULL) + return; + prop = of_find_property(dnode, "ethernet1", &len); + if (prop == NULL) + return; + + /* init FEC pins */ + init_pins(ARRAY_SIZE(tqm8xx_fec_pins), &tqm8xx_fec_pins[0]); +} + +static void __init tqm8xx_setup_arch(void) +{ + cpm_reset(); + init_ioports(); +} + +static int __init tqm8xx_probe(void) +{ + unsigned long node = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(node, "tqc,tqm8xx"); +} + +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + { .compatible = "simple-bus" }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + + return 0; +} +machine_device_initcall(tqm8xx, declare_of_platform_devices); + +define_machine(tqm8xx) { + .name = "TQM8xx", + .probe = tqm8xx_probe, + .setup_arch = tqm8xx_setup_arch, + .init_IRQ = mpc8xx_pics_init, + .get_irq = mpc8xx_get_irq, + .restart = mpc8xx_restart, + .calibrate_decr = mpc8xx_calibrate_decr, + .set_rtc_time = mpc8xx_set_rtc_time, + .get_rtc_time = mpc8xx_get_rtc_time, + .progress = udbg_progress, +}; -- cgit v1.2.3 From 3f0a55e3579a500ce9f5cdab70a5741f99769118 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 5 Aug 2010 09:22:22 -0500 Subject: kgdb,powerpc: Replace hardcoded offset by BREAK_INSTR_SIZE kgdb_handle_breakpoint checks the first arch_kgdb_breakpoint which is not known by gdb that's why is necessary jump over it. The jump lenght is equal to BREAK_INSTR_SIZE that's why is cleaner to use defined macro instead of hardcoded non-described offset. Signed-off-by: Michal Simek Signed-off-by: Jason Wessel Acked-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/kgdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 82a7b228c81a..7f61a3ac787c 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -129,7 +129,7 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs) return 0; if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) - regs->nip += 4; + regs->nip += BREAK_INSTR_SIZE; return 1; } -- cgit v1.2.3