root/dev/cardbus/rbus.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rbus_space_alloc
  2. rbus_space_alloc_subregion
  3. rbus_space_free
  4. rbus_new_body
  5. rbus_new
  6. rbus_new_root_delegate
  7. rbus_new_root_share
  8. rbus_delete

    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 }

/* [<][>][^][v][top][bottom][index][help] */