aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/net
diff options
context:
space:
mode:
authorPhilippe Bergheaud <felix@linux.vnet.ibm.com>2013-09-24 08:13:35 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-10-31 01:19:15 -0400
commit9c662cad2fb66ff3a44b1d4f545bf496bf67ab10 (patch)
tree631ffe0b18388dd7010c2ad36765307816e8ae22 /arch/powerpc/net
parent711b5138d54fcfd5e312cea895d6e706a46eff19 (diff)
powerpc/bpf: BPF JIT compiler for 64-bit Little Endian
This enables the Berkeley Packet Filter JIT compiler for the PowerPC running in 64bit Little Endian. Signed-off-by: Philippe Bergheaud <felix@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/net')
-rw-r--r--arch/powerpc/net/bpf_jit.h10
-rw-r--r--arch/powerpc/net/bpf_jit_64.S9
-rw-r--r--arch/powerpc/net/bpf_jit_comp.c17
3 files changed, 20 insertions, 16 deletions
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 8a5dfaf5c6b7..0baf2b826e25 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -92,6 +92,8 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
92 ___PPC_RA(base) | IMM_L(i)) 92 ___PPC_RA(base) | IMM_L(i))
93#define PPC_LHZ(r, base, i) EMIT(PPC_INST_LHZ | ___PPC_RT(r) | \ 93#define PPC_LHZ(r, base, i) EMIT(PPC_INST_LHZ | ___PPC_RT(r) | \
94 ___PPC_RA(base) | IMM_L(i)) 94 ___PPC_RA(base) | IMM_L(i))
95#define PPC_LHBRX(r, base, b) EMIT(PPC_INST_LHBRX | ___PPC_RT(r) | \
96 ___PPC_RA(base) | ___PPC_RB(b))
95/* Convenience helpers for the above with 'far' offsets: */ 97/* Convenience helpers for the above with 'far' offsets: */
96#define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) PPC_LD(r, base, i); \ 98#define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) PPC_LD(r, base, i); \
97 else { PPC_ADDIS(r, base, IMM_HA(i)); \ 99 else { PPC_ADDIS(r, base, IMM_HA(i)); \
@@ -186,6 +188,14 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
186 PPC_ORI(d, d, (uintptr_t)(i) & 0xffff); \ 188 PPC_ORI(d, d, (uintptr_t)(i) & 0xffff); \
187 } } while (0); 189 } } while (0);
188 190
191#define PPC_LHBRX_OFFS(r, base, i) \
192 do { PPC_LI32(r, i); PPC_LHBRX(r, r, base); } while(0)
193#ifdef __LITTLE_ENDIAN__
194#define PPC_NTOHS_OFFS(r, base, i) PPC_LHBRX_OFFS(r, base, i)
195#else
196#define PPC_NTOHS_OFFS(r, base, i) PPC_LHZ_OFFS(r, base, i)
197#endif
198
189static inline bool is_nearbranch(int offset) 199static inline bool is_nearbranch(int offset)
190{ 200{
191 return (offset < 32768) && (offset >= -32768); 201 return (offset < 32768) && (offset >= -32768);
diff --git a/arch/powerpc/net/bpf_jit_64.S b/arch/powerpc/net/bpf_jit_64.S
index 7d3a3b5619a2..e76eba74d9da 100644
--- a/arch/powerpc/net/bpf_jit_64.S
+++ b/arch/powerpc/net/bpf_jit_64.S
@@ -43,8 +43,11 @@ sk_load_word_positive_offset:
43 cmpd r_scratch1, r_addr 43 cmpd r_scratch1, r_addr
44 blt bpf_slow_path_word 44 blt bpf_slow_path_word
45 /* Nope, just hitting the header. cr0 here is eq or gt! */ 45 /* Nope, just hitting the header. cr0 here is eq or gt! */
46#ifdef __LITTLE_ENDIAN__
47 lwbrx r_A, r_D, r_addr
48#else
46 lwzx r_A, r_D, r_addr 49 lwzx r_A, r_D, r_addr
47 /* When big endian we don't need to byteswap. */ 50#endif
48 blr /* Return success, cr0 != LT */ 51 blr /* Return success, cr0 != LT */
49 52
50 .globl sk_load_half 53 .globl sk_load_half
@@ -56,7 +59,11 @@ sk_load_half_positive_offset:
56 subi r_scratch1, r_HL, 2 59 subi r_scratch1, r_HL, 2
57 cmpd r_scratch1, r_addr 60 cmpd r_scratch1, r_addr
58 blt bpf_slow_path_half 61 blt bpf_slow_path_half
62#ifdef __LITTLE_ENDIAN__
63 lhbrx r_A, r_D, r_addr
64#else
59 lhzx r_A, r_D, r_addr 65 lhzx r_A, r_D, r_addr
66#endif
60 blr 67 blr
61 68
62 .globl sk_load_byte 69 .globl sk_load_byte
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index bf56e33f8257..81cd6c79babe 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -17,14 +17,8 @@
17 17
18#include "bpf_jit.h" 18#include "bpf_jit.h"
19 19
20#ifndef __BIG_ENDIAN
21/* There are endianness assumptions herein. */
22#error "Little-endian PPC not supported in BPF compiler"
23#endif
24
25int bpf_jit_enable __read_mostly; 20int bpf_jit_enable __read_mostly;
26 21
27
28static inline void bpf_flush_icache(void *start, void *end) 22static inline void bpf_flush_icache(void *start, void *end)
29{ 23{
30 smp_wmb(); 24 smp_wmb();
@@ -346,18 +340,11 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
346 break; 340 break;
347 341
348 /*** Ancillary info loads ***/ 342 /*** Ancillary info loads ***/
349
350 /* None of the BPF_S_ANC* codes appear to be passed by
351 * sk_chk_filter(). The interpreter and the x86 BPF
352 * compiler implement them so we do too -- they may be
353 * planted in future.
354 */
355 case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */ 343 case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
356 BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, 344 BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
357 protocol) != 2); 345 protocol) != 2);
358 PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, 346 PPC_NTOHS_OFFS(r_A, r_skb, offsetof(struct sk_buff,
359 protocol)); 347 protocol));
360 /* ntohs is a NOP with BE loads. */
361 break; 348 break;
362 case BPF_S_ANC_IFINDEX: 349 case BPF_S_ANC_IFINDEX:
363 PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff, 350 PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,