fd_asm.s revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1989-1991, by Sun Microsystems, Inc.
*/
#ident "%Z%%M% %I% %E% SMI"
/*
* This file contains no entry points which can be called directly from
* C and hence is of no interest to lint. However, we want to avoid the
* dreaded "Empty translation unit" warning.
*/
#if defined(lint)
#include <sys/types.h>
/*ARGSUSED*/
u_int
fd_intr(caddr_t arg)
{
return (0);
}
#else /* lint */
#include <sys/asm_linkage.h>
#include <sys/fdreg.h>
#include <sys/fdvar.h>
#include "fd_assym.h"
/*
* Since this is part of a Sparc "generic" module, it may be loaded during
* reconfigure time on systems that do not support the fast interrupt
* handler. On these machines the symbol "impl_setintreg_on" will be
* undefined but we don't want to cause error messages when we load.
*/
.weak impl_setintreg_on
.type impl_setintreg_on, #function
.weak fd_softintr_cookie
.type fd_softintr_cookie, #object
#define Tmp2 %l4 /* temp register prior to dispatch to right opmode */
#define Reg %l4 /* pointer to the chip's registers */
#define Fdc %l3 /* pointer to fdctlr structure */
#define Adr %l5 /* data address pointer */
#define Len %l6 /* data length counter */
#define Tmp %l7 /* general scratch */
#define TRIGGER 0x33
ENTRY(fd_intr) ! fd standard interrupt handler
save %sp, -SA(MINFRAME), %sp
clr %l1 ! came from standard interrupt handler
ENTRY_NP(fd_fastintr) ! fd fast trap entry point
!
! Traverse the list of controllers until we find the first
! controller expecting an interrupt. Unfortunately, the
! 82072 floppy controller really doesn't have a way to tell
! you that it is interrupting.
!
set fdctlrs, Fdc ! load list of controllers
ldn [Fdc], Fdc ! get the first in the list...
1: tst Fdc ! do we have any more to check
bz .panic ! Nothing to service. Panic
nop
3: ldub [Fdc + FD_OPMODE], Tmp2 ! load opmode into Tmp2
and Tmp2, 0x3, Tmp2 ! opmode must be 1, 2, or 3
tst Tmp2 ! non-zero?
bnz .mutex_enter ! yes!
nop
ldn [Fdc + FD_NEXT], Tmp ! Try next ctlr...
tst Tmp
bnz,a 1b
mov Tmp, Fdc
! no more controllers
mov 0x2, Tmp2 ! must be spurious or "ready" int
.mutex_enter:
!
! grab high level mutex for this controller
!
sethi %hi(asm_mutex_spin_enter), %l7
jmpl %l7 + %lo(asm_mutex_spin_enter), %l7
add Fdc, FD_HILOCK, %l6
!
! dispatch to correct handler
!
cmp Tmp2, 3 !case 3: results ?
be,a .opmode3 ! yes...
ldn [Fdc + FD_REG], Reg ! load pointer to h/w registers
cmp Tmp2, 2 !case 2: seek/recalibrate ?
be .opmode2 ! yes..
ldn [Fdc + FD_REG], Reg ! load pointer to h/w registers
!
! opmode 1:
! read/write/format data-xfer case - they have a result phase
!
.opmode1:
ld [Fdc + FD_RLEN], Len
!
! XXX- test for null raddr
!
ldn [Fdc + FD_RADDR], Adr
!
! while the fifo ready bit set, then data/status available
!
1: ldub [Reg], Tmp ! get csr
andcc Tmp, RQM, %g0 !
be 4f ! branch if bit clear
andcc Tmp, NDM, %g0 ! NDM set means data
be 7f ! if not set, it is status time
andcc Tmp, DIO, %g0 ! check for input vs. output data
be 2f !
sub Len, 0x1, Len ! predecrement length...
ldub [Reg + 0x1], Tmp ! DIO set, *addr = *fifo
b 3f !
stb Tmp, [Adr] !
2: ldsb [Adr], Tmp ! *fifo = *addr
stb Tmp, [Reg + 0x1] !
3: tst Len ! if (len == 0) send TC
bne 1b ! branch if not....
add Adr, 0x1, Adr !
b 6f !
.empty !
!
! save updated len, addr
!
4: st Len, [Fdc + FD_RLEN]
b .out ! not done yet, return
stn Adr, [Fdc + FD_RADDR]
!
! END OF TRANSFER - if read/write, toggle the TC
! bit in AUXIO_REG then save status and set state = 3.
!
5:
!
! Stash len and addr before they get lost
!
st Len, [Fdc + FD_RLEN]
6: stn Adr, [Fdc + FD_RADDR]
!
! Begin TC delay...
! Old comment:
! five nops provide 100ns of delay at 10MIPS to ensure
! TC is wide enough at slowest possible floppy clock
! (500ns @ 250Kbps).
!
! I gather this mean that we have to give 100ns delay for TC.
!
! At 100 Mips, that would be 1 * 10 (10) nops.
!
ldn [Fdc + FD_AUXIOVA], Adr
ldub [Fdc + FD_AUXIODATA], Tmp2
ldub [Adr], Tmp
or Tmp, Tmp2, Tmp
stb Tmp, [Adr]
nop; nop; nop; nop; nop; nop; nop; nop; nop; nop ! 10 nops
!
! End TC delay...now clear the TC bit
!
ldub [Fdc + FD_AUXIODATA2], Tmp2
andn Tmp, Tmp2, Tmp
stb Tmp, [Adr]
!
! set opmode to 3 to indicate going into status mode
!
mov 3, Tmp
b .out
stb Tmp, [Fdc + FD_OPMODE]
!
! error status state: save old pointers, go direct to result snarfing
!
7: st Len, [Fdc + FD_RLEN]
stn Adr, [Fdc + FD_RADDR]
mov 0x3, Tmp
b .opmode3
stb Tmp, [Fdc + FD_OPMODE]
!
! opmode 2:
! recalibrate/seek - no result phase, must do sense interrupt status.
!
.opmode2:
ldub [Reg], Tmp ! Tmp = *csr
1: andcc Tmp, CB, %g0 ! is CB set?
bne 1b ! yes, keep waiting
ldub [Reg], Tmp !! Tmp = *csr
!
! wait!!! should we check rqm first??? ABSOLUTELY YES!!!!
!
1: andcc Tmp, RQM, %g0 !
be,a 1b ! branch if bit clear
ldub [Reg], Tmp ! busy wait until RQM set
mov SNSISTAT, Tmp ! cmd for SENSE_INTERRUPT_STATUS
stb Tmp, [Reg + 0x1]
!
! NOTE: we ignore DIO here, assume it is set before RQM!
!
ldub [Reg], Tmp ! busy wait until RQM set
1: andcc Tmp, RQM, Tmp
be,a 1b ! branch if bit clear
ldub [Reg], Tmp ! busy wait until RQM set
!
! fdc->c_csb.csb_rslt[0] = *fifo;
!
ldub [Reg + 0x1], Tmp
stb Tmp, [Fdc + FD_RSLT]
ldub [Reg], Tmp ! busy wait until RQM set
1: andcc Tmp, RQM, Tmp
be,a 1b ! branch if bit clear
ldub [Reg], Tmp ! busy wait until RQM set
!
! fdc->c_csb.csb_rslt[1] = *fifo;
!
ldub [Reg + 0x1], Tmp
b .notify
stb Tmp, [Fdc + FD_RSLT + 1]
!
! case 3: result mode
! We are in result mode make sure all status bytes are read out
!
! We have to have *both* RQM and DIO set.
!
.opmode3:
add Fdc, FD_RSLT, Adr ! load address of csb->csb_rslt
add Adr, 10, Len ! put an upper bound on it..
ldub [Reg], Tmp !
1: andcc Tmp, CB, %g0 ! is CB set?
be .notify ! no, jump around, must be done
andcc Tmp, RQM, %g0 ! check for RQM in delay slot
be,a 1b ! No RQM, go back
ldub [Reg], Tmp ! and load control reg in delay
andcc Tmp, DIO, %g0 ! DIO set?
be,a 1b ! No DIO, go back
ldub [Reg], Tmp ! and load control reg in delay
!
! CB && DIO && RQM all true.
! Time to get a byte.
!
ldub [Reg + 0x1], Tmp ! *fifo into Tmp
cmp Adr, Len ! already at our limit?
bge,a 1b ! Yes, go back..
ldub [Reg], Tmp ! and load control reg in delay
stb Tmp, [Adr] ! store new byte
add Adr, 1, Adr ! increment address
b 1b ! and pop back to the top
ldub [Reg], Tmp ! and load control reg in delay
!
! schedule 2nd stage interrupt
!
.notify:
!
! if fast traps are enabled, use the platform dependent
! impl_setintreg_on function.
!
ldub [Fdc + FD_FASTTRAP], Tmp
tst Tmp
bnz .fast
nop
!
! fast traps are not in use. Do not schedule the soft interrupt
! at this time. Wait to trigger it at the end of the handler
! when the mutexes have been released
!
mov TRIGGER, Tmp2
b .out
nop
!
! fast traps are enabled. Schedule the soft interrupt.
! impl_setintreg uses %l4-%l7
!
.fast: sethi %hi(fd_softintr_cookie), %l6
sethi %hi(impl_setintreg_on), %l7
jmpl %l7 + %lo(impl_setintreg_on), %l7
ld [%l6 + %lo(fd_softintr_cookie)], %l6
!
! set new opmode to 4
!
mov 0x4, Tmp
stb Tmp, [Fdc + FD_OPMODE]
!
! and fall through to exit
!
.out:
!
! update high level interrupt counter...
!
ldn [Fdc + FD_HIINTCT], Adr
tst Adr
be,a 1f
nop
ld [Adr], Tmp
inc Tmp
st Tmp, [Adr]
1:
!
! Release mutex
!
sethi %hi(asm_mutex_spin_exit), %l7
jmpl %l7 + %lo(asm_mutex_spin_exit), %l7
add Fdc, FD_HILOCK, %l6
tst %l1 ! %l1 != 0 fast trap handler
bnz 1f
nop
!
! schedule the soft interrupt if needed
!
cmp Tmp2, TRIGGER
bne .end
nop
!
! set new opmode to 4
!
mov 0x4, Tmp
stb Tmp, [Fdc + FD_OPMODE]
! invoke ddi_trigger_softintr. load
! softid parameter in the delay slot
!
call ddi_trigger_softintr
ldn [Fdc + FD_SOFTID], %o0
! standard interrupt epilogue
.end: mov 1, %i0
ret
restore
1:
! fast trap epilogue
mov %l0, %psr ! restore psr - and user's ccodes
nop
nop
jmp %l1 ! return from interrupt
rett %l2
SET_SIZE(fd_intr)
.panic:
! invoke a kernel panic
sethi %hi(panic_msg), %o1
ldn [%o1 + %lo(panic_msg)], %o1
mov 3, %o0
call cmn_err
nop
#endif /* lint */