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