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