Annotation of tme/ic/stp22xx/stp222x-mdu.c, revision 1.1.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.