|
|
1.1 ! root 1: /* $Id: stp222x-main.c,v 1.4 2009/09/07 15:41:07 fredette Exp $ */ ! 2: ! 3: /* ic/stp222x-main.c - main emulation of the UPA to SBus interface ! 4: controller (STP2220) and the UPA to PCI interface controller ! 5: (STP2222): */ ! 6: ! 7: /* ! 8: * Copyright (c) 2009 Matt Fredette ! 9: * All rights reserved. ! 10: * ! 11: * Redistribution and use in source and binary forms, with or without ! 12: * modification, are permitted provided that the following conditions ! 13: * are met: ! 14: * 1. Redistributions of source code must retain the above copyright ! 15: * notice, this list of conditions and the following disclaimer. ! 16: * 2. Redistributions in binary form must reproduce the above copyright ! 17: * notice, this list of conditions and the following disclaimer in the ! 18: * documentation and/or other materials provided with the distribution. ! 19: * 3. All advertising materials mentioning features or use of this software ! 20: * must display the following acknowledgement: ! 21: * This product includes software developed by Matt Fredette. ! 22: * 4. The name of the author may not be used to endorse or promote products ! 23: * derived from this software without specific prior written permission. ! 24: * ! 25: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 26: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 27: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 28: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 29: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 30: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 31: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 33: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 34: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 35: * POSSIBILITY OF SUCH DAMAGE. ! 36: */ ! 37: ! 38: #include <tme/common.h> ! 39: _TME_RCSID("$Id: stp222x-main.c,v 1.4 2009/09/07 15:41:07 fredette Exp $"); ! 40: ! 41: /* includes: */ ! 42: #include <tme/generic/bus-device.h> ! 43: #include "stp222x-impl.h" ! 44: ! 45: /* macros: */ ! 46: ! 47: /* common register offsets: */ ! 48: #define TME_STP222X_REG00_UPA_PORT_ID (0x0000) ! 49: #define TME_STP222X_REG00_UPA_PORT_CONFIG (0x0008) ! 50: #define TME_STP222X_REG00_CSR (0x0010) ! 51: /* 0x0018 unused */ ! 52: #define TME_STP222X_REG00_ECC_CONTROL (0x0020) ! 53: /* 0x0028 unused */ ! 54: #define TME_STP222X_REG00_UE_AFSR (0x0030) ! 55: #define TME_STP222X_REG00_UE_AFAR (0x0038) ! 56: #define TME_STP222X_REG00_CE_AFSR (0x0040) ! 57: #define TME_STP222X_REG00_CE_AFAR (0x0048) ! 58: #define TME_STP222X_REG01_PM_CR (0x0100) ! 59: #define TME_STP222X_REG01_PM_COUNT (0x0108) ! 60: ! 61: /* the control/status register: */ ! 62: #define TME_STP222X_CSR_IMPL ((((tme_uint64_t) 2) << 63) - (((tme_uint64_t) 1) << 60)) ! 63: #define TME_STP222X_CSR_VER ((((tme_uint64_t) 2) << 59) - (((tme_uint64_t) 1) << 56)) ! 64: #define TME_STP222X_CSR_MID ((((tme_uint64_t) 2) << 55) - (((tme_uint64_t) 1) << 51)) ! 65: #define TME_STP222X_CSR_IGN ((((tme_uint64_t) 2) << 50) - (((tme_uint64_t) 1) << 46)) ! 66: #define TME_STP222X_CSR_APCKEN (1 << 3) ! 67: #define TME_STP222X_CSR_APERR (1 << 2) ! 68: #define TME_STP222X_CSR_IAP (1 << 1) ! 69: #define TME_STP222X_CSR_MODE (1 << 0) ! 70: ! 71: /* stp2220-specific registers: */ ! 72: #define TME_STP2220_REG20_SBUS_CSR (0x2000) ! 73: /* 0x2028 unused */ ! 74: #define TME_STP2220_REG20_SBUS_AFSR (0x2010) ! 75: #define TME_STP2220_REG20_SBUS_AFAR (0x2018) ! 76: #define TME_STP2220_REG20_SBUS_CONFIG(n) (0x2020 + (TME_STP222X_REG_SIZE * (n))) ! 77: ! 78: /* the stp2220 slot size: */ ! 79: #define TME_STP2220_SLOT_SIZE (256 * 1024 * 1024) ! 80: ! 81: /* this gives the raw stp2220 address for a slot and offset: */ ! 82: #define TME_STP2220_SBUS_ADDRESS(slot, offset) (((slot) * TME_STP2220_SLOT_SIZE) + (offset)) ! 83: ! 84: /* reset states: */ ! 85: #define TME_STP222X_RESET_STATE_NEGATED (0) ! 86: #define TME_STP222X_RESET_STATE_NEGATING (TME_STP222X_RESET_STATE_NEGATED + TME_STP222X_CONN_NULL) ! 87: #define TME_STP222X_RESET_STATE_ASSERTED (TME_STP222X_RESET_STATE_NEGATING + 1) ! 88: #define TME_STP222X_RESET_STATE_ASSERTING (TME_STP222X_RESET_STATE_ASSERTED + TME_STP222X_CONN_NULL) ! 89: ! 90: /* globals: */ ! 91: ! 92: /* the simple 64-bit register bus router: */ ! 93: static const tme_bus_lane_t _tme_stp222x_bus_router_regs[sizeof(tme_uint64_t)] = { ! 94: TME_BUS_LANE_ROUTE(0), ! 95: TME_BUS_LANE_ROUTE(1), ! 96: TME_BUS_LANE_ROUTE(2), ! 97: TME_BUS_LANE_ROUTE(3), ! 98: TME_BUS_LANE_ROUTE(4), ! 99: TME_BUS_LANE_ROUTE(5), ! 100: TME_BUS_LANE_ROUTE(6), ! 101: TME_BUS_LANE_ROUTE(7) ! 102: }; ! 103: ! 104: /* the STP2220 mapping from obio slot and offset to IDI: */ ! 105: static const struct { ! 106: tme_uint32_t _tme_stp2220_obio_slot; ! 107: tme_uint32_t _tme_stp2220_obio_offset; ! 108: tme_uint32_t _tme_stp2220_obio_idi; ! 109: } _tme_stp2220_obios[] = { ! 110: { TME_STP2220_SLOT_AUDIO, 0x0000000, TME_STP2220_IDI_AUDIO, }, ! 111: { TME_STP2220_SLOT_MACIO, 0x8800000, TME_STP222X_IDI_SCSI }, ! 112: { TME_STP2220_SLOT_MACIO, 0x8c00000, TME_STP222X_IDI_ETHER }, ! 113: { TME_STP2220_SLOT_MACIO, 0xc800000, TME_STP222X_IDI_BPP }, ! 114: { TME_STP2220_SLOT_SLAVIO, 0x1100000, TME_STP2220_IDI_ZS0_ZS1 }, ! 115: { TME_STP2220_SLOT_SLAVIO, 0x1000000, TME_STP2220_IDI_ZS0_ZS1 }, ! 116: { TME_STP2220_SLOT_SLAVIO, 0x1400000, TME_STP2220_IDI_FD }, ! 117: }; ! 118: ! 119: /* this converts an I/O connection into a connection index: */ ! 120: static tme_uint32_t ! 121: _tme_stp222x_io_conn_index(const struct tme_stp222x *stp222x, ! 122: const struct tme_bus_connection *io_conn_bus) ! 123: { ! 124: tme_uint32_t connid; ! 125: tme_uint32_t conn_index; ! 126: ! 127: /* this must be an I/O connection: */ ! 128: assert (io_conn_bus ! 129: != stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus); ! 130: ! 131: /* get the connection id: */ ! 132: connid = io_conn_bus->tme_bus_connection.tme_connection_id; ! 133: ! 134: /* if this is a card connection: */ ! 135: if ((connid ! 136: & TME_STP222X_CONNID_TYPE) ! 137: == TME_STP222X_CONNID_TYPE_CARD) { ! 138: ! 139: /* if this is an stp2220: */ ! 140: if (TME_STP222X_IS_2220(stp222x)) { ! 141: ! 142: /* assume that this is the first master connection for this ! 143: card, which uses the card's primary master connection ! 144: index: */ ! 145: conn_index = TME_FIELD_MASK_EXTRACTU(connid, TME_STP2220_CONNID_CARD_WHICH); ! 146: ! 147: /* if this is an alternate connection for the card: */ ! 148: if (connid & TME_STP2220_CONNID_CARD_ALTERNATE) { ! 149: ! 150: /* starting from the first alternate master connection index ! 151: for this card and moving forward, search all remaining ! 152: connection indices: */ ! 153: conn_index ! 154: = (TME_STP2220_SLOTS_CARD ! 155: + (connid & TME_STP2220_CONNID_CARD_WHICH)); ! 156: for (; stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != io_conn_bus; ) { ! 157: conn_index++; ! 158: assert (conn_index < stp222x->tme_stp222x_slave_conn_index_next); ! 159: } ! 160: } ! 161: } ! 162: ! 163: /* otherwise, this is an stp2222: */ ! 164: else { ! 165: abort(); ! 166: } ! 167: } ! 168: ! 169: /* otherwise, this is an obio connection id: */ ! 170: else { ! 171: ! 172: /* assume that this is an obio short connection id, and get the ! 173: connection index: */ ! 174: conn_index = TME_FIELD_MASK_EXTRACTU(connid, TME_STP222X_CONNID_OBIO_SHORT_CONN_WHICH); ! 175: ! 176: /* if this is an obio long connection id: */ ! 177: if ((connid ! 178: & TME_STP222X_CONNID_OBIO_TYPE) ! 179: == TME_STP222X_CONNID_OBIO_TYPE_LONG) { ! 180: ! 181: /* search all connection indices: */ ! 182: conn_index = 0; ! 183: for (; stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != io_conn_bus; ) { ! 184: conn_index++; ! 185: assert (conn_index < stp222x->tme_stp222x_slave_conn_index_next); ! 186: } ! 187: } ! 188: } ! 189: ! 190: assert (stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus == io_conn_bus); ! 191: return (conn_index); ! 192: } ! 193: ! 194: /* this converts an I/O connection and interrupt signal into an ! 195: IDI: */ ! 196: static tme_uint32_t ! 197: _tme_stp222x_io_idi(const struct tme_stp222x *stp222x, ! 198: const struct tme_bus_connection *io_conn_bus, ! 199: unsigned int signal_int) ! 200: { ! 201: tme_uint32_t connid; ! 202: tme_uint32_t idi; ! 203: tme_uint32_t idi_addend; ! 204: ! 205: /* this must be an I/O connection: */ ! 206: assert (io_conn_bus ! 207: != stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus); ! 208: ! 209: /* get the connection id: */ ! 210: connid = io_conn_bus->tme_bus_connection.tme_connection_id; ! 211: ! 212: /* if this is a card connection: */ ! 213: if ((connid ! 214: & TME_STP222X_CONNID_TYPE) ! 215: == TME_STP222X_CONNID_TYPE_CARD) { ! 216: ! 217: /* if this is an stp2220, bits 1..2 of a card connection id are ! 218: the card (slot) number, which are bits 3..4 of the connection's ! 219: base IDI. otherwise, this is an stp2222, and bits 1..3 of a ! 220: card connection id are the bus and slot number, which are bits ! 221: 2..4 of the connection's base IDI. we take advantage of this ! 222: to quickly make the base IDI: */ ! 223: #if TME_STP222X_CONNID_TYPE != (0x1 << 0) ! 224: #error "TME_STP222X_CONNID_TYPE changed" ! 225: #endif ! 226: #if TME_STP222X_CONNID_TYPE_CARD != 0 ! 227: #error "TME_STP222X_CONNID_TYPE_CARD changed" ! 228: #endif ! 229: #if (TME_STP2222_CONNID_BUS_WHICH + TME_STP2222_CONNID_DEVICE_WHICH) != (0x7 << 1) ! 230: #error "TME_STP2222_CONNID_BUS_WHICH or TME_STP2222_CONNID_DEVICE_WHICH changed" ! 231: #endif ! 232: #if TME_STP2220_CONNID_CARD_WHICH != (0x3 << 1) ! 233: #error "TME_STP2220_CONN_CARD_WHICH changed" ! 234: #endif ! 235: idi = connid << 1; ! 236: if (TME_STP222X_IS_2220(stp222x)) { ! 237: idi <<= 1; ! 238: } ! 239: idi %= TME_STP222X_IDI0_OBIO; ! 240: ! 241: /* the interrupt signal can't be unspecified: */ ! 242: assert (signal_int != TME_BUS_SIGNAL_INT_UNSPEC); ! 243: ! 244: /* convert the interrupt signal into an IDI addend: */ ! 245: idi_addend = TME_BUS_SIGNAL_INDEX_INT(signal_int); ! 246: ! 247: /* the IDI addend must be within range: */ ! 248: assert (idi_addend ! 249: < (TME_STP222X_IS_2220(stp222x) ! 250: ? TME_SBUS_SLOT_INTS ! 251: : TME_PCI_SLOT_INTS)); ! 252: ! 253: /* add in the IDI addend: */ ! 254: idi += idi_addend; ! 255: } ! 256: ! 257: /* otherwise, this is an obio connection: */ ! 258: else { ! 259: ! 260: /* this must be a obio short connection id: */ ! 261: assert ((connid ! 262: & TME_STP222X_CONNID_OBIO_TYPE) ! 263: == TME_STP222X_CONNID_OBIO_TYPE_SHORT); ! 264: ! 265: /* get the connection's base IDI: */ ! 266: idi = TME_FIELD_MASK_EXTRACTU(connid, TME_STP222X_CONNID_OBIO_SHORT_IDI); ! 267: ! 268: /* if the interrupt signal is specified: */ ! 269: if (signal_int != TME_BUS_SIGNAL_INT_UNSPEC) { ! 270: ! 271: /* the audio connection is the only obio connection allowed to ! 272: specify its interrupt signal - zero is used for record, one ! 273: for playback: */ ! 274: assert (signal_int == TME_BUS_SIGNAL_INT(0) ! 275: || signal_int == TME_BUS_SIGNAL_INT(1)); ! 276: if (!TME_STP222X_IS_2220(stp222x)) { ! 277: assert (idi == TME_STP2220_IDI_AUDIO); ! 278: ! 279: /* nothing to do */ ! 280: } ! 281: else { ! 282: #if TME_STP2222_IDI_AUDIO_PLAYBACK != (TME_STP2222_IDI_AUDIO_RECORD + 1) ! 283: #error "TME_STP2222_IDI_AUDIO_ values changed" ! 284: #endif ! 285: assert (idi == TME_STP2222_IDI_AUDIO_RECORD); ! 286: idi += TME_BUS_SIGNAL_INDEX_INT(signal_int); ! 287: } ! 288: } ! 289: } ! 290: ! 291: return (idi); ! 292: } ! 293: ! 294: /* this converts an address into an address space: */ ! 295: static tme_uint32_t ! 296: _tme_stp222x_lookup_address(const struct tme_stp222x *stp222x, ! 297: tme_bus_addr64_t address, ! 298: tme_bus_addr32_t *_region_size_m1) ! 299: { ! 300: tme_bus_addr32_t region_size_m1; ! 301: unsigned int aspace_i; ! 302: tme_uint32_t address_16_47; ! 303: ! 304: /* if this is an stp2220: */ ! 305: if (TME_STP222X_IS_2220(stp222x)) { ! 306: ! 307: /* only the upper half of our UPA address space is mapped to the ! 308: SBus address space: */ ! 309: region_size_m1 = 0xffffffff; ! 310: aspace_i ! 311: = (address <= region_size_m1 ! 312: ? TME_STP222X_ASPACE_NULL ! 313: : TME_STP2220_ASPACE_SBUS); ! 314: } ! 315: ! 316: /* otherwise, this is an stp2222: */ ! 317: else { ! 318: ! 319: /* get bits 16..47 of the UPA address: */ ! 320: address_16_47 = (address >> 16); ! 321: assert (address_16_47 == (address >> 16)); ! 322: ! 323: /* if this is a PCI bus memory space: */ ! 324: if (address_16_47 >= 0x10000) { ! 325: assert (address_16_47 <= 0x1ffff); ! 326: region_size_m1 = 0x7fffffff; ! 327: aspace_i ! 328: = TME_STP2222_ASPACE_PCI_MEMORY(((address_16_47 & 0x8000) == 0) ! 329: == !TME_STP2222_BOOT_BUS(stp222x)); ! 330: } ! 331: ! 332: /* otherwise, if this is a PCI bus I/O space: */ ! 333: else if ((address_16_47 | 1) == 0x00201) { ! 334: region_size_m1 = 0xffff; ! 335: aspace_i = TME_STP2222_ASPACE_PCI_IO(address_16_47 & 1); ! 336: } ! 337: ! 338: /* otherwise, if this is PCI configuration space: */ ! 339: else if (address_16_47 == 0x00100) { ! 340: region_size_m1 = 0xffffff; ! 341: aspace_i = TME_STP2222_ASPACE_PCI_CONFIGURATION; ! 342: } ! 343: ! 344: /* otherwise, this address is in the register space: */ ! 345: else { ! 346: region_size_m1 = 0xffff; ! 347: aspace_i = TME_STP222X_ASPACE_NULL; ! 348: } ! 349: } ! 350: ! 351: /* return the region size and address space: */ ! 352: *_region_size_m1 = region_size_m1; ! 353: return (aspace_i); ! 354: } ! 355: ! 356: /* the 0x00 register group register handler: */ ! 357: static void ! 358: _tme_stp222x_reg00_regs(struct tme_stp222x *stp222x, ! 359: struct tme_stp222x_reg *reg) ! 360: { ! 361: ! 362: /* if this is a write: */ ! 363: if (reg->tme_stp222x_reg_write) { ! 364: ! 365: /* dispatch on the register: */ ! 366: switch (TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address)) { ! 367: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UPA_PORT_CONFIG): ! 368: stp222x->tme_stp222x_upa_port_config ! 369: = (reg->tme_stp222x_reg_value ! 370: & TME_UPA_PORT_CONFIG_SCIQ0); ! 371: break; ! 372: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CSR): ! 373: stp222x->tme_stp222x_csr ! 374: = ((stp222x->tme_stp222x_csr | ~TME_STP222X_CSR_APCKEN) ! 375: & (reg->tme_stp222x_reg_value ^ TME_STP222X_CSR_APCKEN)); ! 376: tme_stp222x_mdu_ign_update(stp222x, ! 377: TME_FIELD_MASK_EXTRACTU(stp222x->tme_stp222x_csr, ! 378: TME_STP222X_CSR_IGN)); ! 379: break; ! 380: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_ECC_CONTROL): ! 381: stp222x->tme_stp222x_ecc_control = (reg->tme_stp222x_reg_value >> 61); ! 382: break; ! 383: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UPA_PORT_ID): ! 384: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UE_AFSR): ! 385: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UE_AFAR): ! 386: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CE_AFSR): ! 387: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CE_AFAR): ! 388: break; ! 389: default: ! 390: return; ! 391: } ! 392: } ! 393: ! 394: /* otherwise, this is a read: */ ! 395: else { ! 396: ! 397: /* dispatch on the register: */ ! 398: switch (TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address)) { ! 399: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UPA_PORT_ID): ! 400: reg->tme_stp222x_reg_value ! 401: = (TME_UPA_PORT_ID_COOKIE ! 402: + !TME_UPA_PORT_ID_ECC_NOT_VALID ! 403: + !TME_UPA_PORT_ID_ONEREAD ! 404: + !TME_UPA_PORT_ID_PINT_RDQ ! 405: + (8 * _TME_FIELD_MASK_FACTOR(TME_UPA_PORT_ID_PREQ_DQ)) ! 406: + (2 * _TME_FIELD_MASK_FACTOR(TME_UPA_PORT_ID_PREQ_RQ)) ! 407: + ((TME_UPA_UPACAP_MASTER ! 408: + !TME_UPA_UPACAP_CACHEMASTER ! 409: + !TME_UPA_UPACAP_SLAVE_INT_L ! 410: + TME_UPA_UPACAP_INTERRUPTMASTER ! 411: + !TME_UPA_UPACAP_HANDLERSLAVE) ! 412: * _TME_FIELD_MASK_FACTOR(TME_UPA_PORT_ID_UPACAP)) ! 413: + ((TME_STP222X_IS_2220(stp222x) ! 414: ? 0xef07 ! 415: : 0x1954) ! 416: * _TME_FIELD_MASK_FACTOR(TME_UPA_PORT_ID_ID))); ! 417: break; ! 418: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UPA_PORT_CONFIG): ! 419: reg->tme_stp222x_reg_value = stp222x->tme_stp222x_upa_port_config; ! 420: break; ! 421: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CSR): ! 422: reg->tme_stp222x_reg_value ! 423: = ((stp222x->tme_stp222x_csr ! 424: & (TME_STP222X_CSR_MID ! 425: | TME_STP222X_CSR_IGN ! 426: | TME_STP222X_CSR_APCKEN ! 427: | TME_STP222X_CSR_APERR ! 428: | TME_STP222X_CSR_IAP ! 429: | TME_STP222X_CSR_MODE)) ! 430: + (TME_STP222X_IS_2220(stp222x) ! 431: ? ((0x0 * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_IMPL)) ! 432: + (0x1 * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_VER))) ! 433: : ((0x0 * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_IMPL)) ! 434: + (0x0 * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_VER))))); ! 435: break; ! 436: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_ECC_CONTROL): ! 437: reg->tme_stp222x_reg_value ! 438: = (((tme_uint64_t) stp222x->tme_stp222x_ecc_control) ! 439: << 61); ! 440: break; ! 441: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UE_AFSR): ! 442: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_UE_AFAR): ! 443: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CE_AFSR): ! 444: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG00_CE_AFAR): ! 445: reg->tme_stp222x_reg_value = 0; ! 446: break; ! 447: default: ! 448: return; ! 449: } ! 450: } ! 451: ! 452: /* this register access has been completed: */ ! 453: reg->tme_stp222x_reg_completed = TRUE; ! 454: } ! 455: ! 456: /* the stp2220 SBus register handler: */ ! 457: static void ! 458: _tme_stp2220_sbus_regs(struct tme_stp222x *stp222x, ! 459: struct tme_stp222x_reg *reg) ! 460: { ! 461: tme_uint64_t mask_w; ! 462: tme_uint64_t mask_ro; ! 463: tme_uint64_t zero; ! 464: tme_uint64_t *_value; ! 465: ! 466: /* assume that all bits of the register are writable: */ ! 467: mask_w = 0 - (tme_uint64_t) 1; ! 468: ! 469: /* assume that all read-only bits of the register are zero: */ ! 470: mask_ro = 0; ! 471: ! 472: /* make a dummy zero register: */ ! 473: zero = 0; ! 474: ! 475: /* if this is the SBus control/status register: */ ! 476: if (reg->tme_stp222x_reg_address == TME_STP2220_REG20_SBUS_CSR) { ! 477: _value = &stp222x->tme_stp2220_sbus_csr; ! 478: mask_w ! 479: = (TME_BIT(10) /* shortens PIO access latency */ ! 480: + TME_BIT(8) /* enables interrupts for SBus errors */ ! 481: + TME_BIT(5) /* enables DVMA for slot 15 */ ! 482: + TME_BIT(4) /* enables DVMA for slot 14 */ ! 483: + 0xf); /* enables DVMA for slots 0..3 */ ! 484: } ! 485: ! 486: /* otherwise, if this is the SBus AFSR or AFAR: */ ! 487: else if (reg->tme_stp222x_reg_address == TME_STP2220_REG20_SBUS_AFSR ! 488: || reg->tme_stp222x_reg_address == TME_STP2220_REG20_SBUS_AFAR) { ! 489: _value = &zero; ! 490: } ! 491: ! 492: /* otherwise, if this is an SBus slot configuration register: */ ! 493: else if ((reg->tme_stp222x_reg_address ! 494: >= TME_STP2220_REG20_SBUS_CONFIG(0)) ! 495: && (reg->tme_stp222x_reg_address ! 496: <= TME_STP2220_REG20_SBUS_CONFIG(TME_STP2220_SLOTS_CARD + TME_STP2220_SLOTS_OBIO - 1))) { ! 497: _value ! 498: = (&stp222x->tme_stp2220_sbus_config_card ! 499: [(reg->tme_stp222x_reg_address ! 500: - TME_STP2220_REG20_SBUS_CONFIG(0)) ! 501: / TME_STP222X_REG_SIZE]); ! 502: mask_w ! 503: = (TME_BIT(14) /* enables extended transfers */ ! 504: + TME_BIT(4) /* enables 64-byte bursts */ ! 505: + TME_BIT(3) /* enables 32-byte bursts */ ! 506: + TME_BIT(2) /* enables 16-byte bursts */ ! 507: + TME_BIT(1) /* enables 8-byte bursts */ ! 508: ); ! 509: } ! 510: ! 511: /* otherwise, this is an unknown register: */ ! 512: else { ! 513: return; ! 514: } ! 515: ! 516: /* if this is a write: */ ! 517: if (reg->tme_stp222x_reg_write) { ! 518: *_value = reg->tme_stp222x_reg_value & mask_w; ! 519: } ! 520: ! 521: /* otherwise, this is a read: */ ! 522: else { ! 523: reg->tme_stp222x_reg_value = *_value | mask_ro; ! 524: } ! 525: ! 526: /* this register access has been completed: */ ! 527: reg->tme_stp222x_reg_completed = TRUE; ! 528: } ! 529: ! 530: /* this completes a bus operation between master and slave: */ ! 531: #define _tme_stp222x_complete_master tme_stp22xx_complete_master ! 532: ! 533: /* this completes a reset assertion or negation: */ ! 534: static void ! 535: _tme_stp222x_complete_reset(struct tme_stp22xx *stp22xx, ! 536: struct tme_completion *completion, ! 537: void *arg) ! 538: { ! 539: struct tme_stp222x *stp222x; ! 540: tme_uint32_t reset_state; ! 541: ! 542: /* recover our data structure: */ ! 543: stp222x = (struct tme_stp222x *) stp22xx; ! 544: ! 545: /* get the next reset state: */ ! 546: reset_state = stp222x->tme_stp222x_reset_state - 1; ! 547: ! 548: /* if we have finished asserting RESET on the I/O bus, and ! 549: the UPA bus reset signal is negated: */ ! 550: if (reset_state == TME_STP222X_RESET_STATE_ASSERTED ! 551: && stp222x->tme_stp222x_reset_level == TME_BUS_SIGNAL_LEVEL_NEGATED) { ! 552: ! 553: /* start negating RESET on the I/O bus: */ ! 554: reset_state = TME_STP222X_RESET_STATE_NEGATING; ! 555: } ! 556: ! 557: /* update the reset state: */ ! 558: stp222x->tme_stp222x_reset_state = reset_state; ! 559: ! 560: /* unused: */ ! 561: completion = 0; ! 562: arg = 0; ! 563: } ! 564: ! 565: /* this completes a bus request assertion or negation: */ ! 566: static void ! 567: _tme_stp222x_complete_br(struct tme_stp22xx *stp22xx, ! 568: struct tme_completion *completion, ! 569: void *arg) ! 570: { ! 571: struct tme_stp222x *stp222x; ! 572: ! 573: /* recover our data structure: */ ! 574: stp222x = (struct tme_stp222x *) stp22xx; ! 575: ! 576: /* our bus request has been flipped: */ ! 577: stp222x->tme_stp222x_br = !stp222x->tme_stp222x_br; ! 578: ! 579: /* unused: */ ! 580: completion = 0; ! 581: arg = 0; ! 582: } ! 583: ! 584: /* this completes a bus grant: */ ! 585: #define _tme_stp222x_complete_bg tme_stp22xx_complete_bg ! 586: ! 587: /* this calls out a bus signal to a connection: */ ! 588: #define _tme_stp222x_callout_signal(stp222x, conn_index, signal, completion_handler) \ ! 589: tme_stp22xx_callout_signal(&(stp222x)->tme_stp222x, conn_index, signal, completion_handler) ! 590: ! 591: /* the run function: */ ! 592: static void ! 593: _tme_stp222x_run(struct tme_stp22xx *stp22xx) ! 594: { ! 595: struct tme_stp222x *stp222x; ! 596: unsigned int reset_state; ! 597: unsigned int io_conn_index; ! 598: unsigned int master_conn_index; ! 599: tme_uint32_t io_brs; ! 600: ! 601: /* recover our data structure: */ ! 602: stp222x = (struct tme_stp222x *) stp22xx; ! 603: ! 604: /* loop forever: */ ! 605: for (;;) { ! 606: ! 607: /* if we need to assert reset to another I/O connection: */ ! 608: reset_state = stp222x->tme_stp222x_reset_state; ! 609: if (reset_state > TME_STP222X_RESET_STATE_ASSERTED) { ! 610: ! 611: /* assert reset to the next I/O connection: */ ! 612: io_conn_index = reset_state - (TME_STP222X_RESET_STATE_ASSERTED + 1); ! 613: _tme_stp222x_callout_signal(stp222x, ! 614: io_conn_index, ! 615: (TME_BUS_SIGNAL_RESET ! 616: | TME_BUS_SIGNAL_EDGE ! 617: | TME_BUS_SIGNAL_LEVEL_ASSERTED), ! 618: _tme_stp222x_complete_reset); ! 619: continue; ! 620: } ! 621: ! 622: /* if there is a current master: */ ! 623: master_conn_index = stp222x->tme_stp222x_master_conn_index; ! 624: if (master_conn_index != TME_STP222X_CONN_NULL) { ! 625: assert (master_conn_index < TME_STP222X_CONN_SLAVE0); ! 626: ! 627: /* if the current master is still requesting the bus: */ ! 628: if (stp222x->tme_stp222x_io_brs & (1 << master_conn_index)) { ! 629: ! 630: /* stop now. we can't do anything else until the current ! 631: master releases the bus: */ ! 632: break; ! 633: } ! 634: ! 635: /* there should be no master completion pending: */ ! 636: assert (stp222x->tme_stp222x.tme_stp22xx_master_completion == NULL); ! 637: ! 638: /* there is no current master: */ ! 639: stp222x->tme_stp222x_master_conn_index = TME_STP222X_CONN_NULL; ! 640: ! 641: /* negate bus grant to the former master: */ ! 642: _tme_stp222x_callout_signal(stp222x, ! 643: master_conn_index, ! 644: (TME_BUS_SIGNAL_BG ! 645: | TME_BUS_SIGNAL_EDGE ! 646: | TME_BUS_SIGNAL_LEVEL_NEGATED), ! 647: tme_stp22xx_complete_nop); ! 648: continue; ! 649: } ! 650: ! 651: /* we need the UPA bus if an I/O connection is requesting the bus, ! 652: or if we have an interrupt to dispatch, or if we have a ! 653: streaming cache to flush. if our UPA bus request line doesn't ! 654: reflect whether we need the UPA bus: */ ! 655: if (!stp222x->tme_stp222x_br ! 656: == (stp222x->tme_stp222x_io_brs != 0 ! 657: #if TME_STP222X_MDU_BUFFER_COUNT != 2 ! 658: #error "TME_STP222X_MDU_BUFFER_COUNT changed" ! 659: #endif ! 660: || (stp222x->tme_stp222x_mdu_dispatch_imr[0] != 0 /* !TME_STP222X_MDU_IMR_V */ ! 661: && stp222x->tme_stp222x_mdu_dispatch_state[0] == 0) /* TME_STP222X_MDU_DISPATCH_NOW */ ! 662: || (stp222x->tme_stp222x_mdu_dispatch_imr[1] != 0 /* !TME_STP222X_MDU_IMR_V */ ! 663: && stp222x->tme_stp222x_mdu_dispatch_state[1] == 0) /* TME_STP222X_MDU_DISPATCH_NOW */ ! 664: #if TME_STP222X_STC_COUNT != 2 ! 665: #error "TME_STP222X_STC_COUNT changed" ! 666: #endif ! 667: || stp222x->tme_stp222x_stcs[0].tme_stp222x_stc_pgflush ! 668: || stp222x->tme_stp222x_stcs[1].tme_stp222x_stc_pgflush ! 669: )) { ! 670: ! 671: /* assert or negate our bus request on the UPA bus: */ ! 672: _tme_stp222x_callout_signal(stp222x, ! 673: TME_STP222X_CONN_UPA, ! 674: (TME_BUS_SIGNAL_BR ! 675: | TME_BUS_SIGNAL_EDGE ! 676: | (stp222x->tme_stp222x_br ! 677: ? TME_BUS_SIGNAL_LEVEL_NEGATED ! 678: : TME_BUS_SIGNAL_LEVEL_ASSERTED)), ! 679: _tme_stp222x_complete_br); ! 680: continue; ! 681: } ! 682: ! 683: /* if we need to negate reset to another I/O connection: */ ! 684: reset_state = stp222x->tme_stp222x_reset_state; ! 685: if (reset_state > TME_STP222X_RESET_STATE_NEGATED ! 686: && reset_state < TME_STP222X_RESET_STATE_ASSERTED) { ! 687: ! 688: /* negate reset to the next I/O connection: */ ! 689: io_conn_index = reset_state - (TME_STP222X_RESET_STATE_NEGATED + 1); ! 690: _tme_stp222x_callout_signal(stp222x, ! 691: io_conn_index, ! 692: (TME_BUS_SIGNAL_RESET ! 693: | TME_BUS_SIGNAL_EDGE ! 694: | TME_BUS_SIGNAL_LEVEL_NEGATED), ! 695: _tme_stp222x_complete_reset); ! 696: continue; ! 697: } ! 698: ! 699: /* if we don't own the UPA bus: */ ! 700: if (!stp222x->tme_stp222x_bg) { ! 701: ! 702: /* stop now. we can't do anything else until we own the UPA ! 703: bus: */ ! 704: break; ! 705: } ! 706: ! 707: /* dispatch any interrupt: */ ! 708: if (tme_stp222x_mdu_dispatch(stp222x)) { ! 709: continue; ! 710: } ! 711: ! 712: /* flush any streaming cache: */ ! 713: if (tme_stp222x_stc_flush(stp222x)) { ! 714: continue; ! 715: } ! 716: ! 717: /* if one or more I/O connections are requesting the bus: */ ! 718: io_brs = stp222x->tme_stp222x_io_brs; ! 719: if (io_brs != 0) { ! 720: ! 721: /* get the connection index for the next master: */ ! 722: /* XXX FIXME - should we do something fair here? */ ! 723: for (master_conn_index = 0; ! 724: (io_brs & 1) == 0; ! 725: io_brs >>= 1, master_conn_index++); ! 726: ! 727: /* set the pending master: */ ! 728: stp222x->tme_stp222x_master_conn_index_pending = master_conn_index; ! 729: ! 730: /* assert bus grant to the current master: */ ! 731: _tme_stp222x_callout_signal(stp222x, ! 732: master_conn_index, ! 733: (TME_BUS_SIGNAL_BG ! 734: | TME_BUS_SIGNAL_EDGE ! 735: | TME_BUS_SIGNAL_LEVEL_ASSERTED), ! 736: _tme_stp222x_complete_bg); ! 737: continue; ! 738: } ! 739: ! 740: /* no other callouts are needed: */ ! 741: break; ! 742: } ! 743: } ! 744: ! 745: /* this handles a bus signal: */ ! 746: static void ! 747: _tme_stp222x_signal(struct tme_bus_connection *conn_bus, ! 748: unsigned int signal, ! 749: struct tme_completion *completion) ! 750: { ! 751: struct tme_stp222x *stp222x; ! 752: tme_uint32_t level; ! 753: tme_uint32_t io_conn_index; ! 754: tme_uint32_t br_mask; ! 755: tme_uint32_t idi; ! 756: ! 757: /* enter: */ ! 758: stp222x = tme_stp222x_enter_bus(conn_bus); ! 759: ! 760: /* get the level. this must be an edge: */ ! 761: assert (signal & TME_BUS_SIGNAL_EDGE); ! 762: level = signal - TME_BUS_SIGNAL_EDGE; ! 763: signal = TME_BUS_SIGNAL_WHICH(signal); ! 764: level ^= signal; ! 765: ! 766: /* if this bus signal is on the UPA connection: */ ! 767: if (conn_bus == stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus) { ! 768: ! 769: /* if this is the bus grant signal: */ ! 770: if (signal == TME_BUS_SIGNAL_BG) { ! 771: ! 772: /* mark our bus grant as either asserted or negated: */ ! 773: assert (level == TME_BUS_SIGNAL_LEVEL_NEGATED ! 774: || level == TME_BUS_SIGNAL_LEVEL_ASSERTED); ! 775: stp222x->tme_stp222x_bg = (level == TME_BUS_SIGNAL_LEVEL_ASSERTED); ! 776: } ! 777: ! 778: /* otherwise, this must be reset signal: */ ! 779: else { ! 780: assert (signal == TME_BUS_SIGNAL_RESET); ! 781: ! 782: /* update the level of the UPA reset signal: */ ! 783: stp222x->tme_stp222x_reset_level = level; ! 784: ! 785: /* if the UPA reset signal is asserted: */ ! 786: if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) { ! 787: ! 788: /* start asserting RESET on the I/O bus: */ ! 789: stp222x->tme_stp222x_reset_state = TME_STP222X_RESET_STATE_ASSERTING; ! 790: } ! 791: ! 792: /* otherwise, the UPA reset signal must be negated: */ ! 793: else { ! 794: assert (level == TME_BUS_SIGNAL_LEVEL_NEGATED); ! 795: ! 796: /* if RESET is currently asserted on the I/O bus, start ! 797: negating it: */ ! 798: assert (stp222x->tme_stp222x_reset_state >= TME_STP222X_RESET_STATE_ASSERTED); ! 799: if (stp222x->tme_stp222x_reset_state == TME_STP222X_RESET_STATE_ASSERTED) { ! 800: stp222x->tme_stp222x_reset_state = TME_STP222X_RESET_STATE_NEGATING; ! 801: } ! 802: } ! 803: } ! 804: } ! 805: ! 806: /* otherwise, this bus signal is on an I/O connection: */ ! 807: else { ! 808: ! 809: /* if this is the bus request signal: */ ! 810: if (signal == TME_BUS_SIGNAL_BR) { ! 811: ! 812: /* get this I/O connection's bus request mask: */ ! 813: io_conn_index = _tme_stp222x_io_conn_index(stp222x, conn_bus); ! 814: assert (io_conn_index < TME_STP222X_CONN_SLAVE0); ! 815: br_mask = (1 << io_conn_index); ! 816: ! 817: /* mark this caller's bus request line as either asserted or ! 818: negated: */ ! 819: assert (level == TME_BUS_SIGNAL_LEVEL_NEGATED ! 820: || level == TME_BUS_SIGNAL_LEVEL_ASSERTED); ! 821: stp222x->tme_stp222x_io_brs ! 822: = ((stp222x->tme_stp222x_io_brs ! 823: | br_mask) ! 824: & (level == TME_BUS_SIGNAL_LEVEL_ASSERTED ! 825: ? 0 ! 826: : ~br_mask)); ! 827: } ! 828: ! 829: /* otherwise, this must be an interrupt signal: */ ! 830: else { ! 831: assert (signal == TME_BUS_SIGNAL_INT_UNSPEC ! 832: || TME_BUS_SIGNAL_IS_INT(signal)); ! 833: ! 834: /* get the IDI: */ ! 835: idi = _tme_stp222x_io_idi(stp222x, conn_bus, signal); ! 836: ! 837: /* update the interrupt concentrator: */ ! 838: tme_stp222x_mdu_intcon(stp222x, idi, level); ! 839: } ! 840: } ! 841: ! 842: /* leave: */ ! 843: tme_stp222x_completion_validate(stp222x, completion); ! 844: tme_stp222x_leave(stp222x); ! 845: } ! 846: ! 847: /* this handles a bus cycle: */ ! 848: static void ! 849: _tme_stp222x_cycle(struct tme_bus_connection *master_conn_bus, ! 850: struct tme_bus_cycle *master_cycle, ! 851: tme_uint32_t *_master_fast_cycle_types, ! 852: struct tme_completion *master_completion) ! 853: { ! 854: struct tme_stp222x *stp222x; ! 855: tme_bus_addr64_t slave_address; ! 856: tme_uint32_t aspace_i; ! 857: unsigned int slave_conn_index; ! 858: tme_bus_addr32_t region_size_m1; ! 859: struct tme_stp222x_reg reg; ! 860: tme_uint32_t reggroup; ! 861: ! 862: /* enter: */ ! 863: stp222x = tme_stp222x_enter_master_bus(master_conn_bus); ! 864: ! 865: /* convert the master's address into an address space, slave ! 866: connection index and address: */ ! 867: slave_address = master_cycle->tme_bus_cycle_address; ! 868: aspace_i ! 869: = _tme_stp222x_lookup_address(stp222x, ! 870: slave_address, ! 871: ®ion_size_m1); ! 872: slave_address &= region_size_m1; ! 873: slave_conn_index ! 874: = (aspace_i == TME_STP222X_ASPACE_NULL ! 875: ? TME_STP222X_CONN_NULL ! 876: : tme_stp222x_aspace_lookup(stp222x, ! 877: aspace_i, ! 878: &slave_address)); ! 879: master_cycle->tme_bus_cycle_address = slave_address; ! 880: ! 881: /* dispatch on the address space: */ ! 882: switch (aspace_i) { ! 883: ! 884: case TME_STP2222_ASPACE_PCI_CONFIGURATION: ! 885: assert (!TME_STP222X_IS_2220(stp222x)); ! 886: #if 0 ! 887: master_cycle->tme_bus_cycle_type |= TME_PCI_CYCLE_CONFIGURATION; ! 888: #endif ! 889: abort(); ! 890: ! 891: case TME_STP2222_ASPACE_PCI_IO(0): ! 892: case TME_STP2222_ASPACE_PCI_IO(1): ! 893: assert (!TME_STP222X_IS_2220(stp222x)); ! 894: #if 0 ! 895: master_cycle->tme_bus_cycle_type |= TME_PCI_CYCLE_IO; ! 896: #endif ! 897: abort(); ! 898: ! 899: case TME_STP2220_ASPACE_SBUS: ! 900: assert (TME_STP222X_IS_2220(stp222x)); ! 901: break; ! 902: ! 903: default: ! 904: assert (!TME_STP222X_IS_2220(stp222x)); ! 905: assert (aspace_i == TME_STP2222_ASPACE_PCI_MEMORY(0) ! 906: || aspace_i == TME_STP2222_ASPACE_PCI_MEMORY(1)); ! 907: abort(); ! 908: ! 909: case TME_STP222X_ASPACE_NULL: ! 910: ! 911: /* if this isn't an aligned 64-bit access: */ ! 912: if (__tme_predict_false((slave_address % TME_STP222X_REG_SIZE) != 0 ! 913: || master_cycle->tme_bus_cycle_size != TME_STP222X_REG_SIZE)) { ! 914: abort(); ! 915: } ! 916: ! 917: /* NB: read the _tme_stp103x_bus_port() comment about bus routing ! 918: information coming out of the CPU: */ ! 919: /* replace the bus cycle routing information: */ ! 920: assert (TME_STP222X_REG_SIZE == (1 << TME_BUS64_LOG2)); ! 921: master_cycle->tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS64_LOG2); ! 922: master_cycle->tme_bus_cycle_lane_routing ! 923: = (_tme_stp222x_bus_router_regs ! 924: - TME_BUS_ROUTER_INDEX(TME_BUS64_LOG2, TME_BUS64_LOG2, 0)); ! 925: ! 926: /* set the register address, poisoning it if it's too big for the ! 927: structure: */ ! 928: reg.tme_stp222x_reg_address = slave_address; ! 929: if (reg.tme_stp222x_reg_address != slave_address) { ! 930: reg.tme_stp222x_reg_address = 0xffff; ! 931: } ! 932: ! 933: /* if this is a write: */ ! 934: reg.tme_stp222x_reg_write = (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE); ! 935: if (reg.tme_stp222x_reg_write) { ! 936: ! 937: /* get value being written: */ ! 938: tme_bus_cycle_xfer_memory(master_cycle, ! 939: ((tme_uint8_t *) ®.tme_stp222x_reg_value) - slave_address, ! 940: slave_address + sizeof(tme_uint64_t) - 1); ! 941: reg.tme_stp222x_reg_value = tme_betoh_u64(reg.tme_stp222x_reg_value); ! 942: } ! 943: ! 944: /* otherwise, this must be a read: */ ! 945: else if (__tme_predict_false(master_cycle->tme_bus_cycle_type != TME_BUS_CYCLE_READ)) { ! 946: abort(); ! 947: } ! 948: ! 949: /* assume that this register access won't be completed: */ ! 950: reg.tme_stp222x_reg_completed = FALSE; ! 951: ! 952: /* dispatch on the register group: */ ! 953: reggroup = TME_STP222X_REGGROUP_WHICH(reg.tme_stp222x_reg_address); ! 954: switch (reggroup) { ! 955: ! 956: case 0x00: ! 957: _tme_stp222x_reg00_regs(stp222x, ®); ! 958: break; ! 959: ! 960: case 0x01: ! 961: switch (TME_STP222X_REGGROUP_INDEX(reg.tme_stp222x_reg_address)) { ! 962: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG01_PM_CR): ! 963: abort(); ! 964: case TME_STP222X_REGGROUP_INDEX(TME_STP222X_REG01_PM_COUNT): ! 965: abort(); ! 966: default: ! 967: break; ! 968: } ! 969: break; ! 970: ! 971: case 0x24: ! 972: case 0x02: ! 973: if (reggroup ! 974: == (TME_STP222X_IS_2220(stp222x) ! 975: ? 0x24 ! 976: : 0x02)) { ! 977: tme_stp222x_iommu_regs(stp222x, ®); ! 978: } ! 979: break; ! 980: ! 981: case 0x2c: ! 982: case 0x0c: ! 983: case 0x30: ! 984: case 0x10: ! 985: case 0x1a: ! 986: case 0x60: ! 987: case 0x80: ! 988: tme_stp222x_mdu_regs_imr_retry(stp222x, ®); ! 989: break; ! 990: ! 991: case 0x20: ! 992: if (TME_STP222X_IS_2220(stp222x)) { ! 993: _tme_stp2220_sbus_regs(stp222x, ®); ! 994: } ! 995: break; ! 996: ! 997: case 0x34: ! 998: case 0x14: ! 999: case 0x38: ! 1000: case 0x18: ! 1001: tme_stp222x_mdu_regs_clear(stp222x, ®); ! 1002: break; ! 1003: ! 1004: case 0x3c: ! 1005: case 0x1c: ! 1006: if ((reggroup < 0x30) == !TME_STP222X_IS_2220(stp222x)) { ! 1007: tme_stp222x_timer_regs(stp222x, ®); ! 1008: } ! 1009: break; ! 1010: ! 1011: case 0x28: ! 1012: tme_stp222x_stc_regs(stp222x, 0, ®); ! 1013: break; ! 1014: ! 1015: case 0x40: ! 1016: abort(); ! 1017: ! 1018: case 0x48: ! 1019: if (TME_STP222X_IS_2220(stp222x)) { ! 1020: tme_stp222x_mdu_regs_diag(stp222x, ®); ! 1021: } ! 1022: else { ! 1023: tme_stp222x_stc_regs(stp222x, 1, ®); ! 1024: } ! 1025: break; ! 1026: ! 1027: case 0xa0: ! 1028: abort(); ! 1029: ! 1030: case 0x44: ! 1031: case 0x45: ! 1032: case 0x46: ! 1033: case 0xa4: ! 1034: case 0xa5: ! 1035: case 0xa6: ! 1036: if ((reggroup >= 0xa0) == !TME_STP222X_IS_2220(stp222x)) { ! 1037: tme_stp222x_iommu_regs_diag(stp222x, ®); ! 1038: } ! 1039: break; ! 1040: ! 1041: case 0xa8: ! 1042: if (!TME_STP222X_IS_2220(stp222x)) { ! 1043: tme_stp222x_mdu_regs_diag(stp222x, ®); ! 1044: } ! 1045: break; ! 1046: ! 1047: default: ! 1048: if (TME_STP222X_IS_2220(stp222x) ! 1049: ? (reggroup >= 0x50 ! 1050: && reggroup <= 0x59) ! 1051: : (reggroup >= 0xb0 ! 1052: && reggroup <= 0xb9)) { ! 1053: tme_stp222x_stc_regs_diag(stp222x, 0, ®); ! 1054: } ! 1055: else if (!TME_STP222X_IS_2220(stp222x) ! 1056: && reggroup >= 0xc0 ! 1057: && reggroup <= 0xc9) { ! 1058: tme_stp222x_stc_regs_diag(stp222x, 1, ®); ! 1059: } ! 1060: break; ! 1061: } ! 1062: ! 1063: /* if this register access was not completed: */ ! 1064: if (__tme_predict_false(!reg.tme_stp222x_reg_completed)) { ! 1065: ! 1066: tme_log(TME_STP222X_LOG_HANDLE(stp222x), 100, TME_OK, ! 1067: (TME_STP222X_LOG_HANDLE(stp222x), ! 1068: _("unknown[0x%04x] %s 0x%" TME_PRIx64), ! 1069: reg.tme_stp222x_reg_address, ! 1070: (reg.tme_stp222x_reg_write ! 1071: ? "<-" ! 1072: : "->"), ! 1073: reg.tme_stp222x_reg_value)); ! 1074: } ! 1075: ! 1076: /* if this was a read: */ ! 1077: if (!reg.tme_stp222x_reg_write) { ! 1078: ! 1079: /* return the value: */ ! 1080: reg.tme_stp222x_reg_value = tme_htobe_u64(reg.tme_stp222x_reg_value); ! 1081: tme_bus_cycle_xfer_memory(master_cycle, ! 1082: ((tme_uint8_t *) ®.tme_stp222x_reg_value) - slave_address, ! 1083: slave_address + sizeof(tme_uint64_t) - 1); ! 1084: } ! 1085: ! 1086: /* complete the cycle: */ ! 1087: master_completion->tme_completion_error = TME_OK; ! 1088: tme_stp222x_completion_validate(stp222x, master_completion); ! 1089: master_completion = NULL; ! 1090: *_master_fast_cycle_types = 0; ! 1091: break; ! 1092: } ! 1093: ! 1094: /* if we didn't complete the cycle ourselves: */ ! 1095: if (master_completion != NULL) { ! 1096: ! 1097: /* start this cycle: */ ! 1098: assert (stp222x->tme_stp222x_master_completion == NULL); ! 1099: stp222x->tme_stp222x_master_completion = &master_completion; ! 1100: ! 1101: /* run the slave bus cycle: */ ! 1102: tme_stp22xx_slave_cycle(master_conn_bus, ! 1103: slave_conn_index, ! 1104: master_cycle, ! 1105: _master_fast_cycle_types, ! 1106: &master_completion); ! 1107: } ! 1108: ! 1109: /* leave: */ ! 1110: tme_stp222x_leave(stp222x); ! 1111: } ! 1112: ! 1113: /* this receives an interrupt: */ ! 1114: static void ! 1115: _tme_stp222x_interrupt(struct tme_upa_bus_connection *master_conn_upa, ! 1116: tme_uint32_t slave_mid, ! 1117: const tme_uint64_t *data, ! 1118: struct tme_completion *master_completion) ! 1119: { ! 1120: abort(); ! 1121: } ! 1122: ! 1123: /* this fills a TLB entry: */ ! 1124: static void ! 1125: _tme_stp222x_tlb_fill(struct tme_bus_connection *agent_conn_bus, ! 1126: struct tme_bus_tlb *tlb, ! 1127: tme_bus_addr_t agent_address_wider, ! 1128: unsigned int cycle_type) ! 1129: { ! 1130: struct tme_stp222x *stp222x; ! 1131: tme_bus_addr64_t slave_address; ! 1132: tme_uint32_t aspace_i; ! 1133: tme_uint32_t slave_conn_index; ! 1134: tme_bus_addr32_t region_size_m1; ! 1135: tme_bus_addr64_t agent_address; ! 1136: struct tme_bus_tlb tlb_mapping; ! 1137: ! 1138: /* enter: */ ! 1139: stp222x = tme_stp222x_enter_bus(agent_conn_bus); ! 1140: ! 1141: /* convert the agent's address into an address space, slave ! 1142: connection index and address: */ ! 1143: slave_address = agent_address_wider; ! 1144: aspace_i ! 1145: = _tme_stp222x_lookup_address(stp222x, ! 1146: agent_address_wider, ! 1147: ®ion_size_m1); ! 1148: slave_address &= region_size_m1; ! 1149: slave_conn_index ! 1150: = (aspace_i == TME_STP222X_ASPACE_NULL ! 1151: ? TME_STP222X_CONN_NULL ! 1152: : tme_stp222x_aspace_lookup(stp222x, ! 1153: aspace_i, ! 1154: &slave_address)); ! 1155: ! 1156: /* fill this TLB entry: */ ! 1157: tme_stp22xx_tlb_fill(agent_conn_bus, ! 1158: tlb, ! 1159: slave_conn_index, ! 1160: slave_address, ! 1161: cycle_type); ! 1162: ! 1163: /* leave: */ ! 1164: tme_stp222x_leave(stp222x); ! 1165: ! 1166: /* map the filled TLB entry: */ ! 1167: agent_address = ~ (tme_bus_addr64_t) region_size_m1; ! 1168: agent_address &= agent_address_wider; ! 1169: tlb_mapping.tme_bus_tlb_addr_first = agent_address; ! 1170: agent_address |= region_size_m1; ! 1171: tlb_mapping.tme_bus_tlb_addr_last = agent_address; ! 1172: #if TME_STP22XX_BUS_TRANSITION ! 1173: tlb_mapping.tme_bus_tlb_cycles_ok = (TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE); ! 1174: #endif /* TME_STP22XX_BUS_TRANSITION */ ! 1175: tme_bus_tlb_map(tlb, slave_address, &tlb_mapping, agent_address_wider); ! 1176: } ! 1177: ! 1178: #if TME_STP22XX_BUS_TRANSITION ! 1179: ! 1180: /* this is the bus signal transition glue: */ ! 1181: static int ! 1182: _tme_stp222x_signal_transition(struct tme_bus_connection *conn_bus, ! 1183: unsigned int signal) ! 1184: { ! 1185: struct tme_completion completion_buffer; ! 1186: tme_completion_init(&completion_buffer); ! 1187: _tme_stp222x_signal(conn_bus, ! 1188: signal, ! 1189: &completion_buffer); ! 1190: return (TME_OK); ! 1191: } ! 1192: #define _tme_stp222x_signal _tme_stp222x_signal_transition ! 1193: ! 1194: /* this is the bus cycle transition glue: */ ! 1195: static int ! 1196: _tme_stp222x_cycle_transition(void *_master_conn_bus, ! 1197: struct tme_bus_cycle *master_cycle) ! 1198: { ! 1199: struct tme_completion completion_buffer; ! 1200: struct tme_stp222x *stp222x; ! 1201: struct tme_bus_connection *master_conn_bus; ! 1202: tme_uint32_t master_fast_cycle_types; ! 1203: ! 1204: tme_completion_init(&completion_buffer); ! 1205: ! 1206: master_conn_bus = (struct tme_bus_connection *) _master_conn_bus; ! 1207: stp222x = (struct tme_stp222x *) master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 1208: (master_conn_bus == stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus ! 1209: ? _tme_stp222x_cycle ! 1210: : tme_stp222x_iommu_cycle) ! 1211: (master_conn_bus, ! 1212: master_cycle, ! 1213: &master_fast_cycle_types, ! 1214: &completion_buffer); ! 1215: return (completion_buffer.tme_completion_error); ! 1216: } ! 1217: ! 1218: /* the bus TLB fill transition glue: */ ! 1219: static int ! 1220: _tme_stp222x_tlb_fill_transition(struct tme_bus_connection *agent_conn_bus, ! 1221: struct tme_bus_tlb *tlb, ! 1222: tme_bus_addr_t agent_address_wider, ! 1223: unsigned int cycle_type) ! 1224: { ! 1225: struct tme_stp222x *stp222x; ! 1226: ! 1227: stp222x = (struct tme_stp222x *) agent_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 1228: (agent_conn_bus == stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_bus ! 1229: ? _tme_stp222x_tlb_fill ! 1230: : tme_stp222x_iommu_tlb_fill) ! 1231: (agent_conn_bus, ! 1232: tlb, ! 1233: agent_address_wider, ! 1234: cycle_type); ! 1235: ! 1236: /* we always handle any slow cycles: */ ! 1237: tlb->tme_bus_tlb_cycles_ok |= cycle_type; ! 1238: tlb->tme_bus_tlb_addr_offset = 0; ! 1239: tlb->tme_bus_tlb_addr_shift = 0; ! 1240: tlb->tme_bus_tlb_cycle = _tme_stp222x_cycle_transition; ! 1241: tlb->tme_bus_tlb_cycle_private = agent_conn_bus; ! 1242: assert (tlb->tme_bus_tlb_fault_handler_count == 0); ! 1243: ! 1244: return (TME_OK); ! 1245: } ! 1246: #define _tme_stp222x_tlb_fill _tme_stp222x_tlb_fill_transition ! 1247: #define tme_stp222x_iommu_tlb_fill _tme_stp222x_tlb_fill_transition ! 1248: ! 1249: #endif /* TME_STP22XX_BUS_TRANSITION */ ! 1250: ! 1251: /* the connection scorer: */ ! 1252: static int ! 1253: _tme_stp222x_connection_score(struct tme_connection *conn, ! 1254: unsigned int *_score) ! 1255: { ! 1256: struct tme_bus_connection *conn_bus; ! 1257: struct tme_stp222x *stp222x; ! 1258: unsigned int score; ! 1259: struct tme_upa_bus_connection *conn_upa_other; ! 1260: struct tme_bus_connection *conn_bus_other; ! 1261: ! 1262: /* recover the bus connection: */ ! 1263: conn_bus = (struct tme_bus_connection *) conn; ! 1264: ! 1265: /* enter: */ ! 1266: stp222x = tme_stp222x_enter_bus(conn_bus); ! 1267: ! 1268: /* assume that this connection is useless: */ ! 1269: score = 0; ! 1270: ! 1271: /* dispatch on the connection type: */ ! 1272: conn_upa_other = (struct tme_upa_bus_connection *) conn->tme_connection_other; ! 1273: conn_bus_other = (struct tme_bus_connection *) conn->tme_connection_other; ! 1274: switch (conn->tme_connection_type) { ! 1275: ! 1276: /* this must be a UPA controller, and not another agent: */ ! 1277: case TME_CONNECTION_BUS_UPA: ! 1278: if (conn_upa_other->tme_upa_bus_connection.tme_bus_tlb_set_add != NULL ! 1279: && conn_upa_other->tme_upa_bus_interrupt != NULL) { ! 1280: score = 10; ! 1281: } ! 1282: break; ! 1283: ! 1284: /* this must be a bus device: */ ! 1285: case TME_CONNECTION_BUS_GENERIC: ! 1286: if (conn_bus_other->tme_bus_tlb_set_add == NULL) { ! 1287: score = 1; ! 1288: } ! 1289: break; ! 1290: ! 1291: default: abort(); ! 1292: } ! 1293: ! 1294: /* leave: */ ! 1295: tme_stp222x_leave(stp222x); ! 1296: *_score = score; ! 1297: return (TME_OK); ! 1298: } ! 1299: ! 1300: /* this makes a new connection: */ ! 1301: static int ! 1302: _tme_stp222x_connection_make(struct tme_connection *conn, unsigned int state) ! 1303: { ! 1304: struct tme_upa_bus_connection *conn_upa; ! 1305: struct tme_bus_connection *conn_bus; ! 1306: struct tme_stp222x *stp222x; ! 1307: unsigned int conn_index; ! 1308: tme_uint32_t slot; ! 1309: tme_bus_addr32_t offset; ! 1310: int slaveonly; ! 1311: tme_uint32_t connid; ! 1312: unsigned int obio_i; ! 1313: ! 1314: /* ignore a half-connection: */ ! 1315: if (state == TME_CONNECTION_HALF) { ! 1316: return (TME_OK); ! 1317: } ! 1318: ! 1319: /* recover the bus connection: */ ! 1320: conn_upa = (struct tme_upa_bus_connection *) conn; ! 1321: conn_bus = (struct tme_bus_connection *) conn; ! 1322: ! 1323: /* enter: */ ! 1324: stp222x = tme_stp222x_enter_bus(conn_bus); ! 1325: ! 1326: /* if this is the UPA bus connection: */ ! 1327: if (conn->tme_connection_type == TME_CONNECTION_BUS_UPA) { ! 1328: ! 1329: /* save the UPA bus connection: */ ! 1330: stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_upa = conn_upa; ! 1331: } ! 1332: ! 1333: /* otherwise, this is a device bus connection: */ ! 1334: else { ! 1335: ! 1336: /* if this is an stp2220: */ ! 1337: if (TME_STP222X_IS_2220(stp222x)) { ! 1338: ! 1339: /* split the temporary connection id into the slot, offset, and ! 1340: slaveonly flag: */ ! 1341: offset = conn->tme_connection_id; ! 1342: slot = (offset / TME_STP2220_SLOT_SIZE); ! 1343: offset %= TME_STP2220_SLOT_SIZE; ! 1344: slaveonly ! 1345: = (slot > TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD - 1) ! 1346: && slot < TME_STP2220_SLOT_OBIO(0)); ! 1347: if (slaveonly) { ! 1348: slot ^= TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD); ! 1349: } ! 1350: ! 1351: /* if this is a card: */ ! 1352: if (slot >= TME_STP2220_SLOT_CARD(0) ! 1353: && slot <= TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD - 1)) { ! 1354: ! 1355: /* start the card connection ID: */ ! 1356: connid = TME_STP222X_CONNID_TYPE_CARD; ! 1357: TME_FIELD_MASK_DEPOSITU(connid, ! 1358: TME_STP2220_CONNID_CARD_WHICH, ! 1359: (slot - TME_STP2220_SLOT_CARD(0))); ! 1360: TME_FIELD_MASK_DEPOSITU(connid, ! 1361: TME_STP2220_CONNID_CARD_OFFSET, ! 1362: offset); ! 1363: ! 1364: /* if this is a slave connection: */ ! 1365: if (slaveonly) { ! 1366: ! 1367: /* this connection will use the next slave connection index, ! 1368: which is an alternate connection index: */ ! 1369: conn_index = stp222x->tme_stp222x_slave_conn_index_next++; ! 1370: connid |= TME_STP2220_CONNID_CARD_ALTERNATE; ! 1371: } ! 1372: ! 1373: else { ! 1374: ! 1375: /* assume that this is the first master connection for this ! 1376: card, which will use the card's primary master connection ! 1377: index: */ ! 1378: conn_index = TME_FIELD_MASK_EXTRACTU(connid, TME_STP2220_CONNID_CARD_WHICH); ! 1379: ! 1380: /* if this is not the first master connection for this card: */ ! 1381: if (stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != NULL) { ! 1382: ! 1383: /* this connection will use an alternate master connection ! 1384: index: */ ! 1385: connid |= TME_STP2220_CONNID_CARD_ALTERNATE; ! 1386: ! 1387: /* starting from the first alternate master connection ! 1388: index for this card and moving forward, search the ! 1389: remaining master connection indices for a free one: */ ! 1390: /* NB: this means if you have an SBus card with a lot of ! 1391: different masters on it, you should put it in the last ! 1392: card slot, to save the preferred alternate master ! 1393: connection indices for the other card slots: */ ! 1394: conn_index ! 1395: = (TME_STP2220_SLOTS_CARD ! 1396: + (connid & TME_STP2220_CONNID_CARD_WHICH)); ! 1397: for (; stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != NULL;) { ! 1398: if (++conn_index == TME_STP222X_CONN_SLAVE0) { ! 1399: abort(); ! 1400: } ! 1401: } ! 1402: } ! 1403: } ! 1404: } ! 1405: ! 1406: /* otherwise, this is an obio device: */ ! 1407: else { ! 1408: ! 1409: /* if this is the slave I/O slot, force slaveonly: */ ! 1410: if (slot == TME_STP2220_SLOT_SLAVIO) { ! 1411: slaveonly = TRUE; ! 1412: } ! 1413: ! 1414: /* if this is a slave connection: */ ! 1415: if (slaveonly) { ! 1416: ! 1417: /* this connection will use the next slave connection index: */ ! 1418: conn_index = stp222x->tme_stp222x_slave_conn_index_next++; ! 1419: } ! 1420: ! 1421: /* otherwise, this is a master connection: */ ! 1422: else { ! 1423: ! 1424: /* starting from the last master connection index and ! 1425: moving backwards, search for a free one: */ ! 1426: conn_index = TME_STP222X_CONN_SLAVE0 - 1; ! 1427: for (; stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus != NULL;) { ! 1428: if (conn_index-- == 0) { ! 1429: abort(); ! 1430: } ! 1431: } ! 1432: } ! 1433: ! 1434: /* assume that this is not a known obio connection, and make ! 1435: the obio long connection id: */ ! 1436: connid ! 1437: = (TME_STP222X_CONNID_TYPE_OBIO ! 1438: | TME_STP222X_CONNID_OBIO_TYPE_LONG); ! 1439: TME_FIELD_MASK_DEPOSITU(connid, ! 1440: TME_STP222X_CONNID_OBIO_LONG_WHICH, ! 1441: (slot - TME_STP2220_SLOT_OBIO(0))); ! 1442: TME_FIELD_MASK_DEPOSITU(connid, ! 1443: TME_STP222X_CONNID_OBIO_LONG_OFFSET, ! 1444: offset); ! 1445: ! 1446: /* if this is a known obio connection: */ ! 1447: for (obio_i = 0; obio_i < TME_ARRAY_ELS(_tme_stp2220_obios); obio_i++) { ! 1448: if (_tme_stp2220_obios[obio_i]._tme_stp2220_obio_slot == slot ! 1449: && _tme_stp2220_obios[obio_i]._tme_stp2220_obio_offset == offset) { ! 1450: ! 1451: /* make the obio short connection id: */ ! 1452: connid ! 1453: = (TME_STP222X_CONNID_TYPE_OBIO ! 1454: | TME_STP222X_CONNID_OBIO_TYPE_SHORT); ! 1455: TME_FIELD_MASK_DEPOSITU(connid, ! 1456: TME_STP222X_CONNID_OBIO_SHORT_IDI, ! 1457: _tme_stp2220_obios[obio_i]._tme_stp2220_obio_idi); ! 1458: TME_FIELD_MASK_DEPOSITU(connid, ! 1459: TME_STP222X_CONNID_OBIO_SHORT_CONN_WHICH, ! 1460: conn_index); ! 1461: break; ! 1462: } ! 1463: } ! 1464: } ! 1465: ! 1466: /* save the SBus offset for this connection: */ ! 1467: assert (conn_index < TME_STP222X_CONN_NULL); ! 1468: stp222x->tme_stp2220_conn_offset[conn_index] = TME_STP2220_SBUS_ADDRESS(slot, offset); ! 1469: } ! 1470: ! 1471: /* otherwise, this is an stp222x: */ ! 1472: else { ! 1473: abort(); ! 1474: } ! 1475: ! 1476: /* update this connection's id: */ ! 1477: conn->tme_connection_id = connid; ! 1478: ! 1479: /* add this connection to the list: */ ! 1480: assert (conn_index < TME_STP222X_CONN_NULL); ! 1481: if (conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC) { ! 1482: assert (TME_STP222X_IS_2220(stp222x)); ! 1483: stp222x->tme_stp222x.tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus = conn_bus; ! 1484: } ! 1485: else { ! 1486: assert (FALSE); ! 1487: } ! 1488: ! 1489: /* rebuild the address spaces: */ ! 1490: if (tme_stp222x_aspaces_rebuild(stp222x)) { ! 1491: abort(); ! 1492: } ! 1493: } ! 1494: ! 1495: /* leave: */ ! 1496: tme_stp222x_leave(stp222x); ! 1497: return (TME_OK); ! 1498: } ! 1499: ! 1500: /* this breaks a connection: */ ! 1501: static int ! 1502: _tme_stp222x_connection_break(struct tme_connection *conn, unsigned int state) ! 1503: { ! 1504: abort(); ! 1505: } ! 1506: ! 1507: /* this makes new connection sides: */ ! 1508: static int ! 1509: _tme_stp222x_connections_new(struct tme_element *element, ! 1510: const char * const *args, ! 1511: struct tme_connection **_conns, ! 1512: char **_output) ! 1513: { ! 1514: int rc; ! 1515: struct tme_stp222x *stp222x; ! 1516: struct tme_upa_bus_connection *conn_upa; ! 1517: struct tme_bus_connection *conn_bus; ! 1518: struct tme_connection *conn; ! 1519: tme_bus_addr_t slot_wider; ! 1520: tme_bus_addr_t offset_wider; ! 1521: int slaveonly; ! 1522: ! 1523: /* assume that we will succeed: */ ! 1524: rc = TME_OK; ! 1525: ! 1526: /* recover our data structure: */ ! 1527: stp222x = (struct tme_stp222x *) element->tme_element_private; ! 1528: ! 1529: /* lock the mutex: */ ! 1530: tme_mutex_lock(&stp222x->tme_stp222x.tme_stp22xx_mutex); ! 1531: ! 1532: /* if we have no arguments, this is the UPA connection: */ ! 1533: if (args[1] == NULL) { ! 1534: ! 1535: /* if we already have the UPA connection: */ ! 1536: if (stp222x->tme_stp222x.tme_stp22xx_conns[TME_STP222X_CONN_UPA].tme_stp22xx_conn_upa != NULL) { ! 1537: rc = EEXIST; ! 1538: } ! 1539: ! 1540: /* otherwise, we don't have a UPA connection yet: */ ! 1541: else { ! 1542: ! 1543: /* create a UPA connection: */ ! 1544: conn_upa = tme_new0(struct tme_upa_bus_connection, 1); ! 1545: conn_upa->tme_upa_bus_connection.tme_bus_connection.tme_connection_type = TME_CONNECTION_BUS_UPA; ! 1546: conn_upa->tme_upa_bus_interrupt = _tme_stp222x_interrupt; ! 1547: ! 1548: /* fill in the generic bus connection: */ ! 1549: conn_bus = &conn_upa->tme_upa_bus_connection; ! 1550: conn_bus->tme_bus_signals_add = NULL; ! 1551: conn_bus->tme_bus_signal = _tme_stp222x_signal; ! 1552: conn_bus->tme_bus_intack = NULL; ! 1553: conn_bus->tme_bus_tlb_set_add = NULL; ! 1554: conn_bus->tme_bus_tlb_fill = _tme_stp222x_tlb_fill; ! 1555: ! 1556: /* fill in the generic connection: */ ! 1557: conn = &conn_bus->tme_bus_connection; ! 1558: conn->tme_connection_score = _tme_stp222x_connection_score; ! 1559: conn->tme_connection_make = _tme_stp222x_connection_make; ! 1560: conn->tme_connection_break = _tme_stp222x_connection_break; ! 1561: ! 1562: /* add in this connection side possibility: */ ! 1563: conn->tme_connection_next = *_conns; ! 1564: *_conns = conn; ! 1565: } ! 1566: } ! 1567: ! 1568: /* otherwise, if this is an stp2220 and we have "slot" and "offset" ! 1569: arguments, and an optional "slaveonly" argument, this is an SBus ! 1570: connection: */ ! 1571: else if (TME_STP222X_IS_2220(stp222x) ! 1572: && TME_ARG_IS(args[1], "slot") ! 1573: && args[2] != NULL ! 1574: && TME_ARG_IS(args[3], "offset") ! 1575: && args[4] != NULL ! 1576: && (((slaveonly = TME_ARG_IS(args[5], "slaveonly")) ! 1577: && args[6] == NULL) ! 1578: || args[5] == NULL)) { ! 1579: ! 1580: /* convert the slot and base offset: */ ! 1581: slot_wider = tme_bus_addr_parse(args[2], TME_STP2220_SLOT_OBIO(TME_STP2220_SLOTS_OBIO)); ! 1582: offset_wider = tme_bus_addr_parse(args[4], TME_STP2220_SLOT_SIZE); ! 1583: ! 1584: /* if this is a bad slot: */ ! 1585: if ((slot_wider < TME_STP2220_SLOT_CARD(0) ! 1586: || slot_wider > TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD - 1)) ! 1587: && (slot_wider < TME_STP2220_SLOT_OBIO(0) ! 1588: || slot_wider > TME_STP2220_SLOT_OBIO(TME_STP2220_SLOTS_OBIO - 1))) { ! 1589: tme_output_append_error(_output, ! 1590: "%s %s", ! 1591: _("bad slot"), ! 1592: args[2]); ! 1593: rc = EINVAL; ! 1594: } ! 1595: ! 1596: /* if this is a bad offset: */ ! 1597: else if (offset_wider >= TME_STP2220_SLOT_SIZE) { ! 1598: tme_output_append_error(_output, ! 1599: "%s %s", ! 1600: _("bad offset"), ! 1601: args[4]); ! 1602: rc = EINVAL; ! 1603: } ! 1604: ! 1605: /* otherwise, the arguments are ok: */ ! 1606: else { ! 1607: ! 1608: /* create a generic bus connection: */ ! 1609: conn_bus = tme_new0(struct tme_bus_connection, 1); ! 1610: conn_bus->tme_bus_connection.tme_connection_type = TME_CONNECTION_BUS_GENERIC; ! 1611: ! 1612: /* fill in the generic bus connection: */ ! 1613: conn_bus->tme_bus_signals_add = NULL; ! 1614: conn_bus->tme_bus_signal = _tme_stp222x_signal; ! 1615: conn_bus->tme_bus_intack = NULL; ! 1616: conn_bus->tme_bus_tlb_set_add = tme_stp22xx_tlb_set_add; ! 1617: conn_bus->tme_bus_tlb_fill = tme_stp222x_iommu_tlb_fill; ! 1618: ! 1619: /* fill in the generic connection: */ ! 1620: /* NB: this connection's temporary id is the SBus address, with ! 1621: the slot exclusive-ORed with the maximum number of cards if ! 1622: the "slaveonly" flag was given: */ ! 1623: conn = &conn_bus->tme_bus_connection; ! 1624: conn->tme_connection_id ! 1625: = TME_STP2220_SBUS_ADDRESS((slot_wider ! 1626: ^ (slaveonly ! 1627: ? TME_STP2220_SLOT_CARD(TME_STP2220_SLOTS_CARD) ! 1628: : 0)), ! 1629: offset_wider); ! 1630: conn->tme_connection_score = _tme_stp222x_connection_score; ! 1631: conn->tme_connection_make = _tme_stp222x_connection_make; ! 1632: conn->tme_connection_break = _tme_stp222x_connection_break; ! 1633: ! 1634: /* add in this connection side possibility: */ ! 1635: conn->tme_connection_next = *_conns; ! 1636: *_conns = conn; ! 1637: } ! 1638: } ! 1639: ! 1640: /* otherwise, the arguments are unknown: */ ! 1641: else { ! 1642: if (TME_STP222X_IS_2220(stp222x)) { ! 1643: tme_output_append_error(_output, ! 1644: "%s %s [ slot %s offset %s [ slaveonly ] ]", ! 1645: _("usage:"), ! 1646: args[0], ! 1647: _("SLOT"), ! 1648: _("OFFSET")); ! 1649: } ! 1650: rc = EINVAL; ! 1651: } ! 1652: ! 1653: /* unlock the mutex: */ ! 1654: tme_mutex_unlock(&stp222x->tme_stp222x.tme_stp22xx_mutex); ! 1655: ! 1656: return (rc); ! 1657: } ! 1658: ! 1659: /* this creates a new stp222x element: */ ! 1660: static int ! 1661: _tme_stp222x_new(struct tme_element *element, ! 1662: const char * const *args, ! 1663: const void *extra, ! 1664: char **_output, ! 1665: unsigned int is_2220) ! 1666: { ! 1667: struct tme_stp222x *stp222x; ! 1668: int arg_i; ! 1669: int usage; ! 1670: ! 1671: /* check our arguments: */ ! 1672: usage = 0; ! 1673: arg_i = 1; ! 1674: for (;;) { ! 1675: ! 1676: if (0) { ! 1677: } ! 1678: ! 1679: /* if we ran out of arguments: */ ! 1680: else if (args[arg_i] == NULL) { ! 1681: ! 1682: break; ! 1683: } ! 1684: ! 1685: /* otherwise this is a bad argument: */ ! 1686: else { ! 1687: tme_output_append_error(_output, ! 1688: "%s %s, ", ! 1689: args[arg_i], ! 1690: _("unexpected")); ! 1691: usage = TRUE; ! 1692: break; ! 1693: } ! 1694: } ! 1695: ! 1696: if (usage) { ! 1697: tme_output_append_error(_output, ! 1698: "%s %s", ! 1699: _("usage:"), ! 1700: args[0]); ! 1701: return (EINVAL); ! 1702: } ! 1703: ! 1704: /* start the stp222x structure: */ ! 1705: stp222x = tme_new0(struct tme_stp222x, 1); ! 1706: stp222x->tme_stp222x.tme_stp22xx_element = element; ! 1707: stp222x->tme_stp222x.tme_stp22xx_run = _tme_stp222x_run; ! 1708: tme_stp22xx_init(&stp222x->tme_stp222x, ! 1709: sizeof(struct tme_stp222x), ! 1710: TME_STP222X_CONN_NULL); ! 1711: ! 1712: /* set the type: */ ! 1713: stp222x->tme_stp222x_is_2220 = is_2220; ! 1714: if (TME_STP222X_IS_2220(stp222x) != is_2220) { ! 1715: tme_free(stp222x); ! 1716: return (ENXIO); ! 1717: } ! 1718: ! 1719: /* the UPA bus reset signal is initially negated: */ ! 1720: stp222x->tme_stp222x_reset_level = TME_BUS_SIGNAL_LEVEL_NEGATED; ! 1721: ! 1722: /* initialize the CSR: */ ! 1723: stp222x->tme_stp222x_csr ! 1724: = (0x1f * _TME_FIELD_MASK_FACTOR(TME_STP222X_CSR_MID)); ! 1725: ! 1726: /* initialize the miscellaneous registers: */ ! 1727: stp222x->tme_stp222x_upa_port_config = 1; ! 1728: ! 1729: /* initialize the connections: */ ! 1730: stp222x->tme_stp222x_slave_conn_index_next = TME_STP222X_CONN_SLAVE0; ! 1731: ! 1732: /* initialize the timers: */ ! 1733: tme_stp222x_timer_init(stp222x, &stp222x->tme_stp222x_timers[0]); ! 1734: tme_stp222x_timer_init(stp222x, &stp222x->tme_stp222x_timers[1]); ! 1735: ! 1736: /* initialize the MDU: */ ! 1737: tme_stp222x_mdu_init(stp222x); ! 1738: ! 1739: /* initialize the IOMMU: */ ! 1740: tme_stp222x_iommu_init(stp222x); ! 1741: ! 1742: /* initialize the streaming caches: */ ! 1743: tme_stp222x_stc_init(&stp222x->tme_stp222x_stcs[0]); ! 1744: tme_stp222x_stc_init(&stp222x->tme_stp222x_stcs[1]); ! 1745: ! 1746: /* fill the element: */ ! 1747: element->tme_element_private = stp222x; ! 1748: element->tme_element_connections_new = _tme_stp222x_connections_new; ! 1749: ! 1750: return (TME_OK); ! 1751: } ! 1752: ! 1753: /* this creates a new stp2220 element: */ ! 1754: TME_ELEMENT_X_NEW_DECL(tme_ic_,stp22xx,stp2220) { ! 1755: return (_tme_stp222x_new(element, args, extra, _output, TRUE)); ! 1756: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.