Annotation of tme/ic/stp22xx/stp222x-main.c, revision 1.1

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:                                  &region_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 *) &reg.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, &reg);
        !           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, &reg);
        !           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, &reg);
        !           989:       break;
        !           990: 
        !           991:     case 0x20:
        !           992:       if (TME_STP222X_IS_2220(stp222x)) {
        !           993:        _tme_stp2220_sbus_regs(stp222x, &reg);
        !           994:       }
        !           995:       break;
        !           996: 
        !           997:     case 0x34:
        !           998:     case 0x14:
        !           999:     case 0x38:
        !          1000:     case 0x18:
        !          1001:       tme_stp222x_mdu_regs_clear(stp222x, &reg);
        !          1002:       break;
        !          1003: 
        !          1004:     case 0x3c:
        !          1005:     case 0x1c:
        !          1006:       if ((reggroup < 0x30) == !TME_STP222X_IS_2220(stp222x)) {
        !          1007:        tme_stp222x_timer_regs(stp222x, &reg);
        !          1008:       }
        !          1009:       break;
        !          1010: 
        !          1011:     case 0x28:
        !          1012:       tme_stp222x_stc_regs(stp222x, 0, &reg);
        !          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, &reg);
        !          1021:       }
        !          1022:       else {
        !          1023:        tme_stp222x_stc_regs(stp222x, 1, &reg);
        !          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, &reg);
        !          1038:       }
        !          1039:       break;
        !          1040: 
        !          1041:     case 0xa8:
        !          1042:       if (!TME_STP222X_IS_2220(stp222x)) {
        !          1043:        tme_stp222x_mdu_regs_diag(stp222x, &reg);
        !          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, &reg);
        !          1054:       }
        !          1055:       else if (!TME_STP222X_IS_2220(stp222x)
        !          1056:               && reggroup >= 0xc0
        !          1057:               && reggroup <= 0xc9) {
        !          1058:        tme_stp222x_stc_regs_diag(stp222x, 1, &reg);
        !          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 *) &reg.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:                                  &region_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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.