Annotation of tme/ic/stp22xx/stp22xx.c, revision 1.1

1.1     ! root        1: /* $Id: stp22xx.c,v 1.4 2009/09/07 15:03:19 fredette Exp $ */
        !             2: 
        !             3: /* ic/stp22xx.c - common STP2200, STP2202, STP2220, and STP2222
        !             4:    emulation: */
        !             5: 
        !             6: /*
        !             7:  * Copyright (c) 2009 Matt Fredette
        !             8:  * All rights reserved.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *      This product includes software developed by Matt Fredette.
        !            21:  * 4. The name of the author may not be used to endorse or promote products
        !            22:  *    derived from this software without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            26:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            27:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
        !            28:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            29:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            30:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            32:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            33:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            34:  * POSSIBILITY OF SUCH DAMAGE.
        !            35:  */
        !            36: 
        !            37: #include <tme/common.h>
        !            38: _TME_RCSID("$Id: stp22xx.c,v 1.4 2009/09/07 15:03:19 fredette Exp $");
        !            39: 
        !            40: /* includes: */
        !            41: #include "stp22xx-impl.h"
        !            42: 
        !            43: /* this busies a generic bus connection: */
        !            44: struct tme_bus_connection *
        !            45: tme_stp22xx_busy_bus(struct tme_stp22xx *stp22xx,
        !            46:                     tme_uint32_t conn_index)
        !            47: {
        !            48:   struct tme_bus_connection *conn_bus;
        !            49: 
        !            50:   /* if the connection index is valid: */
        !            51:   conn_bus = NULL;
        !            52:   if (__tme_predict_true(conn_index != stp22xx->tme_stp22xx_conn_index_null)) {
        !            53: 
        !            54:     /* if there is a connection at this index: */
        !            55:     conn_bus = stp22xx->tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus;
        !            56:     if (__tme_predict_true(conn_bus != NULL)) {
        !            57: 
        !            58:     }
        !            59:   }
        !            60: 
        !            61:   return (conn_bus);
        !            62: }
        !            63: 
        !            64: /* this unbusies a generic bus connection: */
        !            65: void
        !            66: tme_stp22xx_unbusy_bus(struct tme_stp22xx *stp22xx,
        !            67:                       struct tme_bus_connection *conn_bus)
        !            68: {
        !            69:   
        !            70:   /* the connection must be valid: */
        !            71:   assert (conn_bus != NULL);
        !            72: }
        !            73: 
        !            74: /* this busies a slave generic bus connection: */
        !            75: struct tme_bus_connection *
        !            76: tme_stp22xx_slave_busy_bus(struct tme_stp22xx *stp22xx,
        !            77:                           tme_uint32_t slave_conn_index)
        !            78: {
        !            79:   struct tme_bus_connection *slave_conn_bus;
        !            80: 
        !            81:   /* if the connection index is valid: */
        !            82:   slave_conn_bus = tme_stp22xx_busy_bus(stp22xx, slave_conn_index);
        !            83:   if (__tme_predict_true(slave_conn_bus != NULL)) {
        !            84: 
        !            85:     /* this is now the busy slave connection: */
        !            86:     assert (stp22xx->tme_stp22xx_slave_conn_bus == NULL);
        !            87:     stp22xx->tme_stp22xx_slave_conn_bus = slave_conn_bus;
        !            88:   }
        !            89:   return (slave_conn_bus);
        !            90: }
        !            91: 
        !            92: /* this unbusies a slave generic bus connection: */
        !            93: void
        !            94: tme_stp22xx_slave_unbusy(struct tme_stp22xx *stp22xx)
        !            95: {
        !            96: 
        !            97:   /* unbusy the slave connection: */
        !            98:   tme_stp22xx_unbusy_bus(stp22xx, stp22xx->tme_stp22xx_slave_conn_bus);
        !            99: 
        !           100:   /* there is now no busy slave connection: */
        !           101:   stp22xx->tme_stp22xx_slave_conn_bus = NULL;
        !           102: }
        !           103: 
        !           104: /* this enters without locking the mutex: */
        !           105: static struct tme_stp22xx *
        !           106: _tme_stp22xx_enter_locked(struct tme_stp22xx *stp22xx)
        !           107: {
        !           108:   signed long completion_i;
        !           109:   struct tme_completion *completion;
        !           110:   _tme_stp22xx_completion_handler_t handler;
        !           111: 
        !           112:   /* loop over the completions: */
        !           113:   completion_i = TME_STP22XX_COMPLETIONS_MAX - 1;
        !           114:   completion = &stp22xx->tme_stp22xx_completions[completion_i];
        !           115:   do {
        !           116: 
        !           117:     /* if this completion is valid: */
        !           118:     if (tme_completion_is_valid(completion)) {
        !           119: 
        !           120:       /* make a read-before-read barrier: */
        !           121:       tme_memory_barrier(stp22xx, stp22xx->tme_stp22xx_sizeof, TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE);
        !           122: 
        !           123:       /* invalidate the completion: */
        !           124:       tme_completion_invalidate(completion);
        !           125: 
        !           126:       /* call the completion handler: */
        !           127:       handler = stp22xx->tme_stp22xx_completion_handlers[completion_i];
        !           128:       assert (handler != NULL);
        !           129:       stp22xx->tme_stp22xx_completion_handlers[completion_i] = NULL;
        !           130:       (*handler)(stp22xx,
        !           131:                 completion,
        !           132:                 stp22xx->tme_stp22xx_completion_args[completion_i]);
        !           133:     }
        !           134: 
        !           135:     completion--;
        !           136:   } while (--completion_i >= 0);
        !           137: 
        !           138:   return (stp22xx);
        !           139: }
        !           140: 
        !           141: /* this enters: */
        !           142: struct tme_stp22xx *
        !           143: tme_stp22xx_enter(struct tme_stp22xx *stp22xx)
        !           144: {
        !           145: 
        !           146:   /* lock the mutex: */
        !           147:   tme_mutex_lock(&stp22xx->tme_stp22xx_mutex);
        !           148: 
        !           149:   /* finish the enter: */
        !           150:   return (_tme_stp22xx_enter_locked(stp22xx));
        !           151: }
        !           152: 
        !           153: /* this enters as the bus master: */
        !           154: struct tme_stp22xx *
        !           155: tme_stp22xx_enter_master(struct tme_bus_connection *master_conn_bus)
        !           156: {
        !           157:   struct tme_stp22xx *stp22xx;
        !           158: 
        !           159: #if TME_STP22XX_BUS_TRANSITION
        !           160:   signed long completion_i;
        !           161:   struct tme_completion *completion;
        !           162: 
        !           163:   /* if the bus master was making a callout through the bus: */
        !           164: #if !TME_THREADS_COOPERATIVE
        !           165: #error "preemptive threads not supported yet"
        !           166: #endif /* !TME_THREADS_COOPERATIVE */
        !           167:   stp22xx = master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
        !           168:   if (stp22xx->tme_stp22xx_master_completion != NULL) {
        !           169: 
        !           170:     /* find the completion for that callout and force it to be valid.
        !           171:        this is necessary since we may be reentered by a new master
        !           172:        before the original callout returns: */
        !           173:     completion_i = TME_STP22XX_COMPLETIONS_MAX - 1;
        !           174:     for (;;) {
        !           175:       if (stp22xx->tme_stp22xx_completion_handlers[completion_i]
        !           176:          == tme_stp22xx_complete_master) {
        !           177:        break;
        !           178:       }
        !           179:       --completion_i;
        !           180:       assert (completion_i >= 0);
        !           181:     }
        !           182:     assert (stp22xx->tme_stp22xx_completion_args[completion_i]
        !           183:            == stp22xx->tme_stp22xx_master_completion);
        !           184:     completion = &stp22xx->tme_stp22xx_completions[completion_i];
        !           185:     if (!tme_completion_is_valid(completion)) {
        !           186:       tme_completion_validate(completion);
        !           187:     }
        !           188:   }
        !           189: 
        !           190: #endif /* TME_STP22XX_BUS_TRANSITION */
        !           191:   
        !           192:   /* enter: */
        !           193:   stp22xx = tme_stp22xx_enter(master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private);
        !           194: 
        !           195:   /* only the bus master can cause a callout through the bus, and the
        !           196:      bus master can only cause one such callout at a time: */
        !           197:   assert (stp22xx->tme_stp22xx_master_completion == NULL);
        !           198: 
        !           199:   return (stp22xx);
        !           200: }
        !           201: 
        !           202: /* this runs: */
        !           203: static void
        !           204: _tme_stp22xx_run(struct tme_stp22xx *stp22xx)
        !           205: {
        !           206: 
        !           207:   /* if the run function is not running: */
        !           208:   if (!stp22xx->tme_stp22xx_running) {
        !           209: 
        !           210:     /* the run function is now running: */
        !           211:     stp22xx->tme_stp22xx_running = TRUE;
        !           212: 
        !           213:     /* call the run function: */
        !           214:     (*stp22xx->tme_stp22xx_run)(stp22xx);
        !           215: 
        !           216:     /* the run function is not running: */
        !           217:     stp22xx->tme_stp22xx_running = FALSE;
        !           218:   }
        !           219: }
        !           220: 
        !           221: /* this leaves: */
        !           222: void
        !           223: tme_stp22xx_leave(struct tme_stp22xx *stp22xx)
        !           224: {
        !           225:   signed long completion_i;
        !           226:   struct tme_completion *completion;
        !           227:   struct tme_completion *completions_delayed[TME_STP22XX_COMPLETIONS_DELAYED_MAX];
        !           228: 
        !           229:   /* run: */
        !           230:   _tme_stp22xx_run(stp22xx);
        !           231: 
        !           232:   /* get any completions whose validations were delayed: */
        !           233:   for (completion_i = 0;; completion_i++) {
        !           234:     completion = stp22xx->tme_stp22xx_completions_delayed[completion_i];
        !           235:     if (completion == NULL) {
        !           236:       break;
        !           237:     }
        !           238:     stp22xx->tme_stp22xx_completions_delayed[completion_i] = NULL;
        !           239:     completions_delayed[completion_i] = completion;
        !           240:   }
        !           241: 
        !           242:   /* unlock the mutex: */
        !           243:   tme_mutex_unlock(&stp22xx->tme_stp22xx_mutex);
        !           244: 
        !           245:   /* validate any completions: */
        !           246:   for (; --completion_i >= 0; ) {
        !           247:     tme_completion_validate(completions_delayed[completion_i]);
        !           248:   }
        !           249: }
        !           250: 
        !           251: /* this waits on a condition, with an optional sleep time: */
        !           252: void
        !           253: tme_stp22xx_cond_sleep_yield(struct tme_stp22xx *stp22xx,
        !           254:                             struct tme_stp22xx_cond *cond,
        !           255:                             const struct timeval *sleep)
        !           256: {
        !           257:   signed long completion_i;
        !           258:   struct tme_completion *completion;
        !           259: 
        !           260:   /* this condition must be idle: */
        !           261:   assert (cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_IDLE);
        !           262: 
        !           263:   /* we are now running, before waiting on this condition: */
        !           264:   cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_RUNNING;
        !           265: 
        !           266:   /* run: */
        !           267:   _tme_stp22xx_run(stp22xx);
        !           268: 
        !           269:   /* if this condition was notified while we were running: */
        !           270:   if (cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_NOTIFIED) {
        !           271: 
        !           272:     /* this condition is idle again: */
        !           273:     cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_IDLE;
        !           274: 
        !           275:     return;
        !           276:   }
        !           277: 
        !           278:   /* the condition must still be running: */
        !           279:   assert (cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_RUNNING);
        !           280: 
        !           281:   /* make a total write-after-write barrier, to force writes to the
        !           282:      completion states to happen before validation: */
        !           283:   tme_memory_barrier(0, 0, TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE);
        !           284: 
        !           285:   /* validate any completions whose validations were delayed: */
        !           286:   for (completion_i = 0;; completion_i++) {
        !           287:     completion = stp22xx->tme_stp22xx_completions_delayed[completion_i];
        !           288:     if (completion == NULL) {
        !           289:       break;
        !           290:     }
        !           291:     stp22xx->tme_stp22xx_completions_delayed[completion_i] = NULL;
        !           292:     tme_completion_validate(completion);
        !           293:   }
        !           294: 
        !           295:   /* we are now waiting on this condition, unless threading is
        !           296:      cooperative, in which case the condition will be idle again the
        !           297:      next time this thread runs: */
        !           298:   cond->tme_stp22xx_cond_state
        !           299:     = (TME_THREADS_COOPERATIVE
        !           300:        ? TME_STP22XX_COND_STATE_IDLE
        !           301:        : TME_STP22XX_COND_STATE_WAITING);
        !           302: 
        !           303:   /* sleep or wait on the condition variable: */
        !           304:   if (sleep != NULL) {
        !           305:     tme_cond_sleep_yield(&cond->tme_stp22xx_cond_cond,
        !           306:                         &stp22xx->tme_stp22xx_mutex,
        !           307:                         sleep);
        !           308:   }
        !           309:   else {
        !           310:     tme_cond_wait_yield(&cond->tme_stp22xx_cond_cond,
        !           311:                        &stp22xx->tme_stp22xx_mutex);
        !           312:   }
        !           313: 
        !           314:   /* this condition is idle again: */
        !           315:   cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_IDLE;
        !           316: 
        !           317:   /* reenter: */
        !           318:   _tme_stp22xx_enter_locked(stp22xx);
        !           319: }
        !           320: 
        !           321: /* this validates a completion: */
        !           322: /* NB: completion may be NULL: */
        !           323: void
        !           324: tme_stp22xx_completion_validate(struct tme_stp22xx *stp22xx,
        !           325:                                struct tme_completion *completion)
        !           326: {
        !           327:   unsigned long completion_i;
        !           328: 
        !           329:   /* we delay validating completions: */
        !           330:   for (completion_i = 0;; completion_i++) {
        !           331:     assert (completion_i < TME_STP22XX_COMPLETIONS_DELAYED_MAX);
        !           332:     if (stp22xx->tme_stp22xx_completions_delayed[completion_i] == NULL) {
        !           333:       break;
        !           334:     }
        !           335:   }
        !           336:   stp22xx->tme_stp22xx_completions_delayed[completion_i] = completion;
        !           337: }
        !           338: 
        !           339: /* this allocates a completion: */
        !           340: struct tme_completion *
        !           341: tme_stp22xx_completion_alloc(struct tme_stp22xx *stp22xx,
        !           342:                             _tme_stp22xx_completion_handler_t handler,
        !           343:                             void *arg)
        !           344: {
        !           345:   signed long completion_i;
        !           346:   struct tme_completion *completion;
        !           347: 
        !           348:   /* find a free completion: */
        !           349:   completion_i = TME_STP22XX_COMPLETIONS_MAX - 1;
        !           350:   for (; stp22xx->tme_stp22xx_completion_handlers[completion_i] != NULL; ) {
        !           351:     completion_i--;
        !           352:     assert (completion_i >= 0);
        !           353:   }
        !           354: 
        !           355:   /* allocate this completion: */
        !           356:   stp22xx->tme_stp22xx_completion_handlers[completion_i] = handler;
        !           357:   stp22xx->tme_stp22xx_completion_args[completion_i] = arg;
        !           358: 
        !           359:   /* the completion can't still (or already) be valid: */
        !           360:   completion = &stp22xx->tme_stp22xx_completions[completion_i];
        !           361:   assert (!tme_completion_is_valid(completion));
        !           362: 
        !           363:   /* return the completion: */
        !           364:   return (completion);
        !           365: }
        !           366: 
        !           367: /* this calls out a bus signal to a connection: */
        !           368: void
        !           369: tme_stp22xx_callout_signal(struct tme_stp22xx *stp22xx,
        !           370:                           tme_uint32_t conn_index,
        !           371:                           unsigned int signal,
        !           372:                           _tme_stp22xx_completion_handler_t handler)
        !           373: {
        !           374:   struct tme_bus_connection *conn_bus;
        !           375:   struct tme_completion completion_buffer;
        !           376:   struct tme_completion *completion;
        !           377:   struct tme_bus_connection *conn_bus_other;
        !           378: 
        !           379:   /* if there is a connection at this index: */
        !           380:   conn_bus = tme_stp22xx_busy_bus(stp22xx, conn_index);
        !           381:   if (conn_bus != NULL) {
        !           382: 
        !           383:     /* if the connection at this index doesn't care about bus
        !           384:        signals: */
        !           385:     conn_bus_other = (struct tme_bus_connection *) conn_bus->tme_bus_connection.tme_connection_other;
        !           386:     if (conn_bus_other->tme_bus_signal == NULL) {
        !           387: 
        !           388:       /* unbusy the bus connection: */
        !           389:       tme_stp22xx_unbusy_bus(stp22xx, conn_bus);
        !           390: 
        !           391:       /* behave as if there is no connection at this index: */
        !           392:       conn_bus = NULL;
        !           393:     }
        !           394:   }
        !           395: 
        !           396:   /* if there is no connection at this index: */
        !           397:   if (conn_bus == NULL) {
        !           398: 
        !           399:     /* call the completion handler directly: */
        !           400:     completion_buffer.tme_completion_error = TME_OK;
        !           401:     (*handler)(stp22xx, &completion_buffer, (void *) NULL);
        !           402:     return;
        !           403:   }
        !           404: 
        !           405:   /* allocate a completion: */
        !           406:   completion = tme_stp22xx_completion_alloc(stp22xx, handler, (void *) NULL);
        !           407: 
        !           408:   /* leave: */
        !           409:   tme_stp22xx_leave(stp22xx);
        !           410: 
        !           411:   /* call out the bus signal: */
        !           412:   conn_bus_other = (struct tme_bus_connection *) conn_bus->tme_bus_connection.tme_connection_other;
        !           413: #if TME_STP22XX_BUS_TRANSITION
        !           414:   completion->tme_completion_error =
        !           415:   (*conn_bus_other->tme_bus_signal)
        !           416:     (conn_bus_other,
        !           417:      signal);
        !           418:   tme_completion_validate(completion);
        !           419: #else  /* !TME_STP22XX_BUS_TRANSITION */
        !           420: #error WRITEME
        !           421: #endif /* !TME_STP22XX_BUS_TRANSITION */
        !           422: 
        !           423:   /* reenter: */
        !           424:   tme_stp22xx_enter(stp22xx);
        !           425: 
        !           426:   /* unbusy the bus connection: */
        !           427:   tme_stp22xx_unbusy_bus(stp22xx, conn_bus);
        !           428: }
        !           429: 
        !           430: /* this completes a bus operation between master and slave: */
        !           431: void
        !           432: tme_stp22xx_complete_master(struct tme_stp22xx *stp22xx,
        !           433:                            struct tme_completion *completion,
        !           434:                            void *__master_completion)
        !           435: {
        !           436:   struct tme_completion **_master_completion;
        !           437:   struct tme_completion *master_completion;
        !           438: 
        !           439:   /* unbusy the slave connection: */
        !           440:   tme_stp22xx_slave_unbusy(stp22xx);
        !           441: 
        !           442:   /* if this bus operation was not aborted: */
        !           443:   _master_completion = (struct tme_completion **) __master_completion;
        !           444:   if (stp22xx->tme_stp22xx_master_completion == _master_completion) {
        !           445: 
        !           446:     /* pass any slave error and scalar return value back to the master: */
        !           447:     master_completion = *_master_completion;
        !           448:     master_completion->tme_completion_error = completion->tme_completion_error;
        !           449:     master_completion->tme_completion_scalar = completion->tme_completion_scalar;
        !           450: 
        !           451:     /* this bus operation is completed: */
        !           452:     stp22xx->tme_stp22xx_master_completion = NULL;
        !           453: 
        !           454:     /* validate the completion: */
        !           455:     tme_stp22xx_completion_validate(stp22xx, master_completion);
        !           456:   }
        !           457: }
        !           458: 
        !           459: /* this completes a bus grant: */
        !           460: void
        !           461: tme_stp22xx_complete_bg(struct tme_stp22xx *stp22xx,
        !           462:                        struct tme_completion *completion,
        !           463:                        void *arg)
        !           464: {
        !           465:   stp22xx->tme_stp22xx_master_conn_index
        !           466:     = stp22xx->tme_stp22xx_master_conn_index_pending;
        !           467:   stp22xx->tme_stp22xx_master_conn_index_pending = stp22xx->tme_stp22xx_conn_index_null;
        !           468: 
        !           469:   /* unused: */
        !           470:   completion = 0;
        !           471:   arg = 0;
        !           472: }
        !           473: 
        !           474: /* this is a no-op completion: */
        !           475: void
        !           476: tme_stp22xx_complete_nop(struct tme_stp22xx *stp22xx,
        !           477:                         struct tme_completion *completion,
        !           478:                         void *arg)
        !           479: {
        !           480:   /* unused: */
        !           481:   stp22xx = 0;
        !           482:   completion = 0;
        !           483:   arg = 0;
        !           484: }
        !           485: 
        !           486: /* this runs a slave bus cycle: */
        !           487: void
        !           488: tme_stp22xx_slave_cycle(struct tme_bus_connection *master_conn_bus,
        !           489:                        tme_uint32_t slave_conn_index,
        !           490:                        struct tme_bus_cycle *master_cycle,
        !           491:                        tme_uint32_t *_master_fast_cycle_types,
        !           492:                        struct tme_completion **_master_completion)
        !           493: {
        !           494:   struct tme_stp22xx *stp22xx;
        !           495:   struct tme_bus_connection *slave_conn_bus;
        !           496:   int completion_error;
        !           497: #if TME_STP22XX_BUS_TRANSITION
        !           498:   struct tme_bus_tlb tlb_local;
        !           499:   int rc;
        !           500:   tme_uint8_t *memory;
        !           501:   tme_bus_addr_t tlb_cycle_address;
        !           502:   int shift;
        !           503: #endif /* TME_STP22XX_BUS_TRANSITION */
        !           504:   struct tme_completion *completion;
        !           505:   struct tme_bus_connection *slave_conn_bus_other;
        !           506:   struct tme_completion *master_completion;
        !           507: 
        !           508:   /* recover our data structure: */
        !           509:   stp22xx = master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
        !           510: 
        !           511:   /* this cycle must not have been aborted: */
        !           512:   assert (stp22xx->tme_stp22xx_master_completion == _master_completion);
        !           513: 
        !           514:   /* busy the connection to any slave: */
        !           515:   slave_conn_bus = tme_stp22xx_slave_busy_bus(stp22xx, slave_conn_index);
        !           516: 
        !           517:   /* if the connection index is invalid, or if there is no slave at
        !           518:      this connection index: */
        !           519:   if (__tme_predict_false(slave_conn_bus == NULL)) {
        !           520: 
        !           521:     /* complete with an error: */
        !           522:     completion_error = ENOENT;
        !           523:   }
        !           524: 
        !           525:   /* otherwise, if the master is trying a cycle to itself: */
        !           526:   else if (__tme_predict_false(slave_conn_bus == master_conn_bus)) {
        !           527: 
        !           528:     /* unbusy the connection to the slave: */
        !           529:     tme_stp22xx_slave_unbusy(stp22xx);
        !           530: 
        !           531:     /* complete with an error: */
        !           532:     completion_error = EIO;
        !           533:   }
        !           534: 
        !           535:   /* otherwise, we can run this cycle: */
        !           536:   else {
        !           537: 
        !           538: #if TME_STP22XX_BUS_TRANSITION
        !           539: 
        !           540:     /* fill a TLB entry for this address: */
        !           541:     tlb_local.tme_bus_tlb_token = &stp22xx->tme_stp22xx_slave_cycle_tlb_token;
        !           542:     slave_conn_bus_other = (struct tme_bus_connection *) slave_conn_bus->tme_bus_connection.tme_connection_other;
        !           543:     rc = ((*slave_conn_bus_other->tme_bus_tlb_fill)
        !           544:          (slave_conn_bus_other,
        !           545:           &tlb_local,
        !           546:           master_cycle->tme_bus_cycle_address,
        !           547:           master_cycle->tme_bus_cycle_type));
        !           548:     assert (rc == TME_OK);
        !           549: 
        !           550:     /* the master can't do any fast transfers that this TLB entry
        !           551:        doesn't allow: */
        !           552:     if (tlb_local.tme_bus_tlb_emulator_off_read == TME_EMULATOR_OFF_UNDEF) {
        !           553:       *_master_fast_cycle_types &= ~TME_BUS_CYCLE_READ;
        !           554:     }
        !           555:     if (tlb_local.tme_bus_tlb_emulator_off_write == TME_EMULATOR_OFF_UNDEF) {
        !           556:       *_master_fast_cycle_types &= ~TME_BUS_CYCLE_WRITE;
        !           557:     }
        !           558: 
        !           559:     /* if this cycle can be done fast: */
        !           560:     /* NB: this breaks tme_shared and const: */
        !           561:     memory
        !           562:       = (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ
        !           563:         ? (tme_uint8_t *) tlb_local.tme_bus_tlb_emulator_off_read
        !           564:         : (tme_uint8_t *) tlb_local.tme_bus_tlb_emulator_off_write);
        !           565:     if (memory != TME_EMULATOR_OFF_UNDEF) {
        !           566: 
        !           567:       /* do the fast transfer: */
        !           568:       tme_bus_cycle_xfer_memory(master_cycle, memory, tlb_local.tme_bus_tlb_addr_last);
        !           569: 
        !           570:       /* unbusy the connection to the slave: */
        !           571:       tme_stp22xx_slave_unbusy(stp22xx);
        !           572: 
        !           573:       /* complete with success: */
        !           574:       master_completion = *_master_completion;
        !           575:       master_completion->tme_completion_error = TME_OK;
        !           576:       tme_stp22xx_completion_validate(stp22xx, master_completion);
        !           577:       stp22xx->tme_stp22xx_master_completion = NULL;
        !           578:       return;
        !           579:     }
        !           580: 
        !           581: #endif /* TME_STP22XX_BUS_TRANSITION */
        !           582: 
        !           583:     /* when we complete, we will will complete for the master: */
        !           584:     completion
        !           585:       = tme_stp22xx_completion_alloc(stp22xx,
        !           586:                                     tme_stp22xx_complete_master,
        !           587:                                     _master_completion);
        !           588: 
        !           589:     /* leave: */
        !           590:     tme_stp22xx_leave(stp22xx);
        !           591: 
        !           592:     /* run this cycle: */
        !           593: #if TME_STP22XX_BUS_TRANSITION
        !           594:     tlb_cycle_address = tlb_local.tme_bus_tlb_addr_offset + master_cycle->tme_bus_cycle_address;
        !           595:     shift = tlb_local.tme_bus_tlb_addr_shift;
        !           596:     if (shift < 0) {
        !           597:       tlb_cycle_address <<= (0 - shift);
        !           598:     }
        !           599:     else if (shift > 0) {
        !           600:       tlb_cycle_address >>= shift;
        !           601:     }
        !           602:     master_cycle->tme_bus_cycle_address = tlb_cycle_address;
        !           603:     /* NB: we may be reentered before this cycle callout returns,
        !           604:        usually by this slave device immediately turning around to
        !           605:        become a master.  unfortunately, this means that
        !           606:        tme_stp22xx_enter_master() will have to validate the first
        !           607:        master's completion itself, before we would normally do it
        !           608:        here.  this means that we also have to predict how the cycle
        !           609:        will complete - and we assume that if the slave does turn
        !           610:        around to become a master, that the cycle completed
        !           611:        successfully: */
        !           612:     completion->tme_completion_error = TME_OK;
        !           613:     rc
        !           614:       = ((*tlb_local.tme_bus_tlb_cycle)
        !           615:         (tlb_local.tme_bus_tlb_cycle_private,
        !           616:          master_cycle));
        !           617:     if (stp22xx->tme_stp22xx_master_completion != _master_completion) {
        !           618:       assert (rc == TME_OK);
        !           619:     }
        !           620:     else {
        !           621:       completion->tme_completion_error = rc;
        !           622:       tme_completion_validate(completion);
        !           623:     }
        !           624: #else  /* !TME_STP22XX_BUS_TRANSITION */
        !           625: #error WRITEME
        !           626: #endif /* !TME_STP22XX_BUS_TRANSITION */
        !           627: 
        !           628:     /* reenter: */
        !           629:     tme_stp22xx_enter(stp22xx);
        !           630: 
        !           631:     return;
        !           632:   }
        !           633: 
        !           634:   /* complete with the error: */
        !           635:   master_completion = *_master_completion;
        !           636:   master_completion->tme_completion_error = completion_error;
        !           637:   tme_stp22xx_completion_validate(stp22xx, master_completion);
        !           638:   stp22xx->tme_stp22xx_master_completion = NULL;
        !           639:   *_master_fast_cycle_types = 0;
        !           640: }
        !           641: 
        !           642: /* this fills a TLB entry: */
        !           643: void
        !           644: tme_stp22xx_tlb_fill(struct tme_bus_connection *agent_conn_bus,
        !           645:                     struct tme_bus_tlb *tlb,
        !           646:                     tme_uint32_t slave_conn_index,
        !           647:                     tme_bus_addr64_t slave_address,
        !           648:                     unsigned int cycle_type)
        !           649: {
        !           650:   struct tme_stp22xx *stp22xx;
        !           651:   struct tme_bus_connection *slave_conn_bus;
        !           652:   struct tme_bus_connection *slave_conn_bus_other;
        !           653: #if TME_STP22XX_BUS_TRANSITION
        !           654:   int rc;
        !           655: #endif /* TME_STP22XX_BUS_TRANSITION */
        !           656: 
        !           657:   /* recover our data structure: */
        !           658:   stp22xx = agent_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
        !           659: 
        !           660:   /* busy the connection to any slave: */
        !           661:   slave_conn_bus = tme_stp22xx_busy_bus(stp22xx, slave_conn_index);
        !           662: 
        !           663:   /* if the connection index is invalid, or if there is no slave at
        !           664:      this connection index, or if the agent is filling a TLB for an
        !           665:      address in itself: */
        !           666:   if (__tme_predict_false(slave_conn_bus == NULL
        !           667:                          || slave_conn_bus == agent_conn_bus)) {
        !           668: 
        !           669:     /* unbusy any connection to the slave: */
        !           670:     if (slave_conn_bus != NULL) {
        !           671:       tme_stp22xx_unbusy_bus(stp22xx, slave_conn_bus);
        !           672:     }
        !           673: 
        !           674:     /* initialize the TLB entry: */
        !           675:     tme_bus_tlb_initialize(tlb);
        !           676: 
        !           677:     /* our caller will map this TLB entry from covering all addresses
        !           678:        to only covering a region's addresses: */
        !           679:     tlb->tme_bus_tlb_addr_first = 0;
        !           680:     tlb->tme_bus_tlb_addr_last = 0 - (tme_bus_addr_t) 1;
        !           681:   }
        !           682: 
        !           683:   /* otherwise, the slave can fill this TLB entry: */
        !           684:   else {
        !           685: 
        !           686:     /* leave: */
        !           687:     tme_stp22xx_leave(stp22xx);
        !           688: 
        !           689:     /* fill this TLB entry: */
        !           690:     slave_conn_bus_other = (struct tme_bus_connection *) slave_conn_bus->tme_bus_connection.tme_connection_other;
        !           691: #if TME_STP22XX_BUS_TRANSITION
        !           692:     rc = 
        !           693: #endif /* TME_STP22XX_BUS_TRANSITION */
        !           694:     (*slave_conn_bus_other->tme_bus_tlb_fill)
        !           695:       (slave_conn_bus_other,
        !           696:        tlb,
        !           697:        slave_address,
        !           698:        cycle_type);
        !           699: #if TME_STP22XX_BUS_TRANSITION
        !           700:     assert (rc == TME_OK);
        !           701: #endif /* TME_STP22XX_BUS_TRANSITION */
        !           702: 
        !           703:     /* reenter: */
        !           704:     tme_stp22xx_enter(stp22xx);
        !           705: 
        !           706:     /* unbusy the connection to the slave: */
        !           707:     tme_stp22xx_unbusy_bus(stp22xx, slave_conn_bus);
        !           708:   }
        !           709: }
        !           710: 
        !           711: #if TME_STP22XX_BUS_TRANSITION
        !           712: 
        !           713: /* this is the bus TLB set add transition glue: */
        !           714: #undef tme_stp22xx_tlb_set_add
        !           715: int
        !           716: tme_stp22xx_tlb_set_add_transition(struct tme_bus_connection *agent_conn_bus,
        !           717:                                   struct tme_bus_tlb_set_info *tlb_set_info)
        !           718: {
        !           719:   struct tme_completion completion_buffer;
        !           720:   tme_completion_init(&completion_buffer);
        !           721:   tme_stp22xx_tlb_set_add(agent_conn_bus,
        !           722:                          tlb_set_info,
        !           723:                          &completion_buffer);
        !           724:   return (completion_buffer.tme_completion_error);
        !           725: }
        !           726: 
        !           727: #endif /* TME_STP22XX_BUS_TRANSITION */
        !           728: 
        !           729: /* this adds a TLB set: */
        !           730: void
        !           731: tme_stp22xx_tlb_set_add(struct tme_bus_connection *agent_conn_bus,
        !           732:                        struct tme_bus_tlb_set_info *tlb_set_info,
        !           733:                        struct tme_completion *agent_completion)
        !           734: {
        !           735:   struct tme_stp22xx *stp22xx;
        !           736: 
        !           737:   /* enter: */
        !           738:   stp22xx = tme_stp22xx_enter((struct tme_stp22xx *) agent_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private);
        !           739: 
        !           740:   /* if this TLB set provides a bus context register: */
        !           741:   if (tlb_set_info->tme_bus_tlb_set_info_bus_context != NULL) {
        !           742: 
        !           743:     /* this bus only has one context: */
        !           744:     *tlb_set_info->tme_bus_tlb_set_info_bus_context = 0;
        !           745:     tlb_set_info->tme_bus_tlb_set_info_bus_context_max = 0;
        !           746:   }
        !           747: 
        !           748:   /* leave: */
        !           749:   agent_completion->tme_completion_error = TME_OK;
        !           750:   tme_stp22xx_completion_validate(stp22xx, agent_completion);
        !           751:   tme_stp22xx_leave(stp22xx);
        !           752: }
        !           753: 
        !           754: /* this notifies a condition: */
        !           755: void
        !           756: tme_stp22xx_cond_notify(struct tme_stp22xx_cond *cond)
        !           757: {
        !           758: 
        !           759:   /* if threading is cooperative, and this condition is idle: */
        !           760:   if (TME_THREADS_COOPERATIVE
        !           761:       && cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_IDLE) {
        !           762: 
        !           763:     /* we have to assume that a thread has yielded waiting on this
        !           764:        condition, but because threading is cooperative, has already
        !           765:        set the condition back to idle.  we can't mark the condition as
        !           766:        notified, since it would never get set back to idle: */
        !           767:   }
        !           768: 
        !           769:   /* otherwise, threading is not cooperative, or the condition is not
        !           770:      idle: */
        !           771:   else {
        !           772: 
        !           773:     /* this condition must be either running before waiting, or
        !           774:        waiting: */
        !           775:     assert (cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_RUNNING
        !           776:            || cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_WAITING);
        !           777: 
        !           778:     /* this condition has been notified: */
        !           779:     cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_NOTIFIED;
        !           780:   }
        !           781: 
        !           782:   /* notify the real condition: */
        !           783:   tme_cond_notify(&cond->tme_stp22xx_cond_cond, FALSE);
        !           784: }
        !           785: 
        !           786: /* this initializes a condition: */
        !           787: void
        !           788: tme_stp22xx_cond_init(struct tme_stp22xx_cond *cond)
        !           789: {
        !           790:   /* this condition is idle: */
        !           791:   cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_IDLE;
        !           792:   tme_cond_init(&cond->tme_stp22xx_cond_cond);
        !           793: }
        !           794: 
        !           795: /* this initializes an stp22xx: */
        !           796: void
        !           797: tme_stp22xx_init(struct tme_stp22xx *stp22xx,
        !           798:                 unsigned long _sizeof,
        !           799:                 tme_uint32_t conn_index_null)
        !           800: {
        !           801:   unsigned long completion_i;
        !           802: 
        !           803:   /* initialize the mutex: */
        !           804:   tme_mutex_init(&stp22xx->tme_stp22xx_mutex);
        !           805: 
        !           806:   /* set the size of the structure: */
        !           807:   stp22xx->tme_stp22xx_sizeof = _sizeof;
        !           808: 
        !           809:   /* set the undefined connection index: */
        !           810:   stp22xx->tme_stp22xx_conn_index_null = conn_index_null;
        !           811: 
        !           812:   /* initialize the completions: */
        !           813:   for (completion_i = 0; completion_i < TME_STP22XX_COMPLETIONS_MAX; completion_i++) {
        !           814:     tme_completion_init(&stp22xx->tme_stp22xx_completions[completion_i]);
        !           815:     stp22xx->tme_stp22xx_completion_handlers[completion_i] = NULL;
        !           816:   }
        !           817: 
        !           818:   /* initialize the delayed completions: */
        !           819:   for (completion_i = 0; completion_i < TME_STP22XX_COMPLETIONS_DELAYED_MAX; completion_i++) {
        !           820:     stp22xx->tme_stp22xx_completions_delayed[completion_i] = NULL;
        !           821:   }
        !           822: 
        !           823:   /* there is no current bus master: */
        !           824:   stp22xx->tme_stp22xx_master_conn_index = conn_index_null;
        !           825: 
        !           826: #if TME_STP22XX_BUS_TRANSITION
        !           827:   /* initialize the token for filling TLB entries for slave cycles: */
        !           828:   tme_token_init(&stp22xx->tme_stp22xx_slave_cycle_tlb_token);
        !           829: #endif /* TME_STP22XX_BUS_TRANSITION */
        !           830: }

unix.superglobalmegacorp.com

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