xref: /titanic_50/usr/src/uts/sparc/ml/fd_asm.s (revision f38cb554a534c6df738be3f4d23327e69888e634)
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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * This file contains no entry points which can be called directly from
31 * C and hence is of no interest to lint. However, we want to avoid the
32 * dreaded "Empty translation unit"  warning.
33 */
34
35#if defined(lint)
36#include <sys/types.h>
37
38/*ARGSUSED*/
39u_int
40fd_intr(caddr_t arg)
41{
42	return (0);
43}
44
45#else	/* lint */
46
47#include <sys/asm_linkage.h>
48#include <sys/fdreg.h>
49#include <sys/fdvar.h>
50#include "fd_assym.h"
51
52/*
53 * Since this is part of a Sparc "generic" module, it may be loaded during
54 * reconfigure time on systems that do not support the fast interrupt
55 * handler.  On these machines the symbol "impl_setintreg_on" will be
56 * undefined but we don't want to cause error messages when we load.
57 */
58	.weak	impl_setintreg_on
59	.type	impl_setintreg_on, #function
60	.weak	fd_softintr_cookie
61	.type	fd_softintr_cookie, #object
62
63#define	Tmp2	%l4	/* temp register prior to dispatch to right opmode */
64#define	Reg	%l4	/* pointer to the chip's registers */
65#define	Fdc	%l3	/* pointer to fdctlr structure */
66#define	Adr	%l5	/* data address pointer */
67#define	Len	%l6	/* data length counter */
68#define	Tmp	%l7	/* general scratch */
69#define	TRIGGER	0x33
70	ENTRY(fd_intr)		! fd standard interrupt handler
71	save	%sp, -SA(MINFRAME), %sp
72	!
73	! Traverse the list of controllers until we find the first
74	! controller expecting an interrupt. Unfortunately, the
75	! 82072 floppy controller really doesn't have a way to tell
76	! you that it is interrupting.
77	!
78	set	fdctlrs, Fdc		! load list of controllers
79	ldn	[Fdc], Fdc		! get the first in the list...
801:	tst	Fdc			! do we have any more to check
81	bz	.panic			! Nothing to service. Panic
82	nop
83
843:	ldub	[Fdc + FD_OPMODE], Tmp2	! load opmode into Tmp2
85	and	Tmp2, 0x3, Tmp2		! opmode must be 1, 2, or 3
86	tst	Tmp2			! non-zero?
87	bnz	.mutex_enter		! yes!
88	nop
89	ldn	[Fdc + FD_NEXT], Tmp	! Try next ctlr...
90	tst	Tmp
91	bnz,a	1b
92	mov	Tmp, Fdc
93					! no more controllers
94	mov	0x2, Tmp2		! must be spurious or "ready" int
95.mutex_enter:
96	!
97	! grab high level mutex for this controller
98	!
99	sethi	%hi(asm_mutex_spin_enter), %l7
100	jmpl	%l7 + %lo(asm_mutex_spin_enter), %l7
101	add	Fdc, FD_HILOCK, %l6
102	!
103	! dispatch to correct handler
104	!
105	cmp	Tmp2, 3			!case 3: results ?
106	be,a	.opmode3		! yes...
107	ldn	[Fdc + FD_REG], Reg	! load pointer to h/w registers
108	cmp	Tmp2, 2			!case 2: seek/recalibrate ?
109	be	.opmode2		! yes..
110	ldn	[Fdc + FD_REG], Reg	! load pointer to h/w registers
111	!
112	! opmode 1:
113	! read/write/format data-xfer case - they have a result phase
114	!
115.opmode1:
116	ld	[Fdc + FD_RLEN], Len
117	!
118	! XXX- test for null raddr
119	!
120	ldn	[Fdc + FD_RADDR], Adr
121
122	!
123	! while the fifo ready bit set, then data/status available
124	!
1251:	ldub	[Reg], Tmp		! get csr
126	andcc	Tmp, RQM, %g0		!
127	be	4f			! branch if bit clear
128	andcc	Tmp, NDM, %g0		! NDM set means data
129	be	7f			! if not set, it is status time
130	andcc	Tmp, DIO, %g0		! check for input vs. output data
131	be	2f			!
132	sub	Len, 0x1, Len		! predecrement length...
133	ldub	[Reg + 0x1], Tmp	! DIO set, *addr = *fifo
134	b	3f			!
135	stb	Tmp, [Adr]		!
1362:	ldsb	[Adr], Tmp		! *fifo = *addr
137	stb	Tmp, [Reg + 0x1]	!
1383:	tst	Len			! if (len == 0) send TC
139	bne	1b			! branch if not....
140	add	Adr, 0x1, Adr		!
141	b	6f			!
142	.empty				!
143	!
144	! save updated len, addr
145	!
1464:	st	Len, [Fdc + FD_RLEN]
147	b	.out			! not done yet, return
148	stn	Adr, [Fdc + FD_RADDR]
149	!
150	! END OF TRANSFER - if read/write, toggle the TC
151	! bit in AUXIO_REG then save status and set state = 3.
152	!
1535:
154	!
155	! Stash len and addr before they get lost
156	!
157	st	Len, [Fdc + FD_RLEN]
1586:	stn	Adr, [Fdc + FD_RADDR]
159	!
160	! Begin TC delay...
161	! Old comment:
162	!	five nops provide 100ns of delay at 10MIPS to ensure
163	!	TC is wide enough at slowest possible floppy clock
164	!	(500ns @ 250Kbps).
165	!
166	! I gather this mean that we have to give 100ns delay for TC.
167	!
168	! At 100 Mips, that would be 1 * 10 (10) nops.
169	!
170
171	ldn	[Fdc + FD_AUXIOVA], Adr
172	ldub	[Fdc + FD_AUXIODATA], Tmp2
173	ldub	[Adr], Tmp
174	or	Tmp, Tmp2, Tmp
175	stb	Tmp, [Adr]
176	nop; nop; nop; nop; nop; nop; nop; nop; nop; nop	! 10 nops
177	!
178	! End TC delay...now clear the TC bit
179	!
180	ldub	[Fdc + FD_AUXIODATA2], Tmp2
181	andn	Tmp, Tmp2, Tmp
182	stb	Tmp, [Adr]
183
184	!
185	! set opmode to 3 to indicate going into status mode
186	!
187	mov	3, Tmp
188	b	.out
189	stb	Tmp, [Fdc + FD_OPMODE]
190	!
191	! error status state: save old pointers, go direct to result snarfing
192	!
1937:	st	Len, [Fdc + FD_RLEN]
194	stn	Adr, [Fdc + FD_RADDR]
195	mov	0x3, Tmp
196	b	.opmode3
197	stb	Tmp, [Fdc + FD_OPMODE]
198	!
199	! opmode 2:
200	! recalibrate/seek - no result phase, must do sense interrupt status.
201	!
202.opmode2:
203	ldub	[Reg], Tmp			! Tmp = *csr
2041:	andcc	Tmp, CB, %g0			! is CB set?
205	bne	1b				! yes, keep waiting
206	ldub	[Reg], Tmp			!! Tmp = *csr
207	!
208	! wait!!! should we check rqm first???  ABSOLUTELY YES!!!!
209	!
2101:	andcc	Tmp, RQM, %g0		!
211	be,a	1b			! branch if bit clear
212	ldub	[Reg], Tmp		! busy wait until RQM set
213	mov	SNSISTAT, Tmp		! cmd for SENSE_INTERRUPT_STATUS
214	stb	Tmp, [Reg + 0x1]
215	!
216	! NOTE: we ignore DIO here, assume it is set before RQM!
217	!
218	ldub	[Reg], Tmp			! busy wait until RQM set
2191:	andcc	Tmp, RQM, Tmp
220	be,a	1b				! branch if bit clear
221	ldub	[Reg], Tmp			! busy wait until RQM set
222	!
223	! fdc->c_csb.csb_rslt[0] = *fifo;
224	!
225	ldub	[Reg + 0x1], Tmp
226	stb	Tmp, [Fdc + FD_RSLT]
227	ldub	[Reg], Tmp			! busy wait until RQM set
2281:	andcc	Tmp, RQM, Tmp
229	be,a	1b				! branch if bit clear
230	ldub	[Reg], Tmp			! busy wait until RQM set
231	!
232	! fdc->c_csb.csb_rslt[1] = *fifo;
233	!
234	ldub	[Reg + 0x1], Tmp
235	b	.notify
236	stb	Tmp, [Fdc + FD_RSLT + 1]
237	!
238	! case 3: result mode
239	! We are in result mode make sure all status bytes are read out
240	!
241	! We have to have *both* RQM and DIO set.
242	!
243.opmode3:
244	add	Fdc, FD_RSLT, Adr		! load address of csb->csb_rslt
245	add	Adr, 10, Len			! put an upper bound on it..
246	ldub	[Reg], Tmp			!
2471:	andcc	Tmp, CB, %g0			! is CB set?
248	be	.notify				! no, jump around, must be done
249	andcc	Tmp, RQM, %g0			! check for RQM in delay slot
250	be,a	1b				! No RQM, go back
251	ldub	[Reg], Tmp			! and load control reg in delay
252	andcc	Tmp, DIO, %g0			! DIO set?
253	be,a	1b				! No DIO, go back
254	ldub	[Reg], Tmp			! and load control reg in delay
255	!
256	! CB && DIO && RQM all true.
257	! Time to get a byte.
258	!
259	ldub	[Reg + 0x1], Tmp		! *fifo into Tmp
260	cmp	Adr, Len			! already at our limit?
261	bge,a	1b				! Yes, go back..
262	ldub	[Reg], Tmp			! and load control reg in delay
263	stb	Tmp, [Adr]			! store new byte
264	add	Adr, 1, Adr			! increment address
265	b	1b				! and pop back to the top
266	ldub	[Reg], Tmp			! and load control reg in delay
267
268	!
269	! schedule 2nd stage interrupt
270	!
271.notify:
272	!
273	! if fast traps are enabled, use the platform dependent
274	! impl_setintreg_on function.
275	!
276	ldub    [Fdc + FD_FASTTRAP], Tmp
277	tst     Tmp
278	bnz	.fast
279	nop
280
281	!
282	! fast traps are not in use.  Do not schedule the soft interrupt
283	! at this time.  Wait to trigger it at the end of the handler
284	! when the mutexes have been released
285	!
286	mov   	TRIGGER, Tmp2
287	b	.out
288	nop
289
290	!
291	! fast traps are enabled.  Schedule the soft interrupt.
292	! impl_setintreg uses %l4-%l7
293	!
294.fast:	sethi   %hi(fd_softintr_cookie), %l6
295	sethi	%hi(impl_setintreg_on), %l7
296	jmpl	%l7 + %lo(impl_setintreg_on), %l7
297	ld      [%l6 + %lo(fd_softintr_cookie)], %l6
298	!
299	! set new opmode to 4
300	!
301	mov	0x4, Tmp
302	stb	Tmp, [Fdc + FD_OPMODE]
303
304	!
305	! and fall through to exit
306	!
307.out:
308	!
309	! update high level interrupt counter...
310	!
311	ldn	[Fdc + FD_HIINTCT], Adr
312	tst	Adr
313	be,a	1f
314	nop
315	ld	[Adr], Tmp
316	inc	Tmp
317	st	Tmp, [Adr]
3181:
319	!
320	! Release mutex
321	!
322	sethi	%hi(asm_mutex_spin_exit), %l7
323	jmpl	%l7 + %lo(asm_mutex_spin_exit), %l7
324	add	Fdc, FD_HILOCK, %l6
325
326	!
327	! schedule the soft interrupt if needed
328	!
329	cmp	Tmp2, TRIGGER
330	bne	.end
331	nop
332
333   	!
334	! set new opmode to 4
335        !
336	mov     0x4, Tmp
337        stb     Tmp, [Fdc + FD_OPMODE]
338
339	! invoke ddi_trigger_softintr.  load
340	! softid parameter in the delay slot
341	!
342	call	ddi_trigger_softintr
343	ldn	[Fdc + FD_SOFTID], %o0
344
345.end:	mov	1, %i0
346	ret
347	restore
348	SET_SIZE(fd_intr)
349
350.panic:
351        ! invoke a kernel panic
352        sethi   %hi(panic_msg), %o1
353        ldn    [%o1 + %lo(panic_msg)], %o1
354        mov     3, %o0
355        call    cmn_err
356	nop
357
358
359#endif  /* lint */
360