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*/
  39 u_int
  40 fd_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...
  80 1:      tst     Fdc                     ! do we have any more to check
  81         bz      .panic                  ! Nothing to service. Panic
  82         nop
  83 
  84 3:      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         !
 125 1:      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]              !
 136 2:      ldsb    [Adr], Tmp              ! *fifo = *addr
 137         stb     Tmp, [Reg + 0x1]        !
 138 3:      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         !
 146 4:      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         !
 153 5:
 154         !
 155         ! Stash len and addr before they get lost
 156         !
 157         st      Len, [Fdc + FD_RLEN]
 158 6:      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         !
 193 7:      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
 204 1:      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         !
 210 1:      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
 219 1:      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
 228 1:      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                      !
 247 1:      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]
 318 1:
 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 */