Home | History | Annotate | Line # | Download | only in drm
drm_memory.c revision 1.1.2.1
      1 /*	$NetBSD: drm_memory.c,v 1.1.2.1 2013/07/24 02:23:06 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2013 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Taylor R. Campbell.
      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  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: drm_memory.c,v 1.1.2.1 2013/07/24 02:23:06 riastradh Exp $");
     34 
     35 /* XXX Cargo-culted from the old drm_memory.c.  */
     36 
     37 #ifdef _KERNEL_OPT
     38 #include "agp_i810.h"
     39 #include "genfb.h"
     40 #else
     41 #define	NAGP_I810	1	/* XXX WTF?  */
     42 #define	NGENFB		0	/* XXX WTF?  */
     43 #endif
     44 
     45 #include <sys/bus.h>
     46 
     47 #if NAGP_I810 > 0
     48 /* XXX include order botch -- shouldn't need to include pcivar.h */
     49 #include <dev/pci/pcivar.h>
     50 #include <dev/pci/agpvar.h>
     51 #endif
     52 
     53 #if NGENFB > 0
     54 #include <dev/wsfb/genfbvar.h>
     55 #endif
     56 
     57 #include <drm/drmP.h>
     58 
     59 /*
     60  * XXX drm_bus_borrow is a horrible kludge!
     61  */
     62 static bool
     63 drm_bus_borrow(bus_addr_t base, bus_space_handle_t *handlep)
     64 {
     65 
     66 #if NAGP_I810 > 0
     67 	if (agp_i810_borrow(base, handlep))
     68 		return true;
     69 #endif
     70 
     71 #if NGENFB > 0
     72 	if (genfb_borrow(base, handlep))
     73 		return true;
     74 #endif
     75 
     76 	return false;
     77 }
     78 
     79 void *
     80 drm_ioremap(struct drm_device *dev, struct drm_local_map *map)
     81 {
     82 	const bus_space_tag_t bst = dev->bst;
     83 	unsigned int unit;
     84 	int error;
     85 
     86 	/*
     87 	 * Search dev's bus maps for a match.
     88 	 */
     89 	for (unit = 0; unit < dev->bus_nmaps; unit++) {
     90 		struct drm_bus_map *const bm = &dev->bus_maps[unit];
     91 
     92 		/* Reject maps starting after the request.  */
     93 		if (map->offset < bm->bm_base)
     94 			continue;
     95 
     96 		/* Reject maps smaller than the request.  */
     97 		if (bm->bm_size < map->size)
     98 			continue;
     99 
    100 		/*
    101 		 * Reject maps that the request doesn't fit in.  (Make
    102 		 * sure to avoid integer overflow.)
    103 		 */
    104 		if ((bm->bm_size - map->size) <
    105 		    (map->offset - bm->bm_base))
    106 			continue;
    107 
    108 		/* Has it been mapped yet?  If not, map it.  */
    109 		if (bm->bm_mapped == 0) {
    110 			KASSERT(ISSET(bm->bm_flags, BUS_SPACE_MAP_LINEAR));
    111 			error = bus_space_map(bst, bm->bm_base,
    112 			    bm->bm_size, bm->bm_flags, &bm->bm_bsh);
    113 			if (error) {
    114 				if (drm_bus_borrow(map->offset, &map->bsh)) {
    115 					map->bus_map = NULL;
    116 					goto win;
    117 				}
    118 				return NULL;
    119 			}
    120 		}
    121 
    122 		/* Mark it used and make a subregion just for the request.  */
    123 		bm->bm_mapped++;
    124 		error = bus_space_subregion(bst, bm->bm_bsh,
    125 		    map->offset - bm->bm_base, map->size, &map->bsh);
    126 		if (error) {
    127 			/*
    128 			 * Back out: unmark it and, if nobody else was
    129 			 * using it, unmap it.
    130 			 */
    131 			if (--bm->bm_mapped == 0)
    132 				bus_space_unmap(bst, bm->bm_bsh,
    133 				    bm->bm_size);
    134 			return NULL;
    135 		}
    136 
    137 		/* Got it!  */
    138 		map->bus_map = bm;
    139 		goto win;
    140 	}
    141 
    142 	/*
    143 	 * No dice.  Try mapping it directly ourselves.
    144 	 *
    145 	 * XXX Is this sensible?  What prevents us from clobbering some
    146 	 * existing map?  And what does this have to do with agp?
    147 	 */
    148 	for (unit = 0; unit < dev->agp_nmaps; unit++) {
    149 		struct drm_bus_map *const bm = &dev->agp_maps[unit];
    150 
    151 		/* Is this one allocated? */
    152 		if (bm->bm_mapped > 0) {
    153 			/*
    154 			 * Make sure it has the same base.
    155 			 *
    156 			 * XXX Why must it be the same base?  Can't we
    157 			 * subregion here too?
    158 			 */
    159 			if (bm->bm_base != map->offset)
    160 				continue;
    161 
    162 			/* Make sure it's big enough.  */
    163 			if (bm->bm_size < map->size)
    164 				continue;
    165 
    166 			/* Mark it used and return it.  */
    167 			bm->bm_mapped++;
    168 
    169 			/* XXX size is an input/output parameter too...?  */
    170 			map->size = bm->bm_size;
    171 
    172 			map->bsh = bm->bm_bsh;
    173 			map->bus_map = bm;
    174 			goto win;
    175 		} else {
    176 			const int flags = BUS_SPACE_MAP_PREFETCHABLE |
    177 			    BUS_SPACE_MAP_LINEAR;
    178 
    179 			/* Try mapping the request.  */
    180 			error = bus_space_map(bst, map->offset, map->size,
    181 			    flags, &bm->bm_bsh);
    182 			if (error)
    183 				return NULL; /* XXX Why not continue?  */
    184 
    185 			/* Got it.  Allocate this bus map.  */
    186 			bm->bm_mapped++;
    187 			bm->bm_base = map->offset;
    188 			bm->bm_size = map->size;
    189 			bm->bm_flags = flags; /* XXX What for?  */
    190 
    191 			map->bsh = bm->bm_bsh;
    192 			map->bus_map = bm;
    193 			goto win;
    194 		}
    195 	}
    196 
    197 	return NULL;
    198 
    199 win:
    200 	return bus_space_vaddr(bst, map->bsh);
    201 }
    202 
    203 void
    204 drm_iounmap(struct drm_device *dev, struct drm_local_map *map)
    205 {
    206 	const bus_space_tag_t bst = dev->bst;
    207 	struct drm_bus_map *const bm = map->bus_map;
    208 
    209 	/*
    210 	 * bm may be null if we have committed the horrible deed of
    211 	 * borrowing from agp_i810 or genfb.
    212 	 */
    213 	if (bm != NULL) {
    214 		KASSERT(bm->bm_mapped > 0);
    215 		if (--bm->bm_mapped)
    216 			bus_space_unmap(bst, bm->bm_bsh, bm->bm_size);
    217 	}
    218 }
    219