|
|
1.1.1.2 ! root 1: /* $Id: sun-mie.c,v 1.3 2006/09/30 12:43:31 fredette Exp $ */ 1.1 root 2: 3: /* bus/multibus/sun_mie.c - implementation of the Sun Intel Ethernet Multibus emulation: */ 4: 5: /* 6: * Copyright (c) 2003 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> 1.1.1.2 ! root 37: _TME_RCSID("$Id: sun-mie.c,v 1.3 2006/09/30 12:43:31 fredette Exp $"); 1.1 root 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: #undef TME_I825X6_VERSION 45: #define TME_I825X6_VERSION TME_X_VERSION(0, 0) 46: #include <tme/ic/i825x6.h> 47: 48: /* macros: */ 49: 50: /* the amount of memory on the board: */ 51: #define TME_SUN_MIE_MEMSIZE (256 * 1024) 52: 53: /* the board page size: */ 54: #define TME_SUN_MIE_PAGESIZE (1024) 55: 56: /* the number of page map entries: */ 57: #define TME_SUN_MIE_PGMAP_COUNT (1024) 58: 59: /* the number of active TLB entries we can have per page map entry: */ 60: #define TME_SUN_MIE_PGMAP_TLBS (4) 61: 62: /* register offsets and sizes: */ 63: #define TME_SUN_MIE_REG_PGMAP (0) 64: #define TME_SUN_MIE_SIZ_PGMAP (TME_SUN_MIE_PGMAP_COUNT * sizeof(tme_uint16_t)) 65: #define TME_SUN_MIE_REG_PROM (TME_SUN_MIE_REG_PGMAP + TME_SUN_MIE_SIZ_PGMAP) 66: #define TME_SUN_MIE_SIZ_PROM (32 * sizeof(tme_uint16_t)) 67: #define TME_SUN_MIE_REG_CSR (TME_SUN_MIE_REG_PROM + TME_SUN_MIE_SIZ_PROM) 68: #define TME_SUN_MIE_SIZ_CSR (sizeof(tme_uint16_t)) 69: #define TME_SUN_MIE_REG_PCR (TME_SUN_MIE_REG_CSR + TME_SUN_MIE_SIZ_CSR + sizeof(tme_uint16_t)) 70: #define TME_SUN_MIE_SIZ_PCR (sizeof(tme_uint16_t)) 71: #define TME_SUN_MIE_REG_PE_ALO (TME_SUN_MIE_REG_PCR + TME_SUN_MIE_SIZ_PCR) 72: #define TME_SUN_MIE_SIZ_PE_ALO (sizeof(tme_uint16_t)) 73: #define TME_SUN_MIE_SIZ_REGS (TME_SUN_MIE_REG_PE_ALO + TME_SUN_MIE_SIZ_PE_ALO) 74: 75: /* the bits in a pagemap entry: */ 76: #define TME_SUN_MIE_PGMAP_SWAB (0x8000) 77: /* 0x4000 unused */ 78: #define TME_SUN_MIE_PGMAP_P2MEM (0x2000) 79: /* 0x1000 unused */ 80: #define TME_SUN_MIE_PGMAP_PFNUM (0x0fff) 81: 82: /* the bits in the Control/Status Register: */ 83: #define TME_SUN_MIE_CSR_RESET (0x8000) 84: #define TME_SUN_MIE_CSR_NOLOOP (0x4000) 85: #define TME_SUN_MIE_CSR_CA (0x2000) 86: #define TME_SUN_MIE_CSR_IE (0x1000) 87: #define TME_SUN_MIE_CSR_PIE (0x0800) 88: /* 0x0400 unused */ 89: #define TME_SUN_MIE_CSR_PE (0x0200) 90: #define TME_SUN_MIE_CSR_INTR (0x0100) 91: /* 0x0080 unused */ 92: /* 0x0040 unused */ 93: #define TME_SUN_MIE_CSR_P2MEM (0x0020) 94: #define TME_SUN_MIE_CSR_BIGRAM (0x0010) 95: #define TME_SUN_MIE_CSR_MPMHI (0x000f) 96: #define TME_SUN_MIE_CSR_READONLY (0x0400 \ 97: | TME_SUN_MIE_CSR_PE \ 98: | TME_SUN_MIE_CSR_INTR \ 99: | 0x0080 \ 100: | 0x0040 \ 101: | TME_SUN_MIE_CSR_BIGRAM\ 102: | TME_SUN_MIE_CSR_MPMHI) 103: 104: /* the bits in the Parity Control Register: */ 105: #define TME_SUN_MIE_PCR_PEACK (0x0100) 106: #define TME_SUN_MIE_PCR_PESRC (0x0080) 107: #define TME_SUN_MIE_PCR_PEBYTE (0x0040) 108: /* 0x0020 unused */ 109: /* 0x0010 unused */ 110: #define TME_SUN_MIE_PCR_PE_AHI (0x000f) 111: #define TME_SUN_MIE_PCR_READONLY (~TME_SUN_MIE_PCR_PEACK) 112: 113: /* the size of the memory port: */ 114: #define TME_SUN_MIE_SIZ_MBM (0x10000) 115: 116: /* these get and put the CSR: */ 117: #define TME_SUN_MIE_CSR_GET(sun_mie) \ 118: tme_betoh_u16(*((tme_uint16_t *) &(sun_mie)->tme_sun_mie_regs[TME_SUN_MIE_REG_CSR])) 119: #define TME_SUN_MIE_CSR_PUT(sun_mie, csr) \ 120: (*((tme_uint16_t *) &(sun_mie)->tme_sun_mie_regs[TME_SUN_MIE_REG_CSR]) = tme_htobe_u16(csr)) 121: 122: /* these get and put the PCR: */ 123: #define TME_SUN_MIE_PCR_GET(sun_mie) \ 124: tme_betoh_u16(*((tme_uint16_t *) &(sun_mie)->tme_sun_mie_regs[TME_SUN_MIE_REG_PCR])) 125: #define TME_SUN_MIE_PCR_PUT(sun_mie, pcr) \ 126: (*((tme_uint16_t *) &(sun_mie)->tme_sun_mie_regs[TME_SUN_MIE_REG_PCR]) = tme_htobe_u16(pcr)) 127: 128: /* the callout flags: */ 129: #define TME_SUN_MIE_CALLOUT_CHECK (0) 130: #define TME_SUN_MIE_CALLOUT_RUNNING TME_BIT(0) 131: #define TME_SUN_MIE_CALLOUTS_MASK (-2) 132: #define TME_SUN_MIE_CALLOUT_SIGNALS TME_BIT(1) 133: #define TME_SUN_MIE_CALLOUT_INT TME_BIT(2) 134: 135: /* structures: */ 136: 137: /* the card: */ 138: struct tme_sun_mie { 139: 140: /* backpointer to our element: */ 141: struct tme_element *tme_sun_mie_element; 142: 143: /* the mutex protecting the card: */ 144: tme_mutex_t tme_sun_mie_mutex; 145: 146: /* the rwlock protecting the card: */ 147: tme_rwlock_t tme_sun_mie_rwlock; 148: 149: /* the bus connection for the card's registers: */ 150: struct tme_bus_connection *tme_sun_mie_conn_regs; 151: 152: /* the bus connection for the card's memory: */ 153: struct tme_bus_connection *tme_sun_mie_conn_memory; 154: 155: /* the bus connection for the card's i825x6 chip: */ 156: struct tme_bus_connection *tme_sun_mie_conn_i825x6; 157: 158: /* the callout flags: */ 159: int tme_sun_mie_callout_flags; 160: 161: /* if our interrupt line is currently asserted: */ 162: int tme_sun_mie_int_asserted; 163: 164: /* it's easiest to just model the board registers as a chunk of memory: */ 165: tme_uint8_t tme_sun_mie_regs[TME_SUN_MIE_SIZ_REGS]; 166: 167: /* the board memory really is a chunk of memory: */ 168: tme_uint8_t tme_sun_mie_memory[TME_SUN_MIE_MEMSIZE]; 169: 170: /* the active TLB entries for each page map entry on the board: */ 171: struct tme_bus_tlb *tme_sun_mie_tlbs[TME_SUN_MIE_PGMAP_COUNT * TME_SUN_MIE_PGMAP_TLBS]; 172: unsigned int tme_sun_mie_tlb_head[TME_SUN_MIE_PGMAP_COUNT]; 173: 174: /* the i825x6 image of the CSR: */ 175: tme_uint16_t tme_sun_mie_csr_i825x6; 176: 177: #ifndef TME_NO_LOG 178: tme_uint16_t tme_sun_mie_last_log_csr; 179: #endif /* !TME_NO_LOG */ 180: }; 181: 182: /* a sun_mie internal bus connection: */ 183: struct tme_sun_mie_connection { 184: 185: /* the external bus connection: */ 186: struct tme_bus_connection tme_sun_mie_connection; 187: 188: /* this is nonzero if a TME_CONNECTION_BUS_GENERIC chip connection 189: is for the registers: */ 190: tme_uint8_t tme_sun_mie_connection_regs; 191: 192: /* if this connection is for the memory port, this is the high 193: nibble (A19..A16) of that port's connection: */ 194: tme_uint8_t tme_sun_mie_connection_mpmhi; 195: }; 196: 197: /* globals: */ 198: 199: /* our bus signals sets: */ 200: static const struct tme_bus_signals _tme_sun_mie_bus_signals_generic = TME_BUS_SIGNALS_GENERIC; 201: static const struct tme_bus_signals _tme_sun_mie_bus_signals_i825x6 = TME_BUS_SIGNALS_I825X6; 202: 203: /* the sun_mie callout function. it must be called with the mutex locked: */ 204: static void 205: _tme_sun_mie_callout(struct tme_sun_mie *sun_mie, int new_callouts) 206: { 207: struct tme_bus_connection *conn_i825x6; 208: struct tme_bus_connection *conn_bus; 209: tme_uint16_t csr, csr_diff; 210: unsigned int signal, level; 211: int callouts, later_callouts; 212: int rc; 213: int int_asserted; 214: 215: /* add in any new callouts: */ 216: sun_mie->tme_sun_mie_callout_flags |= new_callouts; 217: 218: /* if this function is already running in another thread, simply 219: return now. the other thread will do our work: */ 220: if (sun_mie->tme_sun_mie_callout_flags & TME_SUN_MIE_CALLOUT_RUNNING) { 221: return; 222: } 223: 224: /* callouts are now running: */ 225: sun_mie->tme_sun_mie_callout_flags |= TME_SUN_MIE_CALLOUT_RUNNING; 226: 227: /* assume that we won't need any later callouts: */ 228: later_callouts = 0; 229: 230: /* loop while callouts are needed: */ 231: for (; (callouts = sun_mie->tme_sun_mie_callout_flags) & TME_SUN_MIE_CALLOUTS_MASK; ) { 232: 233: /* clear the needed callouts: */ 234: sun_mie->tme_sun_mie_callout_flags = callouts & ~TME_SUN_MIE_CALLOUTS_MASK; 235: callouts &= TME_SUN_MIE_CALLOUTS_MASK; 236: 237: /* if we need to call out one or more signals to the i825x6: */ 238: if (callouts & TME_SUN_MIE_CALLOUT_SIGNALS) { 239: 240: /* get the current CSR value: */ 241: csr = TME_SUN_MIE_CSR_GET(sun_mie); 242: 243: /* get the next signal to call out to the i825x6: */ 244: csr_diff = ((csr 245: ^ sun_mie->tme_sun_mie_csr_i825x6) 246: & (TME_SUN_MIE_CSR_RESET 247: | TME_SUN_MIE_CSR_NOLOOP 248: | TME_SUN_MIE_CSR_CA)); 249: csr_diff = (csr_diff ^ (csr_diff - 1)) & csr_diff; 250: 251: /* if there is a signal to call out: */ 252: if (csr_diff != 0) { 253: 254: /* assume that if the signal's bit is set in the CSR, it will 255: be asserted: */ 256: level = csr & csr_diff; 257: 258: /* assume that we're calling out an i825x6 signal: */ 259: signal = (_tme_sun_mie_bus_signals_generic.tme_bus_signals_first 260: + TME_BUS_SIGNAL_X(_tme_sun_mie_bus_signals_generic.tme_bus_signals_count)); 261: 262: /* dispatch on the CSR bit: */ 263: switch (csr_diff) { 264: default: 265: assert (FALSE); 266: case TME_SUN_MIE_CSR_RESET: 267: signal = TME_BUS_SIGNAL_RESET; 268: break; 269: case TME_SUN_MIE_CSR_NOLOOP: 270: signal += TME_I825X6_SIGNAL_LOOP; 271: level = !level; 272: break; 273: case TME_SUN_MIE_CSR_CA: 274: signal += TME_I825X6_SIGNAL_CA; 275: break; 276: } 277: 278: /* create a real signal level value: */ 279: level = (level 280: ? TME_BUS_SIGNAL_LEVEL_ASSERTED 281: : TME_BUS_SIGNAL_LEVEL_NEGATED); 282: 283: /* get this card's i825x6 connection: */ 284: conn_i825x6 = sun_mie->tme_sun_mie_conn_i825x6; 285: 286: /* unlock the mutex: */ 287: tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex); 288: 289: /* do the callout: */ 290: rc = (conn_i825x6 != NULL 291: ? ((*conn_i825x6->tme_bus_signal) 292: (conn_i825x6, 293: signal | level)) 294: : TME_OK); 295: 296: /* lock the mutex: */ 297: tme_mutex_lock(&sun_mie->tme_sun_mie_mutex); 298: 299: /* if the callout was unsuccessful, remember that at some later 300: time this callout should be attempted again: */ 301: if (rc != TME_OK) { 302: later_callouts |= TME_SUN_MIE_CALLOUT_SIGNALS; 303: } 304: 305: /* otherwise, the callout was successful: */ 306: else { 307: 308: /* update the i825x6 image of the CSR: */ 309: sun_mie->tme_sun_mie_csr_i825x6 = 310: ((sun_mie->tme_sun_mie_csr_i825x6 & ~csr_diff) 311: | (csr & csr_diff)); 312: 313: /* there may be more signals to call out, so attempt this 314: callout again now: */ 315: sun_mie->tme_sun_mie_callout_flags |= TME_SUN_MIE_CALLOUT_SIGNALS; 316: } 317: } 318: } 319: 320: /* if we need to call out a possible change to our interrupt 321: signal: */ 322: if (callouts & TME_SUN_MIE_CALLOUT_INT) { 323: 324: /* get the current CSR value: */ 325: csr = TME_SUN_MIE_CSR_GET(sun_mie); 326: 327: /* see if the interrupt signal should be asserted or negated: */ 328: int_asserted = ((csr & (TME_SUN_MIE_CSR_IE 329: | TME_SUN_MIE_CSR_INTR)) 330: == (TME_SUN_MIE_CSR_IE 331: | TME_SUN_MIE_CSR_INTR)); 332: 333: /* if the interrupt signal doesn't already have the right state: */ 334: if (!int_asserted != !sun_mie->tme_sun_mie_int_asserted) { 335: 336: /* get our bus connection: */ 337: conn_bus = sun_mie->tme_sun_mie_conn_regs; 338: 339: /* unlock our mutex: */ 340: tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex); 341: 342: /* call out the bus interrupt signal edge: */ 343: rc = (conn_bus != NULL 344: ? ((*conn_bus->tme_bus_signal) 345: (conn_bus, 346: TME_BUS_SIGNAL_INT_UNSPEC 347: | (int_asserted 348: ? TME_BUS_SIGNAL_LEVEL_ASSERTED 349: : TME_BUS_SIGNAL_LEVEL_NEGATED))) 350: : TME_OK); 351: 352: /* lock our mutex: */ 353: tme_mutex_lock(&sun_mie->tme_sun_mie_mutex); 354: 355: /* if this callout was successful, note the new state of the 356: interrupt signal: */ 357: if (rc == TME_OK) { 358: sun_mie->tme_sun_mie_int_asserted = int_asserted; 359: } 360: 361: /* otherwise, remember that at some later time this callout 362: should be attempted again: */ 363: else { 364: later_callouts |= TME_SUN_MIE_CALLOUT_INT; 365: } 366: } 367: } 368: } 369: 370: /* put in any later callouts, and clear that callouts are running: */ 371: sun_mie->tme_sun_mie_callout_flags = later_callouts; 372: } 373: 374: /* the sun_mie bus cycle handler for the board memory: */ 375: static int 376: _tme_sun_mie_bus_cycle(void *_sun_mie, 377: struct tme_bus_cycle *cycle_init) 378: { 379: struct tme_sun_mie *sun_mie; 380: 381: /* recover our data structure: */ 382: sun_mie = (struct tme_sun_mie *) _sun_mie; 383: 384: /* run the cycle: */ 385: tme_bus_cycle_xfer_memory(cycle_init, 386: sun_mie->tme_sun_mie_memory, 387: TME_SUN_MIE_MEMSIZE - 1); 388: 389: /* no faults: */ 390: return (TME_OK); 391: } 392: 393: /* the sun_mie bus cycle handler for the board registers: */ 394: static int 395: _tme_sun_mie_bus_cycle_regs(void *_sun_mie, 396: struct tme_bus_cycle *cycle_init) 397: { 398: struct tme_sun_mie *sun_mie; 399: unsigned int pgmap_i; 400: unsigned int pgmap_j; 401: unsigned int tlb_i; 402: unsigned int tlb_j; 403: tme_uint16_t csr_old, csr_new, csr_diff; 404: tme_uint16_t pcr_old, pcr_new, pcr_diff; 405: int new_callouts; 406: 407: /* recover our data structure: */ 408: sun_mie = (struct tme_sun_mie *) _sun_mie; 409: 410: /* assume we won't need any new callouts: */ 411: new_callouts = 0; 412: 413: /* lock the mutex: */ 414: tme_mutex_lock(&sun_mie->tme_sun_mie_mutex); 415: 416: /* if this is a write cycle and the address falls within one or more 417: page map entries, invalidate the TLBs associated with those 418: entries: */ 419: if ((cycle_init->tme_bus_cycle_type 420: & TME_BUS_CYCLE_WRITE) 421: && (TME_SUN_MIE_REG_PGMAP 422: <= cycle_init->tme_bus_cycle_address) 423: && (cycle_init->tme_bus_cycle_address 424: < (TME_SUN_MIE_REG_PGMAP 425: + TME_SUN_MIE_SIZ_PGMAP))) { 426: 427: /* get the range of page map entries: */ 428: pgmap_i 429: = (cycle_init->tme_bus_cycle_address 430: / sizeof(tme_uint16_t)); 431: pgmap_j 432: = ((cycle_init->tme_bus_cycle_address 433: + cycle_init->tme_bus_cycle_size 434: + sizeof(tme_uint16_t) 435: - 1) 436: / sizeof(tme_uint16_t)); 437: pgmap_j = TME_MIN(pgmap_j, TME_SUN_MIE_PGMAP_COUNT); 438: 439: /* get the range of TLB handles: */ 440: tlb_i = pgmap_i * TME_SUN_MIE_PGMAP_TLBS; 441: tlb_j = pgmap_j * TME_SUN_MIE_PGMAP_TLBS; 442: 443: /* invalidate the TLB entries: */ 444: for (; tlb_i < tlb_j; tlb_i++) { 445: if (sun_mie->tme_sun_mie_tlbs[tlb_i] != NULL) { 446: tme_bus_tlb_invalidate(sun_mie->tme_sun_mie_tlbs[tlb_i]); 447: sun_mie->tme_sun_mie_tlbs[tlb_i] = NULL; 448: } 449: } 450: } 451: 452: /* get the previous CSR and PCR values: */ 453: csr_old = TME_SUN_MIE_CSR_GET(sun_mie); 454: pcr_old = TME_SUN_MIE_PCR_GET(sun_mie); 455: 456: /* unless this address falls within the PROM, run the cycle: */ 457: if ((cycle_init->tme_bus_cycle_address 458: < TME_SUN_MIE_REG_PROM) 459: || (cycle_init->tme_bus_cycle_address 460: >= (TME_SUN_MIE_REG_PROM 461: + TME_SUN_MIE_SIZ_PROM))) { 462: tme_bus_cycle_xfer_memory(cycle_init, 463: sun_mie->tme_sun_mie_regs, 464: TME_SUN_MIE_SIZ_REGS - 1); 465: } 466: 467: /* get the current CSR and PCR values, and put back any bits that 468: software can't change: */ 469: csr_new = ((TME_SUN_MIE_CSR_GET(sun_mie) 470: & ~TME_SUN_MIE_CSR_READONLY) 471: | (csr_old 472: & TME_SUN_MIE_CSR_READONLY)); 473: TME_SUN_MIE_CSR_PUT(sun_mie, csr_new); 474: pcr_new = ((TME_SUN_MIE_PCR_GET(sun_mie) 475: & ~TME_SUN_MIE_PCR_READONLY) 476: | (pcr_old 477: & TME_SUN_MIE_PCR_READONLY)); 478: TME_SUN_MIE_PCR_PUT(sun_mie, pcr_new); 479: 480: /* get the sets of CSR and PCR bits that have changed: */ 481: csr_diff = (csr_old ^ csr_new); 482: pcr_diff = (pcr_old ^ pcr_new); 483: 484: /* if this is a RESET, NOLOOP or CA change, possibly call out the 485: appropriate signal change to the i825x6: */ 486: if (csr_diff & (TME_SUN_MIE_CSR_RESET 487: | TME_SUN_MIE_CSR_NOLOOP 488: | TME_SUN_MIE_CSR_CA)) { 489: new_callouts |= TME_SUN_MIE_CALLOUT_SIGNALS; 490: } 491: 492: /* if this is an interrupt mask change, possibly call out an 493: interrupt signal change to the bus: */ 494: if (csr_diff & TME_SUN_MIE_CSR_IE) { 495: new_callouts |= TME_SUN_MIE_CALLOUT_INT; 496: } 497: 498: /* abort on any attempt to enable the P2 bus: */ 499: if (csr_new & TME_SUN_MIE_CSR_P2MEM) { 500: abort (); 501: } 502: 503: /* if this is acknowledging a parity error: */ 504: if (pcr_diff & TME_SUN_MIE_PCR_PEACK) { 505: /* nothing to do */ 506: } 507: 508: #ifndef TME_NO_LOG 509: if (csr_new != sun_mie->tme_sun_mie_last_log_csr) { 510: sun_mie->tme_sun_mie_last_log_csr = csr_new; 511: tme_log(&sun_mie->tme_sun_mie_element->tme_element_log_handle, 512: 1000, TME_OK, 513: (&sun_mie->tme_sun_mie_element->tme_element_log_handle, 514: "csr now 0x%04x", 515: csr_new)); 516: } 517: #endif /* !TME_NO_LOG */ 518: 519: /* make any new callouts: */ 520: _tme_sun_mie_callout(sun_mie, new_callouts); 521: 522: /* unlock the mutex: */ 523: tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex); 524: 525: /* no faults: */ 526: return (TME_OK); 527: } 528: 529: /* the sun_mie bus signal handler: */ 530: static int 531: _tme_sun_mie_bus_signal(struct tme_bus_connection *conn_bus, 532: unsigned int signal) 533: { 534: struct tme_sun_mie *sun_mie; 535: 536: /* return now if this is not a generic bus signal: */ 537: if (TME_BUS_SIGNAL_INDEX(signal) 538: > _tme_sun_mie_bus_signals_generic.tme_bus_signals_count) { 539: return (TME_OK); 540: } 541: 542: /* recover our data structures: */ 543: sun_mie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; 544: 545: /* since this function is currently only given to the i825x6, 546: just copy its signal through to the Multibus: */ 547: conn_bus = sun_mie->tme_sun_mie_conn_regs; 548: return ((*conn_bus->tme_bus_signal)(conn_bus, signal)); 549: } 550: 551: /* the sun_mie bus signals adder for the i825x6: */ 552: static int 553: _tme_sun_mie_bus_signals_add(struct tme_bus_connection *conn_bus, 554: struct tme_bus_signals *bus_signals_caller) 555: { 556: const struct tme_bus_signals *bus_signals; 557: tme_uint32_t signal_first; 558: 559: /* we only support the generic and i825x6 bus signals: */ 560: switch (bus_signals_caller->tme_bus_signals_id) { 561: case TME_BUS_SIGNALS_ID_GENERIC: 562: bus_signals = &_tme_sun_mie_bus_signals_generic; 563: signal_first = _tme_sun_mie_bus_signals_generic.tme_bus_signals_first; 564: break; 565: case TME_BUS_SIGNALS_ID_I825X6: 566: bus_signals = &_tme_sun_mie_bus_signals_i825x6; 567: signal_first = (_tme_sun_mie_bus_signals_generic.tme_bus_signals_first 568: + TME_BUS_SIGNAL_X(_tme_sun_mie_bus_signals_generic.tme_bus_signals_count)); 569: break; 570: default: 571: return (ENOENT); 572: } 573: 574: /* XXX we should check versions here: */ 575: *bus_signals_caller = *bus_signals; 576: bus_signals_caller->tme_bus_signals_first = signal_first; 577: return (TME_OK); 578: } 579: 580: /* the sun_mie TLB allocator for the i825x6: */ 581: static int 582: _tme_sun_mie_tlb_set_allocate(struct tme_bus_connection *conn_bus, 583: unsigned int count, unsigned int sizeof_one, 1.1.1.2 ! root 584: struct tme_bus_tlb * tme_shared *_tlbs, ! 585: tme_rwlock_t *_tlbs_rwlock) 1.1 root 586: { 587: struct tme_bus_tlb *tlbs, *tlb; 588: unsigned int tlb_i; 589: 590: /* allocate a singleton set: */ 591: tlbs = (struct tme_bus_tlb *) tme_malloc(count * sizeof_one); 592: tlb = tlbs; 593: for (tlb_i = 0; tlb_i < count; tlb_i++) { 1.1.1.2 ! root 594: tme_bus_tlb_construct(tlb); 1.1 root 595: tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + sizeof_one); 596: } 1.1.1.2 ! root 597: tme_memory_atomic_pointer_write(struct tme_bus_tlb *, *_tlbs, tlbs, _tlbs_rwlock); 1.1 root 598: 599: /* done: */ 600: return (TME_OK); 601: } 602: 603: /* the sun_mie TLB filler for the board memory: */ 604: static int 605: _tme_sun_mie_tlb_fill(struct tme_bus_connection *conn_bus, 606: struct tme_bus_tlb *tlb, 607: tme_bus_addr_t address, 608: unsigned int cycles) 609: { 610: struct tme_sun_mie *sun_mie; 611: unsigned int pgmap_i; 612: unsigned int tlb_i; 613: tme_uint16_t pgmap; 614: 615: /* recover our data structures: */ 616: sun_mie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; 617: 618: /* the address must be within range: */ 619: assert(address <= 0xffffff); 620: 621: /* mask the address with the board page size: */ 622: address &= -TME_SUN_MIE_PAGESIZE; 623: 624: /* lock our mutex: */ 625: tme_mutex_lock(&sun_mie->tme_sun_mie_mutex); 626: 627: /* get the pagemap entry: */ 628: pgmap_i = (address / TME_SUN_MIE_PAGESIZE) & (TME_SUN_MIE_PGMAP_COUNT - 1); 629: pgmap = tme_betoh_u16(((tme_uint16_t *) &sun_mie->tme_sun_mie_regs[TME_SUN_MIE_REG_PGMAP])[pgmap_i]); 630: 631: /* update the head pointer for this page map entry's active TLB 632: entry list: */ 633: tlb_i = sun_mie->tme_sun_mie_tlb_head[pgmap_i]; 634: if (++tlb_i == TME_SUN_MIE_PGMAP_TLBS) { 635: tlb_i = 0; 636: } 637: sun_mie->tme_sun_mie_tlb_head[pgmap_i] = tlb_i; 638: tlb_i += pgmap_i * TME_SUN_MIE_PGMAP_TLBS; 639: 640: /* if the new head pointer already has a TLB entry, and it doesn't 641: happen to be the same one that we're filling now, invalidate it: */ 642: if (sun_mie->tme_sun_mie_tlbs[tlb_i] != NULL 1.1.1.2 ! root 643: && sun_mie->tme_sun_mie_tlbs[tlb_i] != tlb->tme_bus_tlb_global) { 1.1 root 644: tme_bus_tlb_invalidate(sun_mie->tme_sun_mie_tlbs[tlb_i]); 645: } 646: 647: /* initialize the TLB entry: */ 648: tme_bus_tlb_initialize(tlb); 649: 650: /* this TLB entry covers this range: */ 1.1.1.2 ! root 651: tlb->tme_bus_tlb_addr_first = address; ! 652: tlb->tme_bus_tlb_addr_last = address | (TME_SUN_MIE_PAGESIZE - 1); 1.1 root 653: 654: /* allow reading and writing: */ 655: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 656: 657: /* our bus cycle handler: */ 658: tlb->tme_bus_tlb_cycle_private = sun_mie; 659: tlb->tme_bus_tlb_cycle = _tme_sun_mie_bus_cycle; 660: 661: /* this TLB entry allows fast reading and writing: */ 662: tlb->tme_bus_tlb_emulator_off_write = 663: (&sun_mie->tme_sun_mie_memory[((pgmap & TME_SUN_MIE_PGMAP_PFNUM) 664: * TME_SUN_MIE_PAGESIZE)] 665: - address); 666: tlb->tme_bus_tlb_emulator_off_read = 667: tlb->tme_bus_tlb_emulator_off_write; 668: 669: /* add this TLB entry to the active list: */ 670: sun_mie->tme_sun_mie_tlbs[tlb_i] = 1.1.1.2 ! root 671: tlb->tme_bus_tlb_global; 1.1 root 672: 673: /* unlock our mutex: */ 674: tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex); 675: 676: return (TME_OK); 677: } 678: 679: /* the sun_mie TLB filler for the board registers: */ 680: static int 681: _tme_sun_mie_tlb_fill_regs(struct tme_bus_connection *conn_bus, 682: struct tme_bus_tlb *tlb, 683: tme_bus_addr_t address, unsigned int cycles) 684: { 685: struct tme_sun_mie *sun_mie; 686: 687: /* recover our data structures: */ 688: sun_mie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; 689: 690: /* the address must be within range: */ 691: assert(address < TME_SUN_MIE_SIZ_REGS); 692: 693: /* initialize the TLB entry: */ 694: tme_bus_tlb_initialize(tlb); 695: 696: /* if the address falls in the page map: */ 697: if (TME_SUN_MIE_REG_PGMAP <= address 698: && address < (TME_SUN_MIE_REG_PGMAP 699: + TME_SUN_MIE_SIZ_PGMAP)) { 700: 701: /* this TLB entry covers this range: */ 1.1.1.2 ! root 702: tlb->tme_bus_tlb_addr_first = TME_SUN_MIE_REG_PGMAP; ! 703: tlb->tme_bus_tlb_addr_last = (TME_SUN_MIE_REG_PGMAP + TME_SUN_MIE_SIZ_PGMAP - 1); 1.1 root 704: } 705: 706: /* if this address falls in the PROM: */ 707: else if (TME_SUN_MIE_REG_PROM <= address 708: && address < (TME_SUN_MIE_REG_PROM 709: + TME_SUN_MIE_SIZ_PROM)) { 710: 711: 712: /* this TLB entry covers this range: */ 1.1.1.2 ! root 713: tlb->tme_bus_tlb_addr_first = TME_SUN_MIE_REG_PROM; ! 714: tlb->tme_bus_tlb_addr_last = TME_SUN_MIE_REG_PROM + TME_SUN_MIE_SIZ_PROM - 1; 1.1 root 715: } 716: 717: /* if this address falls in the CSR: */ 718: else if (TME_SUN_MIE_REG_CSR <= address 719: && address < (TME_SUN_MIE_REG_CSR 720: + TME_SUN_MIE_SIZ_CSR)) { 721: 722: 723: /* this TLB entry covers this range: */ 1.1.1.2 ! root 724: tlb->tme_bus_tlb_addr_first = TME_SUN_MIE_REG_CSR; ! 725: tlb->tme_bus_tlb_addr_last = TME_SUN_MIE_REG_CSR + TME_SUN_MIE_SIZ_CSR - 1; 1.1 root 726: } 727: 728: /* otherwise, this address must fall in the unused hole or in the 729: parity registers: */ 730: else { 731: assert (address >= (TME_SUN_MIE_REG_CSR 732: + TME_SUN_MIE_SIZ_CSR)); 733: 734: /* this TLB entry covers this range: */ 1.1.1.2 ! root 735: tlb->tme_bus_tlb_addr_first = (TME_SUN_MIE_REG_CSR + TME_SUN_MIE_SIZ_CSR); ! 736: tlb->tme_bus_tlb_addr_last = (TME_SUN_MIE_REG_PE_ALO + TME_SUN_MIE_SIZ_PE_ALO - 1); 1.1 root 737: } 738: 739: /* all address ranges allow fast reading: */ 740: tlb->tme_bus_tlb_emulator_off_read = &sun_mie->tme_sun_mie_regs[0]; 741: tlb->tme_bus_tlb_rwlock = &sun_mie->tme_sun_mie_rwlock; 742: 743: /* allow reading and writing: */ 744: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 745: 746: /* our bus cycle handler: */ 747: tlb->tme_bus_tlb_cycle_private = sun_mie; 748: tlb->tme_bus_tlb_cycle = _tme_sun_mie_bus_cycle_regs; 749: 750: return (TME_OK); 751: } 752: 753: /* this scores a new connection: */ 754: static int 755: _tme_sun_mie_connection_score(struct tme_connection *conn, unsigned int *_score) 756: { 757: struct tme_sun_mie *sun_mie; 758: struct tme_sun_mie_connection *conn_sun_mie; 759: 760: /* both sides must be generic bus connections: */ 761: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC); 762: assert(conn->tme_connection_other->tme_connection_type 763: == conn->tme_connection_type); 764: 765: /* recover our data structures: */ 766: sun_mie = conn->tme_connection_element->tme_element_private; 767: conn_sun_mie = (struct tme_sun_mie_connection *)conn; 768: 769: /* this is a generic bus connection, so just score it nonzero and 770: return. note that there's no good way to differentiate a 771: connection to a bus from a connection to just another chip, so we 772: always return a nonzero score here: */ 773: *_score = 1; 774: return (TME_OK); 775: } 776: 777: /* this makes a new connection: */ 778: static int 779: _tme_sun_mie_connection_make(struct tme_connection *conn, unsigned int state) 780: { 781: struct tme_sun_mie *sun_mie; 782: struct tme_sun_mie_connection *conn_sun_mie; 783: struct tme_bus_connection *conn_bus; 784: tme_uint16_t csr; 785: 786: /* both sides must be generic bus connections: */ 787: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC); 788: assert(conn->tme_connection_other->tme_connection_type 789: == conn->tme_connection_type); 790: 791: /* recover our data structures: */ 792: sun_mie = conn->tme_connection_element->tme_element_private; 793: conn_sun_mie = (struct tme_sun_mie_connection *)conn; 794: conn_bus = &conn_sun_mie->tme_sun_mie_connection; 795: 796: /* we're always set up to answer calls across the connection, so we 797: only have to do work when the connection has gone full, namely 798: taking the other side of the connection: */ 799: if (state == TME_CONNECTION_FULL) { 800: 801: /* lock our mutex: */ 802: tme_mutex_lock(&sun_mie->tme_sun_mie_mutex); 803: 804: /* save our connection: */ 805: if (conn_bus->tme_bus_signals_add != NULL) { 806: sun_mie->tme_sun_mie_conn_i825x6 = (struct tme_bus_connection *) conn->tme_connection_other; 807: } 808: else if (conn_sun_mie->tme_sun_mie_connection_regs) { 809: sun_mie->tme_sun_mie_conn_regs = (struct tme_bus_connection *) conn->tme_connection_other; 810: } 811: else { 812: sun_mie->tme_sun_mie_conn_memory = (struct tme_bus_connection *) conn->tme_connection_other; 813: csr = TME_SUN_MIE_CSR_GET(sun_mie); 814: csr &= ~TME_SUN_MIE_CSR_MPMHI; 815: csr |= conn_sun_mie->tme_sun_mie_connection_mpmhi; 816: TME_SUN_MIE_CSR_PUT(sun_mie, csr); 817: } 818: 819: /* unlock our mutex: */ 820: tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex); 821: } 822: 823: return (TME_OK); 824: } 825: 826: /* this breaks a connection: */ 827: static int 828: _tme_sun_mie_connection_break(struct tme_connection *conn, unsigned int state) 829: { 830: abort(); 831: } 832: 833: /* this makes a new connection side for a sun_mie: */ 834: static int 835: _tme_sun_mie_connections_new(struct tme_element *element, 836: const char * const *args, 837: struct tme_connection **_conns, 838: char **_output) 839: { 840: struct tme_sun_mie *sun_mie; 841: struct tme_sun_mie_connection *conn_sun_mie; 842: struct tme_bus_connection *conn_bus; 843: struct tme_connection *conn; 844: unsigned int i825x6; 845: tme_uint8_t regs; 846: tme_bus_addr_t mpmhi; 847: int usage; 848: int rc; 849: 850: /* recover our data structure: */ 851: sun_mie = (struct tme_sun_mie *) element->tme_element_private; 852: 853: /* we don't bother locking the mutex simply to check if connections 854: already exist: */ 855: 856: /* check our arguments: */ 857: usage = FALSE; 858: rc = 0; 859: i825x6 = FALSE; 860: regs = FALSE; 861: mpmhi = 0; 862: 863: /* if this connection is for the registers: */ 864: if (TME_ARG_IS(args[1], "csr")) { 865: 866: /* if we already have a register connection, complain: */ 867: if (sun_mie->tme_sun_mie_conn_regs != NULL) { 868: rc = EEXIST; 869: } 870: 871: /* otherwise, make the new connection: */ 872: else { 873: regs = TRUE; 874: } 875: } 876: 877: /* else, if this connection is for the memory: */ 878: else if (TME_ARG_IS(args[1], "memory")) { 879: 880: /* if we already have a memory connection, complain: */ 881: if (sun_mie->tme_sun_mie_conn_memory != NULL) { 882: rc = EEXIST; 883: } 884: 885: /* otherwise, check the value after "memory". it must be the low 886: 20 bits of the bus address of the board's memory; in our csr we 887: have to report the most significant nibble (A19-A16, as A15..A0 888: are expected to be zero) to software so it can find that 889: memory: */ 890: else { 891: mpmhi = tme_bus_addr_parse_any(args[2], &usage); 892: if (!usage 893: && ((mpmhi > 0xfffff) 894: || (mpmhi & (TME_SUN_MIE_SIZ_MBM - 1)))) { 895: tme_output_append_error(_output, 896: "%s %s, ", 897: args[2], 898: _(" is not a 20-bit address with A15..A0 zero")); 899: usage = TRUE; 900: } 901: } 902: } 903: 904: /* else, the connection must be for the i825x6: */ 905: else if (args[1] == NULL) { 906: 907: /* if we already have an i825x6 connection, complain: */ 908: if (sun_mie->tme_sun_mie_conn_i825x6 != NULL) { 909: rc = EEXIST; 910: } 911: 912: /* otherwise, make the new conection: */ 913: else { 914: i825x6 = TRUE; 915: } 916: } 917: 918: /* otherwise, this is a bad argument: */ 919: else { 920: tme_output_append_error(_output, 921: "%s %s, ", 922: args[1], 923: _("unexpected")); 924: usage = TRUE; 925: } 926: 927: if (usage) { 928: tme_output_append_error(_output, 929: "%s %s [ csr | memory %s ]", 930: _("usage:"), 931: args[0], 932: _("BUS-ADDRESS")); 933: rc = EINVAL; 934: } 935: 936: if (rc) { 937: return (rc); 938: } 939: 940: /* make a new connection: */ 941: conn_sun_mie = tme_new0(struct tme_sun_mie_connection, 1); 942: conn_bus = &conn_sun_mie->tme_sun_mie_connection; 943: conn = &conn_bus->tme_bus_connection; 944: 945: /* fill in the generic connection: */ 946: conn->tme_connection_next = *_conns; 947: conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC; 948: conn->tme_connection_score = _tme_sun_mie_connection_score; 949: conn->tme_connection_make = _tme_sun_mie_connection_make; 950: conn->tme_connection_break = _tme_sun_mie_connection_break; 951: 952: /* fill in the generic bus connection: */ 953: conn_bus->tme_bus_subregions.tme_bus_subregion_address_first = 0; 954: conn_bus->tme_bus_subregions.tme_bus_subregion_next = NULL; 955: if (i825x6) { 956: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0xffffff; 957: conn_bus->tme_bus_signals_add = _tme_sun_mie_bus_signals_add; 958: conn_bus->tme_bus_signal = _tme_sun_mie_bus_signal; 959: conn_bus->tme_bus_tlb_set_allocate = _tme_sun_mie_tlb_set_allocate; 960: conn_bus->tme_bus_tlb_fill = _tme_sun_mie_tlb_fill; 961: } 962: else if (regs) { 963: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_MIE_SIZ_REGS - 1; 964: conn_bus->tme_bus_tlb_fill = _tme_sun_mie_tlb_fill_regs; 965: } 966: else { 967: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_MIE_SIZ_MBM - 1; 968: conn_bus->tme_bus_tlb_fill = _tme_sun_mie_tlb_fill; 969: } 970: 971: /* fill in the internal information: */ 972: conn_sun_mie->tme_sun_mie_connection_regs = regs; 973: conn_sun_mie->tme_sun_mie_connection_mpmhi = (mpmhi >> 16); 974: 975: /* return the connection side possibility: */ 976: *_conns = conn; 977: return (TME_OK); 978: } 979: 980: /* the new sun_mie function: */ 981: TME_ELEMENT_SUB_NEW_DECL(tme_bus_multibus,sun_mie) { 982: struct tme_sun_mie *sun_mie; 983: int arg_i; 984: int usage; 985: 986: /* check our arguments: */ 987: usage = 0; 988: arg_i = 1; 989: for (;;) { 990: 991: if (0) { 992: } 993: 994: /* if we ran out of arguments: */ 995: else if (args[arg_i] == NULL) { 996: 997: break; 998: } 999: 1000: /* otherwise this is a bad argument: */ 1001: else { 1002: tme_output_append_error(_output, 1003: "%s %s, ", 1004: args[arg_i], 1005: _("unexpected")); 1006: usage = TRUE; 1007: break; 1008: } 1009: } 1010: 1011: if (usage) { 1012: tme_output_append_error(_output, 1013: "%s %s", 1014: _("usage:"), 1015: args[0]); 1016: return (EINVAL); 1017: } 1018: 1019: /* start the sun_mie structure: */ 1020: sun_mie = tme_new0(struct tme_sun_mie, 1); 1021: sun_mie->tme_sun_mie_element = element; 1022: TME_SUN_MIE_CSR_PUT(sun_mie, 1023: (TME_SUN_MIE_CSR_NOLOOP 1024: | TME_SUN_MIE_CSR_BIGRAM)); 1025: tme_mutex_init(&sun_mie->tme_sun_mie_mutex); 1026: tme_rwlock_init(&sun_mie->tme_sun_mie_rwlock); 1027: 1028: /* fill the element: */ 1029: element->tme_element_private = sun_mie; 1030: element->tme_element_connections_new = _tme_sun_mie_connections_new; 1031: 1032: return (TME_OK); 1033: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.