[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     ! 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