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