ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ia64 / sn / fakeprom / fpromasm.S
1 /* 
2  *
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  *   (Code copied from or=ther files)
8  * Copyright (C) 1998-2000 Hewlett-Packard Co
9  * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
10  *
11  * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved.
12  */
13
14
15
16 #define __ASSEMBLY__ 1
17 #include <linux/config.h>
18 #include <asm/processor.h>
19 #include <asm/sn/addrs.h>
20 #include <asm/sn/sn2/shub_mmr.h>
21
22 /*
23  * This file contains additional set up code that is needed to get going on
24  * Medusa.  This code should disappear once real hw is available.
25  *
26  * On entry to this routine, the following register values are assumed:
27  *
28  *      gr[8]   - BSP cpu
29  *      pr[9]   - kernel entry address
30  *      pr[10]  - cpu number on the node
31  *
32  * NOTE:
33  *   This FPROM may be loaded/executed at an address different from the
34  *   address that it was linked at. The FPROM is linked to run on node 0
35  *   at address 0x100000. If the code in loaded into another node, it
36  *   must be loaded at offset 0x100000 of the node. In addition, the
37  *   FPROM does the following things:
38  *              - determine the base address of the node it is loaded on
39  *              - add the node base to _gp.
40  *              - add the node base to all addresses derived from "movl" 
41  *                instructions. (I couldnt get GPREL addressing to work)
42  *                (maybe newer versions of the tools will support this)
43  *              - scan the .got section and add the node base to all
44  *                pointers in this section.
45  *              - add the node base to all physical addresses in the
46  *                SAL/PAL/EFI table built by the C code. (This is done
47  *                in the C code - not here)
48  *              - add the node base to the TLB entries for vmlinux
49  */
50
51 #define KERNEL_BASE     0xe000000000000000
52 #define BOOT_PARAM_ADDR 0x40000
53
54
55 /* 
56  * ar.k0 gets set to IOPB_PA value, on 460gx chipset it should 
57  * be 0x00000ffffc000000, but on snia we use the (inverse swizzled)
58  * IOSPEC_BASE value
59  */
60 #ifdef SGI_SN2
61 #define IOPB_PA         0xc000000fcc000000
62 #endif
63
64 #define RR_RID          8
65
66
67
68 // ==================================================================================== 
69         .text
70         .align 16
71         .global _start
72         .proc _start
73 _start:
74
75 // Setup psr and rse for system init
76         mov             psr.l = r0;;
77         srlz.d;;
78         invala
79         mov             ar.rsc = r0;;
80         loadrs
81         ;;
82
83 // Isolate node number we are running on.
84         mov             r6 = ip;;
85 #ifdef SGI_SN2
86         shr             r5 = r6,38                      // r5 = node number
87         dep             r6 = 0,r6,0,36                  // r6 = base memory address of node
88
89 #endif
90
91
92 // Set & relocate gp.
93         movl            r1= __gp;;                      // Add base memory address
94         or              r1 = r1,r6                      // Relocate to boot node
95
96 // Lets figure out who we are & put it in the LID register.
97 #ifdef SGI_SN2
98 // On SN2, we (currently) pass the cpu number in r10 at boot
99         and             r25=3,r10;;
100         movl            r16=0x8000008110000400          // Allow IPIs
101         mov             r17=-1;;
102         st8             [r16]=r17
103         movl            r16=0x8000008110060580;;        // SHUB_ID
104         ld8             r27=[r16];;
105         extr.u          r27=r27,32,11;;
106         shl             r26=r25,28;;                    // Align local cpu# to lid.eid
107         shl             r27=r27,16;;                    // Align NASID to lid.id
108         or              r26=r26,r27;;                   // build the LID
109 #else
110 // The BR_PI_SELF_CPU_NUM register gives us a value of 0-3.
111 // This identifies the cpu on the node. 
112 // Merge the cpu number with the NASID to generate the LID.
113         movl            r24=0x80000a0001000020;;        // BR_PI_SELF_CPU_NUM
114         ld8             r25=[r24]                       // Fetch PI_SELF
115         movl            r27=0x80000a0001600000;;        // Fetch REVID to get local NASID
116         ld8             r27=[r27];;
117         extr.u          r27=r27,32,8;;
118         shl             r26=r25,16;;                    // Align local cpu# to lid.eid
119         shl             r27=r27,24;;                    // Align NASID to lid.id
120         or              r26=r26,r27;;                   // build the LID
121 #endif
122         mov             cr.lid=r26                      // Now put in in the LID register
123
124         movl            r2=FPSR_DEFAULT;;
125         mov             ar.fpsr=r2
126         movl            sp = bootstacke-16;;
127         or              sp = sp,r6                      // Relocate to boot node                        
128
129 // Save the NASID that we are loaded on.
130         movl            r2=base_nasid;;                 // Save base_nasid for C code
131         or              r2 = r2,r6;;                    // Relocate to boot node
132         st8             [r2]=r5                         // Uncond st8 - same on all cpus
133
134 // Save the kernel entry address. It is passed in r9 on one of
135 // the cpus.
136         movl            r2=bsp_entry_pc
137         cmp.ne          p6,p0=r9,r0;;
138         or              r2 = r2,r6;;                    // Relocate to boot node
139 (p6)    st8             [r2]=r9                         // Uncond st8 - same on all cpus
140
141
142 // The following can ONLY be done by 1 cpu. Lets set a lock - the
143 // cpu that gets it does the initilization. The rest just spin waiting
144 // til initilization is complete.
145         movl            r22 = initlock;;
146         or              r22 = r22,r6                    // Relocate to boot node
147         mov             r23 = 1;;
148         xchg8           r23 = [r22],r23;;
149         cmp.eq          p6,p0 = 0,r23
150 (p6)    br.cond.spnt.few init
151 1:      ld4             r23 = [r22];;
152         cmp.eq          p6,p0 = 1,r23
153 (p6)    br.cond.sptk    1b
154         br              initx
155
156 // Add base address of node memory to each pointer in the .got section.
157 init:   movl            r16 = _GLOBAL_OFFSET_TABLE_;;
158         or              r16 = r16,r6;;                  // Relocate to boot node
159 1:      ld8             r17 = [r16];;
160         cmp.eq          p6,p7=0,r17
161 (p6)    br.cond.sptk.few.clr 2f;;
162         or              r17 = r17,r6;;                  // Relocate to boot node
163         st8             [r16] = r17,8
164         br              1b
165 2:
166         mov             r23 = 2;;                       // All done, release the spinning cpus
167         st4             [r22] = r23
168 initx:
169
170 //
171 //      I/O-port space base address:
172 //
173         movl            r2 = IOPB_PA;;
174         mov             ar.k0 = r2
175
176
177 // Now call main & pass it the current LID value.
178         alloc           r2=ar.pfs,0,0,2,0
179         mov             r32=r26
180         mov             r33=r8;;
181         br.call.sptk.few rp=fmain
182         
183 // Initialize Region Registers
184 //
185         mov             r10 = r0
186         mov             r2 = (13<<2)
187         mov             r3 = r0;;
188 1:      cmp4.gtu        p6,p7 = 7, r3
189         dep             r10 = r3, r10, 61, 3
190         dep             r2 = r3, r2, RR_RID, 4;;
191 (p7)    dep             r2 = 0, r2, 0, 1;;
192 (p6)    dep             r2 = -1, r2, 0, 1;;
193         mov             rr[r10] = r2
194         add             r3 = 1, r3;;
195         srlz.d;;
196         cmp4.gtu        p6,p0 = 8, r3
197 (p6)    br.cond.sptk.few.clr 1b
198
199 //
200 // Return value indicates if we are the BSP or AP.
201 //         1 = BSP, 0 = AP
202         mov             cr.tpr=r0;;
203         cmp.eq          p6,p0=r8,r0
204 (p6)    br.cond.spnt    slave
205
206 //
207 // Go to kernel C startup routines
208 //      Need to do a "rfi" in order set "it" and "ed" bits in the PSR.
209 //      This is the only way to set them.
210
211         movl            r28=BOOT_PARAM_ADDR
212         movl            r2=bsp_entry_pc;;
213         or              r28 = r28,r6;;                  // Relocate to boot node
214         or              r2 = r2,r6;;                    // Relocate to boot node
215         ld8             r2=[r2];;
216         or              r2=r2,r6;;
217         dep             r2=0,r2,61,3;;                  // convert to phys mode
218
219 //
220 // Turn on address translation, interrupt collection, psr.ed, protection key.
221 // Interrupts (PSR.i) are still off here.
222 //
223
224         movl            r3 = (  IA64_PSR_BN | \
225                                 IA64_PSR_AC | \
226                                 IA64_PSR_DB | \
227                                 IA64_PSR_DA | \
228                                 IA64_PSR_IC   \
229                              )
230         ;;
231         mov             cr.ipsr = r3
232
233 //
234 // Go to kernel C startup routines
235 //      Need to do a "rfi" in order set "it" and "ed" bits in the PSR.
236 //      This is the only way to set them.
237
238         mov             r8=r28;;
239         bsw.1           ;;
240         mov             r28=r8;;
241         bsw.0           ;;
242         mov             cr.iip = r2
243         srlz.d;;
244         rfi;;
245
246         .endp           _start
247
248
249
250 // Slave processors come here to spin til they get an interrupt. Then they launch themselves to
251 // the place ap_entry points. No initialization is necessary - the kernel makes no
252 // assumptions about state on this entry.
253 //      Note: should verify that the interrupt we got was really the ap_wakeup
254 //            interrupt but this should not be an issue on medusa
255 slave:
256         nop.i           0x8beef                         // Medusa - put cpu to sleep til interrupt occurs
257         mov             r8=cr.irr0;;                    // Check for interrupt pending.
258         cmp.eq          p6,p0=r8,r0
259 (p6)    br.cond.sptk    slave;;
260
261         mov             r8=cr.ivr;;                     // Got one. Must read ivr to accept it
262         srlz.d;;
263         mov             cr.eoi=r0;;                     // must write eoi to clear
264         movl            r8=ap_entry;;                   // now jump to kernel entry
265         or              r8 = r8,r6;;                    // Relocate to boot node
266         ld8             r9=[r8],8;;
267         ld8             r1=[r8]
268         mov             b0=r9;;
269         br              b0
270
271 // Here is the kernel stack used for the fake PROM
272         .bss
273         .align          16384
274 bootstack:
275         .skip           16384
276 bootstacke:
277 initlock:
278         data4
279
280
281
282 //////////////////////////////////////////////////////////////////////////////////////////////////////////
283 // This code emulates the PAL. Only essential interfaces are emulated.
284
285
286         .text
287         .global pal_emulator
288         .proc   pal_emulator
289 pal_emulator:
290         mov     r8=-1
291
292         mov     r9=256
293         ;;
294         cmp.gtu p6,p7=r9,r28            /* r28 <= 255? */
295 (p6)    br.cond.sptk.few static
296         ;;
297         mov     r9=512
298         ;;
299         cmp.gtu p6,p7=r9,r28
300 (p6)    br.cond.sptk.few stacked
301         ;;
302
303 static: cmp.eq  p6,p7=6,r28             /* PAL_PTCE_INFO */
304 (p7)    br.cond.sptk.few 1f
305         movl    r8=0                            /* status = 0 */
306         movl    r9=0x100000000                  /* tc.base */
307         movl    r10=0x0000000200000003          /* count[0], count[1] */
308         movl    r11=0x1000000000002000          /* stride[0], stride[1] */
309         ;;
310
311 1:      cmp.eq  p6,p7=14,r28            /* PAL_FREQ_RATIOS */
312 (p7)    br.cond.sptk.few 1f
313         movl    r8=0                            /* status = 0 */
314         movl    r9 =0x100000064                 /* proc_ratio (1/100) */
315         movl    r10=0x100000100                 /* bus_ratio<<32 (1/256) */
316         movl    r11=0x10000000a                 /* itc_ratio<<32 (1/100) */
317         ;;
318
319 1:      cmp.eq  p6,p7=8,r28             /* PAL_VM_SUMMARY */
320 (p7)    br.cond.sptk.few 1f
321         movl    r8=0
322 #ifdef SGI_SN2
323         movl    r9=0x0203083001151065
324         movl    r10=0x183f
325 #endif
326         movl    r11=0
327         ;;
328
329 1:      cmp.eq  p6,p7=19,r28            /* PAL_RSE_INFO */
330 (p7)    br.cond.sptk.few 1f
331         movl    r8=0
332         movl    r9=0x60
333         movl    r10=0x0
334         movl    r11=0
335         ;;
336
337 1:      cmp.eq  p6,p7=15,r28            /* PAL_PERF_MON_INFO */
338 (p7)    br.cond.sptk.few 1f
339         movl    r8=0
340         movl    r9=0x08122004
341         movl    r10=0x0
342         movl    r11=0
343         mov     r2=ar.lc
344         mov     r3=16;;
345         mov     ar.lc=r3
346         mov     r3=r29;;
347 5:      st8     [r3]=r0,8
348         br.cloop.sptk.few 5b;;
349         mov     ar.lc=r2
350         mov     r3=r29
351         movl    r2=0x1fff;;                     /* PMC regs */
352         st8     [r3]=r2
353         add     r3=32,r3
354         movl    r2=0x3ffff;;                    /* PMD regs */
355         st8     [r3]=r2
356         add     r3=32,r3
357         movl    r2=0xf0;;                       /* cycle regs */
358         st8     [r3]=r2
359         add     r3=32,r3
360         movl    r2=0x10;;                       /* retired regs */
361         st8     [r3]=r2
362         ;;
363
364 1:      cmp.eq  p6,p7=19,r28            /* PAL_RSE_INFO */
365 (p7)    br.cond.sptk.few 1f
366         movl    r8=0                            /* status = 0 */
367         movl    r9=96                           /* num phys stacked */
368         movl    r10=0                           /* hints */
369         movl    r11=0
370         ;;
371
372 1:      cmp.eq  p6,p7=1,r28             /* PAL_CACHE_FLUSH */
373 (p7)    br.cond.sptk.few 1f
374         mov     r9=ar.lc
375         movl    r8=524288                               /* flush 512k million cache lines (16MB) */
376         ;;
377         mov     ar.lc=r8
378         movl    r8=0xe000000000000000
379         ;;
380 .loop:  fc      r8
381         add     r8=32,r8
382         br.cloop.sptk.few .loop
383         sync.i
384         ;;
385         srlz.i
386         ;;
387         mov     ar.lc=r9
388         mov     r8=r0
389 1:      br.cond.sptk.few rp
390
391 stacked:
392         br.ret.sptk.few rp
393
394         .endp pal_emulator
395