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... 68 1: tst Fdc ! do we have any more to check 69 bz .panic ! Nothing to service. Panic 70 nop 71 72 3: 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 ! 113 1: 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] ! 124 2: ldsb [Adr], Tmp ! *fifo = *addr 125 stb Tmp, [Reg + 0x1] ! 126 3: 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 ! 134 4: 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 ! 141 5: 142 ! 143 ! Stash len and addr before they get lost 144 ! 145 st Len, [Fdc + FD_RLEN] 146 6: 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 ! 181 7: 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 192 1: 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 ! 198 1: 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 207 1: 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 216 1: 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 ! 235 1: 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] 306 1: 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