diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2007-10-22 14:01:06 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2007-10-22 15:20:03 -0400 |
commit | d6ec084200c37683278c821338f74ddf21ab80f5 (patch) | |
tree | 931a112061e3a861768384b8b6ea20fdd35bd41b | |
parent | 18dabf473e15850c0dbc8ff13ac1e2806d542c15 (diff) |
Add CONFIG_DEBUG_SG sg validation
Add a Kconfig entry which will toggle some sanity checks on the sg
entry and tables.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
25 files changed, 101 insertions, 0 deletions
diff --git a/include/asm-alpha/scatterlist.h b/include/asm-alpha/scatterlist.h index b7647063bd55..440747ca6349 100644 --- a/include/asm-alpha/scatterlist.h +++ b/include/asm-alpha/scatterlist.h | |||
@@ -5,6 +5,9 @@ | |||
5 | #include <asm/types.h> | 5 | #include <asm/types.h> |
6 | 6 | ||
7 | struct scatterlist { | 7 | struct scatterlist { |
8 | #ifdef CONFIG_DEBUG_SG | ||
9 | unsigned long sg_magic; | ||
10 | #endif | ||
8 | unsigned long page_link; | 11 | unsigned long page_link; |
9 | unsigned int offset; | 12 | unsigned int offset; |
10 | 13 | ||
diff --git a/include/asm-arm/scatterlist.h b/include/asm-arm/scatterlist.h index ab1d85dd0232..ca0a37d03400 100644 --- a/include/asm-arm/scatterlist.h +++ b/include/asm-arm/scatterlist.h | |||
@@ -5,6 +5,9 @@ | |||
5 | #include <asm/types.h> | 5 | #include <asm/types.h> |
6 | 6 | ||
7 | struct scatterlist { | 7 | struct scatterlist { |
8 | #ifdef CONFIG_DEBUG_SG | ||
9 | unsigned long sg_magic; | ||
10 | #endif | ||
8 | unsigned long page_link; | 11 | unsigned long page_link; |
9 | unsigned int offset; /* buffer offset */ | 12 | unsigned int offset; /* buffer offset */ |
10 | dma_addr_t dma_address; /* dma address */ | 13 | dma_addr_t dma_address; /* dma address */ |
diff --git a/include/asm-avr32/scatterlist.h b/include/asm-avr32/scatterlist.h index 1356f29d89f5..377320e3bd17 100644 --- a/include/asm-avr32/scatterlist.h +++ b/include/asm-avr32/scatterlist.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | 5 | ||
6 | struct scatterlist { | 6 | struct scatterlist { |
7 | #ifdef CONFIG_DEBUG_SG | ||
8 | unsigned long sg_magic; | ||
9 | #endif | ||
7 | unsigned long page_link; | 10 | unsigned long page_link; |
8 | unsigned int offset; | 11 | unsigned int offset; |
9 | dma_addr_t dma_address; | 12 | dma_addr_t dma_address; |
diff --git a/include/asm-blackfin/scatterlist.h b/include/asm-blackfin/scatterlist.h index 384af549e5b8..32128d53469b 100644 --- a/include/asm-blackfin/scatterlist.h +++ b/include/asm-blackfin/scatterlist.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <linux/mm.h> | 4 | #include <linux/mm.h> |
5 | 5 | ||
6 | struct scatterlist { | 6 | struct scatterlist { |
7 | #ifdef CONFIG_DEBUG_SG | ||
8 | unsigned long sg_magic; | ||
9 | #endif | ||
7 | unsigned long page_link; | 10 | unsigned long page_link; |
8 | unsigned int offset; | 11 | unsigned int offset; |
9 | dma_addr_t dma_address; | 12 | dma_addr_t dma_address; |
diff --git a/include/asm-cris/scatterlist.h b/include/asm-cris/scatterlist.h index 5a8a83440d3b..faff53ad1f96 100644 --- a/include/asm-cris/scatterlist.h +++ b/include/asm-cris/scatterlist.h | |||
@@ -2,6 +2,9 @@ | |||
2 | #define __ASM_CRIS_SCATTERLIST_H | 2 | #define __ASM_CRIS_SCATTERLIST_H |
3 | 3 | ||
4 | struct scatterlist { | 4 | struct scatterlist { |
5 | #ifdef CONFIG_DEBUG_SG | ||
6 | unsigned long sg_magic; | ||
7 | #endif | ||
5 | char * address; /* Location data is to be transferred to */ | 8 | char * address; /* Location data is to be transferred to */ |
6 | unsigned int length; | 9 | unsigned int length; |
7 | 10 | ||
diff --git a/include/asm-frv/scatterlist.h b/include/asm-frv/scatterlist.h index 53dade7b2e16..f7da007b763c 100644 --- a/include/asm-frv/scatterlist.h +++ b/include/asm-frv/scatterlist.h | |||
@@ -22,6 +22,9 @@ | |||
22 | * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens | 22 | * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens |
23 | */ | 23 | */ |
24 | struct scatterlist { | 24 | struct scatterlist { |
25 | #ifdef CONFIG_DEBUG_SG | ||
26 | unsigned long sg_magic; | ||
27 | #endif | ||
25 | unsigned long page_link; | 28 | unsigned long page_link; |
26 | unsigned int offset; /* for highmem, page offset */ | 29 | unsigned int offset; /* for highmem, page offset */ |
27 | 30 | ||
diff --git a/include/asm-h8300/scatterlist.h b/include/asm-h8300/scatterlist.h index 7e41983d6b26..d3ecdd87ac90 100644 --- a/include/asm-h8300/scatterlist.h +++ b/include/asm-h8300/scatterlist.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | 5 | ||
6 | struct scatterlist { | 6 | struct scatterlist { |
7 | #ifdef CONFIG_DEBUG_SG | ||
8 | unsigned long sg_magic; | ||
9 | #endif | ||
7 | unsigned long page_link; | 10 | unsigned long page_link; |
8 | unsigned int offset; | 11 | unsigned int offset; |
9 | dma_addr_t dma_address; | 12 | dma_addr_t dma_address; |
diff --git a/include/asm-ia64/scatterlist.h b/include/asm-ia64/scatterlist.h index 2f76ce304964..d6f57874041d 100644 --- a/include/asm-ia64/scatterlist.h +++ b/include/asm-ia64/scatterlist.h | |||
@@ -9,6 +9,9 @@ | |||
9 | #include <asm/types.h> | 9 | #include <asm/types.h> |
10 | 10 | ||
11 | struct scatterlist { | 11 | struct scatterlist { |
12 | #ifdef CONFIG_DEBUG_SG | ||
13 | unsigned long sg_magic; | ||
14 | #endif | ||
12 | unsigned long page_link; | 15 | unsigned long page_link; |
13 | unsigned int offset; | 16 | unsigned int offset; |
14 | unsigned int length; /* buffer length */ | 17 | unsigned int length; /* buffer length */ |
diff --git a/include/asm-m32r/scatterlist.h b/include/asm-m32r/scatterlist.h index 33b4b4d2c89e..1ed372c73d0b 100644 --- a/include/asm-m32r/scatterlist.h +++ b/include/asm-m32r/scatterlist.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | 5 | ||
6 | struct scatterlist { | 6 | struct scatterlist { |
7 | #ifdef CONFIG_DEBUG_SG | ||
8 | unsigned long sg_magic; | ||
9 | #endif | ||
7 | char * address; /* Location data is to be transferred to, NULL for | 10 | char * address; /* Location data is to be transferred to, NULL for |
8 | * highmem page */ | 11 | * highmem page */ |
9 | unsigned long page_link; | 12 | unsigned long page_link; |
diff --git a/include/asm-m68k/scatterlist.h b/include/asm-m68k/scatterlist.h index e06bb891048e..d3a7a0edfeca 100644 --- a/include/asm-m68k/scatterlist.h +++ b/include/asm-m68k/scatterlist.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | 5 | ||
6 | struct scatterlist { | 6 | struct scatterlist { |
7 | #ifdef CONFIG_DEBUG_SG | ||
8 | unsigned long sg_magic; | ||
9 | #endif | ||
7 | unsigned long page_link; | 10 | unsigned long page_link; |
8 | unsigned int offset; | 11 | unsigned int offset; |
9 | unsigned int length; | 12 | unsigned int length; |
diff --git a/include/asm-m68knommu/scatterlist.h b/include/asm-m68knommu/scatterlist.h index 28bed41dc80b..10942840e88f 100644 --- a/include/asm-m68knommu/scatterlist.h +++ b/include/asm-m68knommu/scatterlist.h | |||
@@ -5,6 +5,9 @@ | |||
5 | #include <asm/types.h> | 5 | #include <asm/types.h> |
6 | 6 | ||
7 | struct scatterlist { | 7 | struct scatterlist { |
8 | #ifdef CONFIG_DEBUG_SG | ||
9 | unsigned long sg_magic; | ||
10 | #endif | ||
8 | unsigned long page_link; | 11 | unsigned long page_link; |
9 | unsigned int offset; | 12 | unsigned int offset; |
10 | dma_addr_t dma_address; | 13 | dma_addr_t dma_address; |
diff --git a/include/asm-mips/scatterlist.h b/include/asm-mips/scatterlist.h index 787797cdb0a9..83d69fe17c9f 100644 --- a/include/asm-mips/scatterlist.h +++ b/include/asm-mips/scatterlist.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | 5 | ||
6 | struct scatterlist { | 6 | struct scatterlist { |
7 | #ifdef CONFIG_DEBUG_SG | ||
8 | unsigned long sg_magic; | ||
9 | #endif | ||
7 | unsigned long page_link; | 10 | unsigned long page_link; |
8 | unsigned int offset; | 11 | unsigned int offset; |
9 | dma_addr_t dma_address; | 12 | dma_addr_t dma_address; |
diff --git a/include/asm-parisc/scatterlist.h b/include/asm-parisc/scatterlist.h index 26da9146fffb..cd3cfdf82289 100644 --- a/include/asm-parisc/scatterlist.h +++ b/include/asm-parisc/scatterlist.h | |||
@@ -5,6 +5,9 @@ | |||
5 | #include <asm/types.h> | 5 | #include <asm/types.h> |
6 | 6 | ||
7 | struct scatterlist { | 7 | struct scatterlist { |
8 | #ifdef CONFIG_DEBUG_SG | ||
9 | unsigned long sg_magic; | ||
10 | #endif | ||
8 | unsigned long page_link; | 11 | unsigned long page_link; |
9 | unsigned int offset; | 12 | unsigned int offset; |
10 | 13 | ||
diff --git a/include/asm-powerpc/scatterlist.h b/include/asm-powerpc/scatterlist.h index b9f1dbc24843..fcf7d55afe45 100644 --- a/include/asm-powerpc/scatterlist.h +++ b/include/asm-powerpc/scatterlist.h | |||
@@ -14,6 +14,9 @@ | |||
14 | #include <asm/dma.h> | 14 | #include <asm/dma.h> |
15 | 15 | ||
16 | struct scatterlist { | 16 | struct scatterlist { |
17 | #ifdef CONFIG_DEBUG_SG | ||
18 | unsigned long sg_magic; | ||
19 | #endif | ||
17 | unsigned long page_link; | 20 | unsigned long page_link; |
18 | unsigned int offset; | 21 | unsigned int offset; |
19 | unsigned int length; | 22 | unsigned int length; |
diff --git a/include/asm-s390/scatterlist.h b/include/asm-s390/scatterlist.h index eb3948690d6e..29ec8e28c8df 100644 --- a/include/asm-s390/scatterlist.h +++ b/include/asm-s390/scatterlist.h | |||
@@ -2,6 +2,9 @@ | |||
2 | #define _ASMS390_SCATTERLIST_H | 2 | #define _ASMS390_SCATTERLIST_H |
3 | 3 | ||
4 | struct scatterlist { | 4 | struct scatterlist { |
5 | #ifdef CONFIG_DEBUG_SG | ||
6 | unsigned long sg_magic; | ||
7 | #endif | ||
5 | unsigned long page_link; | 8 | unsigned long page_link; |
6 | unsigned int offset; | 9 | unsigned int offset; |
7 | unsigned int length; | 10 | unsigned int length; |
diff --git a/include/asm-sh/scatterlist.h b/include/asm-sh/scatterlist.h index bc7c809e16fb..a7d0d1856a99 100644 --- a/include/asm-sh/scatterlist.h +++ b/include/asm-sh/scatterlist.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | 5 | ||
6 | struct scatterlist { | 6 | struct scatterlist { |
7 | #ifdef CONFIG_DEBUG_SG | ||
8 | unsigned long sg_magic; | ||
9 | #endif | ||
7 | unsigned long page_link; | 10 | unsigned long page_link; |
8 | unsigned int offset;/* for highmem, page offset */ | 11 | unsigned int offset;/* for highmem, page offset */ |
9 | dma_addr_t dma_address; | 12 | dma_addr_t dma_address; |
diff --git a/include/asm-sh64/scatterlist.h b/include/asm-sh64/scatterlist.h index 0afd856e218a..5109251970e7 100644 --- a/include/asm-sh64/scatterlist.h +++ b/include/asm-sh64/scatterlist.h | |||
@@ -14,6 +14,9 @@ | |||
14 | #include <asm/types.h> | 14 | #include <asm/types.h> |
15 | 15 | ||
16 | struct scatterlist { | 16 | struct scatterlist { |
17 | #ifdef CONFIG_DEBUG_SG | ||
18 | unsigned long sg_magic; | ||
19 | #endif | ||
17 | unsigned long page_link; | 20 | unsigned long page_link; |
18 | unsigned int offset;/* for highmem, page offset */ | 21 | unsigned int offset;/* for highmem, page offset */ |
19 | dma_addr_t dma_address; | 22 | dma_addr_t dma_address; |
diff --git a/include/asm-sparc/scatterlist.h b/include/asm-sparc/scatterlist.h index 45b16f1072be..e08d3d775b08 100644 --- a/include/asm-sparc/scatterlist.h +++ b/include/asm-sparc/scatterlist.h | |||
@@ -5,6 +5,9 @@ | |||
5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
6 | 6 | ||
7 | struct scatterlist { | 7 | struct scatterlist { |
8 | #ifdef CONFIG_DEBUG_SG | ||
9 | unsigned long sg_magic; | ||
10 | #endif | ||
8 | unsigned long page_link; | 11 | unsigned long page_link; |
9 | unsigned int offset; | 12 | unsigned int offset; |
10 | 13 | ||
diff --git a/include/asm-sparc64/scatterlist.h b/include/asm-sparc64/scatterlist.h index 4cbaf7c6b0bb..6df23f070b1a 100644 --- a/include/asm-sparc64/scatterlist.h +++ b/include/asm-sparc64/scatterlist.h | |||
@@ -6,6 +6,9 @@ | |||
6 | #include <asm/types.h> | 6 | #include <asm/types.h> |
7 | 7 | ||
8 | struct scatterlist { | 8 | struct scatterlist { |
9 | #ifdef CONFIG_DEBUG_SG | ||
10 | unsigned long sg_magic; | ||
11 | #endif | ||
9 | unsigned long page_link; | 12 | unsigned long page_link; |
10 | unsigned int offset; | 13 | unsigned int offset; |
11 | 14 | ||
diff --git a/include/asm-v850/scatterlist.h b/include/asm-v850/scatterlist.h index db91febc2100..02d27b3fb061 100644 --- a/include/asm-v850/scatterlist.h +++ b/include/asm-v850/scatterlist.h | |||
@@ -17,6 +17,9 @@ | |||
17 | #include <asm/types.h> | 17 | #include <asm/types.h> |
18 | 18 | ||
19 | struct scatterlist { | 19 | struct scatterlist { |
20 | #ifdef CONFIG_DEBUG_SG | ||
21 | unsigned long sg_magic; | ||
22 | #endif | ||
20 | unsigned long page_link; | 23 | unsigned long page_link; |
21 | unsigned offset; | 24 | unsigned offset; |
22 | dma_addr_t dma_address; | 25 | dma_addr_t dma_address; |
diff --git a/include/asm-x86/scatterlist_32.h b/include/asm-x86/scatterlist_32.h index 140a5b37fa77..0e7d997a34be 100644 --- a/include/asm-x86/scatterlist_32.h +++ b/include/asm-x86/scatterlist_32.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | 5 | ||
6 | struct scatterlist { | 6 | struct scatterlist { |
7 | #ifdef CONFIG_DEBUG_SG | ||
8 | unsigned long sg_magic; | ||
9 | #endif | ||
7 | unsigned long page_link; | 10 | unsigned long page_link; |
8 | unsigned int offset; | 11 | unsigned int offset; |
9 | dma_addr_t dma_address; | 12 | dma_addr_t dma_address; |
diff --git a/include/asm-x86/scatterlist_64.h b/include/asm-x86/scatterlist_64.h index e3447846e03d..1847c72befeb 100644 --- a/include/asm-x86/scatterlist_64.h +++ b/include/asm-x86/scatterlist_64.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | 5 | ||
6 | struct scatterlist { | 6 | struct scatterlist { |
7 | #ifdef CONFIG_DEBUG_SG | ||
8 | unsigned long sg_magic; | ||
9 | #endif | ||
7 | unsigned long page_link; | 10 | unsigned long page_link; |
8 | unsigned int offset; | 11 | unsigned int offset; |
9 | unsigned int length; | 12 | unsigned int length; |
diff --git a/include/asm-xtensa/scatterlist.h b/include/asm-xtensa/scatterlist.h index 3b8aba5d2c68..810080bb0a2b 100644 --- a/include/asm-xtensa/scatterlist.h +++ b/include/asm-xtensa/scatterlist.h | |||
@@ -14,6 +14,9 @@ | |||
14 | #include <asm/types.h> | 14 | #include <asm/types.h> |
15 | 15 | ||
16 | struct scatterlist { | 16 | struct scatterlist { |
17 | #ifdef CONFIG_DEBUG_SG | ||
18 | unsigned long sg_magic; | ||
19 | #endif | ||
17 | unsigned long page_link; | 20 | unsigned long page_link; |
18 | unsigned int offset; | 21 | unsigned int offset; |
19 | dma_addr_t dma_address; | 22 | dma_addr_t dma_address; |
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index c6136e8a7f58..42daf5e15265 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h | |||
@@ -23,6 +23,8 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #define SG_MAGIC 0x87654321 | ||
27 | |||
26 | /** | 28 | /** |
27 | * sg_set_page - Set sg entry to point at given page | 29 | * sg_set_page - Set sg entry to point at given page |
28 | * @sg: SG entry | 30 | * @sg: SG entry |
@@ -39,6 +41,9 @@ static inline void sg_set_page(struct scatterlist *sg, struct page *page) | |||
39 | { | 41 | { |
40 | unsigned long page_link = sg->page_link & 0x3; | 42 | unsigned long page_link = sg->page_link & 0x3; |
41 | 43 | ||
44 | #ifdef CONFIG_DEBUG_SG | ||
45 | BUG_ON(sg->sg_magic != SG_MAGIC); | ||
46 | #endif | ||
42 | sg->page_link = page_link | (unsigned long) page; | 47 | sg->page_link = page_link | (unsigned long) page; |
43 | } | 48 | } |
44 | 49 | ||
@@ -81,6 +86,9 @@ static inline void sg_set_buf(struct scatterlist *sg, const void *buf, | |||
81 | **/ | 86 | **/ |
82 | static inline struct scatterlist *sg_next(struct scatterlist *sg) | 87 | static inline struct scatterlist *sg_next(struct scatterlist *sg) |
83 | { | 88 | { |
89 | #ifdef CONFIG_DEBUG_SG | ||
90 | BUG_ON(sg->sg_magic != SG_MAGIC); | ||
91 | #endif | ||
84 | if (sg_is_last(sg)) | 92 | if (sg_is_last(sg)) |
85 | return NULL; | 93 | return NULL; |
86 | 94 | ||
@@ -124,6 +132,10 @@ static inline struct scatterlist *sg_last(struct scatterlist *sgl, | |||
124 | ret = sg; | 132 | ret = sg; |
125 | 133 | ||
126 | #endif | 134 | #endif |
135 | #ifdef CONFIG_DEBUG_SG | ||
136 | BUG_ON(sgl[0].sg_magic != SG_MAGIC); | ||
137 | BUG_ON(!sg_is_last(ret)); | ||
138 | #endif | ||
127 | return ret; | 139 | return ret; |
128 | } | 140 | } |
129 | 141 | ||
@@ -180,6 +192,9 @@ static inline void sg_init_one(struct scatterlist *sg, const void *buf, | |||
180 | unsigned int buflen) | 192 | unsigned int buflen) |
181 | { | 193 | { |
182 | memset(sg, 0, sizeof(*sg)); | 194 | memset(sg, 0, sizeof(*sg)); |
195 | #ifdef CONFIG_DEBUG_SG | ||
196 | sg->sg_magic = SG_MAGIC; | ||
197 | #endif | ||
183 | sg_mark_end(sg, 1); | 198 | sg_mark_end(sg, 1); |
184 | sg_set_buf(sg, buf, buflen); | 199 | sg_set_buf(sg, buf, buflen); |
185 | } | 200 | } |
@@ -198,6 +213,13 @@ static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents) | |||
198 | { | 213 | { |
199 | memset(sgl, 0, sizeof(*sgl) * nents); | 214 | memset(sgl, 0, sizeof(*sgl) * nents); |
200 | sg_mark_end(sgl, nents); | 215 | sg_mark_end(sgl, nents); |
216 | #ifdef CONFIG_DEBUG_SG | ||
217 | { | ||
218 | int i; | ||
219 | for (i = 0; i < nents; i++) | ||
220 | sgl[i].sg_magic = SG_MAGIC; | ||
221 | } | ||
222 | #endif | ||
201 | } | 223 | } |
202 | 224 | ||
203 | /** | 225 | /** |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c567f219191d..1faa5087dc86 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -389,6 +389,16 @@ config DEBUG_LIST | |||
389 | 389 | ||
390 | If unsure, say N. | 390 | If unsure, say N. |
391 | 391 | ||
392 | config DEBUG_SG | ||
393 | bool "Debug SG table operations" | ||
394 | depends on DEBUG_KERNEL | ||
395 | help | ||
396 | Enable this to turn on checks on scatter-gather tables. This can | ||
397 | help find problems with drivers that do not properly initialize | ||
398 | their sg tables. | ||
399 | |||
400 | If unsure, say N. | ||
401 | |||
392 | config FRAME_POINTER | 402 | config FRAME_POINTER |
393 | bool "Compile the kernel with frame pointers" | 403 | bool "Compile the kernel with frame pointers" |
394 | depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH || BFIN) | 404 | depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH || BFIN) |