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*/
76void
77drmach_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
870:
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 */
1031:
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	 */
1232:
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 */
1333:
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
1454:
146	stxa	%o0, [%g0]ASI_MCNTL
147	membar	#Sync
148	wrpr	%g0, %o5, %pstate
149	retl
150	 mov	%o4, %o0
151.align 8
1525:
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*/
165void
166drmach_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*/
180int
181drmach_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
2040:
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 */
2131:
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
2392:
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
2593:
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 */
2684:
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
2765:
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 */
3066:
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 */
3167:
317	mov	SCF_STATUS_CMD_COMPLETE, %o3
318	btst	%o2, %o3
319	be,a	%xcc, 8f
320	 nop
321	stha	%o3, [%o1]ASI_IO
3228:
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	 */
3499:
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
3587:
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??? */
3712:
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 */
4293:
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 */
4374:
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 */
4465:
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 */
4546:
455	ba,a	1b
456	 nop
457	SET_SIZE(drmach_fmem_exec_script)
458#endif /* lint */
459
460#if defined(lint)
461/*ARGSUSED*/
462void
463drmach_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)
472uint64_t
473patch_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)
494void
495drmach_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)
508uint64_t
509drmach_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*/
522void
523drmach_flush(drmach_copy_rename_critical_t *x, uint_t y)
524{}
525
526#else /* lint */
527	ENTRY_NP(drmach_flush)
528	mov	%o0, %o2
5290:
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 */
538