xref: /illumos-gate/usr/src/uts/sparc/ml/fd_asm.S (revision ad4335f7b330ad9b975ac61078b04b64707ffe5c)
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#include <sys/asm_linkage.h>
36#include <sys/fdreg.h>
37#include <sys/fdvar.h>
38#include "fd_assym.h"
39
40/*
41 * Since this is part of a Sparc "generic" module, it may be loaded during
42 * reconfigure time on systems that do not support the fast interrupt
43 * handler.  On these machines the symbol "impl_setintreg_on" will be
44 * undefined but we don't want to cause error messages when we load.
45 */
46	.weak	impl_setintreg_on
47	.type	impl_setintreg_on, #function
48	.weak	fd_softintr_cookie
49	.type	fd_softintr_cookie, #object
50
51#define	Tmp2	%l4	/* temp register prior to dispatch to right opmode */
52#define	Reg	%l4	/* pointer to the chip's registers */
53#define	Fdc	%l3	/* pointer to fdctlr structure */
54#define	Adr	%l5	/* data address pointer */
55#define	Len	%l6	/* data length counter */
56#define	Tmp	%l7	/* general scratch */
57#define	TRIGGER	0x33
58	ENTRY(fd_intr)		! fd standard interrupt handler
59	save	%sp, -SA(MINFRAME), %sp
60	!
61	! Traverse the list of controllers until we find the first
62	! controller expecting an interrupt. Unfortunately, the
63	! 82072 floppy controller really doesn't have a way to tell
64	! you that it is interrupting.
65	!
66	set	fdctlrs, Fdc		! load list of controllers
67	ldn	[Fdc], Fdc		! get the first in the list...
681:	tst	Fdc			! do we have any more to check
69	bz	.panic			! Nothing to service. Panic
70	nop
71
723:	ldub	[Fdc + FD_OPMODE], Tmp2	! load opmode into Tmp2
73	and	Tmp2, 0x3, Tmp2		! opmode must be 1, 2, or 3
74	tst	Tmp2			! non-zero?
75	bnz	.mutex_enter		! yes!
76	nop
77	ldn	[Fdc + FD_NEXT], Tmp	! Try next ctlr...
78	tst	Tmp
79	bnz,a	1b
80	mov	Tmp, Fdc
81					! no more controllers
82	mov	0x2, Tmp2		! must be spurious or "ready" int
83.mutex_enter:
84	!
85	! grab high level mutex for this controller
86	!
87	sethi	%hi(asm_mutex_spin_enter), %l7
88	jmpl	%l7 + %lo(asm_mutex_spin_enter), %l7
89	add	Fdc, FD_HILOCK, %l6
90	!
91	! dispatch to correct handler
92	!
93	cmp	Tmp2, 3			!case 3: results ?
94	be,a	.opmode3		! yes...
95	ldn	[Fdc + FD_REG], Reg	! load pointer to h/w registers
96	cmp	Tmp2, 2			!case 2: seek/recalibrate ?
97	be	.opmode2		! yes..
98	ldn	[Fdc + FD_REG], Reg	! load pointer to h/w registers
99	!
100	! opmode 1:
101	! read/write/format data-xfer case - they have a result phase
102	!
103.opmode1:
104	ld	[Fdc + FD_RLEN], Len
105	!
106	! XXX- test for null raddr
107	!
108	ldn	[Fdc + FD_RADDR], Adr
109
110	!
111	! while the fifo ready bit set, then data/status available
112	!
1131:	ldub	[Reg], Tmp		! get csr
114	andcc	Tmp, RQM, %g0		!
115	be	4f			! branch if bit clear
116	andcc	Tmp, NDM, %g0		! NDM set means data
117	be	7f			! if not set, it is status time
118	andcc	Tmp, DIO, %g0		! check for input vs. output data
119	be	2f			!
120	sub	Len, 0x1, Len		! predecrement length...
121	ldub	[Reg + 0x1], Tmp	! DIO set, *addr = *fifo
122	b	3f			!
123	stb	Tmp, [Adr]		!
1242:	ldsb	[Adr], Tmp		! *fifo = *addr
125	stb	Tmp, [Reg + 0x1]	!
1263:	tst	Len			! if (len == 0) send TC
127	bne	1b			! branch if not....
128	add	Adr, 0x1, Adr		!
129	b	6f			!
130	.empty				!
131	!
132	! save updated len, addr
133	!
1344:	st	Len, [Fdc + FD_RLEN]
135	b	.out			! not done yet, return
136	stn	Adr, [Fdc + FD_RADDR]
137	!
138	! END OF TRANSFER - if read/write, toggle the TC
139	! bit in AUXIO_REG then save status and set state = 3.
140	!
1415:
142	!
143	! Stash len and addr before they get lost
144	!
145	st	Len, [Fdc + FD_RLEN]
1466:	stn	Adr, [Fdc + FD_RADDR]
147	!
148	! Begin TC delay...
149	! Old comment:
150	!	five nops provide 100ns of delay at 10MIPS to ensure
151	!	TC is wide enough at slowest possible floppy clock
152	!	(500ns @ 250Kbps).
153	!
154	! I gather this mean that we have to give 100ns delay for TC.
155	!
156	! At 100 Mips, that would be 1 * 10 (10) nops.
157	!
158
159	ldn	[Fdc + FD_AUXIOVA], Adr
160	ldub	[Fdc + FD_AUXIODATA], Tmp2
161	ldub	[Adr], Tmp
162	or	Tmp, Tmp2, Tmp
163	stb	Tmp, [Adr]
164	nop; nop; nop; nop; nop; nop; nop; nop; nop; nop	! 10 nops
165	!
166	! End TC delay...now clear the TC bit
167	!
168	ldub	[Fdc + FD_AUXIODATA2], Tmp2
169	andn	Tmp, Tmp2, Tmp
170	stb	Tmp, [Adr]
171
172	!
173	! set opmode to 3 to indicate going into status mode
174	!
175	mov	3, Tmp
176	b	.out
177	stb	Tmp, [Fdc + FD_OPMODE]
178	!
179	! error status state: save old pointers, go direct to result snarfing
180	!
1817:	st	Len, [Fdc + FD_RLEN]
182	stn	Adr, [Fdc + FD_RADDR]
183	mov	0x3, Tmp
184	b	.opmode3
185	stb	Tmp, [Fdc + FD_OPMODE]
186	!
187	! opmode 2:
188	! recalibrate/seek - no result phase, must do sense interrupt status.
189	!
190.opmode2:
191	ldub	[Reg], Tmp			! Tmp = *csr
1921:	andcc	Tmp, CB, %g0			! is CB set?
193	bne	1b				! yes, keep waiting
194	ldub	[Reg], Tmp			!! Tmp = *csr
195	!
196	! wait!!! should we check rqm first???  ABSOLUTELY YES!!!!
197	!
1981:	andcc	Tmp, RQM, %g0		!
199	be,a	1b			! branch if bit clear
200	ldub	[Reg], Tmp		! busy wait until RQM set
201	mov	SNSISTAT, Tmp		! cmd for SENSE_INTERRUPT_STATUS
202	stb	Tmp, [Reg + 0x1]
203	!
204	! NOTE: we ignore DIO here, assume it is set before RQM!
205	!
206	ldub	[Reg], Tmp			! busy wait until RQM set
2071:	andcc	Tmp, RQM, Tmp
208	be,a	1b				! branch if bit clear
209	ldub	[Reg], Tmp			! busy wait until RQM set
210	!
211	! fdc->c_csb.csb_rslt[0] = *fifo;
212	!
213	ldub	[Reg + 0x1], Tmp
214	stb	Tmp, [Fdc + FD_RSLT]
215	ldub	[Reg], Tmp			! busy wait until RQM set
2161:	andcc	Tmp, RQM, Tmp
217	be,a	1b				! branch if bit clear
218	ldub	[Reg], Tmp			! busy wait until RQM set
219	!
220	! fdc->c_csb.csb_rslt[1] = *fifo;
221	!
222	ldub	[Reg + 0x1], Tmp
223	b	.notify
224	stb	Tmp, [Fdc + FD_RSLT + 1]
225	!
226	! case 3: result mode
227	! We are in result mode make sure all status bytes are read out
228	!
229	! We have to have *both* RQM and DIO set.
230	!
231.opmode3:
232	add	Fdc, FD_RSLT, Adr		! load address of csb->csb_rslt
233	add	Adr, 10, Len			! put an upper bound on it..
234	ldub	[Reg], Tmp			!
2351:	andcc	Tmp, CB, %g0			! is CB set?
236	be	.notify				! no, jump around, must be done
237	andcc	Tmp, RQM, %g0			! check for RQM in delay slot
238	be,a	1b				! No RQM, go back
239	ldub	[Reg], Tmp			! and load control reg in delay
240	andcc	Tmp, DIO, %g0			! DIO set?
241	be,a	1b				! No DIO, go back
242	ldub	[Reg], Tmp			! and load control reg in delay
243	!
244	! CB && DIO && RQM all true.
245	! Time to get a byte.
246	!
247	ldub	[Reg + 0x1], Tmp		! *fifo into Tmp
248	cmp	Adr, Len			! already at our limit?
249	bge,a	1b				! Yes, go back..
250	ldub	[Reg], Tmp			! and load control reg in delay
251	stb	Tmp, [Adr]			! store new byte
252	add	Adr, 1, Adr			! increment address
253	b	1b				! and pop back to the top
254	ldub	[Reg], Tmp			! and load control reg in delay
255
256	!
257	! schedule 2nd stage interrupt
258	!
259.notify:
260	!
261	! if fast traps are enabled, use the platform dependent
262	! impl_setintreg_on function.
263	!
264	ldub    [Fdc + FD_FASTTRAP], Tmp
265	tst     Tmp
266	bnz	.fast
267	nop
268
269	!
270	! fast traps are not in use.  Do not schedule the soft interrupt
271	! at this time.  Wait to trigger it at the end of the handler
272	! when the mutexes have been released
273	!
274	mov   	TRIGGER, Tmp2
275	b	.out
276	nop
277
278	!
279	! fast traps are enabled.  Schedule the soft interrupt.
280	! impl_setintreg uses %l4-%l7
281	!
282.fast:	sethi   %hi(fd_softintr_cookie), %l6
283	sethi	%hi(impl_setintreg_on), %l7
284	jmpl	%l7 + %lo(impl_setintreg_on), %l7
285	ld      [%l6 + %lo(fd_softintr_cookie)], %l6
286	!
287	! set new opmode to 4
288	!
289	mov	0x4, Tmp
290	stb	Tmp, [Fdc + FD_OPMODE]
291
292	!
293	! and fall through to exit
294	!
295.out:
296	!
297	! update high level interrupt counter...
298	!
299	ldn	[Fdc + FD_HIINTCT], Adr
300	tst	Adr
301	be,a	1f
302	nop
303	ld	[Adr], Tmp
304	inc	Tmp
305	st	Tmp, [Adr]
3061:
307	!
308	! Release mutex
309	!
310	sethi	%hi(asm_mutex_spin_exit), %l7
311	jmpl	%l7 + %lo(asm_mutex_spin_exit), %l7
312	add	Fdc, FD_HILOCK, %l6
313
314	!
315	! schedule the soft interrupt if needed
316	!
317	cmp	Tmp2, TRIGGER
318	bne	.end
319	nop
320
321   	!
322	! set new opmode to 4
323        !
324	mov     0x4, Tmp
325        stb     Tmp, [Fdc + FD_OPMODE]
326
327	! invoke ddi_trigger_softintr.  load
328	! softid parameter in the delay slot
329	!
330	call	ddi_trigger_softintr
331	ldn	[Fdc + FD_SOFTID], %o0
332
333.end:	mov	1, %i0
334	ret
335	restore
336	SET_SIZE(fd_intr)
337
338.panic:
339        ! invoke a kernel panic
340        sethi   %hi(panic_msg), %o1
341        ldn    [%o1 + %lo(panic_msg)], %o1
342        mov     3, %o0
343        call    cmn_err
344	nop
345
346
347