Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[linux-2.6] / arch / ia64 / kernel / pal.S
1 /*
2  * PAL Firmware support
3  * IA-64 Processor Programmers Reference Vol 2
4  *
5  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
6  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
7  * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co
8  *      David Mosberger <davidm@hpl.hp.com>
9  *      Stephane Eranian <eranian@hpl.hp.com>
10  *
11  * 05/22/2000 eranian Added support for stacked register calls
12  * 05/24/2000 eranian Added support for physical mode static calls
13  */
14
15 #include <asm/asmmacro.h>
16 #include <asm/processor.h>
17
18         .data
19 pal_entry_point:
20         data8 ia64_pal_default_handler
21         .text
22
23 /*
24  * Set the PAL entry point address.  This could be written in C code, but we
25  * do it here to keep it all in one module (besides, it's so trivial that it's
26  * not a big deal).
27  *
28  * in0          Address of the PAL entry point (text address, NOT a function
29  *              descriptor).
30  */
31 GLOBAL_ENTRY(ia64_pal_handler_init)
32         alloc r3=ar.pfs,1,0,0,0
33         movl r2=pal_entry_point
34         ;;
35         st8 [r2]=in0
36         br.ret.sptk.many rp
37 END(ia64_pal_handler_init)
38
39 /*
40  * Default PAL call handler.  This needs to be coded in assembly because it
41  * uses the static calling convention, i.e., the RSE may not be used and
42  * calls are done via "br.cond" (not "br.call").
43  */
44 GLOBAL_ENTRY(ia64_pal_default_handler)
45         mov r8=-1
46         br.cond.sptk.many rp
47 END(ia64_pal_default_handler)
48
49 /*
50  * Make a PAL call using the static calling convention.
51  *
52  * in0         Index of PAL service
53  * in1 - in3   Remaining PAL arguments
54  */
55 GLOBAL_ENTRY(ia64_pal_call_static)
56         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
57         alloc loc1 = ar.pfs,4,5,0,0
58         movl loc2 = pal_entry_point
59 1:      {
60           mov r28 = in0
61           mov r29 = in1
62           mov r8 = ip
63         }
64         ;;
65         ld8 loc2 = [loc2]               // loc2 <- entry point
66         adds r8 = 1f-1b,r8
67         mov loc4=ar.rsc                 // save RSE configuration
68         ;;
69         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
70         mov loc3 = psr
71         mov loc0 = rp
72         .body
73         mov r30 = in2
74
75         mov r31 = in3
76         mov b7 = loc2
77
78         rsm psr.i
79         ;;
80         mov rp = r8
81         br.cond.sptk.many b7
82 1:      mov psr.l = loc3
83         mov ar.rsc = loc4               // restore RSE configuration
84         mov ar.pfs = loc1
85         mov rp = loc0
86         ;;
87         srlz.d                          // seralize restoration of psr.l
88         br.ret.sptk.many b0
89 END(ia64_pal_call_static)
90
91 /*
92  * Make a PAL call using the stacked registers calling convention.
93  *
94  * Inputs:
95  *      in0         Index of PAL service
96  *      in2 - in3   Remaining PAL arguments
97  */
98 GLOBAL_ENTRY(ia64_pal_call_stacked)
99         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
100         alloc loc1 = ar.pfs,4,4,4,0
101         movl loc2 = pal_entry_point
102
103         mov r28  = in0                  // Index MUST be copied to r28
104         mov out0 = in0                  // AND in0 of PAL function
105         mov loc0 = rp
106         .body
107         ;;
108         ld8 loc2 = [loc2]               // loc2 <- entry point
109         mov out1 = in1
110         mov out2 = in2
111         mov out3 = in3
112         mov loc3 = psr
113         ;;
114         rsm psr.i
115         mov b7 = loc2
116         ;;
117         br.call.sptk.many rp=b7         // now make the call
118 .ret0:  mov psr.l  = loc3
119         mov ar.pfs = loc1
120         mov rp = loc0
121         ;;
122         srlz.d                          // serialize restoration of psr.l
123         br.ret.sptk.many b0
124 END(ia64_pal_call_stacked)
125
126 /*
127  * Make a physical mode PAL call using the static registers calling convention.
128  *
129  * Inputs:
130  *      in0         Index of PAL service
131  *      in2 - in3   Remaining PAL arguments
132  *
133  * PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel.
134  * So we don't need to clear them.
135  */
136 #define PAL_PSR_BITS_TO_CLEAR                                                 \
137         (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT  | IA64_PSR_DB | IA64_PSR_RT |\
138          IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED |              \
139          IA64_PSR_DFL | IA64_PSR_DFH)
140
141 #define PAL_PSR_BITS_TO_SET                                                   \
142         (IA64_PSR_BN)
143
144
145 GLOBAL_ENTRY(ia64_pal_call_phys_static)
146         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
147         alloc loc1 = ar.pfs,4,7,0,0
148         movl loc2 = pal_entry_point
149 1:      {
150           mov r28  = in0                // copy procedure index
151           mov r8   = ip                 // save ip to compute branch
152           mov loc0 = rp                 // save rp
153         }
154         .body
155         ;;
156         ld8 loc2 = [loc2]               // loc2 <- entry point
157         mov r29  = in1                  // first argument
158         mov r30  = in2                  // copy arg2
159         mov r31  = in3                  // copy arg3
160         ;;
161         mov loc3 = psr                  // save psr
162         adds r8  = 1f-1b,r8             // calculate return address for call
163         ;;
164         mov loc4=ar.rsc                 // save RSE configuration
165         dep.z loc2=loc2,0,61            // convert pal entry point to physical
166         tpa r8=r8                       // convert rp to physical
167         ;;
168         mov b7 = loc2                   // install target to branch reg
169         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
170         movl r16=PAL_PSR_BITS_TO_CLEAR
171         movl r17=PAL_PSR_BITS_TO_SET
172         ;;
173         or loc3=loc3,r17                // add in psr the bits to set
174         ;;
175         andcm r16=loc3,r16              // removes bits to clear from psr
176         br.call.sptk.many rp=ia64_switch_mode_phys
177         mov rp = r8                     // install return address (physical)
178         mov loc5 = r19
179         mov loc6 = r20
180         br.cond.sptk.many b7
181 1:
182         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
183         mov r16=loc3                    // r16= original psr
184         mov r19=loc5
185         mov r20=loc6
186         br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
187         mov psr.l = loc3                // restore init PSR
188
189         mov ar.pfs = loc1
190         mov rp = loc0
191         ;;
192         mov ar.rsc=loc4                 // restore RSE configuration
193         srlz.d                          // seralize restoration of psr.l
194         br.ret.sptk.many b0
195 END(ia64_pal_call_phys_static)
196
197 /*
198  * Make a PAL call using the stacked registers in physical mode.
199  *
200  * Inputs:
201  *      in0         Index of PAL service
202  *      in2 - in3   Remaining PAL arguments
203  */
204 GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
205         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
206         alloc   loc1 = ar.pfs,5,7,4,0
207         movl    loc2 = pal_entry_point
208 1:      {
209           mov r28  = in0                // copy procedure index
210           mov loc0 = rp                 // save rp
211         }
212         .body
213         ;;
214         ld8 loc2 = [loc2]               // loc2 <- entry point
215         mov loc3 = psr                  // save psr
216         ;;
217         mov loc4=ar.rsc                 // save RSE configuration
218         dep.z loc2=loc2,0,61            // convert pal entry point to physical
219         ;;
220         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
221         movl r16=PAL_PSR_BITS_TO_CLEAR
222         movl r17=PAL_PSR_BITS_TO_SET
223         ;;
224         or loc3=loc3,r17                // add in psr the bits to set
225         mov b7 = loc2                   // install target to branch reg
226         ;;
227         andcm r16=loc3,r16              // removes bits to clear from psr
228         br.call.sptk.many rp=ia64_switch_mode_phys
229
230         mov out0 = in0                  // first argument
231         mov out1 = in1                  // copy arg2
232         mov out2 = in2                  // copy arg3
233         mov out3 = in3                  // copy arg3
234         mov loc5 = r19
235         mov loc6 = r20
236
237         br.call.sptk.many rp=b7         // now make the call
238
239         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
240         mov r16=loc3                    // r16= original psr
241         mov r19=loc5
242         mov r20=loc6
243         br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
244
245         mov psr.l  = loc3               // restore init PSR
246         mov ar.pfs = loc1
247         mov rp = loc0
248         ;;
249         mov ar.rsc=loc4                 // restore RSE configuration
250         srlz.d                          // seralize restoration of psr.l
251         br.ret.sptk.many b0
252 END(ia64_pal_call_phys_stacked)
253
254 /*
255  * Save scratch fp scratch regs which aren't saved in pt_regs already
256  * (fp10-fp15).
257  *
258  * NOTE: We need to do this since firmware (SAL and PAL) may use any of the
259  * scratch regs fp-low partition.
260  *
261  * Inputs:
262  *      in0     Address of stack storage for fp regs
263  */
264 GLOBAL_ENTRY(ia64_save_scratch_fpregs)
265         alloc r3=ar.pfs,1,0,0,0
266         add r2=16,in0
267         ;;
268         stf.spill [in0] = f10,32
269         stf.spill [r2]  = f11,32
270         ;;
271         stf.spill [in0] = f12,32
272         stf.spill [r2]  = f13,32
273         ;;
274         stf.spill [in0] = f14,32
275         stf.spill [r2]  = f15,32
276         br.ret.sptk.many rp
277 END(ia64_save_scratch_fpregs)
278
279 /*
280  * Load scratch fp scratch regs (fp10-fp15)
281  *
282  * Inputs:
283  *      in0     Address of stack storage for fp regs
284  */
285 GLOBAL_ENTRY(ia64_load_scratch_fpregs)
286         alloc r3=ar.pfs,1,0,0,0
287         add r2=16,in0
288         ;;
289         ldf.fill  f10 = [in0],32
290         ldf.fill  f11 = [r2],32
291         ;;
292         ldf.fill  f12 = [in0],32
293         ldf.fill  f13 = [r2],32
294         ;;
295         ldf.fill  f14 = [in0],32
296         ldf.fill  f15 = [r2],32
297         br.ret.sptk.many rp
298 END(ia64_load_scratch_fpregs)