|
|
1.1 ! root 1: /* $Id: sun-si.c,v 1.1 2005/02/17 12:19:17 fredette Exp $ */ ! 2: ! 3: /* machine/sun/sun-si.c - Sun ncr5380-based SCSI implementation: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2004 Matt Fredette ! 7: * All rights reserved. ! 8: * ! 9: * Redistribution and use in source and binary forms, with or without ! 10: * modification, are permitted provided that the following conditions ! 11: * are met: ! 12: * 1. Redistributions of source code must retain the above copyright ! 13: * notice, this list of conditions and the following disclaimer. ! 14: * 2. Redistributions in binary form must reproduce the above copyright ! 15: * notice, this list of conditions and the following disclaimer in the ! 16: * documentation and/or other materials provided with the distribution. ! 17: * 3. All advertising materials mentioning features or use of this software ! 18: * must display the following acknowledgement: ! 19: * This product includes software developed by Matt Fredette. ! 20: * 4. The name of the author may not be used to endorse or promote products ! 21: * derived from this software without specific prior written permission. ! 22: * ! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 33: * POSSIBILITY OF SUCH DAMAGE. ! 34: */ ! 35: ! 36: #include <tme/common.h> ! 37: _TME_RCSID("$Id: sun-si.c,v 1.1 2005/02/17 12:19:17 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include <tme/element.h> ! 41: #undef TME_BUS_VERSION ! 42: #define TME_BUS_VERSION TME_X_VERSION(0, 0) ! 43: #include <tme/generic/bus.h> ! 44: ! 45: /* macros: */ ! 46: ! 47: /* controller types: */ ! 48: #define TME_SUN_SI_TYPE_NULL (0) ! 49: #define TME_SUN_SI_TYPE_VME (1) ! 50: #define TME_SUN_SI_TYPE_ONBOARD (2) ! 51: #define TME_SUN_SI_TYPE_3E (3) ! 52: #define TME_SUN_SI_TYPE_COBRA (4) ! 53: ! 54: /* register offsets and sizes: */ ! 55: ! 56: /* all controllers: */ ! 57: #define TME_SUN_SI_REG_NCR5380 (0) ! 58: #define TME_SUN_SI_SIZ_NCR5380 (8) ! 59: ! 60: /* all controllers except onboard, and the Sun 3/E limits these to 16 bits: */ ! 61: #define TME_SUN_SI_REG_DMA_ADDRESS (8) ! 62: #define TME_SUN_SI_REG_DMA_COUNT (12) ! 63: ! 64: /* Cobra controller only: */ ! 65: #define TME_SUN_SI_REG_COBRA_FIFO_COUNT (16) ! 66: #define TME_SUN_SI_REG_COBRA_CSR (20) ! 67: #define TME_SIN_SI_REG_COBRA_BPR (24) ! 68: ! 69: /* onboard controller only: */ ! 70: #define TME_SUN_SI_REG_ONBOARD_UDC_DATA (16) ! 71: #define TME_SUN_SI_REG_ONBOARD_UDC_ADDRESS (18) ! 72: #define TME_SUN_SI_REG_ONBOARD_FIFO_DATA (20) ! 73: ! 74: /* onboard and VME controllers only: */ ! 75: #define TME_SUN_SI_REG_FIFO_COUNT_L (22) ! 76: ! 77: /* all controllers except for the Cobra: */ ! 78: #define TME_SUN_SI_REG_CSR (24) ! 79: ! 80: /* 3/E controller only: */ ! 81: #define TME_SUN_SI_REG_3E_IVEC (27) ! 82: ! 83: /* VME controller only: */ ! 84: #define TME_SUN_SI_REG_VME_BPR_H (26) ! 85: #define TME_SUN_SI_REG_VME_BPR_L (28) ! 86: #define TME_SUN_SI_REG_VME_IV_AM (30) ! 87: #define TME_SUN_SI_REG_VME_FIFO_COUNT_H (32) ! 88: ! 89: #define TME_SUN_SI_SIZ_REGS (34) ! 90: ! 91: /* the 3/E includes a 64KB DMA buffer: */ ! 92: #define TME_SUN_SI_3E_SIZ_DMA (0x10000) ! 93: ! 94: /* the bits in the Control/Status Register: */ ! 95: #define TME_SUN_SI_CSR_ONBOARD_DMA_ACTIVE TME_BIT(15) /* onboard controller only */ ! 96: #define TME_SUN_SI_CSR_DMA_CONFLICT TME_BIT(14) /* all controllers except for the 3/E */ ! 97: #define TME_SUN_SI_CSR_DMA_BUS_ERROR TME_BIT(13) /* all controllers except for the 3/E */ ! 98: #define TME_SUN_SI_CSR_VME_MODIFIED TME_BIT(12) /* VME controller only */ ! 99: #define TME_SUN_SI_CSR_FIFO_FULL TME_BIT(11) /* all controllers except for the 3/E (and Cobra?) */ ! 100: #define TME_SUN_SI_CSR_FIFO_EMPTY TME_BIT(10) /* all controllers except for the 3/E (and Cobra?) */ ! 101: #define TME_SUN_SI_CSR_INT_NCR5380 TME_BIT(9) /* all controllers */ ! 102: #define TME_SUN_SI_CSR_INT_DMA TME_BIT(8) /* all controllers except for the 3/E (and Cobra?) */ ! 103: #define TME_SUN_SI_CSR_VME_LOB_MASK (0x00c0) /* VME controller only */ ! 104: #define TME_SUN_SI_CSR_VME_BPCON TME_BIT(5) /* VME controller only */ ! 105: #define TME_SUN_SI_CSR_DMA_ENABLE TME_BIT(4) /* all controllers except for onboard */ ! 106: #define TME_SUN_SI_CSR_DMA_SEND TME_BIT(3) /* all controllers */ ! 107: #define TME_SUN_SI_CSR_INT_ENABLE TME_BIT(2) /* all controllers */ ! 108: #define TME_SUN_SI_CSR_RESET_FIFO TME_BIT(1) /* all controllers except for the 3/E */ ! 109: #define TME_SUN_SI_CSR_3E_VCC TME_BIT(1) /* 3/E controller only */ ! 110: #define TME_SUN_SI_CSR_RESET_CONTROLLER TME_BIT(0) /* all controllers */ ! 111: ! 112: /* the read-only bits in the Control/Status Register: */ ! 113: /* all controllers except for the 3/E: */ ! 114: #define TME_SUN_SI_CSR_READONLY (~(TME_SUN_SI_CSR_VME_BPCON \ ! 115: | TME_SUN_SI_CSR_DMA_ENABLE \ ! 116: | TME_SUN_SI_CSR_DMA_SEND \ ! 117: | TME_SUN_SI_CSR_INT_ENABLE \ ! 118: | TME_SUN_SI_CSR_RESET_FIFO \ ! 119: | TME_SUN_SI_CSR_RESET_CONTROLLER)) ! 120: /* 3/E controller only: */ ! 121: #define TME_SUN_SI_CSR_3E_READONLY (TME_SUN_SI_CSR_READONLY | TME_SUN_SI_CSR_3E_VCC) ! 122: ! 123: /* these get and put a 32-bit register: */ ! 124: #define TME_SUN_SI_REG32_GET(sun_si, reg) \ ! 125: tme_betoh_u32(*((tme_uint32_t *) &(sun_si)->tme_sun_si_regs[(reg)])) ! 126: #define TME_SUN_SI_REG32_PUT(sun_si, reg, val) \ ! 127: (*((tme_uint32_t *) &(sun_si)->tme_sun_si_regs[(reg)]) = tme_htobe_u32(val)) ! 128: ! 129: /* these get and put a 16-bit register: */ ! 130: #define TME_SUN_SI_REG16_GET(sun_si, reg) \ ! 131: tme_betoh_u16(*((tme_uint16_t *) &(sun_si)->tme_sun_si_regs[(reg)])) ! 132: #define TME_SUN_SI_REG16_PUT(sun_si, reg, val) \ ! 133: (*((tme_uint16_t *) &(sun_si)->tme_sun_si_regs[(reg)]) = tme_htobe_u16(val)) ! 134: ! 135: /* these get and put the CSR register: */ ! 136: #define TME_SUN_SI_CSR_GET(sun_si) \ ! 137: ((sun_si)->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA \ ! 138: ? TME_SUN_SI_REG32_GET(sun_si, TME_SUN_SI_REG_COBRA_CSR) \ ! 139: : TME_SUN_SI_REG16_GET(sun_si, TME_SUN_SI_REG_CSR)) ! 140: #define TME_SUN_SI_CSR_PUT(sun_si, csr) \ ! 141: ((sun_si)->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA \ ! 142: ? TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_COBRA_CSR, csr)\ ! 143: : TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_CSR, csr)) ! 144: ! 145: /* the callout flags: */ ! 146: #define TME_SUN_SI_CALLOUT_CHECK (0) ! 147: #define TME_SUN_SI_CALLOUT_RUNNING TME_BIT(0) ! 148: #define TME_SUN_SI_CALLOUTS_MASK (-2) ! 149: #define TME_SUN_SI_CALLOUT_SIGNALS TME_BIT(1) ! 150: #define TME_SUN_SI_CALLOUT_INT TME_BIT(2) ! 151: ! 152: #if 1 ! 153: #define TME_SUN_SI_DEBUG ! 154: #endif ! 155: ! 156: /* structures: */ ! 157: ! 158: /* the controller: */ ! 159: struct tme_sun_si { ! 160: ! 161: /* backpointer to our element: */ ! 162: struct tme_element *tme_sun_si_element; ! 163: ! 164: /* the mutex protecting the card: */ ! 165: tme_mutex_t tme_sun_si_mutex; ! 166: ! 167: /* the rwlock protecting the card: */ ! 168: tme_rwlock_t tme_sun_si_rwlock; ! 169: ! 170: /* the bus connection for the card's registers: */ ! 171: struct tme_bus_connection *tme_sun_si_conn_regs; ! 172: ! 173: /* the bus connection for the card's memory: */ ! 174: struct tme_bus_connection *tme_sun_si_conn_memory; ! 175: ! 176: /* the bus connection for the card's ncr5380: */ ! 177: struct tme_bus_connection *tme_sun_si_conn_ncr5380; ! 178: ! 179: /* the type of the si: */ ! 180: tme_uint32_t tme_sun_si_type; ! 181: ! 182: /* the callout flags: */ ! 183: int tme_sun_si_callout_flags; ! 184: ! 185: /* if our interrupt line is currently asserted: */ ! 186: int tme_sun_si_last_int_asserted; ! 187: ! 188: /* it's easiest to just model the board registers as a chunk of memory: */ ! 189: tme_uint8_t tme_sun_si_regs[TME_SUN_SI_SIZ_REGS]; ! 190: ! 191: /* any outstanding NCR 5380 TLB entry: */ ! 192: struct tme_bus_tlb *tme_sun_si_ncr5380_tlb; ! 193: ! 194: /* the 3/E DMA buffer: */ ! 195: tme_uint8_t *tme_sun_si_3e_dma; ! 196: ! 197: /* the CSR last called out to the NCR 5380: */ ! 198: tme_uint32_t tme_sun_si_csr_ncr5380; ! 199: }; ! 200: ! 201: /* a sun_si internal bus connection: */ ! 202: struct tme_sun_si_connection { ! 203: ! 204: /* the external bus connection: */ ! 205: struct tme_bus_connection tme_sun_si_connection; ! 206: ! 207: /* this is nonzero if a TME_CONNECTION_BUS_GENERIC chip connection ! 208: is for the registers: */ ! 209: unsigned int tme_sun_si_connection_regs; ! 210: }; ! 211: ! 212: #ifdef TME_SUN_SI_DEBUG ! 213: void ! 214: _tme_sun_si_reg_put(struct tme_sun_si *sun_si, ! 215: int reg, ! 216: tme_uint32_t val_new, ! 217: unsigned int val_size) ! 218: { ! 219: const char *reg_name; ! 220: tme_uint32_t val_old; ! 221: ! 222: if (val_size == sizeof(tme_uint32_t)) { ! 223: val_old = TME_SUN_SI_REG32_GET(sun_si, reg); ! 224: TME_SUN_SI_REG32_PUT(sun_si, reg, val_new); ! 225: } ! 226: else { ! 227: assert (val_size == sizeof(tme_uint16_t)); ! 228: val_old = TME_SUN_SI_REG16_GET(sun_si, reg); ! 229: TME_SUN_SI_REG16_PUT(sun_si, reg, val_new); ! 230: val_new &= 0xffff; ! 231: } ! 232: ! 233: if (val_new == val_old) { ! 234: return; ! 235: } ! 236: ! 237: /* try to get the name of this register: */ ! 238: reg_name = NULL; ! 239: #define _TME_SUN_SI_REG_IS(_reg, type) (reg_name == NULL && reg == (_reg) && val_size == sizeof(type)) ! 240: if (sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_ONBOARD ! 241: && _TME_SUN_SI_REG_IS(TME_SUN_SI_REG_DMA_ADDRESS, tme_uint32_t)) { ! 242: reg_name = "dma_address"; ! 243: } ! 244: if (sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_ONBOARD ! 245: && _TME_SUN_SI_REG_IS(TME_SUN_SI_REG_DMA_COUNT, tme_uint32_t)) { ! 246: reg_name = "dma_count"; ! 247: } ! 248: if ((sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD ! 249: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_VME) ! 250: && _TME_SUN_SI_REG_IS(TME_SUN_SI_REG_FIFO_COUNT_L, tme_uint16_t)) { ! 251: reg_name = "fifo_count_l"; ! 252: } ! 253: if (sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_COBRA ! 254: && _TME_SUN_SI_REG_IS(TME_SUN_SI_REG_CSR, tme_uint16_t)) { ! 255: reg_name = "CSR"; ! 256: } ! 257: if (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_VME) { ! 258: if (_TME_SUN_SI_REG_IS(TME_SUN_SI_REG_VME_BPR_H, tme_uint16_t)) { ! 259: reg_name = "bpr_h"; ! 260: } ! 261: if (_TME_SUN_SI_REG_IS(TME_SUN_SI_REG_VME_BPR_L, tme_uint16_t)) { ! 262: reg_name = "bpr_l"; ! 263: } ! 264: if (_TME_SUN_SI_REG_IS(TME_SUN_SI_REG_VME_FIFO_COUNT_H, tme_uint16_t)) { ! 265: reg_name = "fifo_count_h"; ! 266: } ! 267: } ! 268: #undef _TME_SUN_SI_REG_IS ! 269: if (reg_name == NULL) { ! 270: reg_name = "???"; ! 271: } ! 272: tme_log(&sun_si->tme_sun_si_element->tme_element_log_handle, ! 273: 100, TME_OK, ! 274: (&sun_si->tme_sun_si_element->tme_element_log_handle, ! 275: "%s old 0x%04x new 0x%04x", ! 276: reg_name, ! 277: val_old, ! 278: val_new)); ! 279: } ! 280: #undef TME_SUN_SI_REG16_PUT ! 281: #define TME_SUN_SI_REG16_PUT(sun_si, reg, val) _tme_sun_si_reg_put((sun_si), (reg), (val), sizeof(tme_uint16_t)) ! 282: #undef TME_SUN_SI_REG32_PUT ! 283: #define TME_SUN_SI_REG32_PUT(sun_si, reg, val) _tme_sun_si_reg_put((sun_si), (reg), (val), sizeof(tme_uint32_t)) ! 284: #endif /* TME_SUN_SI_DEBUG */ ! 285: ! 286: /* the sun_si callout function. it must be called with the mutex locked: */ ! 287: static void ! 288: _tme_sun_si_callout(struct tme_sun_si *sun_si, int new_callouts) ! 289: { ! 290: struct tme_bus_connection *conn_ncr5380; ! 291: struct tme_bus_connection *conn_bus; ! 292: tme_uint32_t csr, csr_diff; ! 293: unsigned int signal, level; ! 294: int callouts, later_callouts; ! 295: int rc; ! 296: int int_asserted; ! 297: ! 298: /* add in any new callouts: */ ! 299: sun_si->tme_sun_si_callout_flags |= new_callouts; ! 300: ! 301: /* if this function is already running in another thread, simply ! 302: return now. the other thread will do our work: */ ! 303: if (sun_si->tme_sun_si_callout_flags & TME_SUN_SI_CALLOUT_RUNNING) { ! 304: return; ! 305: } ! 306: ! 307: /* callouts are now running: */ ! 308: sun_si->tme_sun_si_callout_flags |= TME_SUN_SI_CALLOUT_RUNNING; ! 309: ! 310: /* assume that we won't need any later callouts: */ ! 311: later_callouts = 0; ! 312: ! 313: /* loop while callouts are needed: */ ! 314: for (; (callouts = sun_si->tme_sun_si_callout_flags) & TME_SUN_SI_CALLOUTS_MASK; ) { ! 315: ! 316: /* clear the needed callouts: */ ! 317: sun_si->tme_sun_si_callout_flags = callouts & ~TME_SUN_SI_CALLOUTS_MASK; ! 318: callouts &= TME_SUN_SI_CALLOUTS_MASK; ! 319: ! 320: /* get the current CSR value: */ ! 321: csr = TME_SUN_SI_CSR_GET(sun_si); ! 322: ! 323: /* get the next changed CSR bit to convert to a bus signal to the ! 324: NCR 5380: */ ! 325: csr_diff = ((csr ! 326: ^ sun_si->tme_sun_si_csr_ncr5380) ! 327: & (TME_SUN_SI_CSR_RESET_CONTROLLER ! 328: | ((sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_ONBOARD) ! 329: ? TME_SUN_SI_CSR_DMA_ENABLE ! 330: : 0))); ! 331: csr_diff = (csr_diff ^ (csr_diff - 1)) & csr_diff; ! 332: ! 333: /* if there is a changed CSR bit to call out: */ ! 334: if (csr_diff != 0) { ! 335: ! 336: /* assume that if the signal's bit is set in the CSR, it will ! 337: be asserted: */ ! 338: level = (csr & csr_diff) != 0; ! 339: ! 340: /* dispatch on the CSR bit: */ ! 341: switch (csr_diff) { ! 342: default: ! 343: assert (FALSE); ! 344: /* FALLTHROUGH */ ! 345: ! 346: case TME_SUN_SI_CSR_RESET_CONTROLLER: ! 347: signal = TME_BUS_SIGNAL_RESET; ! 348: level = !level; ! 349: break; ! 350: ! 351: case TME_SUN_SI_CSR_DMA_ENABLE: ! 352: signal = TME_BUS_SIGNAL_DACK; ! 353: break; ! 354: } ! 355: ! 356: /* create a real signal level value: */ ! 357: level = (level ! 358: ? TME_BUS_SIGNAL_LEVEL_ASSERTED ! 359: : TME_BUS_SIGNAL_LEVEL_NEGATED); ! 360: ! 361: /* get this card's ncr5380 connection: */ ! 362: conn_ncr5380 = sun_si->tme_sun_si_conn_ncr5380; ! 363: ! 364: /* unlock the mutex: */ ! 365: tme_mutex_unlock(&sun_si->tme_sun_si_mutex); ! 366: ! 367: /* do the callout: */ ! 368: rc = (conn_ncr5380 != NULL ! 369: ? ((*conn_ncr5380->tme_bus_signal) ! 370: (conn_ncr5380, ! 371: signal | level)) ! 372: : TME_OK); ! 373: ! 374: /* lock the mutex: */ ! 375: tme_mutex_lock(&sun_si->tme_sun_si_mutex); ! 376: ! 377: /* if the callout was unsuccessful, remember that at some later ! 378: time this callout should be attempted again: */ ! 379: if (rc != TME_OK) { ! 380: later_callouts |= TME_SUN_SI_CALLOUT_SIGNALS; ! 381: } ! 382: ! 383: /* otherwise, the callout was successful: */ ! 384: else { ! 385: ! 386: /* update the ncr5380 image of the CSR: */ ! 387: sun_si->tme_sun_si_csr_ncr5380 = ! 388: ((sun_si->tme_sun_si_csr_ncr5380 & ~csr_diff) ! 389: | (csr & csr_diff)); ! 390: ! 391: /* there may be more signals to call out, so attempt this ! 392: callout again now: */ ! 393: sun_si->tme_sun_si_callout_flags |= TME_SUN_SI_CALLOUT_SIGNALS; ! 394: } ! 395: } ! 396: ! 397: /* get the current CSR value: */ ! 398: csr = TME_SUN_SI_CSR_GET(sun_si); ! 399: ! 400: /* see if the interrupt signal should be asserted or negated. on ! 401: all controllers except for onboard, DMA must be enabled for the ! 402: interrupt signal to reach the CPU: */ ! 403: int_asserted = ((csr & TME_SUN_SI_CSR_INT_ENABLE) ! 404: && (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD ! 405: || (csr & TME_SUN_SI_CSR_DMA_ENABLE)) ! 406: && (csr & (TME_SUN_SI_CSR_DMA_CONFLICT ! 407: | TME_SUN_SI_CSR_DMA_BUS_ERROR ! 408: | TME_SUN_SI_CSR_INT_NCR5380 ! 409: | TME_SUN_SI_CSR_INT_DMA))); ! 410: ! 411: /* if the interrupt signal doesn't already have the right state: */ ! 412: if (!int_asserted != !sun_si->tme_sun_si_last_int_asserted) { ! 413: ! 414: /* get our bus connection: */ ! 415: conn_bus = sun_si->tme_sun_si_conn_regs; ! 416: ! 417: /* unlock our mutex: */ ! 418: tme_mutex_unlock(&sun_si->tme_sun_si_mutex); ! 419: ! 420: /* call out the bus interrupt signal edge: */ ! 421: rc = (conn_bus != NULL ! 422: ? ((*conn_bus->tme_bus_signal) ! 423: (conn_bus, ! 424: TME_BUS_SIGNAL_INT_UNSPEC ! 425: | (int_asserted ! 426: ? TME_BUS_SIGNAL_LEVEL_ASSERTED ! 427: : TME_BUS_SIGNAL_LEVEL_NEGATED))) ! 428: : TME_OK); ! 429: ! 430: /* lock our mutex: */ ! 431: tme_mutex_lock(&sun_si->tme_sun_si_mutex); ! 432: ! 433: /* if this callout was successful, note the new state of the ! 434: interrupt signal: */ ! 435: if (rc == TME_OK) { ! 436: sun_si->tme_sun_si_last_int_asserted = int_asserted; ! 437: } ! 438: ! 439: /* otherwise, remember that at some later time this callout ! 440: should be attempted again: */ ! 441: else { ! 442: later_callouts |= TME_SUN_SI_CALLOUT_INT; ! 443: } ! 444: } ! 445: } ! 446: ! 447: /* put in any later callouts, and clear that callouts are running: */ ! 448: sun_si->tme_sun_si_callout_flags = later_callouts; ! 449: } ! 450: ! 451: /* the 3/E DMA bus cycle handler: */ ! 452: static int ! 453: _tme_sun_si_bus_cycle_3e_dma(void *_sun_si, struct tme_bus_cycle *cycle) ! 454: { ! 455: struct tme_sun_si *sun_si; ! 456: ! 457: /* recover our data structure: */ ! 458: sun_si = (struct tme_sun_si *) _sun_si; ! 459: ! 460: /* run the cycle: */ ! 461: tme_bus_cycle_xfer_memory(cycle, ! 462: sun_si->tme_sun_si_3e_dma, ! 463: TME_SUN_SI_3E_SIZ_DMA - 1); ! 464: ! 465: /* no faults: */ ! 466: return (TME_OK); ! 467: } ! 468: ! 469: /* the sun_si bus cycle handler for the board registers: */ ! 470: static int ! 471: _tme_sun_si_bus_cycle_regs(void *_sun_si, ! 472: struct tme_bus_cycle *cycle_init) ! 473: { ! 474: struct tme_sun_si *sun_si; ! 475: tme_uint32_t csr_old, csr_new, csr_diff, csr_mask; ! 476: tme_bus_addr_t address; ! 477: tme_uint8_t cycle_size; ! 478: tme_uint32_t csr; ! 479: tme_uint32_t dma_count; ! 480: int new_callouts; ! 481: ! 482: /* get the address and cycle size: */ ! 483: address = cycle_init->tme_bus_cycle_address; ! 484: cycle_size = cycle_init->tme_bus_cycle_size; ! 485: ! 486: /* it appears that si hardware doesn't respond to a byte access ! 487: to its DMA count register. at least, SunOS' sc probe routine ! 488: seems to rely on this to distinguish an si from an sc: */ ! 489: if (address == TME_SUN_SI_REG_DMA_COUNT ! 490: && cycle_size == sizeof(tme_uint8_t)) { ! 491: return (EINVAL); ! 492: } ! 493: ! 494: /* recover our data structure: */ ! 495: sun_si = (struct tme_sun_si *) _sun_si; ! 496: ! 497: /* assume we won't need any new callouts: */ ! 498: new_callouts = 0; ! 499: ! 500: /* lock the mutex: */ ! 501: tme_mutex_lock(&sun_si->tme_sun_si_mutex); ! 502: ! 503: /* get the previous CSR value: */ ! 504: csr_old = TME_SUN_SI_CSR_GET(sun_si); ! 505: ! 506: /* run the cycle: */ ! 507: tme_bus_cycle_xfer_memory(cycle_init, ! 508: sun_si->tme_sun_si_regs, ! 509: TME_SUN_SI_SIZ_REGS - 1); ! 510: ! 511: #define _TME_SUN_SI_REG_IS(reg, type) TME_RANGES_OVERLAP(address, address + cycle_size - 1, (reg), (reg) + sizeof(type) - 1) ! 512: ! 513: /* if this was a write: */ ! 514: if (cycle_init->tme_bus_cycle_type ! 515: == TME_BUS_CYCLE_WRITE) { ! 516: ! 517: /* if this is a VME controller: */ ! 518: if (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_VME) { ! 519: ! 520: /* if this was a write to the DMA count register: */ ! 521: if (_TME_SUN_SI_REG_IS(TME_SUN_SI_REG_DMA_COUNT, tme_uint32_t)) { ! 522: ! 523: /* get the DMA count register: */ ! 524: dma_count = TME_SUN_SI_REG32_GET(sun_si, TME_SUN_SI_REG_DMA_COUNT); ! 525: ! 526: /* copy the DMA count register to the FIFO count register: */ ! 527: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_FIFO_COUNT_H, (dma_count >> 16)); ! 528: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_FIFO_COUNT_L, (dma_count & 0xffff)); ! 529: } ! 530: } ! 531: ! 532: /* get the current CSR value, and put back any bits that ! 533: software can't change: */ ! 534: csr_mask = (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_3E ! 535: ? TME_SUN_SI_CSR_3E_READONLY ! 536: : TME_SUN_SI_CSR_READONLY); ! 537: csr_new = ((TME_SUN_SI_CSR_GET(sun_si) ! 538: & ~csr_mask) ! 539: | (csr_old ! 540: & csr_mask)); ! 541: ! 542: /* get the sets of CSR bits that have changed: */ ! 543: csr_diff = (csr_old ^ csr_new); ! 544: ! 545: /* if the FIFO is being reset: */ ! 546: if (sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_3E ! 547: && (csr_diff & TME_SUN_SI_CSR_RESET_FIFO) ! 548: && !(csr_new & TME_SUN_SI_CSR_RESET_FIFO)) { ! 549: ! 550: /* reset the FIFOs: */ ! 551: TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_DMA_ADDRESS, 0); ! 552: TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_DMA_COUNT, 0); ! 553: switch (sun_si->tme_sun_si_type) { ! 554: default: ! 555: assert(FALSE); ! 556: /* FALLTHROUGH */ ! 557: case TME_SUN_SI_TYPE_ONBOARD: ! 558: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_ONBOARD_FIFO_DATA, 0); ! 559: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_FIFO_COUNT_L, 0); ! 560: break; ! 561: case TME_SUN_SI_TYPE_VME: ! 562: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_FIFO_COUNT_L, 0); ! 563: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_FIFO_COUNT_H, 0); ! 564: csr &= ~TME_SUN_SI_CSR_VME_LOB_MASK; ! 565: break; ! 566: case TME_SUN_SI_TYPE_COBRA: ! 567: abort(); ! 568: break; ! 569: } ! 570: } ! 571: ! 572: /* if the CSR has changed at all: */ ! 573: if (csr_new != csr_old) { ! 574: ! 575: /* put back the new CSR: */ ! 576: tme_log(&sun_si->tme_sun_si_element->tme_element_log_handle, ! 577: 100, TME_OK, ! 578: (&sun_si->tme_sun_si_element->tme_element_log_handle, ! 579: "CSR now 0x%04x", ! 580: csr_new)); ! 581: TME_SUN_SI_CSR_PUT(sun_si, csr_new); ! 582: ! 583: /* assume that we need to call out changes to bus signals and ! 584: our interrupt: */ ! 585: new_callouts |= TME_SUN_SI_CALLOUT_INT | TME_SUN_SI_CALLOUT_SIGNALS; ! 586: } ! 587: } ! 588: ! 589: /* make any new callouts: */ ! 590: _tme_sun_si_callout(sun_si, new_callouts); ! 591: ! 592: /* unlock the mutex: */ ! 593: tme_mutex_unlock(&sun_si->tme_sun_si_mutex); ! 594: ! 595: /* no faults: */ ! 596: return (TME_OK); ! 597: } ! 598: ! 599: /* the sun_si TLB filler for the board registers (and, on the 3/E, for ! 600: the board memory on the VME bus): */ ! 601: static int ! 602: _tme_sun_si_tlb_fill_regs(struct tme_bus_connection *conn_bus, ! 603: struct tme_bus_tlb *tlb, ! 604: tme_bus_addr_t address, unsigned int cycles) ! 605: { ! 606: struct tme_sun_si *sun_si; ! 607: struct tme_bus_connection *conn_ncr5380; ! 608: tme_bus_addr_t address_regs; ! 609: struct tme_bus_tlb tlb_mapping; ! 610: int rc; ! 611: ! 612: /* recover our data structures: */ ! 613: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 614: ! 615: /* assume that the registers start at address zero: */ ! 616: address_regs = 0; ! 617: ! 618: /* dispatch on the controller type: */ ! 619: switch (sun_si->tme_sun_si_type) { ! 620: ! 621: case TME_SUN_SI_TYPE_3E: ! 622: ! 623: /* the board registers follow the DMA buffer: */ ! 624: address_regs = TME_SUN_SI_3E_SIZ_DMA; ! 625: ! 626: /* if this address is in the DMA buffer: */ ! 627: if (address < TME_SUN_SI_3E_SIZ_DMA) { ! 628: ! 629: /* initialize the TLB entry: */ ! 630: tme_bus_tlb_initialize(tlb); ! 631: ! 632: /* this TLB entry covers this range: */ ! 633: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0); ! 634: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_SUN_SI_3E_SIZ_DMA - 1); ! 635: ! 636: /* this TLB entry allows fast reading and writing: */ ! 637: tlb->tme_bus_tlb_emulator_off_read = sun_si->tme_sun_si_3e_dma; ! 638: tlb->tme_bus_tlb_emulator_off_write = sun_si->tme_sun_si_3e_dma; ! 639: ! 640: /* allow reading and writing: */ ! 641: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 642: ! 643: /* our bus cycle handler: */ ! 644: tlb->tme_bus_tlb_cycle_private = sun_si; ! 645: tlb->tme_bus_tlb_cycle = _tme_sun_si_bus_cycle_3e_dma; ! 646: ! 647: return (TME_OK); ! 648: } ! 649: break; ! 650: ! 651: default: ! 652: break; ! 653: } ! 654: ! 655: /* offset the address: */ ! 656: address -= address_regs; ! 657: ! 658: /* the address must be within range: */ ! 659: assert(address < TME_SUN_SI_SIZ_REGS); ! 660: ! 661: /* if this address is in the NCR 5380 registers: */ ! 662: if (address < TME_SUN_SI_SIZ_NCR5380) { ! 663: ! 664: /* get the NCR 5380 connection: */ ! 665: conn_ncr5380 = sun_si->tme_sun_si_conn_ncr5380; ! 666: ! 667: /* call the NCR 5380 TLB fill function: */ ! 668: rc = (conn_ncr5380 != NULL ! 669: ? (*conn_ncr5380->tme_bus_tlb_fill)(conn_ncr5380, tlb, ! 670: address, cycles) ! 671: : EINVAL); ! 672: ! 673: /* if that succeeded: */ ! 674: if (rc == TME_OK) { ! 675: ! 676: /* create the mapping TLB entry: */ ! 677: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 678: tlb_mapping.tme_bus_tlb_addr_first, ! 679: (address_regs ! 680: + TME_SUN_SI_REG_NCR5380)); ! 681: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 682: tlb_mapping.tme_bus_tlb_addr_last, ! 683: (address_regs ! 684: + TME_SUN_SI_REG_NCR5380 ! 685: + TME_SUN_SI_SIZ_NCR5380 ! 686: - 1)); ! 687: tlb_mapping.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 688: ! 689: /* map the filled TLB entry: */ ! 690: tme_bus_tlb_map(tlb, 0, &tlb_mapping, address_regs + TME_SUN_SI_REG_NCR5380); ! 691: } ! 692: ! 693: return (rc); ! 694: } ! 695: ! 696: /* initialize the TLB entry: */ ! 697: tme_bus_tlb_initialize(tlb); ! 698: ! 699: /* this TLB entry covers this range: */ ! 700: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 701: tlb->tme_bus_tlb_addr_first, ! 702: (address_regs ! 703: + TME_SUN_SI_SIZ_NCR5380)); ! 704: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 705: tlb->tme_bus_tlb_addr_last, ! 706: (address_regs ! 707: + TME_SUN_SI_SIZ_REGS ! 708: - 1)); ! 709: ! 710: /* our controller registers don't have read side-effects, so they ! 711: support fast reading: */ ! 712: tlb->tme_bus_tlb_emulator_off_read = sun_si->tme_sun_si_regs - address_regs; ! 713: ! 714: /* allow reading and writing: */ ! 715: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 716: ! 717: /* our bus cycle handler: */ ! 718: tlb->tme_bus_tlb_cycle_private = sun_si; ! 719: tlb->tme_bus_tlb_cycle = _tme_sun_si_bus_cycle_regs; ! 720: ! 721: return (TME_OK); ! 722: } ! 723: ! 724: /* the interrupt acknowledge function for the VME and 3/E types: */ ! 725: static int ! 726: _tme_sun_si_intack(struct tme_bus_connection *conn_bus, unsigned int signal, int *_vector) ! 727: { ! 728: struct tme_sun_si *sun_si; ! 729: int vector; ! 730: ! 731: /* recover our data structure: */ ! 732: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 733: ! 734: /* dispatch on the controller type: */ ! 735: switch (sun_si->tme_sun_si_type) { ! 736: default: ! 737: assert (FALSE); ! 738: /* FALLTHROUGH */ ! 739: ! 740: case TME_SUN_SI_TYPE_3E: ! 741: vector = sun_si->tme_sun_si_regs[TME_SUN_SI_REG_3E_IVEC]; ! 742: break; ! 743: ! 744: case TME_SUN_SI_TYPE_VME: ! 745: vector = TME_SUN_SI_REG16_GET(sun_si, TME_SUN_SI_REG_VME_IV_AM) & 0xff; ! 746: break; ! 747: } ! 748: ! 749: /* return the interrupt vector: */ ! 750: *_vector = vector; ! 751: return (TME_OK); ! 752: } ! 753: ! 754: /* the sun_si bus signal handler for the NCR 5380: */ ! 755: static int ! 756: _tme_sun_si_bus_signal(struct tme_bus_connection *conn_bus, ! 757: unsigned int signal) ! 758: { ! 759: struct tme_sun_si *sun_si; ! 760: tme_uint32_t csr; ! 761: ! 762: /* this must be the unspecified interrupt signal: */ ! 763: assert (TME_BUS_SIGNAL_WHICH(signal) == TME_BUS_SIGNAL_INT_UNSPEC); ! 764: ! 765: /* recover our data structures: */ ! 766: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 767: ! 768: /* lock our mutex: */ ! 769: tme_mutex_lock(&sun_si->tme_sun_si_mutex); ! 770: ! 771: /* update the CSR value: */ ! 772: csr = TME_SUN_SI_CSR_GET(sun_si); ! 773: csr = ((csr ! 774: & ~TME_SUN_SI_CSR_INT_NCR5380) ! 775: | (((signal & TME_BUS_SIGNAL_LEVEL_MASK) ! 776: == TME_BUS_SIGNAL_LEVEL_ASSERTED) ! 777: ? TME_SUN_SI_CSR_INT_NCR5380 ! 778: : 0)); ! 779: TME_SUN_SI_CSR_PUT(sun_si, csr); ! 780: ! 781: /* call out an interrupt change: */ ! 782: _tme_sun_si_callout(sun_si, TME_SUN_SI_CALLOUT_INT); ! 783: ! 784: /* unlock our mutex: */ ! 785: tme_mutex_unlock(&sun_si->tme_sun_si_mutex); ! 786: ! 787: return (TME_OK); ! 788: } ! 789: ! 790: /* the sun_si bus fault handler for the NCR 5380 DMA: */ ! 791: static int ! 792: _tme_sun_si_bus_fault_handler(void *_sun_si, ! 793: struct tme_bus_tlb *tlb, ! 794: struct tme_bus_cycle *cycle, ! 795: int rc) ! 796: { ! 797: struct tme_sun_si *sun_si; ! 798: ! 799: /* recover our data structure: */ ! 800: sun_si = (struct tme_sun_si *) _sun_si; ! 801: ! 802: /* lock our mutex: */ ! 803: tme_mutex_lock(&sun_si->tme_sun_si_mutex); ! 804: ! 805: /* set a DMA bus error and call out an interrupt change: */ ! 806: TME_SUN_SI_CSR_PUT(sun_si, TME_SUN_SI_CSR_GET(sun_si) | TME_SUN_SI_CSR_DMA_BUS_ERROR); ! 807: _tme_sun_si_callout(sun_si, TME_SUN_SI_CALLOUT_INT); ! 808: ! 809: /* unlock our mutex: */ ! 810: tme_mutex_unlock(&sun_si->tme_sun_si_mutex); ! 811: ! 812: return (rc); ! 813: } ! 814: ! 815: /* the sun_si TLB filler for the NCR 5380 DMA: */ ! 816: static int ! 817: _tme_sun_si_tlb_fill(struct tme_bus_connection *conn_bus, ! 818: struct tme_bus_tlb *tlb, ! 819: tme_bus_addr_t ncr5380_address, ! 820: unsigned int cycles) ! 821: { ! 822: struct tme_sun_si *sun_si; ! 823: tme_uint32_t csr; ! 824: tme_bus_addr_t dma_address; ! 825: tme_uint32_t dma_count; ! 826: tme_uint32_t bpr; ! 827: unsigned int bpr_count; ! 828: #if defined(TME_SUN_SI_STRICT_VME) ! 829: unsigned int bpr_i; ! 830: #endif /* defined(TME_SUN_SI_STRICT_VME) */ ! 831: struct tme_bus_tlb tlb_mapping; ! 832: int rc; ! 833: ! 834: /* recover our data structures: */ ! 835: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 836: ! 837: /* assume that this call will succeed: */ ! 838: rc = TME_OK; ! 839: ! 840: /* lock our mutex: */ ! 841: tme_mutex_lock(&sun_si->tme_sun_si_mutex); ! 842: ! 843: /* if the NCR 5380 already has an outstanding TLB entry, and it ! 844: doesn't happen to be this TLB entry, invalidate it: */ ! 845: if (sun_si->tme_sun_si_ncr5380_tlb != NULL ! 846: && (tlb == NULL ! 847: || (sun_si->tme_sun_si_ncr5380_tlb ! 848: != TME_ATOMIC_READ(struct tme_bus_tlb *, ! 849: tlb->tme_bus_tlb_backing_reservation)))) { ! 850: tme_bus_tlb_invalidate(sun_si->tme_sun_si_ncr5380_tlb); ! 851: ! 852: /* the NCR 5380 doesn't have any outstanding TLB entry: */ ! 853: sun_si->tme_sun_si_ncr5380_tlb = NULL; ! 854: } ! 855: ! 856: /* get the CSR value: */ ! 857: csr = TME_SUN_SI_CSR_GET(sun_si); ! 858: ! 859: /* assume that this is not an onboard controller, and get the DMA ! 860: address register, plus the NCR 5380 address, and the DMA count ! 861: register: */ ! 862: dma_address = TME_SUN_SI_REG32_GET(sun_si, TME_SUN_SI_REG_DMA_ADDRESS) + ncr5380_address; ! 863: dma_count = TME_SUN_SI_REG32_GET(sun_si, TME_SUN_SI_REG_DMA_COUNT); ! 864: ! 865: /* dispatch on the controller type: */ ! 866: switch (sun_si->tme_sun_si_type) { ! 867: ! 868: default: ! 869: assert(FALSE); ! 870: /* FALLTHROUGH */ ! 871: ! 872: case TME_SUN_SI_TYPE_3E: ! 873: ! 874: /* mask the DMA address and count registers to 16 bits: */ ! 875: dma_address &= 0xffff; ! 876: dma_count &= 0xffff; ! 877: ! 878: /* if the NCR 5380 has stopped doing DMA, or if it has exhausted ! 879: DMA, or if DMA is not enabled: */ ! 880: if (cycles == TME_BUS_CYCLE_UNDEF ! 881: || ncr5380_address >= dma_count ! 882: || !(csr & TME_SUN_SI_CSR_DMA_ENABLE)) { ! 883: ! 884: /* if the NCR 5380 has stopped doing DMA, cap the DMA count and ! 885: address to the amount of DMA that was available, thus ! 886: cancelling the effect of the NCR 5380 prefetch. this ! 887: prevents the DMA count from going negative, confusing the Sun ! 888: PROM and probably SunOS. I'm guessing that all of the SCSI ! 889: devices ever used with Suns change information transfer phase ! 890: faster than the NCR 5380 prefetches a byte from DMA, which is ! 891: why this DMA-count-going-negative problem is never seen. since ! 892: our NCR 5380 is infinitely fast at prefetch, we have to deal: */ ! 893: if (cycles == TME_BUS_CYCLE_UNDEF ! 894: && ncr5380_address > dma_count) { ! 895: assert (ncr5380_address == (dma_count + 1)); ! 896: dma_address -= (ncr5380_address - dma_count); ! 897: ncr5380_address = dma_count; ! 898: } ! 899: ! 900: /* update the DMA address and count registers: */ ! 901: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_DMA_ADDRESS + sizeof(tme_uint16_t), ! 902: dma_address); ! 903: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_DMA_COUNT + sizeof(tme_uint16_t), ! 904: dma_count - ncr5380_address); ! 905: ! 906: /* return EAGAIN to the NCR 5380, unless it was the NCR 5380 ! 907: that stopped doing DMA: */ ! 908: if (cycles != TME_BUS_CYCLE_UNDEF) { ! 909: rc = EAGAIN; ! 910: } ! 911: break; ! 912: } ! 913: ! 914: /* XXX does DMA wrap around in the 3/E DMA memory? */ ! 915: dma_count = TME_MIN((TME_SUN_SI_3E_SIZ_DMA - dma_address), dma_count); ! 916: ! 917: /* initialize the TLB entry: */ ! 918: tme_bus_tlb_initialize(tlb); ! 919: ! 920: /* this TLB entry covers this range: */ ! 921: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 922: tlb->tme_bus_tlb_addr_first, ! 923: 0); ! 924: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 925: tlb->tme_bus_tlb_addr_last, ! 926: dma_count - 1); ! 927: ! 928: /* this TLB entry supports fast reading and writing: */ ! 929: tlb->tme_bus_tlb_emulator_off_read = sun_si->tme_sun_si_3e_dma + dma_address; ! 930: tlb->tme_bus_tlb_emulator_off_write = sun_si->tme_sun_si_3e_dma + dma_address; ! 931: ! 932: /* allow reading and writing: */ ! 933: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 934: ! 935: /* our bus cycle handler: */ ! 936: tlb->tme_bus_tlb_cycle_private = sun_si; ! 937: tlb->tme_bus_tlb_cycle = _tme_sun_si_bus_cycle_3e_dma; ! 938: ! 939: /* unlock our mutex: */ ! 940: tme_mutex_unlock(&sun_si->tme_sun_si_mutex); ! 941: ! 942: return (TME_OK); ! 943: ! 944: case TME_SUN_SI_TYPE_VME: ! 945: ! 946: /* if the NCR 5380 has stopped doing DMA, or if it has exhausted ! 947: DMA, or if DMA is not enabled: */ ! 948: if (cycles == TME_BUS_CYCLE_UNDEF ! 949: || ncr5380_address >= dma_count ! 950: || ((csr ! 951: & (TME_SUN_SI_CSR_DMA_CONFLICT ! 952: | TME_SUN_SI_CSR_DMA_BUS_ERROR ! 953: | TME_SUN_SI_CSR_DMA_ENABLE)) ! 954: != TME_SUN_SI_CSR_DMA_ENABLE)) { ! 955: ! 956: /* if the NCR 5380 has stopped doing DMA, cap the DMA count and ! 957: address to the amount of DMA that was available, thus ! 958: cancelling the effect of the NCR 5380 prefetch. this ! 959: prevents the DMA count from going negative, confusing the Sun ! 960: PROM and probably SunOS. I'm guessing that all of the SCSI ! 961: devices ever used with Suns change information transfer phase ! 962: faster than the NCR 5380 prefetches a byte from DMA, which is ! 963: why this DMA-count-going-negative problem is never seen. since ! 964: our NCR 5380 is infinitely fast at prefetch, we have to deal: */ ! 965: if (cycles == TME_BUS_CYCLE_UNDEF ! 966: && ncr5380_address > dma_count) { ! 967: assert (ncr5380_address == (dma_count + 1)); ! 968: dma_address -= (ncr5380_address - dma_count); ! 969: ncr5380_address = dma_count; ! 970: } ! 971: ! 972: /* update the DMA address and count registers: */ ! 973: TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_DMA_ADDRESS, dma_address); ! 974: TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_DMA_COUNT, dma_count - ncr5380_address); ! 975: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_FIFO_COUNT_H, ((dma_count - ncr5380_address) >> 16)); ! 976: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_FIFO_COUNT_L, ((dma_count - ncr5380_address) & 0xffff)); ! 977: ! 978: /* assume that our emulated byte pack is empty: */ ! 979: bpr = 0; ! 980: bpr_count = 0; ! 981: ! 982: #ifdef TME_SUN_SI_STRICT_VME ! 983: ! 984: /* if the NCR 5380 was doing DMA writes to memory (i.e., it was ! 985: receiving): */ ! 986: if (!(csr & TME_SUN_SI_CSR_DMA_SEND)) { ! 987: ! 988: /* calculate how many bytes must be left in the byte pack: */ ! 989: bpr_count = ncr5380_address; ! 990: bpr_count &= ((csr & TME_SUN_SI_CSR_VME_BPCON) ! 991: ? (sizeof(tme_uint16_t) - 1) ! 992: : (sizeof(tme_uint32_t) - 1)); ! 993: ! 994: /* get the byte pack contents from the memory that the NCR ! 995: 5380 DMA'ed into. this is why all DMA writes have to be to ! 996: fast memory under TME_SUN_SI_STRICT_VME - if you DMA to ! 997: memory with side-effects, we can't read the data back out ! 998: again without incurring more side-effects, and we don't ! 999: want to do a *full* emulation of the DMA engine: */ ! 1000: for (bpr_i = bpr_count; bpr_i > 0; bpr_i--) { ! 1001: bpr = (bpr << 8) | sun_si->tme_sun_si_dma_buffer_write[ncr5380_address - bpr_i]; ! 1002: } ! 1003: ! 1004: /* left-justify the byte pack: */ ! 1005: bpr <<= ((((csr & TME_SUN_SI_CSR_VME_BPCON) ! 1006: ? sizeof(tme_uint16_t) ! 1007: : sizeof(tme_uint32_t)) ! 1008: - bpr_count) ! 1009: * 8); ! 1010: ! 1011: } ! 1012: ! 1013: /* otherwise, the NCR 5380 was doing DMA reads to memory (i.e., ! 1014: it was sending): */ ! 1015: else { ! 1016: ! 1017: /* nothing to do. we don't emulate the byte pack for sending: */ ! 1018: } ! 1019: ! 1020: #endif /* TME_SUN_SI_STRICT_VME */ ! 1021: ! 1022: /* update the byte pack and the CSR: */ ! 1023: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_BPR_H, (bpr >> 16)); ! 1024: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_BPR_L, (bpr & 0xffff)); ! 1025: TME_FIELD_MASK_DEPOSITU(csr, TME_SUN_SI_CSR_VME_LOB_MASK, bpr_count); ! 1026: TME_SUN_SI_CSR_PUT(sun_si, csr); ! 1027: ! 1028: /* return EAGAIN to the NCR 5380, unless it was the NCR 5380 ! 1029: that stopped doing DMA: */ ! 1030: if (cycles != TME_BUS_CYCLE_UNDEF) { ! 1031: rc = EAGAIN; ! 1032: } ! 1033: break; ! 1034: } ! 1035: break; ! 1036: ! 1037: case TME_SUN_SI_TYPE_ONBOARD: ! 1038: /* TBD */ ! 1039: abort(); ! 1040: ! 1041: case TME_SUN_SI_TYPE_COBRA: ! 1042: /* TBD */ ! 1043: abort(); ! 1044: } ! 1045: ! 1046: /* if DMA is not ready for some reason: */ ! 1047: if (rc == EAGAIN) { ! 1048: ! 1049: /* invalidate any local TLB entry passed by the caller: */ ! 1050: if (tlb != NULL) { ! 1051: tme_bus_tlb_invalidate(tlb); ! 1052: } ! 1053: ! 1054: /* if DMA is enabled: */ ! 1055: if (csr & TME_SUN_SI_CSR_DMA_ENABLE) { ! 1056: ! 1057: /* set a DMA interrupt and call out an interrupt change: */ ! 1058: TME_SUN_SI_CSR_PUT(sun_si, TME_SUN_SI_CSR_GET(sun_si) | TME_SUN_SI_CSR_INT_DMA); ! 1059: _tme_sun_si_callout(sun_si, TME_SUN_SI_CALLOUT_INT); ! 1060: } ! 1061: ! 1062: /* cancel the remainder of the TLB fill: */ ! 1063: cycles = TME_BUS_CYCLE_UNDEF; ! 1064: } ! 1065: ! 1066: /* get the bus connection for memory: */ ! 1067: conn_bus = sun_si->tme_sun_si_conn_memory; ! 1068: ! 1069: /* if we need to fill a TLB entry on the bus: */ ! 1070: if (cycles != TME_BUS_CYCLE_UNDEF) { ! 1071: ! 1072: /* the NCR 5380 now has this outstanding TLB entry: */ ! 1073: sun_si->tme_sun_si_ncr5380_tlb ! 1074: = TME_ATOMIC_READ(struct tme_bus_tlb *, tlb->tme_bus_tlb_backing_reservation); ! 1075: } ! 1076: ! 1077: /* unlock our mutex: */ ! 1078: tme_mutex_unlock(&sun_si->tme_sun_si_mutex); ! 1079: ! 1080: /* if we need to fill a TLB entry on the bus: */ ! 1081: if (cycles != TME_BUS_CYCLE_UNDEF) { ! 1082: ! 1083: /* DMA must be OK so far: */ ! 1084: assert (rc == TME_OK); ! 1085: assert (dma_count > ncr5380_address); ! 1086: ! 1087: /* call out to fill this TLB entry on the bus: */ ! 1088: rc = (conn_bus != NULL ! 1089: ? (*conn_bus->tme_bus_tlb_fill)(conn_bus, ! 1090: tlb, ! 1091: dma_address, ! 1092: cycles) ! 1093: : ENXIO); ! 1094: ! 1095: /* if this callout succeeded: */ ! 1096: if (rc == TME_OK) { ! 1097: ! 1098: #if defined(TME_SUN_SI_STRICT_VME) || defined(TME_SUN_SI_STRICT_ONBOARD) || defined(TME_SUN_SI_STRICT_COBRA) ! 1099: ! 1100: /* when the NCR 5380 wants to do DMA writes, in order to ! 1101: correctly emulate the byte pack registers on these ! 1102: controllers without having to emulate their full DMA behavior ! 1103: (copying 16- or 32-bit words into a controller register for ! 1104: the NCR 5380), we just insist that all DMA be done to memory ! 1105: that supports fast access: */ ! 1106: if ((cycles & TME_BUS_CYCLE_WRITE) ! 1107: && tlb->tme_bus_tlb_emulator_off_write == TME_EMULATOR_OFF_UNDEF) { ! 1108: abort(); ! 1109: } ! 1110: ! 1111: #endif /* defined(TME_SUN_SI_STRICT_VME) || defined(TME_SUN_SI_STRICT_ONBOARD) || defined(TME_SUN_SI_STRICT_COBRA) */ ! 1112: ! 1113: /* create the mapping TLB entry: */ ! 1114: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 1115: tlb_mapping.tme_bus_tlb_addr_first, ! 1116: ncr5380_address); ! 1117: TME_ATOMIC_WRITE(tme_bus_addr_t, ! 1118: tlb_mapping.tme_bus_tlb_addr_last, ! 1119: (dma_count ! 1120: - 1)); ! 1121: tlb_mapping.tme_bus_tlb_cycles_ok = cycles; ! 1122: ! 1123: /* map the filled TLB entry: */ ! 1124: tme_bus_tlb_map(tlb, dma_address, &tlb_mapping, ncr5380_address); ! 1125: ! 1126: /* add our bus fault handler: */ ! 1127: TME_BUS_TLB_FAULT_HANDLER(tlb, _tme_sun_si_bus_fault_handler, sun_si); ! 1128: } ! 1129: } ! 1130: ! 1131: return (rc); ! 1132: } ! 1133: ! 1134: /* the sun_si TLB allocator for the NCR 5380: */ ! 1135: static int ! 1136: _tme_sun_si_tlb_set_allocate(struct tme_bus_connection *conn_bus, ! 1137: unsigned int count, unsigned int sizeof_one, ! 1138: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb *) _tlbs) ! 1139: { ! 1140: struct tme_sun_si *sun_si; ! 1141: ! 1142: /* recover our data structures: */ ! 1143: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 1144: ! 1145: /* pass the sun_si's request through to the memory bus: */ ! 1146: conn_bus = sun_si->tme_sun_si_conn_memory; ! 1147: return (conn_bus != NULL ! 1148: ? (*conn_bus->tme_bus_tlb_set_allocate)(conn_bus, ! 1149: count, sizeof_one, ! 1150: _tlbs) ! 1151: : ENXIO); ! 1152: } ! 1153: ! 1154: /* this scores a new connection: */ ! 1155: static int ! 1156: _tme_sun_si_connection_score(struct tme_connection *conn, unsigned int *_score) ! 1157: { ! 1158: struct tme_sun_si *sun_si; ! 1159: struct tme_sun_si_connection *conn_sun_si; ! 1160: ! 1161: /* both sides must be generic bus connections: */ ! 1162: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC); ! 1163: assert(conn->tme_connection_other->tme_connection_type ! 1164: == conn->tme_connection_type); ! 1165: ! 1166: /* recover our data structures: */ ! 1167: sun_si = conn->tme_connection_element->tme_element_private; ! 1168: conn_sun_si = (struct tme_sun_si_connection *)conn; ! 1169: ! 1170: /* this is a generic bus connection, so just score it nonzero and ! 1171: return. note that there's no good way to differentiate a ! 1172: connection to a bus from a connection to just another chip, so we ! 1173: always return a nonzero score here: */ ! 1174: *_score = 1; ! 1175: return (TME_OK); ! 1176: } ! 1177: ! 1178: /* this makes a new connection: */ ! 1179: static int ! 1180: _tme_sun_si_connection_make(struct tme_connection *conn, unsigned int state) ! 1181: { ! 1182: struct tme_sun_si *sun_si; ! 1183: struct tme_sun_si_connection *conn_sun_si; ! 1184: struct tme_bus_connection *conn_bus; ! 1185: ! 1186: /* both sides must be generic bus connections: */ ! 1187: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC); ! 1188: assert(conn->tme_connection_other->tme_connection_type ! 1189: == conn->tme_connection_type); ! 1190: ! 1191: /* recover our data structures: */ ! 1192: sun_si = conn->tme_connection_element->tme_element_private; ! 1193: conn_sun_si = (struct tme_sun_si_connection *) conn; ! 1194: conn_bus = &conn_sun_si->tme_sun_si_connection; ! 1195: ! 1196: /* we're always set up to answer calls across the connection, so we ! 1197: only have to do work when the connection has gone full, namely ! 1198: taking the other side of the connection: */ ! 1199: if (state == TME_CONNECTION_FULL) { ! 1200: ! 1201: /* lock our mutex: */ ! 1202: tme_mutex_lock(&sun_si->tme_sun_si_mutex); ! 1203: ! 1204: /* save our connection: */ ! 1205: if (conn_bus->tme_bus_tlb_fill == _tme_sun_si_tlb_fill) { ! 1206: sun_si->tme_sun_si_conn_ncr5380 = (struct tme_bus_connection *) conn->tme_connection_other; ! 1207: } ! 1208: else { ! 1209: if (conn_sun_si->tme_sun_si_connection_regs) { ! 1210: sun_si->tme_sun_si_conn_regs = (struct tme_bus_connection *) conn->tme_connection_other; ! 1211: } ! 1212: if (!(sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD ! 1213: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA) ! 1214: || !conn_sun_si->tme_sun_si_connection_regs) { ! 1215: sun_si->tme_sun_si_conn_memory = (struct tme_bus_connection *) conn->tme_connection_other; ! 1216: } ! 1217: } ! 1218: ! 1219: /* unlock our mutex: */ ! 1220: tme_mutex_unlock(&sun_si->tme_sun_si_mutex); ! 1221: } ! 1222: ! 1223: return (TME_OK); ! 1224: } ! 1225: ! 1226: /* this breaks a connection: */ ! 1227: static int ! 1228: _tme_sun_si_connection_break(struct tme_connection *conn, unsigned int state) ! 1229: { ! 1230: abort(); ! 1231: } ! 1232: ! 1233: /* this makes a new connection side for a sun_si: */ ! 1234: static int ! 1235: _tme_sun_si_connections_new(struct tme_element *element, ! 1236: const char * const *args, ! 1237: struct tme_connection **_conns, ! 1238: char **_output) ! 1239: { ! 1240: struct tme_sun_si *sun_si; ! 1241: struct tme_sun_si_connection *conn_sun_si; ! 1242: struct tme_bus_connection *conn_bus; ! 1243: struct tme_connection *conn; ! 1244: unsigned int ncr5380; ! 1245: unsigned int regs; ! 1246: int usage; ! 1247: int rc; ! 1248: ! 1249: /* recover our data structure: */ ! 1250: sun_si = (struct tme_sun_si *) element->tme_element_private; ! 1251: ! 1252: /* we don't bother locking the mutex simply to check if connections ! 1253: already exist: */ ! 1254: ! 1255: /* check our arguments: */ ! 1256: usage = FALSE; ! 1257: rc = 0; ! 1258: regs = FALSE; ! 1259: ncr5380 = FALSE; ! 1260: ! 1261: /* if this connection is for the registers: */ ! 1262: if (TME_ARG_IS(args[1], "csr")) { ! 1263: ! 1264: /* if we already have a register connection, complain: */ ! 1265: if (sun_si->tme_sun_si_conn_regs != NULL) { ! 1266: rc = EEXIST; ! 1267: } ! 1268: ! 1269: /* otherwise, make the new connection: */ ! 1270: else { ! 1271: regs = TRUE; ! 1272: } ! 1273: } ! 1274: ! 1275: /* else, if this connection is for the memory: */ ! 1276: else if ((sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD ! 1277: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA) ! 1278: && TME_ARG_IS(args[1], "memory")) { ! 1279: ! 1280: /* if we already have a memory connection, complain: */ ! 1281: if (sun_si->tme_sun_si_conn_memory != NULL) { ! 1282: rc = EEXIST; ! 1283: } ! 1284: } ! 1285: ! 1286: /* else, the connection must be for the ncr5380: */ ! 1287: else if (args[1] == NULL) { ! 1288: ! 1289: /* if we already have an ncr5380 connection, complain: */ ! 1290: if (sun_si->tme_sun_si_conn_ncr5380 != NULL) { ! 1291: rc = EEXIST; ! 1292: } ! 1293: ! 1294: /* otherwise, make the new connection: */ ! 1295: else { ! 1296: ncr5380 = TRUE; ! 1297: } ! 1298: } ! 1299: ! 1300: /* otherwise, this is a bad argument: */ ! 1301: else { ! 1302: tme_output_append_error(_output, ! 1303: "%s %s, ", ! 1304: args[1], ! 1305: _("unexpected")); ! 1306: usage = TRUE; ! 1307: } ! 1308: ! 1309: if (usage) { ! 1310: tme_output_append_error(_output, ! 1311: ((sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD ! 1312: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA) ! 1313: ? "%s %s [ csr | memory ]" ! 1314: : "%s %s [ csr ]"), ! 1315: _("usage:"), ! 1316: args[0]); ! 1317: rc = EINVAL; ! 1318: } ! 1319: ! 1320: if (rc) { ! 1321: return (rc); ! 1322: } ! 1323: ! 1324: /* make a new connection: */ ! 1325: conn_sun_si = tme_new0(struct tme_sun_si_connection, 1); ! 1326: conn_bus = &conn_sun_si->tme_sun_si_connection; ! 1327: conn = &conn_bus->tme_bus_connection; ! 1328: ! 1329: /* fill in the generic connection: */ ! 1330: conn->tme_connection_next = *_conns; ! 1331: conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC; ! 1332: conn->tme_connection_score = _tme_sun_si_connection_score; ! 1333: conn->tme_connection_make = _tme_sun_si_connection_make; ! 1334: conn->tme_connection_break = _tme_sun_si_connection_break; ! 1335: ! 1336: /* fill in the generic bus connection: */ ! 1337: conn_bus->tme_bus_subregions.tme_bus_subregion_address_first = 0; ! 1338: conn_bus->tme_bus_subregions.tme_bus_subregion_next = NULL; ! 1339: if (ncr5380) { ! 1340: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = ((tme_bus_addr_t) 0) - 1; ! 1341: conn_bus->tme_bus_signals_add = NULL; ! 1342: conn_bus->tme_bus_signal = _tme_sun_si_bus_signal; ! 1343: conn_bus->tme_bus_tlb_set_allocate = _tme_sun_si_tlb_set_allocate; ! 1344: conn_bus->tme_bus_tlb_fill = _tme_sun_si_tlb_fill; ! 1345: } ! 1346: else if (regs) { ! 1347: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_SI_SIZ_REGS - 1; ! 1348: conn_bus->tme_bus_tlb_fill = _tme_sun_si_tlb_fill_regs; ! 1349: if (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_VME ! 1350: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_3E) { ! 1351: conn_bus->tme_bus_intack = _tme_sun_si_intack; ! 1352: } ! 1353: } ! 1354: else { ! 1355: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0; ! 1356: } ! 1357: ! 1358: /* fill in the internal information: */ ! 1359: conn_sun_si->tme_sun_si_connection_regs = regs; ! 1360: ! 1361: /* return the connection side possibility: */ ! 1362: *_conns = conn; ! 1363: return (TME_OK); ! 1364: } ! 1365: ! 1366: /* the new sun_si function: */ ! 1367: int ! 1368: tme_sun_si(struct tme_element *element, const char * const *args, char **_output) ! 1369: { ! 1370: struct tme_sun_si *sun_si; ! 1371: int arg_i; ! 1372: int usage; ! 1373: tme_uint32_t si_type; ! 1374: ! 1375: /* check our arguments: */ ! 1376: usage = 0; ! 1377: si_type = TME_SUN_SI_TYPE_NULL; ! 1378: arg_i = 1; ! 1379: for (;;) { ! 1380: ! 1381: /* the si type: */ ! 1382: if (TME_ARG_IS(args[arg_i + 0], "type")) { ! 1383: if (TME_ARG_IS(args[arg_i + 1], "vme")) { ! 1384: si_type = TME_SUN_SI_TYPE_VME; ! 1385: } ! 1386: else if (TME_ARG_IS(args[arg_i + 1], "onboard")) { ! 1387: si_type = TME_SUN_SI_TYPE_ONBOARD; ! 1388: } ! 1389: else if (TME_ARG_IS(args[arg_i + 1], "3/E")) { ! 1390: si_type = TME_SUN_SI_TYPE_3E; ! 1391: } ! 1392: else if (TME_ARG_IS(args[arg_i + 1], "cobra")) { ! 1393: si_type = TME_SUN_SI_TYPE_COBRA; ! 1394: } ! 1395: else { ! 1396: usage = TRUE; ! 1397: break; ! 1398: } ! 1399: arg_i += 2; ! 1400: } ! 1401: ! 1402: /* if we ran out of arguments: */ ! 1403: else if (args[arg_i] == NULL) { ! 1404: ! 1405: break; ! 1406: } ! 1407: ! 1408: /* otherwise this is a bad argument: */ ! 1409: else { ! 1410: tme_output_append_error(_output, ! 1411: "%s %s, ", ! 1412: args[arg_i], ! 1413: _("unexpected")); ! 1414: usage = TRUE; ! 1415: break; ! 1416: } ! 1417: } ! 1418: ! 1419: if (usage) { ! 1420: tme_output_append_error(_output, ! 1421: "%s %s type { vme | onboard | 3/E | cobra } [ size { 1600x1280 | 1152x900 | 1024x1024 | 1280x1024 | 1440x1440 | 640x480 } ]", ! 1422: _("usage:"), ! 1423: args[0]); ! 1424: return (EINVAL); ! 1425: } ! 1426: ! 1427: /* start the sun_si structure: */ ! 1428: sun_si = tme_new0(struct tme_sun_si, 1); ! 1429: sun_si->tme_sun_si_type = si_type; ! 1430: sun_si->tme_sun_si_3e_dma = (si_type == TME_SUN_SI_TYPE_3E ! 1431: ? tme_new(char, TME_SUN_SI_3E_SIZ_DMA) ! 1432: : NULL); ! 1433: sun_si->tme_sun_si_element = element; ! 1434: TME_SUN_SI_CSR_PUT(sun_si, ! 1435: ((si_type == TME_SUN_SI_TYPE_VME ! 1436: ? TME_SUN_SI_CSR_VME_MODIFIED ! 1437: : 0) ! 1438: | (si_type == TME_SUN_SI_TYPE_3E ! 1439: ? TME_SUN_SI_CSR_3E_VCC ! 1440: : TME_SUN_SI_CSR_RESET_FIFO) ! 1441: | TME_SUN_SI_CSR_RESET_CONTROLLER)); ! 1442: sun_si->tme_sun_si_csr_ncr5380 = TME_SUN_SI_CSR_GET(sun_si); ! 1443: tme_mutex_init(&sun_si->tme_sun_si_mutex); ! 1444: tme_rwlock_init(&sun_si->tme_sun_si_rwlock); ! 1445: ! 1446: /* fill the element: */ ! 1447: element->tme_element_private = sun_si; ! 1448: element->tme_element_connections_new = _tme_sun_si_connections_new; ! 1449: ! 1450: return (TME_OK); ! 1451: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.