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

1.1     ! root        1: /* $Id: stp222x-mdu.c,v 1.5 2010/06/05 18:59:29 fredette Exp $ */
        !             2: 
        !             3: /* ic/stp222x-mdu.c - emulation of the Mondo Dispatch Unit of the UPA
        !             4:    to SBus interface controller (STP2220) and the UPA to PCI interface
        !             5:    controller (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-mdu.c,v 1.5 2010/06/05 18:59:29 fredette Exp $");
        !            40: 
        !            41: /* includes: */
        !            42: #include "stp222x-impl.h"
        !            43: 
        !            44: /* macros: */
        !            45: 
        !            46: /* an interrupt mapping register: */
        !            47: #define TME_STP222X_MDU_IMR_INR                        ((2 << 10) - (1 << 0))
        !            48: #define TME_STP222X_MDU_IMR_TID                        ((2 << 30) - (tme_uint32_t) (1 << 26))
        !            49: #define TME_STP222X_MDU_IMR_V                  TME_BIT(31)
        !            50: 
        !            51: /* interrupt states: */
        !            52: #define TME_STP222X_MDU_STATE_IDLE             (0)
        !            53: #define TME_STP222X_MDU_STATE_RECEIVED         (1)
        !            54: #define TME_STP222X_MDU_STATE_PENDING          (3)
        !            55: 
        !            56: /* the interrupt retry timer register: */
        !            57: #define TME_STP222X_MDU_RETRY_TIMER_LIMIT      ((2 << 19) - (1 << 0))
        !            58: 
        !            59: /* dispatch states: */
        !            60: #define TME_STP222X_MDU_DISPATCH_NOW           (0)
        !            61: #define TME_STP222X_MDU_DISPATCH_RETRY(n)      (1 + (n))
        !            62: 
        !            63: /* priorities: */
        !            64: #define TME_STP222X_MDU_PRIORITY_NULL          (9)
        !            65: 
        !            66: /* this updates an IDI's bit in the received or pending sets: */
        !            67: #define TME_STP222X_MDU_IDIS_UPDATE(field, op, idi)    \
        !            68:   do {                                                 \
        !            69:     field[(idi)                                                \
        !            70:          / (sizeof(tme_stp222x_idis_t) * 8)]           \
        !            71:       op (((tme_stp222x_idis_t) 1)                     \
        !            72:           << ((idi)                                    \
        !            73:              % (sizeof(tme_stp222x_idis_t) * 8)));     \
        !            74:   } while (/* CONSTCOND */ 0)
        !            75: 
        !            76: /* this tests an IDI's bit in an IDI set: */
        !            77: #define TME_STP222X_MDU_IDI_TEST(field, idi)           \
        !            78:   (field[(idi)                                         \
        !            79:         / (sizeof(tme_stp222x_idis_t) * 8)]            \
        !            80:    & (((tme_stp222x_idis_t) 1)                         \
        !            81:       << ((idi)                                                \
        !            82:          % (sizeof(tme_stp222x_idis_t) * 8))))
        !            83: 
        !            84: /* globals: */
        !            85: 
        !            86: /* the stp2220 obio interrupt priorities: */
        !            87: static const tme_uint8_t _tme_stp2220_mdu_idi_obio_priority[] = {
        !            88:   /* TME_STP222X_IDI_SCSI */           3,
        !            89:   /* TME_STP222X_IDI_ETHER */          3,
        !            90:   /* TME_STP222X_IDI_BPP */            2,
        !            91:   /* TME_STP2220_IDI_AUDIO */          8,
        !            92:   /* TME_STP2220_IDI_POWER */          8,
        !            93:   /* TME_STP2220_IDI_ZS0_ZS1 */        7,
        !            94:   /* TME_STP2220_IDI_FD */             8,
        !            95:   /* TME_STP2220_IDI_THERM */          8,
        !            96:   /* TME_STP2220_IDI_KBD */            4,
        !            97:   /* TME_STP2220_IDI_MOUSE */          4,
        !            98:   /* TME_STP2220_IDI_SERIAL */         7,
        !            99:   /* TME_STP2220_IDI_TIMER(0) */       6,
        !           100:   /* TME_STP2220_IDI_TIMER(1) */       6,
        !           101:   /* TME_STP2220_IDI_UE */             8,
        !           102:   /* TME_STP2220_IDI_CE */             8,
        !           103:   /* TME_STP2220_IDI_SBUS_ASYNC */     8,
        !           104:   /* TME_STP2220_IDI_POWER_MANAGE */   1,
        !           105:   /* TME_STP2220_IDI_UPA */            5,
        !           106:   /* TME_STP2220_IDI_RESERVED */       5,
        !           107: };
        !           108: 
        !           109: /* this maps a register group index into an IDI for an obio
        !           110:    interrupt: */
        !           111: static tme_uint32_t
        !           112: _tme_stp222x_reggroup_index_to_obio_idi(struct tme_stp222x *stp222x, 
        !           113:                                        tme_uint32_t reggroup_index)
        !           114: {
        !           115:   tme_uint32_t idi;
        !           116: 
        !           117:   /* assume that the register group index maps directly to IDI: */
        !           118:   idi = TME_STP222X_IDI0_OBIO + reggroup_index;
        !           119: 
        !           120:   /* if this is an stp2220: */
        !           121:   if (TME_STP222X_IS_2220(stp222x)) {
        !           122: 
        !           123:     /* there is a one-register gap before the first timer interrupt: */
        !           124:     if (idi > TME_STP2220_IDI_TIMER(0)) {
        !           125:       idi--;
        !           126:     }
        !           127:   }
        !           128: 
        !           129:   return (idi);
        !           130: }
        !           131: 
        !           132: /* the stp222x interrupt retry thread: */
        !           133: static void
        !           134: _tme_stp222x_mdu_retry_th(void *_stp222x)
        !           135: {
        !           136:   struct tme_stp222x *stp222x;
        !           137:   struct timeval *sleep;
        !           138:   signed long buffer_i;
        !           139:   unsigned int dispatch_state;
        !           140: 
        !           141:   /* recover our data structures: */
        !           142:   stp222x = (struct tme_stp222x *) _stp222x;
        !           143: 
        !           144:   /* enter: */
        !           145:   tme_stp22xx_enter(&stp222x->tme_stp222x);
        !           146: 
        !           147:   /* loop forever: */
        !           148:   for (;;) {
        !           149: 
        !           150:     /* assume that we can block forever: */
        !           151:     sleep = NULL;
        !           152: 
        !           153:     /* loop over the dispatch buffers: */
        !           154:     buffer_i = TME_STP222X_MDU_BUFFER_COUNT - 1;
        !           155:     do {
        !           156: 
        !           157:       /* if this dispatch buffer is valid: */
        !           158:       if (stp222x->tme_stp222x_mdu_dispatch_imr[buffer_i] != !TME_STP222X_MDU_IMR_V) {
        !           159: 
        !           160:        /* if this dispatch buffer is retrying: */
        !           161:        dispatch_state = stp222x->tme_stp222x_mdu_dispatch_state[buffer_i];
        !           162:        if (dispatch_state != TME_STP222X_MDU_DISPATCH_NOW) {
        !           163: 
        !           164:          /* NB: we sleep three times for each buffer before retrying
        !           165:             it.  since the sleep time is half of the retry interval,
        !           166:             this means that the maximum delay is one a half times the
        !           167:             retry interval, which is the expected value of the delay.
        !           168:             the minimum delay is exactly the retry interval, and this
        !           169:             happens only on the stp2222, when the other buffer needs
        !           170:             a retry right at the beginning of one of the sleeps for
        !           171:             this buffer.
        !           172: 
        !           173:             it's impossible for more than one of the three sleeps a
        !           174:             buffer does to be interrupted in this way, because there
        !           175:             is not more than one other buffer: */
        !           176: 
        !           177:          /* if this dispatch buffer has slept three times: */
        !           178:          if (dispatch_state == TME_STP222X_MDU_DISPATCH_RETRY(3)) {
        !           179: 
        !           180:            /* it's time to try this buffer again: */
        !           181:            dispatch_state = TME_STP222X_MDU_DISPATCH_NOW;
        !           182:          }
        !           183: 
        !           184:          /* otherwise, we need to sleep for this buffer: */
        !           185:          else {
        !           186: 
        !           187:            /* advance the retry state: */
        !           188:            dispatch_state++;
        !           189: 
        !           190:            /* sleep: */
        !           191:            sleep = &stp222x->tme_stp222x_mdu_retry_sleep;
        !           192:          }
        !           193: 
        !           194:          /* update this buffer's dispatch state: */
        !           195:          stp222x->tme_stp222x_mdu_dispatch_state[buffer_i] = dispatch_state;
        !           196:        }
        !           197:       }
        !           198:     } while (--buffer_i >= 0);
        !           199: 
        !           200:     /* block: */
        !           201:     tme_stp22xx_cond_sleep_yield(&stp222x->tme_stp222x,
        !           202:                                 &stp222x->tme_stp222x_mdu_retry_cond,
        !           203:                                 sleep);
        !           204:   }
        !           205:   /* NOTREACHED */
        !           206: }
        !           207: 
        !           208: /* this decodes and arbitrates interrupts: */
        !           209: static void
        !           210: _tme_stp222x_mdu_decode_arbitrate(struct tme_stp222x *stp222x)
        !           211: {
        !           212:   signed long buffer_i;
        !           213:   tme_uint32_t chosen_idi[2];
        !           214:   tme_uint32_t chosen_imr[2];
        !           215:   unsigned int chosen_priority[2];
        !           216:   signed long idis_i;
        !           217:   tme_stp222x_idis_t idis_arbitrate;
        !           218:   tme_uint32_t idi;
        !           219:   tme_uint32_t imr;
        !           220:   unsigned int priority;
        !           221: 
        !           222:   /* start with no chosen interrupts for any CPU buffer, but poison
        !           223:      any full CPU buffer with an impossibly high priority, to avoid
        !           224:      overwriting a dispatching interrupt: */
        !           225:   buffer_i = TME_STP222X_MDU_BUFFER_COUNT - 1;
        !           226:   do {
        !           227:     chosen_idi[buffer_i] = TME_STP222X_IDI_NULL;
        !           228:     chosen_imr[buffer_i] = !TME_STP222X_MDU_IMR_V;
        !           229:     chosen_priority[buffer_i]
        !           230:       = (stp222x->tme_stp222x_mdu_dispatch_imr[buffer_i] == !TME_STP222X_MDU_IMR_V
        !           231:         ? 0
        !           232:         : TME_STP222X_MDU_PRIORITY_NULL);
        !           233:   } while (--buffer_i >= 0);
        !           234: 
        !           235:   /* loop over sets of IDIs: */
        !           236:   idis_i = TME_ARRAY_ELS(stp222x->tme_stp222x_mdu_idis_received) - 1;
        !           237:   do {
        !           238: 
        !           239:     /* get another set of IDIs that have been received, but are not
        !           240:        pending: */
        !           241:     idis_arbitrate
        !           242:       = (stp222x->tme_stp222x_mdu_idis_received[idis_i]
        !           243:         & ~stp222x->tme_stp222x_mdu_idis_pending[idis_i]);
        !           244:     if (idis_arbitrate != 0) {
        !           245: 
        !           246:       /* loop over the IDIs in this set: */
        !           247:       idi = idis_i * (sizeof(idis_arbitrate) * 8);
        !           248:       do {
        !           249:        for (; (idis_arbitrate & 1) == 0; idi++, idis_arbitrate >>=1);
        !           250: 
        !           251:        /* get the IMR for this IDI: */
        !           252:        imr = stp222x->tme_stp222x_mdu_imrs[idi];
        !           253: 
        !           254:        /* if this IMR is valid: */
        !           255:        if (imr & TME_STP222X_MDU_IMR_V) {
        !           256: 
        !           257:          /* if this is an stp2220: */
        !           258:          if (TME_STP222X_IS_2220(stp222x)) {
        !           259: 
        !           260:            /* if this is a card IDI: */
        !           261:            if (idi < TME_STP222X_IDI0_OBIO) {
        !           262: 
        !           263:              /* the SBus priority is our priority: */
        !           264:              priority = idi % TME_SBUS_SLOT_INTS;
        !           265:            }
        !           266: 
        !           267:            /* otherwise, this is an obio IDI: */
        !           268:            else {
        !           269: 
        !           270:              /* get the priority for this obio IDI: */
        !           271:              assert ((idi - TME_STP222X_IDI0_OBIO)
        !           272:                      < TME_ARRAY_ELS(_tme_stp2220_mdu_idi_obio_priority));
        !           273:              priority = _tme_stp2220_mdu_idi_obio_priority[idi - TME_STP222X_IDI0_OBIO];
        !           274:            }
        !           275: 
        !           276:            /* all stp2220 interrupts use buffer zero: */
        !           277:            buffer_i = 0;
        !           278:          }
        !           279: 
        !           280:          /* otherwise, this is an stp2222: */
        !           281:          else {
        !           282:            abort();
        !           283:          }
        !           284: 
        !           285:          /* update the chosen IDI: */
        !           286:          if (priority > chosen_priority[buffer_i]) {
        !           287:            chosen_idi[buffer_i] = idi;
        !           288:            chosen_imr[buffer_i] = imr;
        !           289:            chosen_priority[buffer_i] = priority;
        !           290:          }
        !           291:        }
        !           292: 
        !           293:        /* otherwise, this IMR is not valid: */
        !           294:        else {
        !           295: 
        !           296:          /* clear this IDI's received bit: */
        !           297:          /* XXX FIXME - is this right? shouldn't it stay received,
        !           298:             but just never be pending? */
        !           299:          TME_STP222X_MDU_IDIS_UPDATE(stp222x->tme_stp222x_mdu_idis_received, &= ~, idi);
        !           300:        }
        !           301: 
        !           302:        /* advance: */
        !           303:        idi++;
        !           304:        idis_arbitrate >>= 1;
        !           305:       } while (idis_arbitrate != 0);
        !           306:     }
        !           307:   } while (--idis_i >= 0);
        !           308: 
        !           309:   /* update the dispatching interrupts: */
        !           310:   buffer_i = TME_STP222X_MDU_BUFFER_COUNT - 1;
        !           311:   do {
        !           312:     imr = chosen_imr[buffer_i];
        !           313:     if (imr != !TME_STP222X_MDU_IMR_V) {
        !           314:       stp222x->tme_stp222x_mdu_dispatch_idi[buffer_i] = chosen_idi[buffer_i];
        !           315:       stp222x->tme_stp222x_mdu_dispatch_imr[buffer_i] = imr;
        !           316:       assert (stp222x->tme_stp222x_mdu_dispatch_state[buffer_i] == TME_STP222X_MDU_DISPATCH_NOW);
        !           317:     }
        !           318:   } while (--buffer_i >= 0);
        !           319: }
        !           320: 
        !           321: /* this completes dispatch of an interrupt: */
        !           322: static void
        !           323: _tme_stp222x_mdu_dispatch_complete(struct tme_stp22xx *stp22xx,
        !           324:                                   struct tme_completion *completion,
        !           325:                                   void *arg)
        !           326: {
        !           327:   struct tme_stp222x *stp222x;
        !           328:   signed long buffer_i;
        !           329:   int error;
        !           330:   tme_uint32_t idi;
        !           331: 
        !           332:   /* recover our data structure: */
        !           333:   stp222x = (struct tme_stp222x *) stp22xx;
        !           334: 
        !           335:   /* get the interrupt buffer that was dispatched: */
        !           336:   buffer_i = stp222x->tme_stp222x_mdu_dispatch_buffer;
        !           337:   assert (stp222x->tme_stp222x_mdu_dispatch_imr[buffer_i] != !TME_STP222X_MDU_IMR_V);
        !           338:   assert (stp222x->tme_stp222x_mdu_dispatch_state[buffer_i] == TME_STP222X_MDU_DISPATCH_NOW);
        !           339: 
        !           340:   /* get any error code: */
        !           341:   error = completion->tme_completion_error;
        !           342: 
        !           343:   /* if this interrupt was ACKed: */
        !           344:   if (error == TME_OK) {
        !           345: 
        !           346:     /* clear the dispatched interrupt: */
        !           347:     stp222x->tme_stp222x_mdu_dispatch_imr[buffer_i] = !TME_STP222X_MDU_IMR_V;
        !           348: 
        !           349:     /* get the IDI that was dispatched: */
        !           350:     idi = stp222x->tme_stp222x_mdu_dispatch_idi[buffer_i];
        !           351: 
        !           352:     /* if the dispatched interrupt is pulse-driven: */
        !           353:     /* XXX FIXME - we assume that TME_STP2220_IDI_RESERVED is pulse-driven: */
        !           354:     if (TME_STP222X_IS_2220(stp222x)
        !           355:        ? (idi == TME_STP2220_IDI_UPA
        !           356:           || idi == TME_STP2220_IDI_RESERVED)
        !           357:        : (idi == TME_STP2222_IDI_FFB0
        !           358:           || idi == TME_STP2222_IDI_FFB1)) {
        !           359: 
        !           360:       /* nothing to do */
        !           361:     }
        !           362: 
        !           363:     /* otherwise, the dispatched interrupt is level-driven: */
        !           364:     else {
        !           365: 
        !           366:       /* set this IDI's pending bit: */
        !           367:       TME_STP222X_MDU_IDIS_UPDATE(stp222x->tme_stp222x_mdu_idis_pending, |= , idi);
        !           368:     }
        !           369: 
        !           370:     /* decode and arbitrate again: */
        !           371:     _tme_stp222x_mdu_decode_arbitrate(stp222x);
        !           372:   }
        !           373: 
        !           374:   /* otherwise, if interrupt was NACKed: */
        !           375:   else if (error == EAGAIN) {
        !           376: 
        !           377:     /* we need to retry this interrupt buffer later: */
        !           378:     stp222x->tme_stp222x_mdu_dispatch_state[buffer_i] = TME_STP222X_MDU_DISPATCH_RETRY(0);
        !           379: 
        !           380:     /* wake up the retry thread: */
        !           381:     tme_stp22xx_cond_notify(&stp222x->tme_stp222x_mdu_retry_cond);
        !           382:   }
        !           383: 
        !           384:   /* the interrupt target must not exist: */
        !           385:   else {
        !           386:     assert (error == ENOENT);
        !           387: 
        !           388:     /* XXX FIXME - what happens in this case? */
        !           389:     abort();
        !           390:   }
        !           391: 
        !           392:   /* round-robin the interrupt buffer to dispatch: */
        !           393:   buffer_i = (buffer_i + 1) % TME_STP222X_MDU_BUFFER_COUNT;
        !           394:   stp222x->tme_stp222x_mdu_dispatch_buffer = buffer_i;
        !           395: 
        !           396:   /* unused: */
        !           397:   arg = 0;
        !           398: }
        !           399: 
        !           400: /* this dispatches an interrupt: */
        !           401: int
        !           402: tme_stp222x_mdu_dispatch(struct tme_stp222x *stp222x)
        !           403: {
        !           404:   unsigned long buffer_i;
        !           405:   struct tme_upa_bus_connection *conn_upa;
        !           406:   struct tme_completion *completion;
        !           407:   tme_uint32_t imr;
        !           408:   tme_uint32_t mid;
        !           409:   tme_uint64_t interrupt_data[8];
        !           410:   struct tme_upa_bus_connection *conn_upa_other;
        !           411: 
        !           412:   /* find a full interrupt buffer: */
        !           413:   buffer_i = stp222x->tme_stp222x_mdu_dispatch_buffer;
        !           414:   for (;;) {
        !           415: 
        !           416:     /* if this interrupt buffer is full, and can be dispatched now: */
        !           417:     if (stp222x->tme_stp222x_mdu_dispatch_imr[buffer_i] != !TME_STP222X_MDU_IMR_V
        !           418:        && stp222x->tme_stp222x_mdu_dispatch_state[buffer_i] == TME_STP222X_MDU_DISPATCH_NOW) {
        !           419:       break;
        !           420:     }
        !           421: 
        !           422:     /* round-robin to the next interrupt buffer: */
        !           423:     buffer_i = (buffer_i + 1) % TME_STP222X_MDU_BUFFER_COUNT;
        !           424: 
        !           425:     /* if all interrupt buffers are empty: */
        !           426:     if (buffer_i == stp222x->tme_stp222x_mdu_dispatch_buffer) {
        !           427: 
        !           428:       /* we didn't dispatch an interrupt: */
        !           429:       return (FALSE);
        !           430:     }
        !           431:   }
        !           432:   stp222x->tme_stp222x_mdu_dispatch_buffer = buffer_i;
        !           433: 
        !           434:   /* busy the UPA bus connection: */
        !           435:   conn_upa = tme_stp222x_busy_upa(stp222x);
        !           436: 
        !           437:   /* allocate a completion: */
        !           438:   completion
        !           439:     = tme_stp222x_completion_alloc(stp222x,
        !           440:                                   _tme_stp222x_mdu_dispatch_complete,
        !           441:                                   (void *) NULL);
        !           442: 
        !           443:   /* get the interrupt information: */
        !           444:   imr = stp222x->tme_stp222x_mdu_dispatch_imr[buffer_i];
        !           445:   mid = TME_FIELD_MASK_EXTRACTU(imr, TME_STP222X_MDU_IMR_TID);
        !           446:   memset(interrupt_data, 0, sizeof(interrupt_data));
        !           447:   interrupt_data[0] = tme_htobe_u64(TME_FIELD_MASK_EXTRACTU(imr, TME_STP222X_MDU_IMR_INR));
        !           448: 
        !           449:   /* leave: */
        !           450:   tme_stp222x_leave(stp222x);
        !           451: 
        !           452:   /* call out the interrupt: */
        !           453:   conn_upa_other = (struct tme_upa_bus_connection *) conn_upa->tme_upa_bus_connection.tme_bus_connection.tme_connection_other;
        !           454:   (*conn_upa_other->tme_upa_bus_interrupt)
        !           455:     (conn_upa_other,
        !           456:      mid,
        !           457:      interrupt_data,
        !           458:      completion);
        !           459: 
        !           460:   /* reenter: */
        !           461:   stp222x = tme_stp222x_enter_bus(&conn_upa->tme_upa_bus_connection);
        !           462: 
        !           463:   /* unbusy the UPA bus connection: */
        !           464:   tme_stp222x_unbusy_bus(stp222x, &conn_upa->tme_upa_bus_connection);
        !           465: 
        !           466:   /* we dispatched an interrupt: */
        !           467:   return (TRUE);
        !           468: }
        !           469: 
        !           470: /* this receives an interrupt: */
        !           471: void
        !           472: tme_stp222x_mdu_receive(struct tme_stp222x *stp222x,
        !           473:                        tme_uint32_t idi)
        !           474: {
        !           475: 
        !           476:   /* set this IDI's received bit: */
        !           477:   TME_STP222X_MDU_IDIS_UPDATE(stp222x->tme_stp222x_mdu_idis_received, |= , idi);
        !           478: 
        !           479:   /* decode and arbitrate again: */
        !           480:   _tme_stp222x_mdu_decode_arbitrate(stp222x);
        !           481: }
        !           482: 
        !           483: /* this updates the interrupt concentrator: */
        !           484: void
        !           485: tme_stp222x_mdu_intcon(struct tme_stp222x *stp222x,
        !           486:                       tme_uint32_t idi,
        !           487:                       tme_uint32_t level)
        !           488: {
        !           489: 
        !           490:   /* NB: the interrupt concentrator is really in the RIC chip
        !           491:      (STP2210): */
        !           492: 
        !           493:   /* if this is an stp2220, and this is the zs0/zs1 IDI: */
        !           494:   if (TME_STP222X_IS_2220(stp222x)
        !           495:       && idi == TME_STP2220_IDI_ZS0_ZS1) {
        !           496: 
        !           497:     /* the interrupt signals from zs0 and zs1 are wired together
        !           498:        somewhere in a real system, probably inside the sym89c105
        !           499:        (which is apparently not identical to an ncr89c105, because the
        !           500:        latter doesn't even have output pins for its individual
        !           501:        functions' interrupts).  we have to mimic this wiring here: */
        !           502: 
        !           503:     /* if the interrupt signal is being asserted, increase the active
        !           504:        count, otherwise decrease the active count.  the active count
        !           505:        (which is unsigned) can never be greater than two: */
        !           506:     assert (level == TME_BUS_SIGNAL_LEVEL_ASSERTED
        !           507:            || level == TME_BUS_SIGNAL_LEVEL_NEGATED);
        !           508:     stp222x->tme_stp2220_mdu_idi_zs0_zs1_active
        !           509:       += (level == TME_BUS_SIGNAL_LEVEL_ASSERTED
        !           510:          ? 1
        !           511:          : -1);
        !           512:     assert (stp222x->tme_stp2220_mdu_idi_zs0_zs1_active <= 2);
        !           513: 
        !           514:     /* if the interrupt signal is being asserted, but the active count
        !           515:        was already one, or if the interrupt signal is being negated,
        !           516:        but the active count is still one: */
        !           517:     if ((level == TME_BUS_SIGNAL_LEVEL_ASSERTED)
        !           518:        != stp222x->tme_stp2220_mdu_idi_zs0_zs1_active) {
        !           519: 
        !           520:       /* the state of the interrupt signal at the RIC chip is
        !           521:         unchanged: */
        !           522:       return;
        !           523:     }
        !           524:   }
        !           525: 
        !           526:   /* if this interrupt signal is being asserted: */
        !           527:   if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) {
        !           528: 
        !           529:     /* set this IDI's active bit: */
        !           530:     TME_STP222X_MDU_IDIS_UPDATE(stp222x->tme_stp222x_mdu_idis_active, |= , idi);
        !           531: 
        !           532:     /* receive this interrupt: */
        !           533:     tme_stp222x_mdu_receive(stp222x, idi);
        !           534:   }
        !           535: 
        !           536:   /* otherwise, this interrupt signal must be being negated: */
        !           537:   else {
        !           538:     assert (level == TME_BUS_SIGNAL_LEVEL_NEGATED);
        !           539: 
        !           540:     /* clear this IDI's active bit: */
        !           541:     TME_STP222X_MDU_IDIS_UPDATE(stp222x->tme_stp222x_mdu_idis_active, &= ~, idi);
        !           542:   }
        !           543: }
        !           544: 
        !           545: /* this recalculates the interrupt retry period: */
        !           546: static void
        !           547: _tme_stp222x_mdu_retry_set(struct tme_stp222x *stp222x)
        !           548: {
        !           549:   tme_uint64_t sleep_usec;
        !           550: 
        !           551:   /* the retry timer has a period of 15.7ms at the maximum limit of
        !           552:      2^20 ticks.  calculate half of the period of the retry timer for
        !           553:      _tme_stp222x_mdu_retry_th(): */
        !           554:   sleep_usec = TME_FIELD_MASK_EXTRACTU(stp222x->tme_stp222x_mdu_retry, TME_STP222X_MDU_RETRY_TIMER_LIMIT) + 1;
        !           555:   sleep_usec *= 15700;
        !           556: #if (TME_STP222X_MDU_RETRY_TIMER_LIMIT & 1) == 0
        !           557: #error "TME_STP222X_MDU_RETRY_TIMER_LIMIT changed"
        !           558: #endif
        !           559:   sleep_usec = (sleep_usec + TME_STP222X_MDU_RETRY_TIMER_LIMIT) / (TME_STP222X_MDU_RETRY_TIMER_LIMIT + 1);
        !           560:   stp222x->tme_stp222x_mdu_retry_sleep.tv_sec = 0;
        !           561:   stp222x->tme_stp222x_mdu_retry_sleep.tv_usec = sleep_usec;
        !           562: }
        !           563: 
        !           564: /* the MDU IMR and retry register handler: */
        !           565: void
        !           566: tme_stp222x_mdu_regs_imr_retry(struct tme_stp222x *stp222x,
        !           567:                               struct tme_stp222x_reg *reg)
        !           568: {
        !           569:   tme_uint32_t reggroup;
        !           570:   tme_uint32_t reggroup_index;
        !           571:   tme_uint32_t imr_partial;
        !           572:   tme_uint32_t idi;
        !           573:   const char *name;
        !           574: 
        !           575:   /* get the register: */
        !           576:   reggroup = TME_STP222X_REGGROUP_WHICH(reg->tme_stp222x_reg_address);
        !           577:   reggroup_index = TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address);
        !           578: 
        !           579:   /* assume that this is a write to a partial IMR, and get a partial
        !           580:      IMR value: */
        !           581:   imr_partial
        !           582:     = (reg->tme_stp222x_reg_value
        !           583:        & (TME_STP222X_MDU_IMR_TID
        !           584:          | TME_STP222X_MDU_IMR_V));
        !           585: 
        !           586:   /* assume that this is a register for an obio interrupt: */
        !           587:   idi = _tme_stp222x_reggroup_index_to_obio_idi(stp222x, reggroup_index);
        !           588: 
        !           589:   /* dispatch on the register: */
        !           590:   name = NULL;
        !           591:   switch (reggroup) {
        !           592: 
        !           593:     /* the stp2220 SBus card IMRs and the retry register: */
        !           594:   case 0x2c:
        !           595:     if (__tme_predict_false(!TME_STP222X_IS_2220(stp222x))) {
        !           596:       return;
        !           597:     }
        !           598: 
        !           599:     /* if this is an SBus card IMR: */
        !           600:     if (reggroup_index < TME_STP2220_SLOTS_CARD) {
        !           601: 
        !           602:       /* get the IDI for this card's ipl 0 interrupt.  SBus ipl 0
        !           603:         doesn't really exist, but the partial IMR for this IDI will
        !           604:         have zeros in the ipl position, which is what a read must
        !           605:         return: */
        !           606:       idi = reggroup_index * TME_SBUS_SLOT_INTS;
        !           607: 
        !           608:       /* if this is a write: */
        !           609:       if (reg->tme_stp222x_reg_write) {
        !           610: 
        !           611:        /* write the partial IMRs for all of this card's ipls, only
        !           612:           updating the V and TID fields: */
        !           613:        do {
        !           614:          stp222x->tme_stp222x_mdu_imrs[idi]
        !           615:            = ((stp222x->tme_stp222x_mdu_imrs[idi]
        !           616:                & ~(TME_STP222X_MDU_IMR_TID
        !           617:                    | TME_STP222X_MDU_IMR_V))
        !           618:               | imr_partial);
        !           619:        } while (++idi % TME_SBUS_SLOT_INTS);
        !           620:        idi -= TME_SBUS_SLOT_INTS;
        !           621:       }
        !           622: 
        !           623:       /* otherwise, this is a read: */
        !           624:       else {
        !           625: 
        !           626:        /* read the partial IMR for this card: */
        !           627:        reg->tme_stp222x_reg_value = stp222x->tme_stp222x_mdu_imrs[idi];
        !           628:       }
        !           629:       break;
        !           630:     }
        !           631:     /* FALLTHROUGH */
        !           632: 
        !           633:     /* the STP2222 retry register: */
        !           634:   case 0x1a:
        !           635:     if (__tme_predict_false(reg->tme_stp222x_reg_address
        !           636:                            != (TME_STP222X_IS_2220(stp222x)
        !           637:                                ? 0x2c20
        !           638:                                : 0x1a00))) {
        !           639:       return;
        !           640:     }
        !           641:     if (reg->tme_stp222x_reg_write) {
        !           642:       stp222x->tme_stp222x_mdu_retry = reg->tme_stp222x_reg_value;
        !           643:       _tme_stp222x_mdu_retry_set(stp222x);
        !           644:     }
        !           645:     else {
        !           646:       reg->tme_stp222x_reg_value = stp222x->tme_stp222x_mdu_retry;
        !           647:     }
        !           648:     name = "RETRY";
        !           649:     break;
        !           650: 
        !           651:     /* the STP2222 PCI card IMRs: */
        !           652:   case 0x0c:
        !           653:     if (__tme_predict_false(TME_STP222X_IS_2220(stp222x))) {
        !           654:       return;
        !           655:     }
        !           656: 
        !           657:     /* if this is not a PCI card IMR: */
        !           658:     idi = reggroup_index * TME_PCI_SLOT_INTS;
        !           659:     if (__tme_predict_false((((1 << TME_STP2222_IDI_CARD(0, 0, 0))
        !           660:                              | (1 << TME_STP2222_IDI_CARD(0, 1, 0))
        !           661:                              | (1 << TME_STP2222_IDI_CARD(1, 0, 0))
        !           662:                              | (1 << TME_STP2222_IDI_CARD(1, 1, 0))
        !           663:                              | (1 << TME_STP2222_IDI_CARD(1, 2, 0))
        !           664:                              | (1 << TME_STP2222_IDI_CARD(1, 3, 0)))
        !           665:                             & (1 << idi)) == 0)) {
        !           666:       return;
        !           667:     }
        !           668: 
        !           669:     /* if this is a write: */
        !           670:     if (reg->tme_stp222x_reg_write) {
        !           671: 
        !           672:       /* write the partial IMRs for all of this PCI card's INTx, only
        !           673:         updating the V and TID fields: */
        !           674:       do {
        !           675:        stp222x->tme_stp222x_mdu_imrs[idi]
        !           676:          = ((stp222x->tme_stp222x_mdu_imrs[idi]
        !           677:              & ~(TME_STP222X_MDU_IMR_TID
        !           678:                  | TME_STP222X_MDU_IMR_V))
        !           679:             | imr_partial);
        !           680:       } while (++idi % TME_PCI_SLOT_INTS);
        !           681:       idi -= TME_PCI_SLOT_INTS;
        !           682:     }
        !           683: 
        !           684:     /* otherwise, this is a read: */
        !           685:     else {
        !           686: 
        !           687:       /* read the partial IMR for this PCI card's INTA: */
        !           688:       reg->tme_stp222x_reg_value = stp222x->tme_stp222x_mdu_imrs[idi];
        !           689:     }
        !           690:     break;
        !           691: 
        !           692:     /* the STP2222 alternate FFB0 and FFB1 IMRs: */
        !           693:   case 0x60:
        !           694:   case 0x80:
        !           695:     idi = (reggroup == 0x60 ? TME_STP2222_IDI_FFB0 : TME_STP2222_IDI_FFB1);
        !           696:     reggroup = 0x10;
        !           697:     /* FALLTHROUGH */
        !           698: 
        !           699:     /* the obio IMRs: */
        !           700:   default:
        !           701: 
        !           702:     /* if this is the wrong obio IMR register group for this part, or
        !           703:        if this is not an obio IMR, return failure: */
        !           704:     if (TME_STP222X_IS_2220(stp222x)) {
        !           705:       if (__tme_predict_false(reggroup != 0x30
        !           706:                              || idi > TME_STP2220_IDI_RESERVED)) {
        !           707:        return;
        !           708:       }
        !           709:     }
        !           710:     else {
        !           711:       if (__tme_predict_false(reggroup != 0x10
        !           712:                              || idi > TME_STP2222_IDI_FFB1)) {
        !           713:        return;
        !           714:       }
        !           715:     }
        !           716: 
        !           717:     /* if this is an obio IMR write: */
        !           718:     if (reg->tme_stp222x_reg_write) {
        !           719: 
        !           720:       /* if this is a obio full IMR write: */
        !           721:       if (TME_STP222X_IS_2220(stp222x)
        !           722:          ? (idi == TME_STP2220_IDI_UPA
        !           723:             || idi == TME_STP2220_IDI_RESERVED)
        !           724:          : (idi == TME_STP2222_IDI_FFB0
        !           725:             || idi == TME_STP2222_IDI_FFB1)) {
        !           726: 
        !           727:        /* do the obio full IMR write: */
        !           728:        stp222x->tme_stp222x_mdu_imrs[idi]
        !           729:          = (reg->tme_stp222x_reg_value
        !           730:             & (TME_STP222X_MDU_IMR_INR
        !           731:                | TME_STP222X_MDU_IMR_TID
        !           732:                | TME_STP222X_MDU_IMR_V));
        !           733:       }
        !           734: 
        !           735:       /* otherwise, this is a obio partial IMR write: */
        !           736:       else {
        !           737: 
        !           738:        /* do the obio partial IMR write: */
        !           739:        stp222x->tme_stp222x_mdu_imrs[idi]
        !           740:          = ((stp222x->tme_stp222x_mdu_imrs[idi]
        !           741:              & ~(TME_STP222X_MDU_IMR_TID
        !           742:                  | TME_STP222X_MDU_IMR_V))
        !           743:             | imr_partial);
        !           744:       }
        !           745:     }
        !           746: 
        !           747:     /* otherwise, read the obio IMR: */
        !           748:     else {
        !           749:       reg->tme_stp222x_reg_value = stp222x->tme_stp222x_mdu_imrs[idi];
        !           750:     }
        !           751:     break;
        !           752:   }
        !           753:   
        !           754:   if (name == NULL) {
        !           755:     tme_log(TME_STP222X_LOG_HANDLE(stp222x), 2000, TME_OK,
        !           756:            (TME_STP222X_LOG_HANDLE(stp222x),
        !           757:             _("MDU IMR[0x%x] %s 0x%" TME_PRIx64),
        !           758:             idi,
        !           759:             (reg->tme_stp222x_reg_write
        !           760:              ? "<-"
        !           761:              : "->"),
        !           762:             reg->tme_stp222x_reg_value));
        !           763:   }
        !           764:   else {
        !           765:     tme_log(TME_STP222X_LOG_HANDLE(stp222x), 2000, TME_OK,
        !           766:            (TME_STP222X_LOG_HANDLE(stp222x),
        !           767:             _("MDU %s %s 0x%" TME_PRIx64),
        !           768:             name,
        !           769:             (reg->tme_stp222x_reg_write
        !           770:              ? "<-"
        !           771:              : "->"),
        !           772:             reg->tme_stp222x_reg_value));
        !           773:   }
        !           774: 
        !           775:   /* this register access has been completed: */
        !           776:   reg->tme_stp222x_reg_completed = TRUE;
        !           777: }
        !           778: 
        !           779: /* the MDU clear register handler: */
        !           780: void
        !           781: tme_stp222x_mdu_regs_clear(struct tme_stp222x *stp222x,
        !           782:                           struct tme_stp222x_reg *reg)
        !           783: {
        !           784:   tme_uint32_t reggroup;
        !           785:   tme_uint32_t reggroup_index;
        !           786:   tme_uint32_t idi;
        !           787:   tme_uint32_t mdu_state;
        !           788:   tme_uint32_t imr;
        !           789:   unsigned long buffer_i;
        !           790: 
        !           791:   /* get the register: */
        !           792:   reggroup = TME_STP222X_REGGROUP_WHICH(reg->tme_stp222x_reg_address);
        !           793:   reggroup_index = TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address);
        !           794: 
        !           795:   /* assume that this is a register for an obio interrupt: */
        !           796:   idi = _tme_stp222x_reggroup_index_to_obio_idi(stp222x, reggroup_index);
        !           797: 
        !           798:   /* dispatch on the register: */
        !           799:   switch (reggroup) {
        !           800: 
        !           801:     /* the STP2220 SBus and obio card clears: */
        !           802:   case 0x34:
        !           803:     idi = reggroup_index;
        !           804:     /* FALLTHROUGH */
        !           805:   case 0x38:
        !           806:     if (__tme_predict_false(!TME_STP222X_IS_2220(stp222x))) {
        !           807:       return;
        !           808:     }
        !           809:     if (__tme_predict_false(idi > TME_STP2220_IDI_POWER_MANAGE)) {
        !           810:       return;
        !           811:     }
        !           812:     break;
        !           813: 
        !           814:     /* the STP2222 PCI card clears: */
        !           815:   case 0x14:
        !           816:     if (__tme_predict_false(TME_STP222X_IS_2220(stp222x))) {
        !           817:       return;
        !           818:     }
        !           819: 
        !           820:     /* if this is not a PCI card clear register: */
        !           821:     idi = reggroup_index;
        !           822:     if (idi >= TME_STP2222_IDI_CARD(0, 2, 0)
        !           823:        && idi < TME_STP2222_IDI_CARD(1, 0, 0)) {
        !           824:       return;
        !           825:     }
        !           826:     break;
        !           827: 
        !           828:     /* the STP2222 obio clears: */
        !           829:   default:
        !           830:     assert (reggroup == 0x10);
        !           831:     if (__tme_predict_false(TME_STP222X_IS_2220(stp222x))) {
        !           832:       return;
        !           833:     }
        !           834:     if (__tme_predict_false(idi > TME_STP2222_IDI_POWER_MANAGE)) {
        !           835:       return;
        !           836:     }
        !           837:     break;
        !           838:   }
        !           839: 
        !           840:   /* if this is a write: */
        !           841:   if (reg->tme_stp222x_reg_write) {
        !           842: 
        !           843:     /* update the MDU state for this IDI: */
        !           844:     mdu_state = reg->tme_stp222x_reg_value;
        !           845:     if ((mdu_state & TME_STP222X_MDU_STATE_RECEIVED)
        !           846:        || TME_STP222X_MDU_IDI_TEST(stp222x->tme_stp222x_mdu_idis_active, idi)) {
        !           847:       TME_STP222X_MDU_IDIS_UPDATE(stp222x->tme_stp222x_mdu_idis_received, |= , idi);
        !           848:     }
        !           849:     else {
        !           850:       TME_STP222X_MDU_IDIS_UPDATE(stp222x->tme_stp222x_mdu_idis_received, &= ~, idi);
        !           851:     }
        !           852:     if (mdu_state == TME_STP222X_MDU_STATE_PENDING) {
        !           853:       TME_STP222X_MDU_IDIS_UPDATE(stp222x->tme_stp222x_mdu_idis_pending, |= , idi);
        !           854:     }
        !           855:     else {
        !           856:       TME_STP222X_MDU_IDIS_UPDATE(stp222x->tme_stp222x_mdu_idis_pending, &= ~, idi);
        !           857: 
        !           858:       /* get the IMR for this IDI: */
        !           859:       imr = stp222x->tme_stp222x_mdu_imrs[idi];
        !           860: 
        !           861:       /* loop over the interrupt dispatch buffers: */
        !           862:       for (buffer_i = 0; buffer_i < TME_STP222X_MDU_BUFFER_COUNT; buffer_i++) {
        !           863: 
        !           864:        /* if this interrupt dispatch buffer has the same V and TID
        !           865:           values as the IMR for this IDI: */
        !           866:        if (((stp222x->tme_stp222x_mdu_dispatch_imr[buffer_i]
        !           867:              ^ imr)
        !           868:             & (TME_STP222X_MDU_IMR_V
        !           869:                + TME_STP222X_MDU_IMR_TID)) == 0) {
        !           870: 
        !           871:          /* assume that this interrupt buffer has its V bit set, and
        !           872:             force it to dispatch now (if its V bit is clear, this
        !           873:             should not change its dispatch state): */
        !           874:          /* NB: this is a hack to improve interrupt latency when the
        !           875:             retry thread has high latency (due to poor
        !           876:             tme_cond_sleep_yield() sleep resolution): whenever a CPU
        !           877:             writes an MDU state other than pending for an IDI, assume
        !           878:             that the CPU can accept another interrupt and force any
        !           879:             interrupt waiting to dispatch to that CPU to dispatch
        !           880:             immediately: */
        !           881:          assert ((imr & TME_STP222X_MDU_IMR_V)
        !           882:                  || (stp222x->tme_stp222x_mdu_dispatch_state[buffer_i]
        !           883:                      == TME_STP222X_MDU_DISPATCH_NOW));
        !           884:          stp222x->tme_stp222x_mdu_dispatch_state[buffer_i] = TME_STP222X_MDU_DISPATCH_NOW;
        !           885:        }
        !           886:       }
        !           887:     }
        !           888: 
        !           889:     /* decode and arbitrate again: */
        !           890:     _tme_stp222x_mdu_decode_arbitrate(stp222x);
        !           891: 
        !           892:     tme_log(TME_STP222X_LOG_HANDLE(stp222x), 2000, TME_OK,
        !           893:            (TME_STP222X_LOG_HANDLE(stp222x),
        !           894:             _("MDU clear[0x%x] <- 0x%" TME_PRIx32),
        !           895:             idi,
        !           896:             mdu_state));
        !           897:   }
        !           898: 
        !           899:   /* otherwise, this is a read: */
        !           900:   else {
        !           901:     reg->tme_stp222x_reg_value = 0;
        !           902:   }
        !           903: 
        !           904:   /* this register access has been completed: */
        !           905:   reg->tme_stp222x_reg_completed = TRUE;
        !           906: }
        !           907: 
        !           908: /* the MDU diagnostic register handler: */
        !           909: void
        !           910: tme_stp222x_mdu_regs_diag(struct tme_stp222x *stp222x,
        !           911:                          struct tme_stp222x_reg *reg)
        !           912: {
        !           913:   unsigned long idis_i;
        !           914:   tme_stp222x_idis_t idis_received;
        !           915:   tme_stp222x_idis_t idis_pending;
        !           916:   tme_uint32_t bit;
        !           917:   tme_uint32_t value_32_63;
        !           918:   tme_uint32_t value_0_31;
        !           919: 
        !           920:   /* check the register and cycle type: */
        !           921:   assert (sizeof(tme_stp222x_idis_t) == sizeof(tme_uint32_t));
        !           922:   idis_i = TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address);
        !           923:   if (__tme_predict_false(idis_i > TME_ARRAY_ELS(stp222x->tme_stp222x_mdu_idis_received))) {
        !           924:     return;
        !           925:   }
        !           926:   if (__tme_predict_false(reg->tme_stp222x_reg_write)) {
        !           927:     return;
        !           928:   }
        !           929: 
        !           930:   /* get the selected internal received and pending registers: */
        !           931:   idis_received = stp222x->tme_stp222x_mdu_idis_received[idis_i];
        !           932:   idis_pending = stp222x->tme_stp222x_mdu_idis_pending[idis_i];
        !           933: 
        !           934:   /* if this diagnostic register covers the obio interrupts: */
        !           935:   if (idis_i == 1) {
        !           936: 
        !           937:     /* both parts have two pulse-driven interrupts at the end of the
        !           938:        diagnostic register, using only one bit each instead of the two
        !           939:        bits each that the level-driven interrupts use.  we move the
        !           940:        received bit of the last pulse-driven interrupt into the
        !           941:        pending bit for the next to last pulse-driven interrupt, to
        !           942:        make the two pulse-driven interrupts look like a single
        !           943:        level-driven interrupt: */
        !           944:     if (TME_STP222X_IS_2220(stp222x)) {
        !           945:       idis_pending
        !           946:        |= ((idis_received & (1 << (TME_STP2220_IDI_RESERVED - TME_STP222X_IDI0_OBIO)))
        !           947:            >> (TME_STP2220_IDI_RESERVED - TME_STP2220_IDI_UPA));
        !           948:       idis_received &= ~ (tme_uint32_t) (1 << (TME_STP2220_IDI_RESERVED - TME_STP222X_IDI0_OBIO));
        !           949:     }
        !           950:     else {
        !           951:       idis_pending
        !           952:        |= ((idis_received & (1 << (TME_STP2222_IDI_FFB1 - TME_STP222X_IDI0_OBIO)))
        !           953:            >> (TME_STP2222_IDI_FFB1 - TME_STP2222_IDI_FFB0));
        !           954:       idis_received &= ~ (tme_uint32_t) (1 << (TME_STP2222_IDI_FFB1 - TME_STP222X_IDI0_OBIO));
        !           955:     }
        !           956:   }
        !           957: 
        !           958:   /* make bits 32..63 of the value: */
        !           959:   bit = ((tme_uint32_t) 1) << 31;
        !           960:   value_32_63 = 0;
        !           961:   do {
        !           962:     if (idis_pending & (((tme_uint32_t) 1) << 31)) {
        !           963:       value_32_63 += bit;
        !           964:     }
        !           965:     idis_pending <<= 1;
        !           966:     bit >>= 1;
        !           967:     if (idis_received & (((tme_uint32_t) 1) << 31)) {
        !           968:       value_32_63 += bit;
        !           969:     }
        !           970:     idis_received <<= 1;
        !           971:     bit >>= 1;
        !           972:   } while (bit != 0);
        !           973: 
        !           974:   /* make bits 0..31 of the value: */
        !           975:   value_0_31 = 0;
        !           976:   bit = ((tme_uint32_t) 1) << 31;
        !           977:   do {
        !           978:     if (idis_pending & (((tme_uint32_t) 1) << 31)) {
        !           979:       value_0_31 += bit;
        !           980:     }
        !           981:     idis_pending <<= 1;
        !           982:     bit >>= 1;
        !           983:     if (idis_received & (((tme_uint32_t) 1) << 31)) {
        !           984:       value_0_31 += bit;
        !           985:     }
        !           986:     idis_received <<= 1;
        !           987:     bit >>= 1;
        !           988:   } while (bit != 0);
        !           989: 
        !           990:   reg->tme_stp222x_reg_value
        !           991:     = ((((tme_uint64_t) value_32_63) << 32)
        !           992:        | value_0_31);
        !           993: 
        !           994:   tme_log(TME_STP222X_LOG_HANDLE(stp222x), 2000, TME_OK,
        !           995:          (TME_STP222X_LOG_HANDLE(stp222x),
        !           996:           _("MDU DIAG -> 0x%" TME_PRIx64),
        !           997:           reg->tme_stp222x_reg_value));
        !           998: 
        !           999:   /* this register access has been completed: */
        !          1000:   reg->tme_stp222x_reg_completed = TRUE;
        !          1001: }
        !          1002: 
        !          1003: /* this updates the IGN for the partial IMRs: */
        !          1004: void
        !          1005: tme_stp222x_mdu_ign_update(struct tme_stp222x *stp222x,
        !          1006:                           tme_uint32_t ign)
        !          1007: {
        !          1008:   tme_uint32_t idi;
        !          1009:   tme_uint32_t ino;
        !          1010: 
        !          1011:   /* loop over all IDIs: */
        !          1012:   for (idi = 0; idi < TME_STP222X_IDI_NULL; idi++) {
        !          1013: 
        !          1014:     /* if this IDI has a partial IMR: */
        !          1015:     if (TME_STP222X_IS_2220(stp222x)
        !          1016:        ? (idi != TME_STP2220_IDI_UPA
        !          1017:           && idi != TME_STP2220_IDI_RESERVED)
        !          1018:        : (idi != TME_STP2222_IDI_FFB0
        !          1019:           && idi != TME_STP2222_IDI_FFB1)) {
        !          1020: 
        !          1021:       /* assume that the IDI is also the INO: */
        !          1022:       ino = idi;
        !          1023: 
        !          1024:       /* if this is an stp2220 obio interrupt: */
        !          1025:       if (TME_STP222X_IS_2220(stp222x)
        !          1026:          && idi >= TME_STP222X_IDI0_OBIO) {
        !          1027: 
        !          1028:        /* the stp2220 obio interrupt to INO mapping is not regular: */
        !          1029:        switch (idi) {
        !          1030:        case TME_STP222X_IDI_SCSI: ino = 0x20; break;
        !          1031:        case TME_STP222X_IDI_ETHER: ino = 0x21; break;
        !          1032:        case TME_STP222X_IDI_BPP: ino = 0x22; break;
        !          1033:        case TME_STP2220_IDI_AUDIO: ino = 0x24; break;
        !          1034:        case TME_STP2220_IDI_POWER: ino = 0x25; break;
        !          1035:        case TME_STP2220_IDI_ZS0_ZS1: ino = 0x28; break;
        !          1036:        case TME_STP2220_IDI_FD: ino = 0x29; break;
        !          1037:        case TME_STP2220_IDI_THERM: ino = 0x2a; break;
        !          1038:        case TME_STP2220_IDI_KBD: ino = 0x2b; break;
        !          1039:        case TME_STP2220_IDI_MOUSE: ino = 0x2c; break;
        !          1040:        case TME_STP2220_IDI_SERIAL: ino = 0x2d; break;
        !          1041:        case TME_STP2220_IDI_TIMER(0): ino = 0x30; break;
        !          1042:        case TME_STP2220_IDI_TIMER(1): ino = 0x31; break;
        !          1043:        case TME_STP2220_IDI_UE: ino = 0x34; break;
        !          1044:        case TME_STP2220_IDI_CE: ino = 0x35; break;
        !          1045:        case TME_STP2220_IDI_SBUS_ASYNC: ino = 0x36; break;
        !          1046:        case TME_STP2220_IDI_POWER_MANAGE: ino = 0x37; break;
        !          1047:        case TME_STP2220_IDI_UPA: ino = 0x38; break;
        !          1048:        case TME_STP2220_IDI_RESERVED: ino = 0x39; break;
        !          1049:        default: break;
        !          1050:        }
        !          1051:       }
        !          1052: 
        !          1053:       /* update the INR in the IDI's IMR: */
        !          1054:       stp222x->tme_stp222x_mdu_imrs[idi]
        !          1055:        = ((stp222x->tme_stp222x_mdu_imrs[idi]
        !          1056:            & ~TME_STP222X_MDU_IMR_INR)
        !          1057:           + (ign * TME_STP222X_IDI_NULL)
        !          1058:           + ino);
        !          1059:     }
        !          1060:   }
        !          1061: }
        !          1062: 
        !          1063: /* this initializes the MDU: */
        !          1064: void
        !          1065: tme_stp222x_mdu_init(struct tme_stp222x *stp222x)
        !          1066: {
        !          1067: 
        !          1068:   /* initialize the IMRs: */
        !          1069:   memset(stp222x->tme_stp222x_mdu_imrs, 0, sizeof(stp222x->tme_stp222x_mdu_imrs));
        !          1070:   tme_stp222x_mdu_ign_update(stp222x, 0);
        !          1071: 
        !          1072:   /* initialize the retry timer: */
        !          1073:   stp222x->tme_stp222x_mdu_retry = 0;
        !          1074:   _tme_stp222x_mdu_retry_set(stp222x);
        !          1075: 
        !          1076:   /* initialize the retry condition: */
        !          1077:   tme_stp22xx_cond_init(&stp222x->tme_stp222x_mdu_retry_cond);
        !          1078: 
        !          1079:   /* start the retry thread: */
        !          1080:   tme_thread_create(_tme_stp222x_mdu_retry_th, stp222x);
        !          1081: }
        !          1082: 

unix.superglobalmegacorp.com

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