2 * Copyright 2001 Mike Corrigan, IBM Corp
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 #include <linux/config.h>
10 #include <linux/types.h>
11 #include <linux/threads.h>
12 #include <linux/module.h>
13 #include <linux/bitops.h>
14 #include <asm/processor.h>
15 #include <asm/ptrace.h>
17 #include <asm/abs_addr.h>
18 #include <asm/iSeries/ItLpNaca.h>
19 #include <asm/lppaca.h>
20 #include <asm/iSeries/ItLpRegSave.h>
22 #include <asm/iSeries/HvReleaseData.h>
23 #include <asm/iSeries/LparMap.h>
24 #include <asm/iSeries/ItVpdAreas.h>
25 #include <asm/iSeries/ItIplParmsReal.h>
26 #include <asm/iSeries/ItExtVpdPanel.h>
27 #include <asm/iSeries/ItLpQueue.h>
28 #include <asm/iSeries/IoHriProcessorVpd.h>
29 #include <asm/iSeries/ItSpCommArea.h>
32 /* The HvReleaseData is the root of the information shared between
33 * the hypervisor and Linux.
37 * WARNING - magic here
39 * Ok, this is a horrid hack below, but marginally better than the
40 * alternatives. What we really want is just to initialize
41 * hvReleaseData in C as in the #if 0 section here. However, gcc
42 * refuses to believe that (u32)&x is a constant expression, so will
43 * not allow the xMsNucDataOffset field to be properly initialized.
44 * So, we declare hvReleaseData in inline asm instead. We use inline
45 * asm, rather than a .S file, because the assembler won't generate
46 * the necessary relocation for the LparMap either, unless that symbol
47 * is declared in the same source file. Finally, we put the asm in a
48 * dummy, attribute-used function, instead of at file scope, because
49 * file scope asms don't allow contraints. We want to use the "i"
50 * constraints to put sizeof() and offsetof() expressions in there,
51 * because including asm/offsets.h in C code then stringifying causes
52 * all manner of warnings.
55 struct HvReleaseData hvReleaseData = {
56 .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */
57 .xSize = sizeof(struct HvReleaseData),
58 .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas),
59 .xSlicNacaAddr = &naca, /* 64-bit Naca address */
60 .xMsNucDataOffset = (u32)((unsigned long)&xLparMap - KERNELBASE),
61 .xFlags = HVREL_TAGSINACTIVE /* tags inactive */
63 /* shared processors */
65 | 6, /* TEMP: This allows non-GA driver */
66 .xVrmIndex = 4, /* We are v5r2m0 */
67 .xMinSupportedPlicVrmIndex = 3, /* v5r1m0 */
68 .xMinCompatablePlicVrmIndex = 3, /* v5r1m0 */
69 .xVrmName = { 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4.64" ebcdic */
70 0xa7, 0x40, 0xf2, 0x4b,
71 0xf4, 0x4b, 0xf6, 0xf4 },
76 extern struct HvReleaseData hvReleaseData;
78 static void __attribute_used__ hvReleaseData_wrapper(void)
80 /* This doesn't appear to need any alignment (even 4 byte) */
82 " lparMapPhys = xLparMap - %3\n"
84 " .globl hvReleaseData\n"
86 " .long 0xc8a5d9c4\n" /* xDesc */
87 /* "HvRD" in ebcdic */
88 " .short %0\n" /* xSize */
89 " .short %1\n" /* xVpdAreasPtrOffset */
90 " .llong naca\n" /* xSlicNacaAddr */
91 " .long lparMapPhys\n" /* xMsNucDataOffset */
92 " .long 0\n" /* xRsvd1 */
93 " .short %2\n" /* xFlags */
94 " .short 4\n" /* xVrmIndex - v5r2m0 */
95 " .short 3\n" /* xMinSupportedPlicVrmIndex - v5r1m0 */
96 " .short 3\n" /* xMinCompatablePlicVrmIndex - v5r1m0 */
97 " .long 0xd38995a4\n" /* xVrmName */
98 " .long 0xa740f24b\n" /* "Linux 2.4.64" ebcdic */
100 " . = hvReleaseData + %0\n"
102 : : "i"(sizeof(hvReleaseData)),
103 "i"(offsetof(struct naca_struct, xItVpdAreas)),
104 "i"(HVREL_TAGSINACTIVE /* tags inactive, 64 bit, */
105 /* shared processors, HMT allowed */
106 | 6), /* TEMP: This allows non-GA drivers */
111 struct LparMap __attribute__((aligned (16))) xLparMap = {
112 .xNumberEsids = HvEsidsToMap,
113 .xNumberRanges = HvRangesToMap,
114 .xSegmentTableOffs = STAB0_PAGE,
117 { .xKernelEsid = GET_ESID(KERNELBASE),
118 .xKernelVsid = KERNEL_VSID(KERNELBASE), },
119 { .xKernelEsid = GET_ESID(VMALLOCBASE),
120 .xKernelVsid = KERNEL_VSID(VMALLOCBASE), },
124 { .xPages = HvPagesToMap,
126 .xVPN = KERNEL_VSID(KERNELBASE) << (SID_SHIFT - PAGE_SHIFT),
131 extern void system_reset_iSeries(void);
132 extern void machine_check_iSeries(void);
133 extern void data_access_iSeries(void);
134 extern void instruction_access_iSeries(void);
135 extern void hardware_interrupt_iSeries(void);
136 extern void alignment_iSeries(void);
137 extern void program_check_iSeries(void);
138 extern void fp_unavailable_iSeries(void);
139 extern void decrementer_iSeries(void);
140 extern void trap_0a_iSeries(void);
141 extern void trap_0b_iSeries(void);
142 extern void system_call_iSeries(void);
143 extern void single_step_iSeries(void);
144 extern void trap_0e_iSeries(void);
145 extern void performance_monitor_iSeries(void);
146 extern void data_access_slb_iSeries(void);
147 extern void instruction_access_slb_iSeries(void);
149 struct ItLpNaca itLpNaca = {
150 .xDesc = 0xd397d581, /* "LpNa" ebcdic */
151 .xSize = 0x0400, /* size of ItLpNaca */
152 .xIntHdlrOffset = 0x0300, /* offset to int array */
153 .xMaxIntHdlrEntries = 19, /* # ents */
154 .xPrimaryLpIndex = 0, /* Part # of primary */
155 .xServiceLpIndex = 0, /* Part # of serv */
156 .xLpIndex = 0, /* Part # of me */
157 .xMaxLpQueues = 0, /* # of LP queues */
158 .xLpQueueOffset = 0x100, /* offset of start of LP queues */
159 .xPirEnvironMode = 0, /* Piranha stuff */
160 .xPirConsoleMode = 0,
163 .xSysPartitioned = 0,
165 .xIntProcUtilHmt = 0,
168 .xPlicVrmIndex = 0, /* VRM index of PLIC */
169 .xMinSupportedSlicVrmInd = 0, /* min supported SLIC */
170 .xMinCompatableSlicVrmInd = 0, /* min compat SLIC */
171 .xLoadAreaAddr = 0, /* 64-bit addr of load area */
172 .xLoadAreaChunks = 0, /* chunks for load area */
173 .xPaseSysCallCRMask = 0, /* PASE mask */
174 .xSlicSegmentTablePtr = 0, /* seg table */
175 .xOldLpQueue = { 0 }, /* Old LP Queue */
177 (u64)system_reset_iSeries, /* 0x100 System Reset */
178 (u64)machine_check_iSeries, /* 0x200 Machine Check */
179 (u64)data_access_iSeries, /* 0x300 Data Access */
180 (u64)instruction_access_iSeries, /* 0x400 Instruction Access */
181 (u64)hardware_interrupt_iSeries, /* 0x500 External */
182 (u64)alignment_iSeries, /* 0x600 Alignment */
183 (u64)program_check_iSeries, /* 0x700 Program Check */
184 (u64)fp_unavailable_iSeries, /* 0x800 FP Unavailable */
185 (u64)decrementer_iSeries, /* 0x900 Decrementer */
186 (u64)trap_0a_iSeries, /* 0xa00 Trap 0A */
187 (u64)trap_0b_iSeries, /* 0xb00 Trap 0B */
188 (u64)system_call_iSeries, /* 0xc00 System Call */
189 (u64)single_step_iSeries, /* 0xd00 Single Step */
190 (u64)trap_0e_iSeries, /* 0xe00 Trap 0E */
191 (u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */
194 0, /* int 0x1020 CPU ctls */
195 (u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */
196 (u64)data_access_slb_iSeries, /* 0x380 D-SLB */
197 (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */
200 EXPORT_SYMBOL(itLpNaca);
202 /* May be filled in by the hypervisor so cannot end up in the BSS */
203 struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data")));
205 /* May be filled in by the hypervisor so cannot end up in the BSS */
206 struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data")));
207 EXPORT_SYMBOL(xItExtVpdPanel);
209 #define maxPhysicalProcessors 32
211 struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {
213 .xInstCacheOperandSize = 32,
214 .xDataCacheOperandSize = 32,
215 .xProcFreq = 50000000,
216 .xTimeBaseFreq = 50000000,
221 /* Space for Main Store Vpd 27,200 bytes */
222 /* May be filled in by the hypervisor so cannot end up in the BSS */
223 u64 xMsVpd[3400] __attribute__((__section__(".data")));
225 /* Space for Recovery Log Buffer */
226 /* May be filled in by the hypervisor so cannot end up in the BSS */
227 u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data")));
229 struct SpCommArea xSpCommArea = {
234 /* The LparMap data is now located at offset 0x6000 in head.S
235 * It was put there so that the HvReleaseData could address it
236 * with a 32-bit offset as required by the iSeries hypervisor
238 * The Naca has a pointer to the ItVpdAreas. The hypervisor finds
239 * the Naca via the HvReleaseData area. The HvReleaseData has the
240 * offset into the Naca of the pointer to the ItVpdAreas.
242 struct ItVpdAreas itVpdAreas = {
243 .xSlicDesc = 0xc9a3e5c1, /* "ItVA" */
244 .xSlicSize = sizeof(struct ItVpdAreas),
245 .xSlicVpdEntries = ItVpdMaxEntries, /* # VPD array entries */
246 .xSlicDmaEntries = ItDmaMaxEntries, /* # DMA array entries */
247 .xSlicMaxLogicalProcs = NR_CPUS * 2, /* Max logical procs */
248 .xSlicMaxPhysicalProcs = maxPhysicalProcessors, /* Max physical procs */
249 .xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks),
250 .xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs),
251 .xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens),
252 .xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens),
253 .xSlicMaxSlotLabels = 0, /* max slot labels */
254 .xSlicMaxLpQueues = 1, /* max LP queues */
255 .xPlicDmaLens = { 0 }, /* DMA lengths */
256 .xPlicDmaToks = { 0 }, /* DMA tokens */
257 .xSlicVpdLens = { /* VPD lengths */
259 sizeof(xItExtVpdPanel), /* 3 Extended VPD */
260 sizeof(struct paca_struct), /* 4 length of Paca */
262 sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */
263 26992, /* 7 length of MS VPD */
265 sizeof(struct ItLpNaca),/* 9 length of LP Naca */
267 256, /* 11 length of Recovery Log Buf */
268 sizeof(struct SpCommArea), /* 12 length of SP Comm Area */
270 sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */
271 0,0,0,0,0,0, /* 17 - 22 */
272 sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */
275 .xSlicVpdAdrs = { /* VPD addresses */
277 &xItExtVpdPanel, /* 3 Extended VPD */
278 &paca[0], /* 4 first Paca */
280 &xItIplParmsReal, /* 6 IPL parms */
281 &xMsVpd, /* 7 MS Vpd */
283 &itLpNaca, /* 9 LpNaca */
285 &xRecoveryLogBuffer, /* 11 Recovery Log Buffer */
286 &xSpCommArea, /* 12 SP Comm Area */
288 &xIoHriProcessorVpd, /* 16 Proc Vpd */
289 0,0,0,0,0,0, /* 17 - 22 */
290 &hvlpevent_queue, /* 23 Lp Queue */
295 struct msChunks msChunks;
296 EXPORT_SYMBOL(msChunks);
298 /* Depending on whether this is called from iSeries or pSeries setup
299 * code, the location of the msChunks struct may or may not have
300 * to be reloc'd, so we force the caller to do that for us by passing
301 * in a pointer to the structure.
304 msChunks_alloc(unsigned long mem, unsigned long num_chunks, unsigned long chunk_size)
306 unsigned long offset = reloc_offset();
307 struct msChunks *_msChunks = PTRRELOC(&msChunks);
309 _msChunks->num_chunks = num_chunks;
310 _msChunks->chunk_size = chunk_size;
311 _msChunks->chunk_shift = __ilog2(chunk_size);
312 _msChunks->chunk_mask = (1UL<<_msChunks->chunk_shift)-1;
314 mem = _ALIGN(mem, sizeof(msChunks_entry));
315 _msChunks->abs = (msChunks_entry *)(mem + offset);
316 mem += num_chunks * sizeof(msChunks_entry);