1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * This file is through cpp before being used as
29 * an inline. It contains support routines used
30 * only by DR for the copy-rename sequence.
31 */
32
33 #if defined(lint)
34 #include <sys/types.h>
35 #else
36 #include "assym.h"
37 #include "drmach_offsets.h"
38 #endif /* lint */
39
40 #include <sys/asm_linkage.h>
41 #include <sys/param.h>
42 #include <sys/privregs.h>
43 #include <sys/spitregs.h>
44 #include <sys/mmu.h>
45 #include <sys/machthread.h>
46 #include <sys/pte.h>
47 #include <sys/stack.h>
48 #include <sys/vis.h>
49 #include <sys/intreg.h>
50 #include <sys/cheetahregs.h>
51 #include <sys/drmach.h>
52 #include <sys/sbd_ioctl.h>
53
54 #if !defined(lint)
55
56 /*
57 * turn off speculative mode to prevent unwanted memory access
58 * when we are in the FMEM loops
59 */
60
61 #define FJSV_SPECULATIVE_OFF(reg, tmp1, tmp2) \
62 rdpr %pstate, reg ;\
63 andn reg, PSTATE_IE, tmp1 ;\
64 wrpr %g0, tmp1, %pstate ;\
65 ldxa [%g0]ASI_MCNTL, tmp1 ;\
66 set 1, tmp2 ;\
67 sllx tmp2, MCNTL_SPECULATIVE_SHIFT, tmp2 ;\
68 or tmp1, tmp2, tmp1 ;\
69 stxa tmp1, [%g0]ASI_MCNTL ;\
70 membar #Sync
71 #endif
72
73
74 #if defined(lint)
75 /*ARGSUSED*/
76 void
77 drmach_fmem_loop_script(caddr_t critical, int size, caddr_t stat)
78 { return; }
79 #else /* lint */
80 .align 8
81 ENTRY_NP(drmach_fmem_loop_script)
82 /* turn off speculative mode */
83 FJSV_SPECULATIVE_OFF(%o5, %o3, %o4);
84
85 /* read the critical region to get everything in the cache */
86 mov %o0, %o3
87 0:
88 ldx [%o3], %o4
89 sub %o1, 8, %o1
90 brnz %o1, 0b
91 add %o3, 8, %o3
92
93 /* clear L2_CTRL_UGE_TRAP error bit */
94 mov ASI_L2_CTRL_RW_ADDR, %o1
95 ldxa [%o1]ASI_L2_CTRL, %o3
96 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4
97 btst %o3, %o4
98 bz,pn %xcc, 1f
99 nop
100 stxa %o4, [%o1]ASI_L2_CTRL
101
102 /* now tell the master CPU that we are ready */
103 1:
104 set FMEM_LOOP_FMEM_READY, %o3
105 stb %o3, [%o2]
106 membar #Sync
107 ba 5f
108 nop
109
110 /*
111 * note that we branch to 5f, which branches right back to 2 here.
112 * The trick is that when that branch instruction has already been
113 * patched to a branch to itself - an infinite loop.
114 * The master thread will patch it back to "ba 2b" when it
115 * completes.
116 */
117
118 /* Once we are back, we first check if there has been any
119 * L2_CTRL_UGE_TRAP errors, if so we have to fail the
120 * operation. This will cause a panic because the system
121 * is already in inconsistent state.
122 */
123 2:
124 mov ASI_L2_CTRL_RW_ADDR, %o3
125 ldxa [%o3]ASI_L2_CTRL, %o3
126 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4
127 btst %o3, %o4
128 bz,pn %xcc, 3f
129 mov %g0, %o4
130 set EOPL_FMEM_HW_ERROR, %o4
131
132 /* set error code and stat code */
133 3:
134 set FMEM_LOOP_DONE, %o3
135 stb %o3, [%o2]
136
137 /* turn on speculative mode again */
138 ldxa [%g0]ASI_MCNTL, %o0
139 set 1, %o1
140 sllx %o1, MCNTL_SPECULATIVE_SHIFT, %o1
141 andn %o0, %o1, %o0
142 ba 4f
143 nop
144 .align 32
145 4:
146 stxa %o0, [%g0]ASI_MCNTL
147 membar #Sync
148 wrpr %g0, %o5, %pstate
149 retl
150 mov %o4, %o0
151 .align 8
152 5:
153 ALTENTRY(drmach_fmem_loop_script_rtn)
154 /*
155 * busy wait will affect sibling strands so
156 * we put sleep instruction in the delay slot
157 */
158 ba 2b
159 .word 0x81b01060
160 SET_SIZE(drmach_fmem_loop_script)
161 #endif /* lint */
162
163 #if defined(lint)
164 /*ARGSUSED*/
165 void
166 drmach_flush_icache(void)
167 { return; }
168 #else /* lint */
169 .align 8
170 ENTRY_NP(drmach_flush_icache)
171 stxa %g0, [%g0]ASI_ALL_FLUSH_L1I
172 membar #Sync
173 retl
174 nop
175 SET_SIZE(drmach_flush_icache)
176 #endif
177
178 #if defined(lint)
179 /*ARGSUSED*/
180 int
181 drmach_fmem_exec_script(caddr_t critical, int size)
182 { return (0); }
183 #else /* lint */
184 .align 32
185 ENTRY_NP(drmach_fmem_exec_script)
186 /* turn off speculative mode */
187 FJSV_SPECULATIVE_OFF(%o5, %o3, %o4);
188 /* save locals to save area */
189 add %o0, SAVE_LOCAL, %o2
190 stx %l0, [%o2+8*0]
191 stx %l1, [%o2+8*1]
192 stx %l2, [%o2+8*2]
193 stx %l3, [%o2+8*3]
194 stx %l4, [%o2+8*4]
195 stx %l5, [%o2+8*5]
196 stx %l6, [%o2+8*6]
197 stx %l7, [%o2+8*7]
198 mov %o5, %l6
199 /* l7 is set only when FMEM cmd is issued to SCF */
200 mov %g0, %l7
201
202 /* read the critical region to put everything in the cache */
203 mov %o0, %o2
204 0:
205 ldx [%o2], %o4
206 sub %o1, 8, %o1
207 brnz %o1, 0b
208 add %o2, 8, %o2
209 ba 4f
210 nop
211
212 /* we branch to 4f but eventually we branch back here to finish up */
213 1:
214 mov %l6, %o5
215 /*
216 * save some registers for debugging
217 * l0 - SCF_REG_BASE
218 * l1 - SCF_TD
219 * l2 - SCF_TD + 8
220 * l5 - DELAY
221 */
222 add %o0, SAVE_LOG, %o1
223 stx %l0, [%o1+8*0]
224 stx %l1, [%o1+8*1]
225 stx %l2, [%o1+8*2]
226 stx %l5, [%o1+8*3]
227
228 add %o0, FMEM_ISSUED, %o1
229 st %l7, [%o1]
230
231 /* Check for L2_CTRL_UGE_TRAP error */
232 mov ASI_L2_CTRL_RW_ADDR, %l0
233 ldxa [%l0]ASI_L2_CTRL, %l1
234 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2
235 btst %l1, %l2
236 bz,pn %xcc, 2f
237 nop
238 set EOPL_FMEM_HW_ERROR, %o4
239 2:
240 /* restore all locals */
241 add %o0, SAVE_LOCAL, %o1
242 ldx [%o1+8*0], %l0
243 ldx [%o1+8*1], %l1
244 ldx [%o1+8*2], %l2
245 ldx [%o1+8*3], %l3
246 ldx [%o1+8*4], %l4
247 ldx [%o1+8*5], %l5
248 ldx [%o1+8*6], %l6
249 ldx [%o1+8*7], %l7
250
251 /* turn on speculative mode */
252 ldxa [%g0]ASI_MCNTL, %o1
253 set 1, %o2
254 sllx %o2, MCNTL_SPECULATIVE_SHIFT, %o2
255 andn %o1, %o2, %o1
256 ba 3f
257 nop
258 .align 32
259 3:
260 stxa %o1, [%g0]ASI_MCNTL
261 membar #Sync
262 /* return error code here */
263 mov %o4, %o0
264 retl
265 wrpr %g0, %o5, %pstate
266
267 /* clear L2_CTRL_UGE_TRAP error bit */
268 4:
269 mov ASI_L2_CTRL_RW_ADDR, %l0
270 ldxa [%l0]ASI_L2_CTRL, %l1
271 sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2
272 btst %l1, %l2
273 bz,pn %xcc, 5f
274 nop
275 stxa %l2, [%l0]ASI_L2_CTRL
276 5:
277 /* set up the register locations and parameters */
278 ldx [%o0 + SCF_REG_BASE], %l0
279 ldx [%o0 + SCF_TD], %l1
280 ldx [%o0 + SCF_TD+8], %l2
281 ldx [%o0 + DELAY], %l5
282
283 /* check if SCF is ONLINE */
284 add %l0, SCF_STATUS_EX, %o1
285 lduwa [%o1]ASI_IO, %o2
286 sethi %hi(SCF_STATUS_EX_ONLINE), %o3
287 btst %o2, %o3
288 bne %xcc, 6f
289 nop
290 set EOPL_FMEM_SCF_OFFLINE, %o4
291 ba 1b
292 nop
293
294 /* check if SCF is busy */
295 add %l0, SCF_COMMAND, %o1
296 lduha [%o1]ASI_IO, %o2
297 sethi %hi(SCF_CMD_BUSY), %o3
298 btst %o2, %o3
299 be %xcc, 6f
300 nop
301 set EOPL_FMEM_SCF_BUSY, %o4
302 ba 1b
303 nop
304
305 /* clear STATUS bit */
306 6:
307 add %l0, SCF_STATUS, %o1
308 lduha [%o1]ASI_IO, %o2
309 sethi %hi(SCF_STATUS_READY), %o3
310 btst %o2, %o3
311 be %xcc, 7f
312 nop
313 stha %o3, [%o1]ASI_IO
314
315 /* clear CMD_COMPLETE bit */
316 7:
317 mov SCF_STATUS_CMD_COMPLETE, %o3
318 btst %o2, %o3
319 be,a %xcc, 8f
320 nop
321 stha %o3, [%o1]ASI_IO
322 8:
323 add %l0, (SCF_TDATA+0xe), %o1
324 mov %l2, %o4
325 mov SCF_RETRY_CNT, %o5
326
327 sethi %hi(0xffff), %l2
328 or %l2, %lo(0xffff), %l2
329
330 and %o4, %l2, %o3
331
332 /*
333 * o1 points to SCFBASE.SCF_TDATA[0xe]
334 * l0 points to SCFBASE
335 * crticial->SCF_TD[0] = source board #
336 * crticial->SCF_TD[1] = target board #
337 * l1 = critical->SCF_TD[0 - 7]
338 * l2 = 0xffff
339 * o4 = critical->SCF_TD[8 - 15]
340 * o3 = (*o4) & 0xffff
341
342 /*
343 * Because there is no parity protection on the ebus
344 * we read the data back after the write to verify
345 * we write 2 bytes at a time.
346 * If the data read is not the same as data written
347 * we retry up to a limit of SCF_RETRY_CNT
348 */
349 9:
350 stha %o3, [%o1]ASI_IO
351 lduha [%o1]ASI_IO, %o2
352 sub %o5, 1, %o5
353 brnz %o5, 7f
354 nop
355 set EOPL_FMEM_RETRY_OUT, %o4
356 ba 1b
357 nop
358 7:
359 cmp %o2, %o3
360 bne,a 9b
361 nop
362
363 sub %o1, %l0, %o2
364 cmp %o2, (SCF_TDATA+0x8)
365 bne %xcc, 2f
366 srlx %o4, 16, %o4
367 mov %l1, %o4
368
369 /* if we have reach TDATA+8, we switch to l1 */
370 /* XXX: Why we need 2 loops??? */
371 2:
372 sub %o1, 2, %o1
373 mov SCF_RETRY_CNT, %o5
374 and %o4, %l2, %o3
375
376 sub %o1, %l0, %o2
377 cmp %o2, (SCF_TDATA)
378 bge,a 9b
379 nop
380
381 /* if we reach TDATA, we are done */
382
383 /* read from SCF back to our buffer for debugging */
384 add %l0, (SCF_TDATA), %o1
385 ldxa [%o1]ASI_IO, %o2
386 stx %o2, [%o0+SCF_TD]
387
388 add %l0, (SCF_TDATA+8), %o1
389 ldxa [%o1]ASI_IO, %o2
390 stx %o2, [%o0+SCF_TD+8]
391
392 /* The following code conforms to the FMEM
393 sequence (4) as described in the Columbus2
394 logical spec section 4.6
395 */
396
397 /* read from SCF SB INFO register */
398 sethi %hi(SCF_SB_INFO_OFFSET), %o2
399 or %o2, %lo(SCF_SB_INFO_OFFSET), %o2
400 add %l0, %o2, %o1
401 lduba [%o1]ASI_IO, %o2
402
403 /* If BUSY bit is set, abort */
404 or %g0, (SCF_SB_INFO_BUSY), %o1
405 btst %o1, %o2
406 set EOPL_FMEM_SCF_BUSY, %o4
407 bne 1b
408 nop
409
410 rd STICK, %l1
411 add %l5, %l1, %l5
412
413 /* Now tell SCF to do it */
414 add %l0, SCF_COMMAND, %o1
415
416 /* 0x10A6 is the magic command */
417 sethi %hi(0x10A6), %o2
418 or %o2, %lo(0x10A6), %o2
419 stha %o2, [%o1]ASI_IO
420
421 mov 1, %l7 ! FMEM is issued
422
423 add %l0, SCF_STATUS, %o1
424 sethi %hi(SCF_STATUS_READY), %o2
425 mov SCF_STATUS_CMD_COMPLETE, %o3
426
427 /* read STATUS_READY bit and clear it only if it is set */
428 /* XXX: this STATUS_READY checking seems meaningless */
429 3:
430 lduha [%o1]ASI_IO, %o4
431 btst %o2, %o4
432 be %xcc, 4f ! STATUS_READY is not set
433 nop
434 stha %o2, [%o1]ASI_IO ! Clear if the bit is set
435
436 /* check CMD_COMPLETE bit and clear */
437 4:
438 btst %o3, %o4
439 be %xcc, 5f ! CMD_COMPLETE is not set
440 nop
441 stha %o3, [%o1]ASI_IO ! Now we are done and clear it
442 ba %xcc, 6f
443 mov ESBD_NOERROR, %o4
444
445 /* timeout delay checking */
446 5:
447 rd STICK, %l2
448 cmp %l5, %l2
449 bge %xcc, 3b
450 nop
451 set EOPL_FMEM_TIMEOUT, %o4
452
453 /* we are done or timed out */
454 6:
455 ba,a 1b
456 nop
457 SET_SIZE(drmach_fmem_exec_script)
458 #endif /* lint */
459
460 #if defined(lint)
461 /*ARGSUSED*/
462 void
463 drmach_fmem_exec_script_end(caddr_t critical, int size)
464 { return; }
465 #else /* lint */
466 ENTRY_NP(drmach_fmem_exec_script_end)
467 nop
468 SET_SIZE(drmach_fmem_exec_script_end)
469 #endif /* lint */
470
471 #if defined(lint)
472 uint64_t
473 patch_inst(uint64_t *x, uint64_t y)
474 {
475 *x = y;
476 return (0);
477 }
478
479 #else /* lint */
480
481 ENTRY_NP(patch_inst)
482 ldx [%o0], %o2
483 casx [%o0], %o2, %o1
484 flush %o0
485 membar #Sync
486 ldx [%o0], %o2
487 retl
488 mov %o2, %o0
489 SET_SIZE(patch_inst)
490
491 #endif /* lint */
492
493 #if defined(lint)
494 void
495 drmach_sys_trap()
496 {
497 }
498 #else /* lint */
499 ENTRY_NP(drmach_sys_trap)
500 mov -1, %g4
501 set sys_trap, %g5
502 jmp %g5
503 nop
504 SET_SIZE(drmach_sys_trap)
505 #endif /* lint */
506
507 #if defined(lint)
508 uint64_t
509 drmach_get_stick()
510 {
511 return (0);
512 }
513 #else /* lint */
514 ENTRY_NP(drmach_get_stick)
515 retl
516 rd STICK, %o0
517 SET_SIZE(drmach_get_stick)
518 #endif /* lint */
519
520 #if defined(lint)
521 /*ARGSUSED*/
522 void
523 drmach_flush(drmach_copy_rename_critical_t *x, uint_t y)
524 {}
525
526 #else /* lint */
527 ENTRY_NP(drmach_flush)
528 mov %o0, %o2
529 0:
530 flush %o2
531 sub %o1, 8, %o1
532 brnz %o1, 0b
533 add %o2, 8, %o2
534 retl
535 nop
536 SET_SIZE(drmach_flush)
537 #endif /* lint */