[BACK]Return to rbus.c CVS log [TXT][DIR] Up to [local] / sys / dev / cardbus

Annotation of sys/dev/cardbus/rbus.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: rbus.c,v 1.10 2005/09/13 18:53:01 fgsch Exp $ */
                      2: /*     $NetBSD: rbus.c,v 1.3 1999/11/06 06:20:53 soren Exp $   */
                      3: /*
                      4:  * Copyright (c) 1999
                      5:  *     HAYAKAWA Koichi.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by HAYAKAWA Koichi.
                     18:  * 4. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     24:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     25:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     26:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     27:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     28:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     29:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     30:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     31:  */
                     32:
                     33: #include <sys/param.h>
                     34: #include <sys/systm.h>
                     35: #include <sys/device.h>
                     36: #include <sys/malloc.h>
                     37: #include <sys/extent.h>
                     38:
                     39: #include <machine/bus.h>
                     40:
                     41: #include <dev/cardbus/rbus.h>
                     42:
                     43: /* #define RBUS_DEBUG */
                     44:
                     45: #if defined RBUS_DEBUG
                     46: #define STATIC
                     47: #define DPRINTF(a) printf a
                     48: #define DDELAY(x) delay((x)*1000*1000)
                     49: #else
                     50: #define STATIC static
                     51: #define DPRINTF(a)
                     52: #endif
                     53:
                     54:
                     55: static rbus_tag_t rbus_new_body(bus_space_tag_t, rbus_tag_t, struct extent *,
                     56:                      bus_addr_t, bus_addr_t, bus_addr_t, int);
                     57:
                     58: int
                     59: rbus_space_alloc(rbus_tag_t rbt, bus_addr_t addr, bus_size_t size,
                     60:     bus_addr_t mask, bus_addr_t align, int flags, bus_addr_t *addrp,
                     61:     bus_space_handle_t *bshp)
                     62: {
                     63:        return (rbus_space_alloc_subregion(rbt, rbt->rb_start, rbt->rb_end,
                     64:            addr, size, mask, align, flags, addrp, bshp));
                     65: }
                     66:
                     67: int
                     68: rbus_space_alloc_subregion(rbus_tag_t rbt, bus_addr_t substart,
                     69:     bus_addr_t subend, bus_addr_t addr, bus_size_t size,
                     70:     bus_addr_t mask, bus_addr_t align, int flags, bus_addr_t *addrp,
                     71:     bus_space_handle_t *bshp)
                     72: {
                     73:        bus_addr_t decodesize = mask + 1;
                     74:        bus_addr_t boundary, search_addr;
                     75:        int val;
                     76:        u_long result;
                     77:        int exflags = EX_FAST | EX_NOWAIT | EX_MALLOCOK;
                     78:
                     79:        DPRINTF(("rbus_space_alloc: addr %lx, size %lx, mask %lx, align %lx\n",
                     80:            (u_long)addr, (u_long)size, (u_long)mask, (u_long)align));
                     81:
                     82:        addr += rbt->rb_offset;
                     83:
                     84:        if (mask == 0) {
                     85:                /* FULL Decode */
                     86:                decodesize = 0;
                     87:        }
                     88:
                     89:        if (rbt->rb_flags == RBUS_SPACE_ASK_PARENT) {
                     90:                return (rbus_space_alloc(rbt->rb_parent, addr, size, mask,
                     91:                    align, flags, addrp, bshp));
                     92:        } else if (rbt->rb_flags == RBUS_SPACE_SHARE ||
                     93:            rbt->rb_flags == RBUS_SPACE_DEDICATE) {
                     94:                /* rbt has its own sh_extent */
                     95:
                     96:                /* sanity check: the subregion [substart, subend] should be
                     97:                   smaller than the region included in sh_extent */
                     98:                if (substart < rbt->rb_ext->ex_start ||
                     99:                    subend > rbt->rb_ext->ex_end) {
                    100:                        DPRINTF(("rbus: out of range\n"));
                    101:                        return (1);
                    102:                }
                    103:
                    104:                if (decodesize == align) {
                    105:                        if (extent_alloc_subregion(rbt->rb_ext, substart,
                    106:                            subend, size, align, 0, 0, exflags, &result))
                    107:                                return (1);
                    108:                } else if (decodesize == 0) {
                    109:                        /* maybe, the register is overflowed. */
                    110:
                    111:                        if (extent_alloc_subregion(rbt->rb_ext, addr,
                    112:                            addr + size, size, 1, 0, 0, exflags, &result))
                    113:                                return (1);
                    114:                } else {
                    115:                        boundary = decodesize > align ? decodesize : align;
                    116:
                    117:                        search_addr = (substart & ~(boundary - 1)) + addr;
                    118:
                    119:                        if (search_addr < substart)
                    120:                                search_addr += boundary;
                    121:
                    122:                        val = 1;
                    123:                        for (; search_addr + size <= subend;
                    124:                            search_addr += boundary) {
                    125:                                val = extent_alloc_subregion(
                    126:                                    rbt->rb_ext,search_addr,
                    127:                                    search_addr + size, size, align, 0, 0,
                    128:                                    exflags, &result);
                    129:                                DPRINTF(("rbus: trying [%lx:%lx] %lx\n",
                    130:                                    (u_long)search_addr,
                    131:                                    (u_long)search_addr + size,
                    132:                                    (u_long)align));
                    133:                                if (val == 0)
                    134:                                        break;
                    135:                        }
                    136:
                    137:                        if (val != 0) {
                    138:                                /* no space found */
                    139:                                DPRINTF(("rbus: no space found\n"));
                    140:                                return (1);
                    141:                        }
                    142:                }
                    143:
                    144:                if (md_space_map(rbt->rb_bt, result, size, flags, bshp)) {
                    145:                        /* map failed */
                    146:                        extent_free(rbt->rb_ext, result, size, exflags);
                    147:                        return (1);
                    148:                }
                    149:
                    150:                if (addrp != NULL)
                    151:                        *addrp = result + rbt->rb_offset;
                    152:                return (0);
                    153:        } else {
                    154:                /* error!! */
                    155:                DPRINTF(("rbus: no rbus type\n"));
                    156:                return (1);
                    157:        }
                    158: }
                    159:
                    160: int
                    161: rbus_space_free(rbus_tag_t rbt, bus_space_handle_t bsh, bus_size_t size,
                    162:     bus_addr_t *addrp)
                    163: {
                    164:        int exflags = EX_FAST | EX_NOWAIT;
                    165:        bus_addr_t addr;
                    166:        int status = 1;
                    167:
                    168:        if (rbt->rb_flags == RBUS_SPACE_ASK_PARENT) {
                    169:                status = rbus_space_free(rbt->rb_parent, bsh, size, &addr);
                    170:        } else if (rbt->rb_flags == RBUS_SPACE_SHARE ||
                    171:            rbt->rb_flags == RBUS_SPACE_DEDICATE) {
                    172:                md_space_unmap(rbt->rb_bt, bsh, size, &addr);
                    173:
                    174:                extent_free(rbt->rb_ext, addr, size, exflags);
                    175:
                    176:                status = 0;
                    177:        } else {
                    178:                /* error. INVALID rbustag */
                    179:                status = 1;
                    180:        }
                    181:
                    182:        if (addrp != NULL)
                    183:                *addrp = addr;
                    184:
                    185:        return (status);
                    186: }
                    187:
                    188: /*
                    189:  * static rbus_tag_t
                    190:  * rbus_new_body(bus_space_tag_t bt, rbus_tag_t parent,
                    191:  *               struct extent *ex, bus_addr_t start, bus_size_t end,
                    192:  *               bus_addr_t offset, int flags)
                    193:  *
                    194:  */
                    195: static rbus_tag_t
                    196: rbus_new_body(bus_space_tag_t bt, rbus_tag_t parent, struct extent *ex,
                    197:     bus_addr_t start, bus_addr_t end, bus_addr_t offset, int flags)
                    198: {
                    199:        rbus_tag_t rb;
                    200:
                    201:        /* sanity check */
                    202:        if (parent != NULL) {
                    203:                if (start < parent->rb_start || end > parent->rb_end) {
                    204:                        /* out of range: [start, size] should be contained
                    205:                         * in parent space
                    206:                         */
                    207:                        return (0);
                    208:                        /* Should I invoke panic? */
                    209:                }
                    210:        }
                    211:
                    212:        if ((rb = (rbus_tag_t)malloc(sizeof(struct rbustag), M_DEVBUF,
                    213:            M_NOWAIT)) == NULL) {
                    214:                panic("no memory for rbus instance");
                    215:        }
                    216:
                    217:        rb->rb_bt = bt;
                    218:        rb->rb_parent = parent;
                    219:        rb->rb_start = start;
                    220:        rb->rb_end = end;
                    221:        rb->rb_offset = offset;
                    222:        rb->rb_flags = flags;
                    223:        rb->rb_ext = ex;
                    224:
                    225:        DPRINTF(("rbus_new_body: [%lx, %lx] type %s name [%s]\n",
                    226:            (u_long)start, (u_long)end,
                    227:           flags == RBUS_SPACE_SHARE ? "share" :
                    228:           flags == RBUS_SPACE_DEDICATE ? "dedicated" :
                    229:           flags == RBUS_SPACE_ASK_PARENT ? "parent" : "invalid",
                    230:           ex != NULL ? ex->ex_name : "noname"));
                    231:
                    232:        return (rb);
                    233: }
                    234:
                    235: /*
                    236:  * rbus_tag_t rbus_new(rbus_tag_t parent, bus_addr_t start, bus_size_t
                    237:  *                     size, bus_addr_t offset, int flags)
                    238:  *
                    239:  *  This function makes a new child rbus instance.
                    240:  */
                    241: rbus_tag_t
                    242: rbus_new(rbus_tag_t parent, bus_addr_t start, bus_size_t size,
                    243:     bus_addr_t offset, int flags)
                    244: {
                    245:        rbus_tag_t rb;
                    246:        struct extent *ex = NULL;
                    247:        bus_addr_t end = start + size;
                    248:
                    249:        if (flags == RBUS_SPACE_SHARE) {
                    250:                ex = parent->rb_ext;
                    251:        } else if (flags == RBUS_SPACE_DEDICATE) {
                    252:                if ((ex = extent_create("rbus", start, end, M_DEVBUF, NULL, 0,
                    253:                    EX_NOCOALESCE|EX_NOWAIT)) == NULL)
                    254:                        return (NULL);
                    255:        } else if (flags == RBUS_SPACE_ASK_PARENT) {
                    256:                ex = NULL;
                    257:        } else {
                    258:                /* Invalid flag */
                    259:                return (0);
                    260:        }
                    261:
                    262:        rb = rbus_new_body(parent->rb_bt, parent, ex, start, start + size,
                    263:            offset, flags);
                    264:
                    265:        if ((rb == NULL) && (flags == RBUS_SPACE_DEDICATE))
                    266:                extent_destroy(ex);
                    267:
                    268:        return (rb);
                    269: }
                    270:
                    271: /*
                    272:  * rbus_tag_t rbus_new_root_delegate(bus_space_tag, bus_addr_t,
                    273:  *                                   bus_size_t, bus_addr_t offset)
                    274:  *
                    275:  *  This function makes a root rbus instance.
                    276:  */
                    277: rbus_tag_t
                    278: rbus_new_root_delegate(bus_space_tag_t bt, bus_addr_t start, bus_size_t size,
                    279:     bus_addr_t offset)
                    280: {
                    281:        rbus_tag_t rb;
                    282:        struct extent *ex;
                    283:
                    284:        if ((ex = extent_create("rbus root", start, start + size, M_DEVBUF,
                    285:            NULL, 0, EX_NOCOALESCE|EX_NOWAIT)) == NULL)
                    286:                return (NULL);
                    287:
                    288:        rb = rbus_new_body(bt, NULL, ex, start, start + size, offset,
                    289:            RBUS_SPACE_DEDICATE);
                    290:
                    291:        if (rb == NULL)
                    292:                extent_destroy(ex);
                    293:
                    294:        return (rb);
                    295: }
                    296:
                    297: /*
                    298:  * rbus_tag_t rbus_new_root_share(bus_space_tag, struct extent *,
                    299:  *                                 bus_addr_t, bus_size_t, bus_addr_t offset)
                    300:  *
                    301:  *  This function makes a root rbus instance.
                    302:  */
                    303: rbus_tag_t
                    304: rbus_new_root_share(bus_space_tag_t bt, struct extent *ex, bus_addr_t start,
                    305:     bus_size_t size, bus_addr_t offset)
                    306: {
                    307:        /* sanity check */
                    308:        if (start < ex->ex_start || start + size > ex->ex_end) {
                    309:                /* out of range: [start, size] should be contained in
                    310:                 * parent space
                    311:                 */
                    312:                return (0);
                    313:                /* Should I invoke panic? */
                    314:        }
                    315:
                    316:        return (rbus_new_body(bt, NULL, ex, start, start + size, offset,
                    317:            RBUS_SPACE_SHARE));
                    318: }
                    319:
                    320: /*
                    321:  * int rbus_delete (rbus_tag_t rb)
                    322:  *
                    323:  *   This function deletes the rbus structure pointed in the argument.
                    324:  */
                    325: int
                    326: rbus_delete(rbus_tag_t rb)
                    327: {
                    328:        DPRINTF(("rbus_delete called [%s]\n", rb->rb_ext != NULL ?
                    329:            rb->rb_ext->ex_name : "noname"));
                    330:
                    331:        if (rb->rb_flags == RBUS_SPACE_DEDICATE)
                    332:                extent_destroy(rb->rb_ext);
                    333:
                    334:        free(rb, M_DEVBUF);
                    335:
                    336:        return (0);
                    337: }

CVSweb