1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/debug.h>
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/time.h>
33 #include <sys/buf.h>
34 #include <sys/errno.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/signal.h>
38 #include <vm/page.h>
39 #include <vm/as.h>
40 #include <vm/hat.h>
41 #include <vm/seg.h>
42 #include <vm/seg_dev.h>
43 #include <vm/hat_i86.h>
44 #include <sys/ddi.h>
45 #include <sys/devops.h>
46 #include <sys/sunddi.h>
47 #include <sys/ddi_impldefs.h>
48 #include <sys/fs/snode.h>
49 #include <sys/pci.h>
50 #include <sys/vmsystm.h>
51 #include "gfx_private.h"
52 
53 /*
54  * Create a dummy ddi_umem_cookie given to gfxp_devmap_umem_setup().
55  */
56 ddi_umem_cookie_t
57 gfxp_umem_cookie_init(caddr_t kva, size_t size)
58 {
59 	struct ddi_umem_cookie *umem_cookie;
60 
61 	umem_cookie = kmem_zalloc(sizeof (struct ddi_umem_cookie), KM_SLEEP);
62 
63 	if (umem_cookie == NULL)
64 		return (NULL);
65 
66 	umem_cookie->cvaddr = kva;
67 	umem_cookie->type = KMEM_NON_PAGEABLE;
68 	umem_cookie->size = size;
69 
70 	return ((ddi_umem_cookie_t *)umem_cookie);
71 }
72 
73 void
74 gfxp_umem_cookie_destroy(ddi_umem_cookie_t cookie)
75 {
76 	kmem_free(cookie, sizeof (struct ddi_umem_cookie));
77 }
78 
79 /*
80  * called by driver devmap routine to pass kernel virtual address  mapping
81  * info to the framework.    used only for kernel memory
82  * allocated from ddi_dma_mem_alloc().
83  */
84 /*ARGSUSED*/
85 int
86 gfxp_devmap_umem_setup(devmap_cookie_t dhc, dev_info_t *dip,
87     struct devmap_callback_ctl *callbackops, ddi_umem_cookie_t cookie,
88     offset_t off, size_t len, uint_t maxprot, uint_t flags,
89     ddi_device_acc_attr_t *accattrp)
90 {
91 	devmap_handle_t *dhp = (devmap_handle_t *)dhc;
92 	struct ddi_umem_cookie *cp = (struct ddi_umem_cookie *)cookie;
93 
94 #ifdef lint
95 	dip = dip;
96 #endif
97 
98 	if (cookie == NULL)
99 		return (DDI_FAILURE);
100 
101 	/* For UMEM_TRASH, this restriction is not needed */
102 	if ((off + len) > cp->size)
103 		return (DDI_FAILURE);
104 
105 	/*
106 	 * First to check if this function has been called for this dhp.
107 	 */
108 	if (dhp->dh_flags & DEVMAP_SETUP_DONE)
109 		return (DDI_FAILURE);
110 
111 	if ((dhp->dh_prot & dhp->dh_orig_maxprot & maxprot) != dhp->dh_prot)
112 		return (DDI_FAILURE);
113 
114 	if (flags & DEVMAP_MAPPING_INVALID) {
115 		/*
116 		 * If DEVMAP_MAPPING_INVALID is specified, we have to grant
117 		 * remap permission.
118 		 */
119 		if (!(flags & DEVMAP_ALLOW_REMAP)) {
120 			return (DDI_FAILURE);
121 		}
122 	} else {
123 		dhp->dh_cookie = cookie;
124 		dhp->dh_roff = ptob(btop(off));
125 		dhp->dh_cvaddr = cp->cvaddr + dhp->dh_roff;
126 	}
127 
128 	if (accattrp != NULL) {
129 		switch (accattrp->devacc_attr_dataorder) {
130 		case DDI_STRICTORDER_ACC:
131 			dhp->dh_hat_attr &= ~HAT_ORDER_MASK;
132 			dhp->dh_hat_attr |= (HAT_STRICTORDER|HAT_PLAT_NOCACHE);
133 			break;
134 		case DDI_UNORDERED_OK_ACC:
135 			dhp->dh_hat_attr &= ~HAT_ORDER_MASK;
136 			dhp->dh_hat_attr |= HAT_UNORDERED_OK;
137 			break;
138 		case DDI_MERGING_OK_ACC:
139 			dhp->dh_hat_attr &= ~HAT_ORDER_MASK;
140 			dhp->dh_hat_attr |= (HAT_MERGING_OK|HAT_PLAT_NOCACHE);
141 			break;
142 		case DDI_LOADCACHING_OK_ACC:
143 			dhp->dh_hat_attr &= ~HAT_ORDER_MASK;
144 			dhp->dh_hat_attr |= HAT_LOADCACHING_OK;
145 			break;
146 		case DDI_STORECACHING_OK_ACC:
147 			dhp->dh_hat_attr &= ~HAT_ORDER_MASK;
148 			dhp->dh_hat_attr |= HAT_STORECACHING_OK;
149 			break;
150 		default:
151 			return (DDI_FAILURE);
152 		}
153 	}
154 
155 #ifdef __sparc
156 	if (accattrp != NULL) {
157 		if (accattrp->devacc_attr_endian_flags ==
158 			DDI_STRUCTURE_LE_ACC) {
159 			dhp->dh_hat_attr &= ~HAT_ENDIAN_MASK;
160 			dhp->dh_hat_attr |= HAT_STRUCTURE_LE;
161 		}
162 	}
163 #endif
164 
165 	/*
166 	 * The default is _not_ to pass HAT_LOAD_NOCONSIST to hat_devload();
167 	 * we pass HAT_LOAD_NOCONSIST _only_ in cases where hat tries to
168 	 * create consistent mappings but our intention was to create
169 	 * non-consistent mappings.
170 	 *
171 	 * DEVMEM: hat figures it out it's DEVMEM and creates non-consistent
172 	 * mappings.
173 	 *
174 	 * kernel exported memory: hat figures it out it's memory and always
175 	 * creates consistent mappings.
176 	 *
177 	 * /dev/mem: non-consistent mappings. See comments in common/io/mem.c
178 	 *
179 	 * /dev/kmem: consistent mappings are created unless they are
180 	 * MAP_FIXED. We _explicitly_ tell hat to create non-consistent
181 	 * mappings by passing HAT_LOAD_NOCONSIST in case of MAP_FIXED
182 	 * mappings of /dev/kmem. See common/io/mem.c
183 	 */
184 
185 	/* Only some of the flags bits are settable by the driver */
186 	dhp->dh_flags |= (flags & DEVMAP_SETUP_FLAGS);
187 
188 	dhp->dh_len = ptob(btopr(len));
189 	dhp->dh_maxprot = maxprot & dhp->dh_orig_maxprot;
190 	ASSERT((dhp->dh_prot & dhp->dh_orig_maxprot & maxprot) == dhp->dh_prot);
191 
192 	if (callbackops != NULL) {
193 		bcopy(callbackops, &dhp->dh_callbackops,
194 			sizeof (struct devmap_callback_ctl));
195 	}
196 	/*
197 	 * Initialize dh_lock if we want to do remap.
198 	 */
199 	if (dhp->dh_flags & DEVMAP_ALLOW_REMAP) {
200 		mutex_init(&dhp->dh_lock, NULL, MUTEX_DEFAULT, NULL);
201 		dhp->dh_flags |= DEVMAP_LOCK_INITED;
202 	}
203 
204 	dhp->dh_flags |= DEVMAP_SETUP_DONE;
205 
206 	return (DDI_SUCCESS);
207 }
208