|
|
1.1.1.3 ! root 1: /* $Id: sun-mie.c,v 1.4 2010/06/05 13:57:27 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.3 ! root 37: _TME_RCSID("$Id: sun-mie.c,v 1.4 2010/06/05 13:57:27 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: */ 1.1.1.3 ! root 171: struct tme_token *tme_sun_mie_tlb_tokens[TME_SUN_MIE_PGMAP_COUNT * TME_SUN_MIE_PGMAP_TLBS]; 1.1 root 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++) { 1.1.1.3 ! root 445: if (sun_mie->tme_sun_mie_tlb_tokens[tlb_i] != NULL) { ! 446: tme_token_invalidate(sun_mie->tme_sun_mie_tlb_tokens[tlb_i]); ! 447: sun_mie->tme_sun_mie_tlb_tokens[tlb_i] = NULL; 1.1 root 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: 1.1.1.3 ! root 580: /* the sun_mie TLB adder for the i825x6: */ 1.1 root 581: static int 1.1.1.3 ! root 582: _tme_sun_mie_tlb_set_add(struct tme_bus_connection *conn_bus, ! 583: struct tme_bus_tlb_set_info *tlb_set_info) 1.1 root 584: { 585: 1.1.1.3 ! root 586: /* if this TLB set provides a bus context register: */ ! 587: if (tlb_set_info->tme_bus_tlb_set_info_bus_context != NULL) { ! 588: ! 589: /* this bus only has one context: */ ! 590: (*tlb_set_info->tme_bus_tlb_set_info_bus_context) = 0; ! 591: tlb_set_info->tme_bus_tlb_set_info_bus_context_max = 0; 1.1 root 592: } 1.1.1.3 ! root 593: 1.1 root 594: return (TME_OK); 595: } 596: 597: /* the sun_mie TLB filler for the board memory: */ 598: static int 599: _tme_sun_mie_tlb_fill(struct tme_bus_connection *conn_bus, 600: struct tme_bus_tlb *tlb, 1.1.1.3 ! root 601: tme_bus_addr_t address_wider, 1.1 root 602: unsigned int cycles) 603: { 604: struct tme_sun_mie *sun_mie; 1.1.1.3 ! root 605: tme_bus_addr32_t address; 1.1 root 606: unsigned int pgmap_i; 607: unsigned int tlb_i; 608: tme_uint16_t pgmap; 609: 610: /* recover our data structures: */ 611: sun_mie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; 612: 1.1.1.3 ! root 613: /* get the normal-width address: */ ! 614: address = address_wider; ! 615: assert (address == address_wider); ! 616: 1.1 root 617: /* the address must be within range: */ 618: assert(address <= 0xffffff); 619: 620: /* mask the address with the board page size: */ 621: address &= -TME_SUN_MIE_PAGESIZE; 622: 623: /* lock our mutex: */ 624: tme_mutex_lock(&sun_mie->tme_sun_mie_mutex); 625: 626: /* get the pagemap entry: */ 627: pgmap_i = (address / TME_SUN_MIE_PAGESIZE) & (TME_SUN_MIE_PGMAP_COUNT - 1); 628: pgmap = tme_betoh_u16(((tme_uint16_t *) &sun_mie->tme_sun_mie_regs[TME_SUN_MIE_REG_PGMAP])[pgmap_i]); 629: 630: /* update the head pointer for this page map entry's active TLB 631: entry list: */ 632: tlb_i = sun_mie->tme_sun_mie_tlb_head[pgmap_i]; 633: if (++tlb_i == TME_SUN_MIE_PGMAP_TLBS) { 634: tlb_i = 0; 635: } 636: sun_mie->tme_sun_mie_tlb_head[pgmap_i] = tlb_i; 637: tlb_i += pgmap_i * TME_SUN_MIE_PGMAP_TLBS; 638: 639: /* if the new head pointer already has a TLB entry, and it doesn't 640: happen to be the same one that we're filling now, invalidate it: */ 1.1.1.3 ! root 641: if (sun_mie->tme_sun_mie_tlb_tokens[tlb_i] != NULL ! 642: && sun_mie->tme_sun_mie_tlb_tokens[tlb_i] != tlb->tme_bus_tlb_token) { ! 643: tme_token_invalidate(sun_mie->tme_sun_mie_tlb_tokens[tlb_i]); 1.1 root 644: } 645: 646: /* initialize the TLB entry: */ 647: tme_bus_tlb_initialize(tlb); 648: 649: /* this TLB entry covers this range: */ 1.1.1.2 root 650: tlb->tme_bus_tlb_addr_first = address; 651: tlb->tme_bus_tlb_addr_last = address | (TME_SUN_MIE_PAGESIZE - 1); 1.1 root 652: 653: /* allow reading and writing: */ 654: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 655: 656: /* our bus cycle handler: */ 657: tlb->tme_bus_tlb_cycle_private = sun_mie; 658: tlb->tme_bus_tlb_cycle = _tme_sun_mie_bus_cycle; 659: 660: /* this TLB entry allows fast reading and writing: */ 661: tlb->tme_bus_tlb_emulator_off_write = 662: (&sun_mie->tme_sun_mie_memory[((pgmap & TME_SUN_MIE_PGMAP_PFNUM) 663: * TME_SUN_MIE_PAGESIZE)] 664: - address); 665: tlb->tme_bus_tlb_emulator_off_read = 666: tlb->tme_bus_tlb_emulator_off_write; 667: 668: /* add this TLB entry to the active list: */ 1.1.1.3 ! root 669: sun_mie->tme_sun_mie_tlb_tokens[tlb_i] = ! 670: tlb->tme_bus_tlb_token; 1.1 root 671: 672: /* unlock our mutex: */ 673: tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex); 674: 675: return (TME_OK); 676: } 677: 678: /* the sun_mie TLB filler for the board registers: */ 679: static int 680: _tme_sun_mie_tlb_fill_regs(struct tme_bus_connection *conn_bus, 681: struct tme_bus_tlb *tlb, 1.1.1.3 ! root 682: tme_bus_addr_t address_wider, ! 683: unsigned int cycles) 1.1 root 684: { 685: struct tme_sun_mie *sun_mie; 1.1.1.3 ! root 686: tme_bus_addr32_t address; 1.1 root 687: 688: /* recover our data structures: */ 689: sun_mie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; 690: 1.1.1.3 ! root 691: /* get the normal-width address: */ ! 692: address = address_wider; ! 693: assert (address == address_wider); ! 694: 1.1 root 695: /* the address must be within range: */ 696: assert(address < TME_SUN_MIE_SIZ_REGS); 697: 698: /* initialize the TLB entry: */ 699: tme_bus_tlb_initialize(tlb); 700: 701: /* if the address falls in the page map: */ 702: if (TME_SUN_MIE_REG_PGMAP <= address 703: && address < (TME_SUN_MIE_REG_PGMAP 704: + TME_SUN_MIE_SIZ_PGMAP)) { 705: 706: /* this TLB entry covers this range: */ 1.1.1.2 root 707: tlb->tme_bus_tlb_addr_first = TME_SUN_MIE_REG_PGMAP; 708: tlb->tme_bus_tlb_addr_last = (TME_SUN_MIE_REG_PGMAP + TME_SUN_MIE_SIZ_PGMAP - 1); 1.1 root 709: } 710: 711: /* if this address falls in the PROM: */ 712: else if (TME_SUN_MIE_REG_PROM <= address 713: && address < (TME_SUN_MIE_REG_PROM 714: + TME_SUN_MIE_SIZ_PROM)) { 715: 716: 717: /* this TLB entry covers this range: */ 1.1.1.2 root 718: tlb->tme_bus_tlb_addr_first = TME_SUN_MIE_REG_PROM; 719: tlb->tme_bus_tlb_addr_last = TME_SUN_MIE_REG_PROM + TME_SUN_MIE_SIZ_PROM - 1; 1.1 root 720: } 721: 722: /* if this address falls in the CSR: */ 723: else if (TME_SUN_MIE_REG_CSR <= address 724: && address < (TME_SUN_MIE_REG_CSR 725: + TME_SUN_MIE_SIZ_CSR)) { 726: 727: 728: /* this TLB entry covers this range: */ 1.1.1.2 root 729: tlb->tme_bus_tlb_addr_first = TME_SUN_MIE_REG_CSR; 730: tlb->tme_bus_tlb_addr_last = TME_SUN_MIE_REG_CSR + TME_SUN_MIE_SIZ_CSR - 1; 1.1 root 731: } 732: 733: /* otherwise, this address must fall in the unused hole or in the 734: parity registers: */ 735: else { 736: assert (address >= (TME_SUN_MIE_REG_CSR 737: + TME_SUN_MIE_SIZ_CSR)); 738: 739: /* this TLB entry covers this range: */ 1.1.1.2 root 740: tlb->tme_bus_tlb_addr_first = (TME_SUN_MIE_REG_CSR + TME_SUN_MIE_SIZ_CSR); 741: tlb->tme_bus_tlb_addr_last = (TME_SUN_MIE_REG_PE_ALO + TME_SUN_MIE_SIZ_PE_ALO - 1); 1.1 root 742: } 743: 744: /* all address ranges allow fast reading: */ 745: tlb->tme_bus_tlb_emulator_off_read = &sun_mie->tme_sun_mie_regs[0]; 746: tlb->tme_bus_tlb_rwlock = &sun_mie->tme_sun_mie_rwlock; 747: 748: /* allow reading and writing: */ 749: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 750: 751: /* our bus cycle handler: */ 752: tlb->tme_bus_tlb_cycle_private = sun_mie; 753: tlb->tme_bus_tlb_cycle = _tme_sun_mie_bus_cycle_regs; 754: 755: return (TME_OK); 756: } 757: 758: /* this scores a new connection: */ 759: static int 760: _tme_sun_mie_connection_score(struct tme_connection *conn, unsigned int *_score) 761: { 762: struct tme_sun_mie *sun_mie; 763: struct tme_sun_mie_connection *conn_sun_mie; 764: 765: /* both sides must be generic bus connections: */ 766: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC); 767: assert(conn->tme_connection_other->tme_connection_type 768: == conn->tme_connection_type); 769: 770: /* recover our data structures: */ 771: sun_mie = conn->tme_connection_element->tme_element_private; 772: conn_sun_mie = (struct tme_sun_mie_connection *)conn; 773: 774: /* this is a generic bus connection, so just score it nonzero and 775: return. note that there's no good way to differentiate a 776: connection to a bus from a connection to just another chip, so we 777: always return a nonzero score here: */ 778: *_score = 1; 779: return (TME_OK); 780: } 781: 782: /* this makes a new connection: */ 783: static int 784: _tme_sun_mie_connection_make(struct tme_connection *conn, unsigned int state) 785: { 786: struct tme_sun_mie *sun_mie; 787: struct tme_sun_mie_connection *conn_sun_mie; 788: struct tme_bus_connection *conn_bus; 789: tme_uint16_t csr; 790: 791: /* both sides must be generic bus connections: */ 792: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC); 793: assert(conn->tme_connection_other->tme_connection_type 794: == conn->tme_connection_type); 795: 796: /* recover our data structures: */ 797: sun_mie = conn->tme_connection_element->tme_element_private; 798: conn_sun_mie = (struct tme_sun_mie_connection *)conn; 799: conn_bus = &conn_sun_mie->tme_sun_mie_connection; 800: 801: /* we're always set up to answer calls across the connection, so we 802: only have to do work when the connection has gone full, namely 803: taking the other side of the connection: */ 804: if (state == TME_CONNECTION_FULL) { 805: 806: /* lock our mutex: */ 807: tme_mutex_lock(&sun_mie->tme_sun_mie_mutex); 808: 809: /* save our connection: */ 810: if (conn_bus->tme_bus_signals_add != NULL) { 811: sun_mie->tme_sun_mie_conn_i825x6 = (struct tme_bus_connection *) conn->tme_connection_other; 812: } 813: else if (conn_sun_mie->tme_sun_mie_connection_regs) { 814: sun_mie->tme_sun_mie_conn_regs = (struct tme_bus_connection *) conn->tme_connection_other; 815: } 816: else { 817: sun_mie->tme_sun_mie_conn_memory = (struct tme_bus_connection *) conn->tme_connection_other; 818: csr = TME_SUN_MIE_CSR_GET(sun_mie); 819: csr &= ~TME_SUN_MIE_CSR_MPMHI; 820: csr |= conn_sun_mie->tme_sun_mie_connection_mpmhi; 821: TME_SUN_MIE_CSR_PUT(sun_mie, csr); 822: } 823: 824: /* unlock our mutex: */ 825: tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex); 826: } 827: 828: return (TME_OK); 829: } 830: 831: /* this breaks a connection: */ 832: static int 833: _tme_sun_mie_connection_break(struct tme_connection *conn, unsigned int state) 834: { 835: abort(); 836: } 837: 838: /* this makes a new connection side for a sun_mie: */ 839: static int 840: _tme_sun_mie_connections_new(struct tme_element *element, 841: const char * const *args, 842: struct tme_connection **_conns, 843: char **_output) 844: { 845: struct tme_sun_mie *sun_mie; 846: struct tme_sun_mie_connection *conn_sun_mie; 847: struct tme_bus_connection *conn_bus; 848: struct tme_connection *conn; 849: unsigned int i825x6; 850: tme_uint8_t regs; 851: tme_bus_addr_t mpmhi; 852: int usage; 853: int rc; 854: 855: /* recover our data structure: */ 856: sun_mie = (struct tme_sun_mie *) element->tme_element_private; 857: 858: /* we don't bother locking the mutex simply to check if connections 859: already exist: */ 860: 861: /* check our arguments: */ 862: usage = FALSE; 863: rc = 0; 864: i825x6 = FALSE; 865: regs = FALSE; 866: mpmhi = 0; 867: 868: /* if this connection is for the registers: */ 869: if (TME_ARG_IS(args[1], "csr")) { 870: 871: /* if we already have a register connection, complain: */ 872: if (sun_mie->tme_sun_mie_conn_regs != NULL) { 873: rc = EEXIST; 874: } 875: 876: /* otherwise, make the new connection: */ 877: else { 878: regs = TRUE; 879: } 880: } 881: 882: /* else, if this connection is for the memory: */ 883: else if (TME_ARG_IS(args[1], "memory")) { 884: 885: /* if we already have a memory connection, complain: */ 886: if (sun_mie->tme_sun_mie_conn_memory != NULL) { 887: rc = EEXIST; 888: } 889: 890: /* otherwise, check the value after "memory". it must be the low 891: 20 bits of the bus address of the board's memory; in our csr we 892: have to report the most significant nibble (A19-A16, as A15..A0 893: are expected to be zero) to software so it can find that 894: memory: */ 895: else { 896: mpmhi = tme_bus_addr_parse_any(args[2], &usage); 897: if (!usage 898: && ((mpmhi > 0xfffff) 899: || (mpmhi & (TME_SUN_MIE_SIZ_MBM - 1)))) { 900: tme_output_append_error(_output, 901: "%s %s, ", 902: args[2], 903: _(" is not a 20-bit address with A15..A0 zero")); 904: usage = TRUE; 905: } 906: } 907: } 908: 909: /* else, the connection must be for the i825x6: */ 910: else if (args[1] == NULL) { 911: 912: /* if we already have an i825x6 connection, complain: */ 913: if (sun_mie->tme_sun_mie_conn_i825x6 != NULL) { 914: rc = EEXIST; 915: } 916: 917: /* otherwise, make the new conection: */ 918: else { 919: i825x6 = TRUE; 920: } 921: } 922: 923: /* otherwise, this is a bad argument: */ 924: else { 925: tme_output_append_error(_output, 926: "%s %s, ", 927: args[1], 928: _("unexpected")); 929: usage = TRUE; 930: } 931: 932: if (usage) { 933: tme_output_append_error(_output, 934: "%s %s [ csr | memory %s ]", 935: _("usage:"), 936: args[0], 937: _("BUS-ADDRESS")); 938: rc = EINVAL; 939: } 940: 941: if (rc) { 942: return (rc); 943: } 944: 945: /* make a new connection: */ 946: conn_sun_mie = tme_new0(struct tme_sun_mie_connection, 1); 947: conn_bus = &conn_sun_mie->tme_sun_mie_connection; 948: conn = &conn_bus->tme_bus_connection; 949: 950: /* fill in the generic connection: */ 951: conn->tme_connection_next = *_conns; 952: conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC; 953: conn->tme_connection_score = _tme_sun_mie_connection_score; 954: conn->tme_connection_make = _tme_sun_mie_connection_make; 955: conn->tme_connection_break = _tme_sun_mie_connection_break; 956: 957: /* fill in the generic bus connection: */ 958: conn_bus->tme_bus_subregions.tme_bus_subregion_address_first = 0; 959: conn_bus->tme_bus_subregions.tme_bus_subregion_next = NULL; 960: if (i825x6) { 961: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0xffffff; 962: conn_bus->tme_bus_signals_add = _tme_sun_mie_bus_signals_add; 963: conn_bus->tme_bus_signal = _tme_sun_mie_bus_signal; 1.1.1.3 ! root 964: conn_bus->tme_bus_tlb_set_add = _tme_sun_mie_tlb_set_add; 1.1 root 965: conn_bus->tme_bus_tlb_fill = _tme_sun_mie_tlb_fill; 966: } 967: else if (regs) { 968: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_MIE_SIZ_REGS - 1; 969: conn_bus->tme_bus_tlb_fill = _tme_sun_mie_tlb_fill_regs; 970: } 971: else { 972: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_MIE_SIZ_MBM - 1; 973: conn_bus->tme_bus_tlb_fill = _tme_sun_mie_tlb_fill; 974: } 975: 976: /* fill in the internal information: */ 977: conn_sun_mie->tme_sun_mie_connection_regs = regs; 978: conn_sun_mie->tme_sun_mie_connection_mpmhi = (mpmhi >> 16); 979: 980: /* return the connection side possibility: */ 981: *_conns = conn; 982: return (TME_OK); 983: } 984: 985: /* the new sun_mie function: */ 986: TME_ELEMENT_SUB_NEW_DECL(tme_bus_multibus,sun_mie) { 987: struct tme_sun_mie *sun_mie; 988: int arg_i; 989: int usage; 990: 991: /* check our arguments: */ 992: usage = 0; 993: arg_i = 1; 994: for (;;) { 995: 996: if (0) { 997: } 998: 999: /* if we ran out of arguments: */ 1000: else if (args[arg_i] == NULL) { 1001: 1002: break; 1003: } 1004: 1005: /* otherwise this is a bad argument: */ 1006: else { 1007: tme_output_append_error(_output, 1008: "%s %s, ", 1009: args[arg_i], 1010: _("unexpected")); 1011: usage = TRUE; 1012: break; 1013: } 1014: } 1015: 1016: if (usage) { 1017: tme_output_append_error(_output, 1018: "%s %s", 1019: _("usage:"), 1020: args[0]); 1021: return (EINVAL); 1022: } 1023: 1024: /* start the sun_mie structure: */ 1025: sun_mie = tme_new0(struct tme_sun_mie, 1); 1026: sun_mie->tme_sun_mie_element = element; 1027: TME_SUN_MIE_CSR_PUT(sun_mie, 1028: (TME_SUN_MIE_CSR_NOLOOP 1029: | TME_SUN_MIE_CSR_BIGRAM)); 1030: tme_mutex_init(&sun_mie->tme_sun_mie_mutex); 1031: tme_rwlock_init(&sun_mie->tme_sun_mie_rwlock); 1032: 1033: /* fill the element: */ 1034: element->tme_element_private = sun_mie; 1035: element->tme_element_connections_new = _tme_sun_mie_connections_new; 1036: 1037: return (TME_OK); 1038: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.