aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:34:57 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:34:57 -0400
commita989705c4cf6e6c1a339c95f9daf658b4ba88ca8 (patch)
treed1925b831ec9fbae65db1b193dbad1869c43a9bc
parent2d56d3c43cc97ae48586745556f5a5b564d61582 (diff)
parentd29182534c5f39ff899763d1e0982d8f33791d6f (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6: [IA64] update memory attribute aliasing documentation & test cases [IA64] fail mmaps that span areas with incompatible attributes [IA64] allow WB /sys/.../legacy_mem mmaps [IA64] make ioremap avoid unsupported attributes [IA64] rename ioremap variables to match i386 [IA64] relax per-cpu TLB requirement to DTC [IA64] remove per-cpu ia64_phys_stacked_size_p8 [IA64] Fix example error injection program [IA64] Itanium MC Error Injection Tool: pal_mc_error_inject() interface [IA64] Itanium MC Error Injection Tool: Makefile changes [IA64] Itanium MC Error Injection Tool: Driver sysfs interface [IA64] Itanium MC Error Injection Tool: Doc and sample application [IA64] Itanium MC Error Injection Tool: Kernel configuration
-rw-r--r--Documentation/ia64/aliasing-test.c247
-rw-r--r--Documentation/ia64/aliasing.txt71
-rw-r--r--Documentation/ia64/err_inject.txt1068
-rw-r--r--arch/ia64/Kconfig10
-rw-r--r--arch/ia64/defconfig1
-rw-r--r--arch/ia64/kernel/Makefile1
-rw-r--r--arch/ia64/kernel/efi.c46
-rw-r--r--arch/ia64/kernel/entry.S7
-rw-r--r--arch/ia64/kernel/err_inject.c293
-rw-r--r--arch/ia64/kernel/ivt.S19
-rw-r--r--arch/ia64/kernel/mca_asm.S24
-rw-r--r--arch/ia64/kernel/patch.c20
-rw-r--r--arch/ia64/kernel/setup.c7
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S7
-rw-r--r--arch/ia64/mm/init.c11
-rw-r--r--arch/ia64/mm/ioremap.c78
-rw-r--r--arch/ia64/pci/pci.c2
-rw-r--r--include/asm-ia64/asmmacro.h10
-rw-r--r--include/asm-ia64/io.h6
-rw-r--r--include/asm-ia64/kregs.h3
-rw-r--r--include/asm-ia64/pal.h33
-rw-r--r--include/asm-ia64/patch.h1
-rw-r--r--include/asm-ia64/processor.h1
-rw-r--r--include/asm-ia64/sections.h1
24 files changed, 1861 insertions, 106 deletions
diff --git a/Documentation/ia64/aliasing-test.c b/Documentation/ia64/aliasing-test.c
new file mode 100644
index 000000000000..3153167b41c3
--- /dev/null
+++ b/Documentation/ia64/aliasing-test.c
@@ -0,0 +1,247 @@
1/*
2 * Exercise /dev/mem mmap cases that have been troublesome in the past
3 *
4 * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
5 * Bjorn Helgaas <bjorn.helgaas@hp.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/types.h>
15#include <dirent.h>
16#include <fcntl.h>
17#include <fnmatch.h>
18#include <string.h>
19#include <sys/mman.h>
20#include <sys/stat.h>
21#include <unistd.h>
22
23int sum;
24
25int map_mem(char *path, off_t offset, size_t length, int touch)
26{
27 int fd, rc;
28 void *addr;
29 int *c;
30
31 fd = open(path, O_RDWR);
32 if (fd == -1) {
33 perror(path);
34 return -1;
35 }
36
37 addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
38 if (addr == MAP_FAILED)
39 return 1;
40
41 if (touch) {
42 c = (int *) addr;
43 while (c < (int *) (offset + length))
44 sum += *c++;
45 }
46
47 rc = munmap(addr, length);
48 if (rc == -1) {
49 perror("munmap");
50 return -1;
51 }
52
53 close(fd);
54 return 0;
55}
56
57int scan_sysfs(char *path, char *file, off_t offset, size_t length, int touch)
58{
59 struct dirent **namelist;
60 char *name, *path2;
61 int i, n, r, rc, result = 0;
62 struct stat buf;
63
64 n = scandir(path, &namelist, 0, alphasort);
65 if (n < 0) {
66 perror("scandir");
67 return -1;
68 }
69
70 for (i = 0; i < n; i++) {
71 name = namelist[i]->d_name;
72
73 if (fnmatch(".", name, 0) == 0)
74 goto skip;
75 if (fnmatch("..", name, 0) == 0)
76 goto skip;
77
78 path2 = malloc(strlen(path) + strlen(name) + 3);
79 strcpy(path2, path);
80 strcat(path2, "/");
81 strcat(path2, name);
82
83 if (fnmatch(file, name, 0) == 0) {
84 rc = map_mem(path2, offset, length, touch);
85 if (rc == 0)
86 fprintf(stderr, "PASS: %s 0x%lx-0x%lx is %s\n", path2, offset, offset + length, touch ? "readable" : "mappable");
87 else if (rc > 0)
88 fprintf(stderr, "PASS: %s 0x%lx-0x%lx not mappable\n", path2, offset, offset + length);
89 else {
90 fprintf(stderr, "FAIL: %s 0x%lx-0x%lx not accessible\n", path2, offset, offset + length);
91 return rc;
92 }
93 } else {
94 r = lstat(path2, &buf);
95 if (r == 0 && S_ISDIR(buf.st_mode)) {
96 rc = scan_sysfs(path2, file, offset, length, touch);
97 if (rc < 0)
98 return rc;
99 }
100 }
101
102 result |= rc;
103 free(path2);
104
105skip:
106 free(namelist[i]);
107 }
108 free(namelist);
109 return rc;
110}
111
112char buf[1024];
113
114int read_rom(char *path)
115{
116 int fd, rc;
117 size_t size = 0;
118
119 fd = open(path, O_RDWR);
120 if (fd == -1) {
121 perror(path);
122 return -1;
123 }
124
125 rc = write(fd, "1", 2);
126 if (rc <= 0) {
127 perror("write");
128 return -1;
129 }
130
131 do {
132 rc = read(fd, buf, sizeof(buf));
133 if (rc > 0)
134 size += rc;
135 } while (rc > 0);
136
137 close(fd);
138 return size;
139}
140
141int scan_rom(char *path, char *file)
142{
143 struct dirent **namelist;
144 char *name, *path2;
145 int i, n, r, rc, result = 0;
146 struct stat buf;
147
148 n = scandir(path, &namelist, 0, alphasort);
149 if (n < 0) {
150 perror("scandir");
151 return -1;
152 }
153
154 for (i = 0; i < n; i++) {
155 name = namelist[i]->d_name;
156
157 if (fnmatch(".", name, 0) == 0)
158 goto skip;
159 if (fnmatch("..", name, 0) == 0)
160 goto skip;
161
162 path2 = malloc(strlen(path) + strlen(name) + 3);
163 strcpy(path2, path);
164 strcat(path2, "/");
165 strcat(path2, name);
166
167 if (fnmatch(file, name, 0) == 0) {
168 rc = read_rom(path2);
169
170 /*
171 * It's OK if the ROM is unreadable. Maybe there
172 * is no ROM, or some other error ocurred. The
173 * important thing is that no MCA happened.
174 */
175 if (rc > 0)
176 fprintf(stderr, "PASS: %s read %ld bytes\n", path2, rc);
177 else {
178 fprintf(stderr, "PASS: %s not readable\n", path2);
179 return rc;
180 }
181 } else {
182 r = lstat(path2, &buf);
183 if (r == 0 && S_ISDIR(buf.st_mode)) {
184 rc = scan_rom(path2, file);
185 if (rc < 0)
186 return rc;
187 }
188 }
189
190 result |= rc;
191 free(path2);
192
193skip:
194 free(namelist[i]);
195 }
196 free(namelist);
197 return rc;
198}
199
200main()
201{
202 int rc;
203
204 if (map_mem("/dev/mem", 0, 0xA0000, 1) == 0)
205 fprintf(stderr, "PASS: /dev/mem 0x0-0xa0000 is readable\n");
206 else
207 fprintf(stderr, "FAIL: /dev/mem 0x0-0xa0000 not accessible\n");
208
209 /*
210 * It's not safe to blindly read the VGA frame buffer. If you know
211 * how to poke the card the right way, it should respond, but it's
212 * not safe in general. Many machines, e.g., Intel chipsets, cover
213 * up a non-responding card by just returning -1, but others will
214 * report the failure as a machine check.
215 */
216 if (map_mem("/dev/mem", 0xA0000, 0x20000, 0) == 0)
217 fprintf(stderr, "PASS: /dev/mem 0xa0000-0xc0000 is mappable\n");
218 else
219 fprintf(stderr, "FAIL: /dev/mem 0xa0000-0xc0000 not accessible\n");
220
221 if (map_mem("/dev/mem", 0xC0000, 0x40000, 1) == 0)
222 fprintf(stderr, "PASS: /dev/mem 0xc0000-0x100000 is readable\n");
223 else
224 fprintf(stderr, "FAIL: /dev/mem 0xc0000-0x100000 not accessible\n");
225
226 /*
227 * Often you can map all the individual pieces above (0-0xA0000,
228 * 0xA0000-0xC0000, and 0xC0000-0x100000), but can't map the whole
229 * thing at once. This is because the individual pieces use different
230 * attributes, and there's no single attribute supported over the
231 * whole region.
232 */
233 rc = map_mem("/dev/mem", 0, 1024*1024, 0);
234 if (rc == 0)
235 fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 is mappable\n");
236 else if (rc > 0)
237 fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 not mappable\n");
238 else
239 fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n");
240
241 scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1);
242 scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0);
243 scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1);
244 scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0);
245
246 scan_rom("/sys/devices", "rom");
247}
diff --git a/Documentation/ia64/aliasing.txt b/Documentation/ia64/aliasing.txt
index 38f9a52d1820..9a431a7d0f5d 100644
--- a/Documentation/ia64/aliasing.txt
+++ b/Documentation/ia64/aliasing.txt
@@ -112,16 +112,6 @@ POTENTIAL ATTRIBUTE ALIASING CASES
112 112
113 The /dev/mem mmap constraints apply. 113 The /dev/mem mmap constraints apply.
114 114
115 However, since this is for mapping legacy MMIO space, WB access
116 does not make sense. This matters on machines without legacy
117 VGA support: these machines may have WB memory for the entire
118 first megabyte (or even the entire first granule).
119
120 On these machines, we could mmap legacy_mem as WB, which would
121 be safe in terms of attribute aliasing, but X has no way of
122 knowing that it is accessing regular memory, not a frame buffer,
123 so the kernel should fail the mmap rather than doing it with WB.
124
125 read/write of /dev/mem 115 read/write of /dev/mem
126 116
127 This uses copy_from_user(), which implicitly uses a kernel 117 This uses copy_from_user(), which implicitly uses a kernel
@@ -138,14 +128,20 @@ POTENTIAL ATTRIBUTE ALIASING CASES
138 128
139 ioremap() 129 ioremap()
140 130
141 This returns a kernel identity mapping for use inside the 131 This returns a mapping for use inside the kernel.
142 kernel.
143 132
144 If the region is in kern_memmap, we should use the attribute 133 If the region is in kern_memmap, we should use the attribute
145 specified there. Otherwise, if the EFI memory map reports that 134 specified there.
146 the entire granule supports WB, we should use that (granules 135
147 that are partially reserved or occupied by firmware do not appear 136 If the EFI memory map reports that the entire granule supports
148 in kern_memmap). Otherwise, we should use a UC mapping. 137 WB, we should use that (granules that are partially reserved
138 or occupied by firmware do not appear in kern_memmap).
139
140 If the granule contains non-WB memory, but we can cover the
141 region safely with kernel page table mappings, we can use
142 ioremap_page_range() as most other architectures do.
143
144 Failing all of the above, we have to fall back to a UC mapping.
149 145
150PAST PROBLEM CASES 146PAST PROBLEM CASES
151 147
@@ -158,7 +154,7 @@ PAST PROBLEM CASES
158 succeed. It may create either WB or UC user mappings, depending 154 succeed. It may create either WB or UC user mappings, depending
159 on whether the region is in kern_memmap or the EFI memory map. 155 on whether the region is in kern_memmap or the EFI memory map.
160 156
161 mmap of 0x0-0xA0000 /dev/mem by "hwinfo" on HP sx1000 with VGA enabled 157 mmap of 0x0-0x9FFFF /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
162 158
163 See https://bugzilla.novell.com/show_bug.cgi?id=140858. 159 See https://bugzilla.novell.com/show_bug.cgi?id=140858.
164 160
@@ -171,28 +167,25 @@ PAST PROBLEM CASES
171 so it is safe to use WB mappings. 167 so it is safe to use WB mappings.
172 168
173 The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000, 169 The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000,
174 which will use a granule-sized UC mapping covering 0-0xFFFFF. This 170 which uses a granule-sized UC mapping. This granule will cover some
175 granule covers some WB-only memory, but since UC is non-speculative, 171 WB-only memory, but since UC is non-speculative, the processor will
176 the processor will never generate an uncacheable reference to the 172 never generate an uncacheable reference to the WB-only areas unless
177 WB-only areas unless the driver explicitly touches them. 173 the driver explicitly touches them.
178 174
179 mmap of 0x0-0xFFFFF legacy_mem by "X" 175 mmap of 0x0-0xFFFFF legacy_mem by "X"
180 176
181 If the EFI memory map reports this entire range as WB, there 177 If the EFI memory map reports that the entire range supports the
182 is no VGA MMIO hole, and the mmap should fail or be done with 178 same attributes, we can allow the mmap (and we will prefer WB if
183 a WB mapping. 179 supported, as is the case with HP sx[12]000 machines with VGA
180 disabled).
184 181
185 There's no easy way for X to determine whether the 0xA0000-0xBFFFF 182 If EFI reports the range as partly WB and partly UC (as on sx[12]000
186 region is a frame buffer or just memory, so I think it's best to 183 machines with VGA enabled), we must fail the mmap because there's no
187 just fail this mmap request rather than using a WB mapping. As 184 safe attribute to use.
188 far as I know, there's no need to map legacy_mem with WB
189 mappings.
190 185
191 Otherwise, a UC mapping of the entire region is probably safe. 186 If EFI reports some of the range but not all (as on Intel firmware
192 The VGA hole means the region will not be in kern_memmap. The 187 that doesn't report the VGA frame buffer at all), we should fail the
193 HP sx1000 chipset doesn't support UC access to the memory surrounding 188 mmap and force the user to map just the specific region of interest.
194 the VGA hole, but X doesn't need that area anyway and should not
195 reference it.
196 189
197 mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled 190 mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled
198 191
@@ -202,6 +195,16 @@ PAST PROBLEM CASES
202 This is a special case of the previous case, and the mmap should 195 This is a special case of the previous case, and the mmap should
203 fail for the same reason as above. 196 fail for the same reason as above.
204 197
198 read of /sys/devices/.../rom
199
200 For VGA devices, this may cause an ioremap() of 0xC0000. This
201 used to be done with a UC mapping, because the VGA frame buffer
202 at 0xA0000 prevents use of a WB granule. The UC mapping causes
203 an MCA on HP sx[12]000 chipsets.
204
205 We should use WB page table mappings to avoid covering the VGA
206 frame buffer.
207
205NOTES 208NOTES
206 209
207 [1] SDM rev 2.2, vol 2, sec 4.4.1. 210 [1] SDM rev 2.2, vol 2, sec 4.4.1.
diff --git a/Documentation/ia64/err_inject.txt b/Documentation/ia64/err_inject.txt
new file mode 100644
index 000000000000..6449a7090dbb
--- /dev/null
+++ b/Documentation/ia64/err_inject.txt
@@ -0,0 +1,1068 @@
1
2IPF Machine Check (MC) error inject tool
3========================================
4
5IPF Machine Check (MC) error inject tool is used to inject MC
6errors from Linux. The tool is a test bed for IPF MC work flow including
7hardware correctable error handling, OS recoverable error handling, MC
8event logging, etc.
9
10The tool includes two parts: a kernel driver and a user application
11sample. The driver provides interface to PAL to inject error
12and query error injection capabilities. The driver code is in
13arch/ia64/kernel/err_inject.c. The application sample (shown below)
14provides a combination of various errors and calls the driver's interface
15(sysfs interface) to inject errors or query error injection capabilities.
16
17The tool can be used to test Intel IPF machine MC handling capabilities.
18It's especially useful for people who can not access hardware MC injection
19tool to inject error. It's also very useful to integrate with other
20software test suits to do stressful testing on IPF.
21
22Below is a sample application as part of the whole tool. The sample
23can be used as a working test tool. Or it can be expanded to include
24more features. It also can be a integrated into a libary or other user
25application to have more thorough test.
26
27The sample application takes err.conf as error configuation input. Gcc
28compiles the code. After you install err_inject driver, you can run
29this sample application to inject errors.
30
31Errata: Itanium 2 Processors Specification Update lists some errata against
32the pal_mc_error_inject PAL procedure. The following err.conf has been tested
33on latest Montecito PAL.
34
35err.conf:
36
37#This is configuration file for err_inject_tool.
38#The format of the each line is:
39#cpu, loop, interval, err_type_info, err_struct_info, err_data_buffer
40#where
41# cpu: logical cpu number the error will be inject in.
42# loop: times the error will be injected.
43# interval: In second. every so often one error is injected.
44# err_type_info, err_struct_info: PAL parameters.
45#
46#Note: All values are hex w/o or w/ 0x prefix.
47
48
49#On cpu2, inject only total 0x10 errors, interval 5 seconds
50#corrected, data cache, hier-2, physical addr(assigned by tool code).
51#working on Montecito latest PAL.
522, 10, 5, 4101, 95
53
54#On cpu4, inject and consume total 0x10 errors, interval 5 seconds
55#corrected, data cache, hier-2, physical addr(assigned by tool code).
56#working on Montecito latest PAL.
574, 10, 5, 4109, 95
58
59#On cpu15, inject and consume total 0x10 errors, interval 5 seconds
60#recoverable, DTR0, hier-2.
61#working on Montecito latest PAL.
620xf, 0x10, 5, 4249, 15
63
64The sample application source code:
65
66err_injection_tool.c:
67
68/*
69 * This program is free software; you can redistribute it and/or modify
70 * it under the terms of the GNU General Public License as published by
71 * the Free Software Foundation; either version 2 of the License, or
72 * (at your option) any later version.
73 *
74 * This program is distributed in the hope that it will be useful, but
75 * WITHOUT ANY WARRANTY; without even the implied warranty of
76 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
77 * NON INFRINGEMENT. See the GNU General Public License for more
78 * details.
79 *
80 * You should have received a copy of the GNU General Public License
81 * along with this program; if not, write to the Free Software
82 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
83 *
84 * Copyright (C) 2006 Intel Co
85 * Fenghua Yu <fenghua.yu@intel.com>
86 *
87 */
88#include <sys/types.h>
89#include <sys/stat.h>
90#include <fcntl.h>
91#include <stdio.h>
92#include <sched.h>
93#include <unistd.h>
94#include <stdlib.h>
95#include <stdarg.h>
96#include <string.h>
97#include <errno.h>
98#include <time.h>
99#include <sys/ipc.h>
100#include <sys/sem.h>
101#include <sys/wait.h>
102#include <sys/mman.h>
103#include <sys/shm.h>
104
105#define MAX_FN_SIZE 256
106#define MAX_BUF_SIZE 256
107#define DATA_BUF_SIZE 256
108#define NR_CPUS 512
109#define MAX_TASK_NUM 2048
110#define MIN_INTERVAL 5 // seconds
111#define ERR_DATA_BUFFER_SIZE 3 // Three 8-byte.
112#define PARA_FIELD_NUM 5
113#define MASK_SIZE (NR_CPUS/64)
114#define PATH_FORMAT "/sys/devices/system/cpu/cpu%d/err_inject/"
115
116int sched_setaffinity(pid_t pid, unsigned int len, unsigned long *mask);
117
118int verbose;
119#define vbprintf if (verbose) printf
120
121int log_info(int cpu, const char *fmt, ...)
122{
123 FILE *log;
124 char fn[MAX_FN_SIZE];
125 char buf[MAX_BUF_SIZE];
126 va_list args;
127
128 sprintf(fn, "%d.log", cpu);
129 log=fopen(fn, "a+");
130 if (log==NULL) {
131 perror("Error open:");
132 return -1;
133 }
134
135 va_start(args, fmt);
136 vprintf(fmt, args);
137 memset(buf, 0, MAX_BUF_SIZE);
138 vsprintf(buf, fmt, args);
139 va_end(args);
140
141 fwrite(buf, sizeof(buf), 1, log);
142 fclose(log);
143
144 return 0;
145}
146
147typedef unsigned long u64;
148typedef unsigned int u32;
149
150typedef union err_type_info_u {
151 struct {
152 u64 mode : 3, /* 0-2 */
153 err_inj : 3, /* 3-5 */
154 err_sev : 2, /* 6-7 */
155 err_struct : 5, /* 8-12 */
156 struct_hier : 3, /* 13-15 */
157 reserved : 48; /* 16-63 */
158 } err_type_info_u;
159 u64 err_type_info;
160} err_type_info_t;
161
162typedef union err_struct_info_u {
163 struct {
164 u64 siv : 1, /* 0 */
165 c_t : 2, /* 1-2 */
166 cl_p : 3, /* 3-5 */
167 cl_id : 3, /* 6-8 */
168 cl_dp : 1, /* 9 */
169 reserved1 : 22, /* 10-31 */
170 tiv : 1, /* 32 */
171 trigger : 4, /* 33-36 */
172 trigger_pl : 3, /* 37-39 */
173 reserved2 : 24; /* 40-63 */
174 } err_struct_info_cache;
175 struct {
176 u64 siv : 1, /* 0 */
177 tt : 2, /* 1-2 */
178 tc_tr : 2, /* 3-4 */
179 tr_slot : 8, /* 5-12 */
180 reserved1 : 19, /* 13-31 */
181 tiv : 1, /* 32 */
182 trigger : 4, /* 33-36 */
183 trigger_pl : 3, /* 37-39 */
184 reserved2 : 24; /* 40-63 */
185 } err_struct_info_tlb;
186 struct {
187 u64 siv : 1, /* 0 */
188 regfile_id : 4, /* 1-4 */
189 reg_num : 7, /* 5-11 */
190 reserved1 : 20, /* 12-31 */
191 tiv : 1, /* 32 */
192 trigger : 4, /* 33-36 */
193 trigger_pl : 3, /* 37-39 */
194 reserved2 : 24; /* 40-63 */
195 } err_struct_info_register;
196 struct {
197 u64 reserved;
198 } err_struct_info_bus_processor_interconnect;
199 u64 err_struct_info;
200} err_struct_info_t;
201
202typedef union err_data_buffer_u {
203 struct {
204 u64 trigger_addr; /* 0-63 */
205 u64 inj_addr; /* 64-127 */
206 u64 way : 5, /* 128-132 */
207 index : 20, /* 133-152 */
208 : 39; /* 153-191 */
209 } err_data_buffer_cache;
210 struct {
211 u64 trigger_addr; /* 0-63 */
212 u64 inj_addr; /* 64-127 */
213 u64 way : 5, /* 128-132 */
214 index : 20, /* 133-152 */
215 reserved : 39; /* 153-191 */
216 } err_data_buffer_tlb;
217 struct {
218 u64 trigger_addr; /* 0-63 */
219 } err_data_buffer_register;
220 struct {
221 u64 reserved; /* 0-63 */
222 } err_data_buffer_bus_processor_interconnect;
223 u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
224} err_data_buffer_t;
225
226typedef union capabilities_u {
227 struct {
228 u64 i : 1,
229 d : 1,
230 rv : 1,
231 tag : 1,
232 data : 1,
233 mesi : 1,
234 dp : 1,
235 reserved1 : 3,
236 pa : 1,
237 va : 1,
238 wi : 1,
239 reserved2 : 20,
240 trigger : 1,
241 trigger_pl : 1,
242 reserved3 : 30;
243 } capabilities_cache;
244 struct {
245 u64 d : 1,
246 i : 1,
247 rv : 1,
248 tc : 1,
249 tr : 1,
250 reserved1 : 27,
251 trigger : 1,
252 trigger_pl : 1,
253 reserved2 : 30;
254 } capabilities_tlb;
255 struct {
256 u64 gr_b0 : 1,
257 gr_b1 : 1,
258 fr : 1,
259 br : 1,
260 pr : 1,
261 ar : 1,
262 cr : 1,
263 rr : 1,
264 pkr : 1,
265 dbr : 1,
266 ibr : 1,
267 pmc : 1,
268 pmd : 1,
269 reserved1 : 3,
270 regnum : 1,
271 reserved2 : 15,
272 trigger : 1,
273 trigger_pl : 1,
274 reserved3 : 30;
275 } capabilities_register;
276 struct {
277 u64 reserved;
278 } capabilities_bus_processor_interconnect;
279} capabilities_t;
280
281typedef struct resources_s {
282 u64 ibr0 : 1,
283 ibr2 : 1,
284 ibr4 : 1,
285 ibr6 : 1,
286 dbr0 : 1,
287 dbr2 : 1,
288 dbr4 : 1,
289 dbr6 : 1,
290 reserved : 48;
291} resources_t;
292
293
294long get_page_size(void)
295{
296 long page_size=sysconf(_SC_PAGESIZE);
297 return page_size;
298}
299
300#define PAGE_SIZE (get_page_size()==-1?0x4000:get_page_size())
301#define SHM_SIZE (2*PAGE_SIZE*NR_CPUS)
302#define SHM_VA 0x2000000100000000
303
304int shmid;
305void *shmaddr;
306
307int create_shm(void)
308{
309 key_t key;
310 char fn[MAX_FN_SIZE];
311
312 /* cpu0 is always existing */
313 sprintf(fn, PATH_FORMAT, 0);
314 if ((key = ftok(fn, 's')) == -1) {
315 perror("ftok");
316 return -1;
317 }
318
319 shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT);
320 if (shmid == -1) {
321 if (errno==EEXIST) {
322 shmid = shmget(key, SHM_SIZE, 0);
323 if (shmid == -1) {
324 perror("shmget");
325 return -1;
326 }
327 }
328 else {
329 perror("shmget");
330 return -1;
331 }
332 }
333 vbprintf("shmid=%d", shmid);
334
335 /* connect to the segment: */
336 shmaddr = shmat(shmid, (void *)SHM_VA, 0);
337 if (shmaddr == (void*)-1) {
338 perror("shmat");
339 return -1;
340 }
341
342 memset(shmaddr, 0, SHM_SIZE);
343 mlock(shmaddr, SHM_SIZE);
344
345 return 0;
346}
347
348int free_shm()
349{
350 munlock(shmaddr, SHM_SIZE);
351 shmdt(shmaddr);
352 semctl(shmid, 0, IPC_RMID);
353
354 return 0;
355}
356
357#ifdef _SEM_SEMUN_UNDEFINED
358union semun
359{
360 int val;
361 struct semid_ds *buf;
362 unsigned short int *array;
363 struct seminfo *__buf;
364};
365#endif
366
367u32 mode=1; /* 1: physical mode; 2: virtual mode. */
368int one_lock=1;
369key_t key[NR_CPUS];
370int semid[NR_CPUS];
371
372int create_sem(int cpu)
373{
374 union semun arg;
375 char fn[MAX_FN_SIZE];
376 int sid;
377
378 sprintf(fn, PATH_FORMAT, cpu);
379 sprintf(fn, "%s/%s", fn, "err_type_info");
380 if ((key[cpu] = ftok(fn, 'e')) == -1) {
381 perror("ftok");
382 return -1;
383 }
384
385 if (semid[cpu]!=0)
386 return 0;
387
388 /* clear old semaphore */
389 if ((sid = semget(key[cpu], 1, 0)) != -1)
390 semctl(sid, 0, IPC_RMID);
391
392 /* get one semaphore */
393 if ((semid[cpu] = semget(key[cpu], 1, IPC_CREAT | IPC_EXCL)) == -1) {
394 perror("semget");
395 printf("Please remove semaphore with key=0x%lx, then run the tool.\n",
396 (u64)key[cpu]);
397 return -1;
398 }
399
400 vbprintf("semid[%d]=0x%lx, key[%d]=%lx\n",cpu,(u64)semid[cpu],cpu,
401 (u64)key[cpu]);
402 /* initialize the semaphore to 1: */
403 arg.val = 1;
404 if (semctl(semid[cpu], 0, SETVAL, arg) == -1) {
405 perror("semctl");
406 return -1;
407 }
408
409 return 0;
410}
411
412static int lock(int cpu)
413{
414 struct sembuf lock;
415
416 lock.sem_num = cpu;
417 lock.sem_op = 1;
418 semop(semid[cpu], &lock, 1);
419
420 return 0;
421}
422
423static int unlock(int cpu)
424{
425 struct sembuf unlock;
426
427 unlock.sem_num = cpu;
428 unlock.sem_op = -1;
429 semop(semid[cpu], &unlock, 1);
430
431 return 0;
432}
433
434void free_sem(int cpu)
435{
436 semctl(semid[cpu], 0, IPC_RMID);
437}
438
439int wr_multi(char *fn, unsigned long *data, int size)
440{
441 int fd;
442 char buf[MAX_BUF_SIZE];
443 int ret;
444
445 if (size==1)
446 sprintf(buf, "%lx", *data);
447 else if (size==3)
448 sprintf(buf, "%lx,%lx,%lx", data[0], data[1], data[2]);
449 else {
450 fprintf(stderr,"write to file with wrong size!\n");
451 return -1;
452 }
453
454 fd=open(fn, O_RDWR);
455 if (!fd) {
456 perror("Error:");
457 return -1;
458 }
459 ret=write(fd, buf, sizeof(buf));
460 close(fd);
461 return ret;
462}
463
464int wr(char *fn, unsigned long data)
465{
466 return wr_multi(fn, &data, 1);
467}
468
469int rd(char *fn, unsigned long *data)
470{
471 int fd;
472 char buf[MAX_BUF_SIZE];
473
474 fd=open(fn, O_RDONLY);
475 if (fd<0) {
476 perror("Error:");
477 return -1;
478 }
479 read(fd, buf, MAX_BUF_SIZE);
480 *data=strtoul(buf, NULL, 16);
481 close(fd);
482 return 0;
483}
484
485int rd_status(char *path, int *status)
486{
487 char fn[MAX_FN_SIZE];
488 sprintf(fn, "%s/status", path);
489 if (rd(fn, (u64*)status)<0) {
490 perror("status reading error.\n");
491 return -1;
492 }
493
494 return 0;
495}
496
497int rd_capabilities(char *path, u64 *capabilities)
498{
499 char fn[MAX_FN_SIZE];
500 sprintf(fn, "%s/capabilities", path);
501 if (rd(fn, capabilities)<0) {
502 perror("capabilities reading error.\n");
503 return -1;
504 }
505
506 return 0;
507}
508
509int rd_all(char *path)
510{
511 unsigned long err_type_info, err_struct_info, err_data_buffer;
512 int status;
513 unsigned long capabilities, resources;
514 char fn[MAX_FN_SIZE];
515
516 sprintf(fn, "%s/err_type_info", path);
517 if (rd(fn, &err_type_info)<0) {
518 perror("err_type_info reading error.\n");
519 return -1;
520 }
521 printf("err_type_info=%lx\n", err_type_info);
522
523 sprintf(fn, "%s/err_struct_info", path);
524 if (rd(fn, &err_struct_info)<0) {
525 perror("err_struct_info reading error.\n");
526 return -1;
527 }
528 printf("err_struct_info=%lx\n", err_struct_info);
529
530 sprintf(fn, "%s/err_data_buffer", path);
531 if (rd(fn, &err_data_buffer)<0) {
532 perror("err_data_buffer reading error.\n");
533 return -1;
534 }
535 printf("err_data_buffer=%lx\n", err_data_buffer);
536
537 sprintf(fn, "%s/status", path);
538 if (rd("status", (u64*)&status)<0) {
539 perror("status reading error.\n");
540 return -1;
541 }
542 printf("status=%d\n", status);
543
544 sprintf(fn, "%s/capabilities", path);
545 if (rd(fn,&capabilities)<0) {
546 perror("capabilities reading error.\n");
547 return -1;
548 }
549 printf("capabilities=%lx\n", capabilities);
550
551 sprintf(fn, "%s/resources", path);
552 if (rd(fn, &resources)<0) {
553 perror("resources reading error.\n");
554 return -1;
555 }
556 printf("resources=%lx\n", resources);
557
558 return 0;
559}
560
561int query_capabilities(char *path, err_type_info_t err_type_info,
562 u64 *capabilities)
563{
564 char fn[MAX_FN_SIZE];
565 err_struct_info_t err_struct_info;
566 err_data_buffer_t err_data_buffer;
567
568 err_struct_info.err_struct_info=0;
569 memset(err_data_buffer.err_data_buffer, -1, ERR_DATA_BUFFER_SIZE*8);
570
571 sprintf(fn, "%s/err_type_info", path);
572 wr(fn, err_type_info.err_type_info);
573 sprintf(fn, "%s/err_struct_info", path);
574 wr(fn, 0x0);
575 sprintf(fn, "%s/err_data_buffer", path);
576 wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
577
578 // Fire pal_mc_error_inject procedure.
579 sprintf(fn, "%s/call_start", path);
580 wr(fn, mode);
581
582 if (rd_capabilities(path, capabilities)<0)
583 return -1;
584
585 return 0;
586}
587
588int query_all_capabilities()
589{
590 int status;
591 err_type_info_t err_type_info;
592 int err_sev, err_struct, struct_hier;
593 int cap=0;
594 u64 capabilities;
595 char path[MAX_FN_SIZE];
596
597 err_type_info.err_type_info=0; // Initial
598 err_type_info.err_type_info_u.mode=0; // Query mode;
599 err_type_info.err_type_info_u.err_inj=0;
600
601 printf("All capabilities implemented in pal_mc_error_inject:\n");
602 sprintf(path, PATH_FORMAT ,0);
603 for (err_sev=0;err_sev<3;err_sev++)
604 for (err_struct=0;err_struct<5;err_struct++)
605 for (struct_hier=0;struct_hier<5;struct_hier++)
606 {
607 status=-1;
608 capabilities=0;
609 err_type_info.err_type_info_u.err_sev=err_sev;
610 err_type_info.err_type_info_u.err_struct=err_struct;
611 err_type_info.err_type_info_u.struct_hier=struct_hier;
612
613 if (query_capabilities(path, err_type_info, &capabilities)<0)
614 continue;
615
616 if (rd_status(path, &status)<0)
617 continue;
618
619 if (status==0) {
620 cap=1;
621 printf("For err_sev=%d, err_struct=%d, struct_hier=%d: ",
622 err_sev, err_struct, struct_hier);
623 printf("capabilities 0x%lx\n", capabilities);
624 }
625 }
626 if (!cap) {
627 printf("No capabilities supported.\n");
628 return 0;
629 }
630
631 return 0;
632}
633
634int err_inject(int cpu, char *path, err_type_info_t err_type_info,
635 err_struct_info_t err_struct_info,
636 err_data_buffer_t err_data_buffer)
637{
638 int status;
639 char fn[MAX_FN_SIZE];
640
641 log_info(cpu, "err_type_info=%lx, err_struct_info=%lx, ",
642 err_type_info.err_type_info,
643 err_struct_info.err_struct_info);
644 log_info(cpu,"err_data_buffer=[%lx,%lx,%lx]\n",
645 err_data_buffer.err_data_buffer[0],
646 err_data_buffer.err_data_buffer[1],
647 err_data_buffer.err_data_buffer[2]);
648 sprintf(fn, "%s/err_type_info", path);
649 wr(fn, err_type_info.err_type_info);
650 sprintf(fn, "%s/err_struct_info", path);
651 wr(fn, err_struct_info.err_struct_info);
652 sprintf(fn, "%s/err_data_buffer", path);
653 wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
654
655 // Fire pal_mc_error_inject procedure.
656 sprintf(fn, "%s/call_start", path);
657 wr(fn,mode);
658
659 if (rd_status(path, &status)<0) {
660 vbprintf("fail: read status\n");
661 return -100;
662 }
663
664 if (status!=0) {
665 log_info(cpu, "fail: status=%d\n", status);
666 return status;
667 }
668
669 return status;
670}
671
672static int construct_data_buf(char *path, err_type_info_t err_type_info,
673 err_struct_info_t err_struct_info,
674 err_data_buffer_t *err_data_buffer,
675 void *va1)
676{
677 char fn[MAX_FN_SIZE];
678 u64 virt_addr=0, phys_addr=0;
679
680 vbprintf("va1=%lx\n", (u64)va1);
681 memset(&err_data_buffer->err_data_buffer_cache, 0, ERR_DATA_BUFFER_SIZE*8);
682
683 switch (err_type_info.err_type_info_u.err_struct) {
684 case 1: // Cache
685 switch (err_struct_info.err_struct_info_cache.cl_id) {
686 case 1: //Virtual addr
687 err_data_buffer->err_data_buffer_cache.inj_addr=(u64)va1;
688 break;
689 case 2: //Phys addr
690 sprintf(fn, "%s/virtual_to_phys", path);
691 virt_addr=(u64)va1;
692 if (wr(fn,virt_addr)<0)
693 return -1;
694 rd(fn, &phys_addr);
695 err_data_buffer->err_data_buffer_cache.inj_addr=phys_addr;
696 break;
697 default:
698 printf("Not supported cl_id\n");
699 break;
700 }
701 break;
702 case 2: // TLB
703 break;
704 case 3: // Register file
705 break;
706 case 4: // Bus/system interconnect
707 default:
708 printf("Not supported err_struct\n");
709 break;
710 }
711
712 return 0;
713}
714
715typedef struct {
716 u64 cpu;
717 u64 loop;
718 u64 interval;
719 u64 err_type_info;
720 u64 err_struct_info;
721 u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
722} parameters_t;
723
724parameters_t line_para;
725int para;
726
727static int empty_data_buffer(u64 *err_data_buffer)
728{
729 int empty=1;
730 int i;
731
732 for (i=0;i<ERR_DATA_BUFFER_SIZE; i++)
733 if (err_data_buffer[i]!=-1)
734 empty=0;
735
736 return empty;
737}
738
739int err_inj()
740{
741 err_type_info_t err_type_info;
742 err_struct_info_t err_struct_info;
743 err_data_buffer_t err_data_buffer;
744 int count;
745 FILE *fp;
746 unsigned long cpu, loop, interval, err_type_info_conf, err_struct_info_conf;
747 u64 err_data_buffer_conf[ERR_DATA_BUFFER_SIZE];
748 int num;
749 int i;
750 char path[MAX_FN_SIZE];
751 parameters_t parameters[MAX_TASK_NUM]={};
752 pid_t child_pid[MAX_TASK_NUM];
753 time_t current_time;
754 int status;
755
756 if (!para) {
757 fp=fopen("err.conf", "r");
758 if (fp==NULL) {
759 perror("Error open err.conf");
760 return -1;
761 }
762
763 num=0;
764 while (!feof(fp)) {
765 char buf[256];
766 memset(buf,0,256);
767 fgets(buf, 256, fp);
768 count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
769 &cpu, &loop, &interval,&err_type_info_conf,
770 &err_struct_info_conf,
771 &err_data_buffer_conf[0],
772 &err_data_buffer_conf[1],
773 &err_data_buffer_conf[2]);
774 if (count!=PARA_FIELD_NUM+3) {
775 err_data_buffer_conf[0]=-1;
776 err_data_buffer_conf[1]=-1;
777 err_data_buffer_conf[2]=-1;
778 count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx\n",
779 &cpu, &loop, &interval,&err_type_info_conf,
780 &err_struct_info_conf);
781 if (count!=PARA_FIELD_NUM)
782 continue;
783 }
784
785 parameters[num].cpu=cpu;
786 parameters[num].loop=loop;
787 parameters[num].interval= interval>MIN_INTERVAL
788 ?interval:MIN_INTERVAL;
789 parameters[num].err_type_info=err_type_info_conf;
790 parameters[num].err_struct_info=err_struct_info_conf;
791 memcpy(parameters[num++].err_data_buffer,
792 err_data_buffer_conf,ERR_DATA_BUFFER_SIZE*8) ;
793
794 if (num>=MAX_TASK_NUM)
795 break;
796 }
797 }
798 else {
799 parameters[0].cpu=line_para.cpu;
800 parameters[0].loop=line_para.loop;
801 parameters[0].interval= line_para.interval>MIN_INTERVAL
802 ?line_para.interval:MIN_INTERVAL;
803 parameters[0].err_type_info=line_para.err_type_info;
804 parameters[0].err_struct_info=line_para.err_struct_info;
805 memcpy(parameters[0].err_data_buffer,
806 line_para.err_data_buffer,ERR_DATA_BUFFER_SIZE*8) ;
807
808 num=1;
809 }
810
811 /* Create semaphore: If one_lock, one semaphore for all processors.
812 Otherwise, one sempaphore for each processor. */
813 if (one_lock) {
814 if (create_sem(0)) {
815 printf("Can not create semaphore...exit\n");
816 free_sem(0);
817 return -1;
818 }
819 }
820 else {
821 for (i=0;i<num;i++) {
822 if (create_sem(parameters[i].cpu)) {
823 printf("Can not create semaphore for cpu%d...exit\n",i);
824 free_sem(parameters[num].cpu);
825 return -1;
826 }
827 }
828 }
829
830 /* Create a shm segment which will be used to inject/consume errors on.*/
831 if (create_shm()==-1) {
832 printf("Error to create shm...exit\n");
833 return -1;
834 }
835
836 for (i=0;i<num;i++) {
837 pid_t pid;
838
839 current_time=time(NULL);
840 log_info(parameters[i].cpu, "\nBegine at %s", ctime(&current_time));
841 log_info(parameters[i].cpu, "Configurations:\n");
842 log_info(parameters[i].cpu,"On cpu%ld: loop=%lx, interval=%lx(s)",
843 parameters[i].cpu,
844 parameters[i].loop,
845 parameters[i].interval);
846 log_info(parameters[i].cpu," err_type_info=%lx,err_struct_info=%lx\n",
847 parameters[i].err_type_info,
848 parameters[i].err_struct_info);
849
850 sprintf(path, PATH_FORMAT, (int)parameters[i].cpu);
851 err_type_info.err_type_info=parameters[i].err_type_info;
852 err_struct_info.err_struct_info=parameters[i].err_struct_info;
853 memcpy(err_data_buffer.err_data_buffer,
854 parameters[i].err_data_buffer,
855 ERR_DATA_BUFFER_SIZE*8);
856
857 pid=fork();
858 if (pid==0) {
859 unsigned long mask[MASK_SIZE];
860 int j, k;
861
862 void *va1, *va2;
863
864 /* Allocate two memory areas va1 and va2 in shm */
865 va1=shmaddr+parameters[i].cpu*PAGE_SIZE;
866 va2=shmaddr+parameters[i].cpu*PAGE_SIZE+PAGE_SIZE;
867
868 vbprintf("va1=%lx, va2=%lx\n", (u64)va1, (u64)va2);
869 memset(va1, 0x1, PAGE_SIZE);
870 memset(va2, 0x2, PAGE_SIZE);
871
872 if (empty_data_buffer(err_data_buffer.err_data_buffer))
873 /* If not specified yet, construct data buffer
874 * with va1
875 */
876 construct_data_buf(path, err_type_info,
877 err_struct_info, &err_data_buffer,va1);
878
879 for (j=0;j<MASK_SIZE;j++)
880 mask[j]=0;
881
882 cpu=parameters[i].cpu;
883 k = cpu%64;
884 j = cpu/64;
885 mask[j]=1<<k;
886
887 if (sched_setaffinity(0, MASK_SIZE*8, mask)==-1) {
888 perror("Error sched_setaffinity:");
889 return -1;
890 }
891
892 for (j=0; j<parameters[i].loop; j++) {
893 log_info(parameters[i].cpu,"Injection ");
894 log_info(parameters[i].cpu,"on cpu%ld: #%d/%ld ",
895
896 parameters[i].cpu,j+1, parameters[i].loop);
897
898 /* Hold the lock */
899 if (one_lock)
900 lock(0);
901 else
902 /* Hold lock on this cpu */
903 lock(parameters[i].cpu);
904
905 if ((status=err_inject(parameters[i].cpu,
906 path, err_type_info,
907 err_struct_info, err_data_buffer))
908 ==0) {
909 /* consume the error for "inject only"*/
910 memcpy(va2, va1, PAGE_SIZE);
911 memcpy(va1, va2, PAGE_SIZE);
912 log_info(parameters[i].cpu,
913 "successful\n");
914 }
915 else {
916 log_info(parameters[i].cpu,"fail:");
917 log_info(parameters[i].cpu,
918 "status=%d\n", status);
919 unlock(parameters[i].cpu);
920 break;
921 }
922 if (one_lock)
923 /* Release the lock */
924 unlock(0);
925 /* Release lock on this cpu */
926 else
927 unlock(parameters[i].cpu);
928
929 if (j < parameters[i].loop-1)
930 sleep(parameters[i].interval);
931 }
932 current_time=time(NULL);
933 log_info(parameters[i].cpu, "Done at %s", ctime(&current_time));
934 return 0;
935 }
936 else if (pid<0) {
937 perror("Error fork:");
938 continue;
939 }
940 child_pid[i]=pid;
941 }
942 for (i=0;i<num;i++)
943 waitpid(child_pid[i], NULL, 0);
944
945 if (one_lock)
946 free_sem(0);
947 else
948 for (i=0;i<num;i++)
949 free_sem(parameters[i].cpu);
950
951 printf("All done.\n");
952
953 return 0;
954}
955
956void help()
957{
958 printf("err_inject_tool:\n");
959 printf("\t-q: query all capabilities. default: off\n");
960 printf("\t-m: procedure mode. 1: physical 2: virtual. default: 1\n");
961 printf("\t-i: inject errors. default: off\n");
962 printf("\t-l: one lock per cpu. default: one lock for all\n");
963 printf("\t-e: error parameters:\n");
964 printf("\t\tcpu,loop,interval,err_type_info,err_struct_info[,err_data_buffer[0],err_data_buffer[1],err_data_buffer[2]]\n");
965 printf("\t\t cpu: logical cpu number the error will be inject in.\n");
966 printf("\t\t loop: times the error will be injected.\n");
967 printf("\t\t interval: In second. every so often one error is injected.\n");
968 printf("\t\t err_type_info, err_struct_info: PAL parameters.\n");
969 printf("\t\t err_data_buffer: PAL parameter. Optional. If not present,\n");
970 printf("\t\t it's constructed by tool automatically. Be\n");
971 printf("\t\t careful to provide err_data_buffer and make\n");
972 printf("\t\t sure it's working with the environment.\n");
973 printf("\t Note:no space between error parameters.\n");
974 printf("\t default: Take error parameters from err.conf instead of command line.\n");
975 printf("\t-v: verbose. default: off\n");
976 printf("\t-h: help\n\n");
977 printf("The tool will take err.conf file as ");
978 printf("input to inject single or multiple errors ");
979 printf("on one or multiple cpus in parallel.\n");
980}
981
982int main(int argc, char **argv)
983{
984 char c;
985 int do_err_inj=0;
986 int do_query_all=0;
987 int count;
988 u32 m;
989
990 /* Default one lock for all cpu's */
991 one_lock=1;
992 while ((c = getopt(argc, argv, "m:iqvhle:")) != EOF)
993 switch (c) {
994 case 'm': /* Procedure mode. 1: phys 2: virt */
995 count=sscanf(optarg, "%x", &m);
996 if (count!=1 || (m!=1 && m!=2)) {
997 printf("Wrong mode number.\n");
998 help();
999 return -1;
1000 }
1001 mode=m;
1002 break;
1003 case 'i': /* Inject errors */
1004 do_err_inj=1;
1005 break;
1006 case 'q': /* Query */
1007 do_query_all=1;
1008 break;
1009 case 'v': /* Verbose */
1010 verbose=1;
1011 break;
1012 case 'l': /* One lock per cpu */
1013 one_lock=0;
1014 break;
1015 case 'e': /* error arguments */
1016 /* Take parameters:
1017 * #cpu, loop, interval, err_type_info, err_struct_info[, err_data_buffer]
1018 * err_data_buffer is optional. Recommend not to specify
1019 * err_data_buffer. Better to use tool to generate it.
1020 */
1021 count=sscanf(optarg,
1022 "%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
1023 &line_para.cpu,
1024 &line_para.loop,
1025 &line_para.interval,
1026 &line_para.err_type_info,
1027 &line_para.err_struct_info,
1028 &line_para.err_data_buffer[0],
1029 &line_para.err_data_buffer[1],
1030 &line_para.err_data_buffer[2]);
1031 if (count!=PARA_FIELD_NUM+3) {
1032 line_para.err_data_buffer[0]=-1,
1033 line_para.err_data_buffer[1]=-1,
1034 line_para.err_data_buffer[2]=-1;
1035 count=sscanf(optarg, "%lx, %lx, %lx, %lx, %lx\n",
1036 &line_para.cpu,
1037 &line_para.loop,
1038 &line_para.interval,
1039 &line_para.err_type_info,
1040 &line_para.err_struct_info);
1041 if (count!=PARA_FIELD_NUM) {
1042 printf("Wrong error arguments.\n");
1043 help();
1044 return -1;
1045 }
1046 }
1047 para=1;
1048 break;
1049 continue;
1050 break;
1051 case 'h':
1052 help();
1053 return 0;
1054 default:
1055 break;
1056 }
1057
1058 if (do_query_all)
1059 query_all_capabilities();
1060 if (do_err_inj)
1061 err_inj();
1062
1063 if (!do_query_all && !do_err_inj)
1064 help();
1065
1066 return 0;
1067}
1068
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 3b71f97d0b60..e23af4b6ae8c 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -439,6 +439,16 @@ config IA64_PALINFO
439 To use this option, you have to ensure that the "/proc file system 439 To use this option, you have to ensure that the "/proc file system
440 support" (CONFIG_PROC_FS) is enabled, too. 440 support" (CONFIG_PROC_FS) is enabled, too.
441 441
442config IA64_MC_ERR_INJECT
443 tristate "MC error injection support"
444 help
445 Selets whether support for MC error injection. By enabling the
446 support, kernel provide sysfs interface for user application to
447 call MC error injection PAL procedure to inject various errors.
448 This is a useful tool for MCA testing.
449
450 If you're unsure, do not select this option.
451
442config SGI_SN 452config SGI_SN
443 def_bool y if (IA64_SGI_SN2 || IA64_GENERIC) 453 def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)
444 454
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig
index 153bfdc0182d..90bd9601cdde 100644
--- a/arch/ia64/defconfig
+++ b/arch/ia64/defconfig
@@ -164,6 +164,7 @@ CONFIG_COMPAT=y
164CONFIG_IA64_MCA_RECOVERY=y 164CONFIG_IA64_MCA_RECOVERY=y
165CONFIG_PERFMON=y 165CONFIG_PERFMON=y
166CONFIG_IA64_PALINFO=y 166CONFIG_IA64_PALINFO=y
167# CONFIG_MC_ERR_INJECT is not set
167CONFIG_SGI_SN=y 168CONFIG_SGI_SN=y
168# CONFIG_IA64_ESI is not set 169# CONFIG_IA64_ESI is not set
169 170
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 098ee605bf5e..33e5a598672d 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
34obj-$(CONFIG_AUDIT) += audit.o 34obj-$(CONFIG_AUDIT) += audit.o
35obj-$(CONFIG_PCI_MSI) += msi_ia64.o 35obj-$(CONFIG_PCI_MSI) += msi_ia64.o
36mca_recovery-y += mca_drv.o mca_drv_asm.o 36mca_recovery-y += mca_drv.o mca_drv_asm.o
37obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
37 38
38obj-$(CONFIG_IA64_ESI) += esi.o 39obj-$(CONFIG_IA64_ESI) += esi.o
39ifneq ($(CONFIG_IA64_ESI),) 40ifneq ($(CONFIG_IA64_ESI),)
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index f45f91d38cab..78d29b79947d 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -660,6 +660,29 @@ efi_memory_descriptor (unsigned long phys_addr)
660 return NULL; 660 return NULL;
661} 661}
662 662
663static int
664efi_memmap_intersects (unsigned long phys_addr, unsigned long size)
665{
666 void *efi_map_start, *efi_map_end, *p;
667 efi_memory_desc_t *md;
668 u64 efi_desc_size;
669 unsigned long end;
670
671 efi_map_start = __va(ia64_boot_param->efi_memmap);
672 efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
673 efi_desc_size = ia64_boot_param->efi_memdesc_size;
674
675 end = phys_addr + size;
676
677 for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
678 md = p;
679
680 if (md->phys_addr < end && efi_md_end(md) > phys_addr)
681 return 1;
682 }
683 return 0;
684}
685
663u32 686u32
664efi_mem_type (unsigned long phys_addr) 687efi_mem_type (unsigned long phys_addr)
665{ 688{
@@ -766,11 +789,28 @@ valid_phys_addr_range (unsigned long phys_addr, unsigned long size)
766int 789int
767valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size) 790valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size)
768{ 791{
792 unsigned long phys_addr = pfn << PAGE_SHIFT;
793 u64 attr;
794
795 attr = efi_mem_attribute(phys_addr, size);
796
769 /* 797 /*
770 * MMIO regions are often missing from the EFI memory map. 798 * /dev/mem mmap uses normal user pages, so we don't need the entire
771 * We must allow mmap of them for programs like X, so we 799 * granule, but the entire region we're mapping must support the same
772 * currently can't do any useful validation. 800 * attribute.
773 */ 801 */
802 if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
803 return 1;
804
805 /*
806 * Intel firmware doesn't tell us about all the MMIO regions, so
807 * in general we have to allow mmap requests. But if EFI *does*
808 * tell us about anything inside this region, we should deny it.
809 * The user can always map a smaller region to avoid the overlap.
810 */
811 if (efi_memmap_intersects(phys_addr, size))
812 return 0;
813
774 return 1; 814 return 1;
775} 815}
776 816
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index e7873eeae448..55fd2d5471e1 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -767,7 +767,7 @@ ENTRY(ia64_leave_syscall)
767 ld8.fill r15=[r3] // M0|1 restore r15 767 ld8.fill r15=[r3] // M0|1 restore r15
768 mov b6=r18 // I0 restore b6 768 mov b6=r18 // I0 restore b6
769 769
770 addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 // A 770 LOAD_PHYS_STACK_REG_SIZE(r17)
771 mov f9=f0 // F clear f9 771 mov f9=f0 // F clear f9
772(pKStk) br.cond.dpnt.many skip_rbs_switch // B 772(pKStk) br.cond.dpnt.many skip_rbs_switch // B
773 773
@@ -775,7 +775,6 @@ ENTRY(ia64_leave_syscall)
775 shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition 775 shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition
776 cover // B add current frame into dirty partition & set cr.ifs 776 cover // B add current frame into dirty partition & set cr.ifs
777 ;; 777 ;;
778(pUStk) ld4 r17=[r17] // M0|1 r17 = cpu_data->phys_stacked_size_p8
779 mov r19=ar.bsp // M2 get new backing store pointer 778 mov r19=ar.bsp // M2 get new backing store pointer
780 mov f10=f0 // F clear f10 779 mov f10=f0 // F clear f10
781 780
@@ -953,9 +952,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
953 shr.u r18=r19,16 // get byte size of existing "dirty" partition 952 shr.u r18=r19,16 // get byte size of existing "dirty" partition
954 ;; 953 ;;
955 mov r16=ar.bsp // get existing backing store pointer 954 mov r16=ar.bsp // get existing backing store pointer
956 addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 955 LOAD_PHYS_STACK_REG_SIZE(r17)
957 ;;
958 ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8
959(pKStk) br.cond.dpnt skip_rbs_switch 956(pKStk) br.cond.dpnt skip_rbs_switch
960 957
961 /* 958 /*
diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c
new file mode 100644
index 000000000000..d3e9f33e8bdd
--- /dev/null
+++ b/arch/ia64/kernel/err_inject.c
@@ -0,0 +1,293 @@
1/*
2 * err_inject.c -
3 * 1.) Inject errors to a processor.
4 * 2.) Query error injection capabilities.
5 * This driver along with user space code can be acting as an error
6 * injection tool.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
16 * NON INFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * Written by: Fenghua Yu <fenghua.yu@intel.com>, Intel Corporation
24 * Copyright (C) 2006, Intel Corp. All rights reserved.
25 *
26 */
27#include <linux/sysdev.h>
28#include <linux/init.h>
29#include <linux/mm.h>
30#include <linux/cpu.h>
31#include <linux/module.h>
32
33#define ERR_INJ_DEBUG
34
35#define ERR_DATA_BUFFER_SIZE 3 // Three 8-byte;
36
37#define define_one_ro(name) \
38static SYSDEV_ATTR(name, 0444, show_##name, NULL)
39
40#define define_one_rw(name) \
41static SYSDEV_ATTR(name, 0644, show_##name, store_##name)
42
43static u64 call_start[NR_CPUS];
44static u64 phys_addr[NR_CPUS];
45static u64 err_type_info[NR_CPUS];
46static u64 err_struct_info[NR_CPUS];
47static struct {
48 u64 data1;
49 u64 data2;
50 u64 data3;
51} __attribute__((__aligned__(16))) err_data_buffer[NR_CPUS];
52static s64 status[NR_CPUS];
53static u64 capabilities[NR_CPUS];
54static u64 resources[NR_CPUS];
55
56#define show(name) \
57static ssize_t \
58show_##name(struct sys_device *dev, char *buf) \
59{ \
60 u32 cpu=dev->id; \
61 return sprintf(buf, "%lx\n", name[cpu]); \
62}
63
64#define store(name) \
65static ssize_t \
66store_##name(struct sys_device *dev, const char *buf, size_t size) \
67{ \
68 unsigned int cpu=dev->id; \
69 name[cpu] = simple_strtoull(buf, NULL, 16); \
70 return size; \
71}
72
73show(call_start)
74
75/* It's user's responsibility to call the PAL procedure on a specific
76 * processor. The cpu number in driver is only used for storing data.
77 */
78static ssize_t
79store_call_start(struct sys_device *dev, const char *buf, size_t size)
80{
81 unsigned int cpu=dev->id;
82 unsigned long call_start = simple_strtoull(buf, NULL, 16);
83
84#ifdef ERR_INJ_DEBUG
85 printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu);
86 printk(KERN_DEBUG "err_type_info=%lx,\n", err_type_info[cpu]);
87 printk(KERN_DEBUG "err_struct_info=%lx,\n", err_struct_info[cpu]);
88 printk(KERN_DEBUG "err_data_buffer=%lx, %lx, %lx.\n",
89 err_data_buffer[cpu].data1,
90 err_data_buffer[cpu].data2,
91 err_data_buffer[cpu].data3);
92#endif
93 switch (call_start) {
94 case 0: /* Do nothing. */
95 break;
96 case 1: /* Call pal_mc_error_inject in physical mode. */
97 status[cpu]=ia64_pal_mc_error_inject_phys(err_type_info[cpu],
98 err_struct_info[cpu],
99 ia64_tpa(&err_data_buffer[cpu]),
100 &capabilities[cpu],
101 &resources[cpu]);
102 break;
103 case 2: /* Call pal_mc_error_inject in virtual mode. */
104 status[cpu]=ia64_pal_mc_error_inject_virt(err_type_info[cpu],
105 err_struct_info[cpu],
106 ia64_tpa(&err_data_buffer[cpu]),
107 &capabilities[cpu],
108 &resources[cpu]);
109 break;
110 default:
111 status[cpu] = -EINVAL;
112 break;
113 }
114
115#ifdef ERR_INJ_DEBUG
116 printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
117 printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]);
118 printk(KERN_DEBUG "resources=%lx\n", resources[cpu]);
119#endif
120 return size;
121}
122
123show(err_type_info)
124store(err_type_info)
125
126static ssize_t
127show_virtual_to_phys(struct sys_device *dev, char *buf)
128{
129 unsigned int cpu=dev->id;
130 return sprintf(buf, "%lx\n", phys_addr[cpu]);
131}
132
133static ssize_t
134store_virtual_to_phys(struct sys_device *dev, const char *buf, size_t size)
135{
136 unsigned int cpu=dev->id;
137 u64 virt_addr=simple_strtoull(buf, NULL, 16);
138 int ret;
139
140 ret = get_user_pages(current, current->mm, virt_addr,
141 1, VM_READ, 0, NULL, NULL);
142 if (ret<=0) {
143#ifdef ERR_INJ_DEBUG
144 printk("Virtual address %lx is not existing.\n",virt_addr);
145#endif
146 return -EINVAL;
147 }
148
149 phys_addr[cpu] = ia64_tpa(virt_addr);
150 return size;
151}
152
153show(err_struct_info)
154store(err_struct_info)
155
156static ssize_t
157show_err_data_buffer(struct sys_device *dev, char *buf)
158{
159 unsigned int cpu=dev->id;
160
161 return sprintf(buf, "%lx, %lx, %lx\n",
162 err_data_buffer[cpu].data1,
163 err_data_buffer[cpu].data2,
164 err_data_buffer[cpu].data3);
165}
166
167static ssize_t
168store_err_data_buffer(struct sys_device *dev, const char *buf, size_t size)
169{
170 unsigned int cpu=dev->id;
171 int ret;
172
173#ifdef ERR_INJ_DEBUG
174 printk("write err_data_buffer=[%lx,%lx,%lx] on cpu%d\n",
175 err_data_buffer[cpu].data1,
176 err_data_buffer[cpu].data2,
177 err_data_buffer[cpu].data3,
178 cpu);
179#endif
180 ret=sscanf(buf, "%lx, %lx, %lx",
181 &err_data_buffer[cpu].data1,
182 &err_data_buffer[cpu].data2,
183 &err_data_buffer[cpu].data3);
184 if (ret!=ERR_DATA_BUFFER_SIZE)
185 return -EINVAL;
186
187 return size;
188}
189
190show(status)
191show(capabilities)
192show(resources)
193
194define_one_rw(call_start);
195define_one_rw(err_type_info);
196define_one_rw(err_struct_info);
197define_one_rw(err_data_buffer);
198define_one_rw(virtual_to_phys);
199define_one_ro(status);
200define_one_ro(capabilities);
201define_one_ro(resources);
202
203static struct attribute *default_attrs[] = {
204 &attr_call_start.attr,
205 &attr_virtual_to_phys.attr,
206 &attr_err_type_info.attr,
207 &attr_err_struct_info.attr,
208 &attr_err_data_buffer.attr,
209 &attr_status.attr,
210 &attr_capabilities.attr,
211 &attr_resources.attr,
212 NULL
213};
214
215static struct attribute_group err_inject_attr_group = {
216 .attrs = default_attrs,
217 .name = "err_inject"
218};
219/* Add/Remove err_inject interface for CPU device */
220static int __cpuinit err_inject_add_dev(struct sys_device * sys_dev)
221{
222 return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
223}
224
225static int __cpuinit err_inject_remove_dev(struct sys_device * sys_dev)
226{
227 sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
228 return 0;
229}
230static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
231 unsigned long action, void *hcpu)
232{
233 unsigned int cpu = (unsigned long)hcpu;
234 struct sys_device *sys_dev;
235
236 sys_dev = get_cpu_sysdev(cpu);
237 switch (action) {
238 case CPU_ONLINE:
239 err_inject_add_dev(sys_dev);
240 break;
241 case CPU_DEAD:
242 err_inject_remove_dev(sys_dev);
243 break;
244 }
245
246 return NOTIFY_OK;
247}
248
249static struct notifier_block __cpuinitdata err_inject_cpu_notifier =
250{
251 .notifier_call = err_inject_cpu_callback,
252};
253
254static int __init
255err_inject_init(void)
256{
257 int i;
258
259#ifdef ERR_INJ_DEBUG
260 printk(KERN_INFO "Enter error injection driver.\n");
261#endif
262 for_each_online_cpu(i) {
263 err_inject_cpu_callback(&err_inject_cpu_notifier, CPU_ONLINE,
264 (void *)(long)i);
265 }
266
267 register_hotcpu_notifier(&err_inject_cpu_notifier);
268
269 return 0;
270}
271
272static void __exit
273err_inject_exit(void)
274{
275 int i;
276 struct sys_device *sys_dev;
277
278#ifdef ERR_INJ_DEBUG
279 printk(KERN_INFO "Exit error injection driver.\n");
280#endif
281 for_each_online_cpu(i) {
282 sys_dev = get_cpu_sysdev(i);
283 sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
284 }
285 unregister_hotcpu_notifier(&err_inject_cpu_notifier);
286}
287
288module_init(err_inject_init);
289module_exit(err_inject_exit);
290
291MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
292MODULE_DESCRIPTION("MC error injection kenrel sysfs interface");
293MODULE_LICENSE("GPL");
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index 6b7fcbd3f6f1..34f44d8be00d 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -374,6 +374,7 @@ ENTRY(alt_dtlb_miss)
374 movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) 374 movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
375 mov r21=cr.ipsr 375 mov r21=cr.ipsr
376 mov r31=pr 376 mov r31=pr
377 mov r24=PERCPU_ADDR
377 ;; 378 ;;
378#ifdef CONFIG_DISABLE_VHPT 379#ifdef CONFIG_DISABLE_VHPT
379 shr.u r22=r16,61 // get the region number into r21 380 shr.u r22=r16,61 // get the region number into r21
@@ -386,22 +387,30 @@ ENTRY(alt_dtlb_miss)
386(p8) mov r29=b0 // save b0 387(p8) mov r29=b0 // save b0
387(p8) br.cond.dptk dtlb_fault 388(p8) br.cond.dptk dtlb_fault
388#endif 389#endif
390 cmp.ge p10,p11=r16,r24 // access to per_cpu_data?
391 tbit.z p12,p0=r16,61 // access to region 6?
392 mov r25=PERCPU_PAGE_SHIFT << 2
393 mov r26=PERCPU_PAGE_SIZE
394 nop.m 0
395 nop.b 0
396 ;;
397(p10) mov r19=IA64_KR(PER_CPU_DATA)
398(p11) and r19=r19,r16 // clear non-ppn fields
389 extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl 399 extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl
390 and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field 400 and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field
391 tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? 401 tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on?
392 shr.u r18=r16,57 // move address bit 61 to bit 4
393 and r19=r19,r16 // clear ed, reserved bits, and PTE control bits
394 tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on? 402 tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on?
395 ;; 403 ;;
396 andcm r18=0x10,r18 // bit 4=~address-bit(61) 404(p10) sub r19=r19,r26
405(p10) mov cr.itir=r25
397 cmp.ne p8,p0=r0,r23 406 cmp.ne p8,p0=r0,r23
398(p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field 407(p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field
408(p12) dep r17=-1,r17,4,1 // set ma=UC for region 6 addr
399(p8) br.cond.spnt page_fault 409(p8) br.cond.spnt page_fault
400 410
401 dep r21=-1,r21,IA64_PSR_ED_BIT,1 411 dep r21=-1,r21,IA64_PSR_ED_BIT,1
402 or r19=r19,r17 // insert PTE control bits into r19
403 ;; 412 ;;
404 or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 413 or r19=r19,r17 // insert PTE control bits into r19
405(p6) mov cr.ipsr=r21 414(p6) mov cr.ipsr=r21
406 ;; 415 ;;
407(p7) itc.d r19 // insert the TLB entry 416(p7) itc.d r19 // insert the TLB entry
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index c6b607c00dee..8c9c26aa6ae0 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -101,14 +101,6 @@ ia64_do_tlb_purge:
101 ;; 101 ;;
102 srlz.d 102 srlz.d
103 ;; 103 ;;
104 // 2. Purge DTR for PERCPU data.
105 movl r16=PERCPU_ADDR
106 mov r18=PERCPU_PAGE_SHIFT<<2
107 ;;
108 ptr.d r16,r18
109 ;;
110 srlz.d
111 ;;
112 // 3. Purge ITR for PAL code. 104 // 3. Purge ITR for PAL code.
113 GET_THIS_PADDR(r2, ia64_mca_pal_base) 105 GET_THIS_PADDR(r2, ia64_mca_pal_base)
114 ;; 106 ;;
@@ -196,22 +188,6 @@ ia64_reload_tr:
196 srlz.i 188 srlz.i
197 srlz.d 189 srlz.d
198 ;; 190 ;;
199 // 2. Reload DTR register for PERCPU data.
200 GET_THIS_PADDR(r2, ia64_mca_per_cpu_pte)
201 ;;
202 movl r16=PERCPU_ADDR // vaddr
203 movl r18=PERCPU_PAGE_SHIFT<<2
204 ;;
205 mov cr.itir=r18
206 mov cr.ifa=r16
207 ;;
208 ld8 r18=[r2] // load per-CPU PTE
209 mov r16=IA64_TR_PERCPU_DATA;
210 ;;
211 itr.d dtr[r16]=r18
212 ;;
213 srlz.d
214 ;;
215 // 3. Reload ITR for PAL code. 191 // 3. Reload ITR for PAL code.
216 GET_THIS_PADDR(r2, ia64_mca_pal_pte) 192 GET_THIS_PADDR(r2, ia64_mca_pal_pte)
217 ;; 193 ;;
diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c
index bc11bb096f58..e796e29f8e15 100644
--- a/arch/ia64/kernel/patch.c
+++ b/arch/ia64/kernel/patch.c
@@ -195,3 +195,23 @@ ia64_patch_gate (void)
195 ia64_patch_vtop(START(vtop), END(vtop)); 195 ia64_patch_vtop(START(vtop), END(vtop));
196 ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9)); 196 ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9));
197} 197}
198
199void ia64_patch_phys_stack_reg(unsigned long val)
200{
201 s32 * offp = (s32 *) __start___phys_stack_reg_patchlist;
202 s32 * end = (s32 *) __end___phys_stack_reg_patchlist;
203 u64 ip, mask, imm;
204
205 /* see instruction format A4: adds r1 = imm13, r3 */
206 mask = (0x3fUL << 27) | (0x7f << 13);
207 imm = (((val >> 7) & 0x3f) << 27) | (val & 0x7f) << 13;
208
209 while (offp < end) {
210 ip = (u64) offp + *offp;
211 ia64_patch(ip, mask, imm);
212 ia64_fc(ip);
213 ++offp;
214 }
215 ia64_sync_i();
216 ia64_srlz_i();
217}
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index dc7dd7648ec5..6e19da122ae3 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -75,7 +75,6 @@ extern void ia64_setup_printk_clock(void);
75 75
76DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info); 76DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
77DEFINE_PER_CPU(unsigned long, local_per_cpu_offset); 77DEFINE_PER_CPU(unsigned long, local_per_cpu_offset);
78DEFINE_PER_CPU(unsigned long, ia64_phys_stacked_size_p8);
79unsigned long ia64_cycles_per_usec; 78unsigned long ia64_cycles_per_usec;
80struct ia64_boot_param *ia64_boot_param; 79struct ia64_boot_param *ia64_boot_param;
81struct screen_info screen_info; 80struct screen_info screen_info;
@@ -869,6 +868,7 @@ void __cpuinit
869cpu_init (void) 868cpu_init (void)
870{ 869{
871 extern void __cpuinit ia64_mmu_init (void *); 870 extern void __cpuinit ia64_mmu_init (void *);
871 static unsigned long max_num_phys_stacked = IA64_NUM_PHYS_STACK_REG;
872 unsigned long num_phys_stacked; 872 unsigned long num_phys_stacked;
873 pal_vm_info_2_u_t vmi; 873 pal_vm_info_2_u_t vmi;
874 unsigned int max_ctx; 874 unsigned int max_ctx;
@@ -982,7 +982,10 @@ cpu_init (void)
982 num_phys_stacked = 96; 982 num_phys_stacked = 96;
983 } 983 }
984 /* size of physical stacked register partition plus 8 bytes: */ 984 /* size of physical stacked register partition plus 8 bytes: */
985 __get_cpu_var(ia64_phys_stacked_size_p8) = num_phys_stacked*8 + 8; 985 if (num_phys_stacked > max_num_phys_stacked) {
986 ia64_patch_phys_stack_reg(num_phys_stacked*8 + 8);
987 max_num_phys_stacked = num_phys_stacked;
988 }
986 platform_cpu_init(); 989 platform_cpu_init();
987 pm_idle = default_idle; 990 pm_idle = default_idle;
988} 991}
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 25dd55e4db24..692382642118 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -78,6 +78,13 @@ SECTIONS
78 __stop___mca_table = .; 78 __stop___mca_table = .;
79 } 79 }
80 80
81 .data.patch.phys_stack_reg : AT(ADDR(.data.patch.phys_stack_reg) - LOAD_OFFSET)
82 {
83 __start___phys_stack_reg_patchlist = .;
84 *(.data.patch.phys_stack_reg)
85 __end___phys_stack_reg_patchlist = .;
86 }
87
81 /* Global data */ 88 /* Global data */
82 _data = .; 89 _data = .;
83 90
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 2da841110727..cffb1e8325e8 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -355,7 +355,7 @@ setup_gate (void)
355void __devinit 355void __devinit
356ia64_mmu_init (void *my_cpu_data) 356ia64_mmu_init (void *my_cpu_data)
357{ 357{
358 unsigned long psr, pta, impl_va_bits; 358 unsigned long pta, impl_va_bits;
359 extern void __devinit tlb_init (void); 359 extern void __devinit tlb_init (void);
360 360
361#ifdef CONFIG_DISABLE_VHPT 361#ifdef CONFIG_DISABLE_VHPT
@@ -364,15 +364,6 @@ ia64_mmu_init (void *my_cpu_data)
364# define VHPT_ENABLE_BIT 1 364# define VHPT_ENABLE_BIT 1
365#endif 365#endif
366 366
367 /* Pin mapping for percpu area into TLB */
368 psr = ia64_clear_ic();
369 ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR,
370 pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)),
371 PERCPU_PAGE_SHIFT);
372
373 ia64_set_psr(psr);
374 ia64_srlz_i();
375
376 /* 367 /*
377 * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped 368 * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped
378 * address space. The IA-64 architecture guarantees that at least 50 bits of 369 * address space. The IA-64 architecture guarantees that at least 50 bits of
diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c
index 4280c074d64e..2a140627dfd6 100644
--- a/arch/ia64/mm/ioremap.c
+++ b/arch/ia64/mm/ioremap.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * (c) Copyright 2006 Hewlett-Packard Development Company, L.P. 2 * (c) Copyright 2006, 2007 Hewlett-Packard Development Company, L.P.
3 * Bjorn Helgaas <bjorn.helgaas@hp.com> 3 * Bjorn Helgaas <bjorn.helgaas@hp.com>
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
@@ -10,51 +10,101 @@
10#include <linux/compiler.h> 10#include <linux/compiler.h>
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/efi.h> 12#include <linux/efi.h>
13#include <linux/io.h>
14#include <linux/vmalloc.h>
13#include <asm/io.h> 15#include <asm/io.h>
14#include <asm/meminit.h> 16#include <asm/meminit.h>
15 17
16static inline void __iomem * 18static inline void __iomem *
17__ioremap (unsigned long offset, unsigned long size) 19__ioremap (unsigned long phys_addr)
18{ 20{
19 return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset); 21 return (void __iomem *) (__IA64_UNCACHED_OFFSET | phys_addr);
20} 22}
21 23
22void __iomem * 24void __iomem *
23ioremap (unsigned long offset, unsigned long size) 25ioremap (unsigned long phys_addr, unsigned long size)
24{ 26{
27 void __iomem *addr;
28 struct vm_struct *area;
29 unsigned long offset;
30 pgprot_t prot;
25 u64 attr; 31 u64 attr;
26 unsigned long gran_base, gran_size; 32 unsigned long gran_base, gran_size;
33 unsigned long page_base;
27 34
28 /* 35 /*
29 * For things in kern_memmap, we must use the same attribute 36 * For things in kern_memmap, we must use the same attribute
30 * as the rest of the kernel. For more details, see 37 * as the rest of the kernel. For more details, see
31 * Documentation/ia64/aliasing.txt. 38 * Documentation/ia64/aliasing.txt.
32 */ 39 */
33 attr = kern_mem_attribute(offset, size); 40 attr = kern_mem_attribute(phys_addr, size);
34 if (attr & EFI_MEMORY_WB) 41 if (attr & EFI_MEMORY_WB)
35 return (void __iomem *) phys_to_virt(offset); 42 return (void __iomem *) phys_to_virt(phys_addr);
36 else if (attr & EFI_MEMORY_UC) 43 else if (attr & EFI_MEMORY_UC)
37 return __ioremap(offset, size); 44 return __ioremap(phys_addr);
38 45
39 /* 46 /*
40 * Some chipsets don't support UC access to memory. If 47 * Some chipsets don't support UC access to memory. If
41 * WB is supported for the whole granule, we prefer that. 48 * WB is supported for the whole granule, we prefer that.
42 */ 49 */
43 gran_base = GRANULEROUNDDOWN(offset); 50 gran_base = GRANULEROUNDDOWN(phys_addr);
44 gran_size = GRANULEROUNDUP(offset + size) - gran_base; 51 gran_size = GRANULEROUNDUP(phys_addr + size) - gran_base;
45 if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB) 52 if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB)
46 return (void __iomem *) phys_to_virt(offset); 53 return (void __iomem *) phys_to_virt(phys_addr);
47 54
48 return __ioremap(offset, size); 55 /*
56 * WB is not supported for the whole granule, so we can't use
57 * the region 7 identity mapping. If we can safely cover the
58 * area with kernel page table mappings, we can use those
59 * instead.
60 */
61 page_base = phys_addr & PAGE_MASK;
62 size = PAGE_ALIGN(phys_addr + size) - page_base;
63 if (efi_mem_attribute(page_base, size) & EFI_MEMORY_WB) {
64 prot = PAGE_KERNEL;
65
66 /*
67 * Mappings have to be page-aligned
68 */
69 offset = phys_addr & ~PAGE_MASK;
70 phys_addr &= PAGE_MASK;
71
72 /*
73 * Ok, go for it..
74 */
75 area = get_vm_area(size, VM_IOREMAP);
76 if (!area)
77 return NULL;
78
79 area->phys_addr = phys_addr;
80 addr = (void __iomem *) area->addr;
81 if (ioremap_page_range((unsigned long) addr,
82 (unsigned long) addr + size, phys_addr, prot)) {
83 vunmap((void __force *) addr);
84 return NULL;
85 }
86
87 return (void __iomem *) (offset + (char __iomem *)addr);
88 }
89
90 return __ioremap(phys_addr);
49} 91}
50EXPORT_SYMBOL(ioremap); 92EXPORT_SYMBOL(ioremap);
51 93
52void __iomem * 94void __iomem *
53ioremap_nocache (unsigned long offset, unsigned long size) 95ioremap_nocache (unsigned long phys_addr, unsigned long size)
54{ 96{
55 if (kern_mem_attribute(offset, size) & EFI_MEMORY_WB) 97 if (kern_mem_attribute(phys_addr, size) & EFI_MEMORY_WB)
56 return NULL; 98 return NULL;
57 99
58 return __ioremap(offset, size); 100 return __ioremap(phys_addr);
59} 101}
60EXPORT_SYMBOL(ioremap_nocache); 102EXPORT_SYMBOL(ioremap_nocache);
103
104void
105iounmap (volatile void __iomem *addr)
106{
107 if (REGION_NUMBER(addr) == RGN_GATE)
108 vunmap((void *) ((unsigned long) addr & PAGE_MASK));
109}
110EXPORT_SYMBOL(iounmap);
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 0e83f3b419b5..9f635896d252 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -659,8 +659,6 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma)
659 return -EINVAL; 659 return -EINVAL;
660 prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size, 660 prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
661 vma->vm_page_prot); 661 vma->vm_page_prot);
662 if (pgprot_val(prot) != pgprot_val(pgprot_noncached(vma->vm_page_prot)))
663 return -EINVAL;
664 662
665 addr = pci_get_legacy_mem(bus); 663 addr = pci_get_legacy_mem(bus);
666 if (IS_ERR(addr)) 664 if (IS_ERR(addr))
diff --git a/include/asm-ia64/asmmacro.h b/include/asm-ia64/asmmacro.h
index c22b4658fc61..c1642fd64029 100644
--- a/include/asm-ia64/asmmacro.h
+++ b/include/asm-ia64/asmmacro.h
@@ -104,6 +104,16 @@ name:
104#endif 104#endif
105 105
106/* 106/*
107 * If physical stack register size is different from DEF_NUM_STACK_REG,
108 * dynamically patch the kernel for correct size.
109 */
110 .section ".data.patch.phys_stack_reg", "a"
111 .previous
112#define LOAD_PHYS_STACK_REG_SIZE(reg) \
113[1:] adds reg=IA64_NUM_PHYS_STACK_REG*8+8,r0; \
114 .xdata4 ".data.patch.phys_stack_reg", 1b-.
115
116/*
107 * Up until early 2004, use of .align within a function caused bad unwind info. 117 * Up until early 2004, use of .align within a function caused bad unwind info.
108 * TEXT_ALIGN(n) expands into ".align n" if a fixed GAS is available or into nothing 118 * TEXT_ALIGN(n) expands into ".align n" if a fixed GAS is available or into nothing
109 * otherwise. 119 * otherwise.
diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
index 6311e168cd34..eb17a8692967 100644
--- a/include/asm-ia64/io.h
+++ b/include/asm-ia64/io.h
@@ -421,11 +421,7 @@ __writeq (unsigned long val, volatile void __iomem *addr)
421 421
422extern void __iomem * ioremap(unsigned long offset, unsigned long size); 422extern void __iomem * ioremap(unsigned long offset, unsigned long size);
423extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); 423extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
424 424extern void iounmap (volatile void __iomem *addr);
425static inline void
426iounmap (volatile void __iomem *addr)
427{
428}
429 425
430/* Use normal IO mappings for DMI */ 426/* Use normal IO mappings for DMI */
431#define dmi_ioremap ioremap 427#define dmi_ioremap ioremap
diff --git a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h
index 221b5cb564b2..7e55a584975c 100644
--- a/include/asm-ia64/kregs.h
+++ b/include/asm-ia64/kregs.h
@@ -29,8 +29,7 @@
29 */ 29 */
30#define IA64_TR_KERNEL 0 /* itr0, dtr0: maps kernel image (code & data) */ 30#define IA64_TR_KERNEL 0 /* itr0, dtr0: maps kernel image (code & data) */
31#define IA64_TR_PALCODE 1 /* itr1: maps PALcode as required by EFI */ 31#define IA64_TR_PALCODE 1 /* itr1: maps PALcode as required by EFI */
32#define IA64_TR_PERCPU_DATA 1 /* dtr1: percpu data */ 32#define IA64_TR_CURRENT_STACK 1 /* dtr1: maps kernel's memory- & register-stacks */
33#define IA64_TR_CURRENT_STACK 2 /* dtr2: maps kernel's memory- & register-stacks */
34 33
35/* Processor status register bits: */ 34/* Processor status register bits: */
36#define IA64_PSR_BE_BIT 1 35#define IA64_PSR_BE_BIT 1
diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
index 67656ce767c2..abfcb3a2588f 100644
--- a/include/asm-ia64/pal.h
+++ b/include/asm-ia64/pal.h
@@ -89,6 +89,8 @@
89#define PAL_GET_PSTATE_TYPE_AVGNORESET 2 89#define PAL_GET_PSTATE_TYPE_AVGNORESET 2
90#define PAL_GET_PSTATE_TYPE_INSTANT 3 90#define PAL_GET_PSTATE_TYPE_INSTANT 3
91 91
92#define PAL_MC_ERROR_INJECT 276 /* Injects processor error or returns injection capabilities */
93
92#ifndef __ASSEMBLY__ 94#ifndef __ASSEMBLY__
93 95
94#include <linux/types.h> 96#include <linux/types.h>
@@ -1235,6 +1237,37 @@ ia64_pal_mc_error_info (u64 info_index, u64 type_index, u64 *size, u64 *error_in
1235 return iprv.status; 1237 return iprv.status;
1236} 1238}
1237 1239
1240/* Injects the requested processor error or returns info on
1241 * supported injection capabilities for current processor implementation
1242 */
1243static inline s64
1244ia64_pal_mc_error_inject_phys (u64 err_type_info, u64 err_struct_info,
1245 u64 err_data_buffer, u64 *capabilities, u64 *resources)
1246{
1247 struct ia64_pal_retval iprv;
1248 PAL_CALL_PHYS_STK(iprv, PAL_MC_ERROR_INJECT, err_type_info,
1249 err_struct_info, err_data_buffer);
1250 if (capabilities)
1251 *capabilities= iprv.v0;
1252 if (resources)
1253 *resources= iprv.v1;
1254 return iprv.status;
1255}
1256
1257static inline s64
1258ia64_pal_mc_error_inject_virt (u64 err_type_info, u64 err_struct_info,
1259 u64 err_data_buffer, u64 *capabilities, u64 *resources)
1260{
1261 struct ia64_pal_retval iprv;
1262 PAL_CALL_STK(iprv, PAL_MC_ERROR_INJECT, err_type_info,
1263 err_struct_info, err_data_buffer);
1264 if (capabilities)
1265 *capabilities= iprv.v0;
1266 if (resources)
1267 *resources= iprv.v1;
1268 return iprv.status;
1269}
1270
1238/* Inform PALE_CHECK whether a machine check is expected so that PALE_CHECK willnot 1271/* Inform PALE_CHECK whether a machine check is expected so that PALE_CHECK willnot
1239 * attempt to correct any expected machine checks. 1272 * attempt to correct any expected machine checks.
1240 */ 1273 */
diff --git a/include/asm-ia64/patch.h b/include/asm-ia64/patch.h
index 4797f3535e6d..a71543084fb4 100644
--- a/include/asm-ia64/patch.h
+++ b/include/asm-ia64/patch.h
@@ -20,6 +20,7 @@ extern void ia64_patch_imm60 (u64 insn_addr, u64 val); /* patch "brl" w/ip-rel
20 20
21extern void ia64_patch_mckinley_e9 (unsigned long start, unsigned long end); 21extern void ia64_patch_mckinley_e9 (unsigned long start, unsigned long end);
22extern void ia64_patch_vtop (unsigned long start, unsigned long end); 22extern void ia64_patch_vtop (unsigned long start, unsigned long end);
23extern void ia64_patch_phys_stack_reg(unsigned long val);
23extern void ia64_patch_gate (void); 24extern void ia64_patch_gate (void);
24 25
25#endif /* _ASM_IA64_PATCH_H */ 26#endif /* _ASM_IA64_PATCH_H */
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index 4f4ee1c2db2f..db81ba406cef 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -19,6 +19,7 @@
19#include <asm/ptrace.h> 19#include <asm/ptrace.h>
20#include <asm/ustack.h> 20#include <asm/ustack.h>
21 21
22#define IA64_NUM_PHYS_STACK_REG 96
22#define IA64_NUM_DBG_REGS 8 23#define IA64_NUM_DBG_REGS 8
23 24
24#define DEFAULT_MAP_BASE __IA64_UL_CONST(0x2000000000000000) 25#define DEFAULT_MAP_BASE __IA64_UL_CONST(0x2000000000000000)
diff --git a/include/asm-ia64/sections.h b/include/asm-ia64/sections.h
index e9eb7f62d32b..dc42a359894f 100644
--- a/include/asm-ia64/sections.h
+++ b/include/asm-ia64/sections.h
@@ -11,6 +11,7 @@
11extern char __per_cpu_start[], __per_cpu_end[], __phys_per_cpu_start[]; 11extern char __per_cpu_start[], __per_cpu_end[], __phys_per_cpu_start[];
12extern char __start___vtop_patchlist[], __end___vtop_patchlist[]; 12extern char __start___vtop_patchlist[], __end___vtop_patchlist[];
13extern char __start___mckinley_e9_bundles[], __end___mckinley_e9_bundles[]; 13extern char __start___mckinley_e9_bundles[], __end___mckinley_e9_bundles[];
14extern char __start___phys_stack_reg_patchlist[], __end___phys_stack_reg_patchlist[];
14extern char __start_gate_section[]; 15extern char __start_gate_section[];
15extern char __start_gate_mckinley_e9_patchlist[], __end_gate_mckinley_e9_patchlist[]; 16extern char __start_gate_mckinley_e9_patchlist[], __end_gate_mckinley_e9_patchlist[];
16extern char __start_gate_vtop_patchlist[], __end_gate_vtop_patchlist[]; 17extern char __start_gate_vtop_patchlist[], __end_gate_vtop_patchlist[];