xref: /titanic_50/usr/src/uts/common/io/drm/drm_sunmod.c (revision c1374a13e412c4ec42cba867e57347a0e049a822)
160405de4Skz151634 /*
260405de4Skz151634  * CDDL HEADER START
360405de4Skz151634  *
460405de4Skz151634  * The contents of this file are subject to the terms of the
560405de4Skz151634  * Common Development and Distribution License (the "License").
660405de4Skz151634  * You may not use this file except in compliance with the License.
760405de4Skz151634  *
860405de4Skz151634  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
960405de4Skz151634  * or http://www.opensolaris.org/os/licensing.
1060405de4Skz151634  * See the License for the specific language governing permissions
1160405de4Skz151634  * and limitations under the License.
1260405de4Skz151634  *
1360405de4Skz151634  * When distributing Covered Code, include this CDDL HEADER in each
1460405de4Skz151634  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1560405de4Skz151634  * If applicable, add the following below this CDDL HEADER, with the
1660405de4Skz151634  * fields enclosed by brackets "[]" replaced with your own identifying
1760405de4Skz151634  * information: Portions Copyright [yyyy] [name of copyright owner]
1860405de4Skz151634  *
1960405de4Skz151634  * CDDL HEADER END
2060405de4Skz151634  */
2160405de4Skz151634 
2260405de4Skz151634 /*
230035d21cSmiao chen - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2460405de4Skz151634  * Use is subject to license terms.
2560405de4Skz151634  */
2660405de4Skz151634 
2760405de4Skz151634 /*
2860405de4Skz151634  * Common misc module interfaces of DRM under Solaris
2960405de4Skz151634  */
3060405de4Skz151634 
31d0538f66Scg149915 /*
32d0538f66Scg149915  * This module calls into gfx and agpmaster misc modules respectively
33d0538f66Scg149915  * for generic graphics operations and AGP master device support.
34d0538f66Scg149915  */
35d0538f66Scg149915 
36d0538f66Scg149915 #include "drm_sunmod.h"
3760405de4Skz151634 #include <sys/modctl.h>
38d0538f66Scg149915 #include <sys/kmem.h>
39d0538f66Scg149915 #include <vm/seg_kmem.h>
4060405de4Skz151634 
4160405de4Skz151634 static struct modlmisc modlmisc = {
4239b361b2SRichard Bean 	&mod_miscops, "DRM common interfaces"
4360405de4Skz151634 };
4460405de4Skz151634 
4560405de4Skz151634 static struct modlinkage modlinkage = {
4660405de4Skz151634 	MODREV_1, (void *)&modlmisc, NULL
4760405de4Skz151634 };
4860405de4Skz151634 
49d0538f66Scg149915 static drm_inst_list_t	*drm_inst_head;
50d0538f66Scg149915 static kmutex_t	drm_inst_list_lock;
51d0538f66Scg149915 
52d0538f66Scg149915 static int drm_sun_open(dev_t *, int, int, cred_t *);
53d0538f66Scg149915 static int drm_sun_close(dev_t, int, int, cred_t *);
54d0538f66Scg149915 static int drm_sun_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
55d0538f66Scg149915 static int drm_sun_devmap(dev_t, devmap_cookie_t, offset_t, size_t,
56d0538f66Scg149915     size_t *, uint_t);
57d0538f66Scg149915 
58d0538f66Scg149915 /*
59d0538f66Scg149915  * devmap callbacks for AGP and PCI GART
60d0538f66Scg149915  */
61d0538f66Scg149915 static int drm_devmap_map(devmap_cookie_t, dev_t,
62d0538f66Scg149915     uint_t, offset_t, size_t, void **);
63d0538f66Scg149915 static int drm_devmap_dup(devmap_cookie_t, void *,
64d0538f66Scg149915     devmap_cookie_t, void **);
65d0538f66Scg149915 static void drm_devmap_unmap(devmap_cookie_t, void *,
66d0538f66Scg149915     offset_t, size_t, devmap_cookie_t, void **, devmap_cookie_t, void **);
67d0538f66Scg149915 
68d0538f66Scg149915 static drm_inst_list_t *drm_supp_alloc_drv_entry(dev_info_t *);
69d0538f66Scg149915 static drm_inst_state_t *drm_sup_devt_to_state(dev_t);
70d0538f66Scg149915 static void drm_supp_free_drv_entry(dev_info_t *);
71d0538f66Scg149915 
72d0538f66Scg149915 static struct devmap_callback_ctl drm_devmap_callbacks = {
73d0538f66Scg149915 		DEVMAP_OPS_REV, 		/* devmap_rev */
74d0538f66Scg149915 		drm_devmap_map,				/* devmap_map */
75d0538f66Scg149915 		NULL,			/* devmap_access */
76d0538f66Scg149915 		drm_devmap_dup,			/* devmap_dup */
77d0538f66Scg149915 		drm_devmap_unmap 		/* devmap_unmap */
78d0538f66Scg149915 };
79d0538f66Scg149915 
80d0538f66Scg149915 /*
81d0538f66Scg149915  * Common device operations structure for all DRM drivers
82d0538f66Scg149915  */
83d0538f66Scg149915 struct cb_ops drm_cb_ops = {
84d0538f66Scg149915 	drm_sun_open,			/* cb_open */
85d0538f66Scg149915 	drm_sun_close,			/* cb_close */
86d0538f66Scg149915 	nodev,					/* cb_strategy */
87d0538f66Scg149915 	nodev,					/* cb_print */
88d0538f66Scg149915 	nodev,					/* cb_dump */
89d0538f66Scg149915 	nodev,					/* cb_read */
90d0538f66Scg149915 	nodev,					/* cb_write */
91d0538f66Scg149915 	drm_sun_ioctl,		/* cb_ioctl */
92d0538f66Scg149915 	drm_sun_devmap,		/* cb_devmap */
93d0538f66Scg149915 	nodev,					/* cb_mmap */
94d0538f66Scg149915 	NULL,			/* cb_segmap */
95d0538f66Scg149915 	nochpoll,				/* cb_chpoll */
96d0538f66Scg149915 	ddi_prop_op,		/* cb_prop_op */
97d0538f66Scg149915 	0,					/* cb_stream */
98d0538f66Scg149915 	D_NEW | D_MTSAFE |D_DEVMAP	/* cb_flag */
99d0538f66Scg149915 };
100d0538f66Scg149915 
10160405de4Skz151634 int
_init(void)10260405de4Skz151634 _init(void)
10360405de4Skz151634 {
104d0538f66Scg149915 	int	error;
10560405de4Skz151634 
106d0538f66Scg149915 	if ((error = mod_install(&modlinkage)) != 0) {
107d0538f66Scg149915 		return (error);
108d0538f66Scg149915 	}
10960405de4Skz151634 
110d0538f66Scg149915 	/* initialize the instance list lock */
111d0538f66Scg149915 	mutex_init(&drm_inst_list_lock, NULL, MUTEX_DRIVER, NULL);
11260405de4Skz151634 	return (0);
11360405de4Skz151634 }
11460405de4Skz151634 
11560405de4Skz151634 int
_fini(void)11660405de4Skz151634 _fini(void)
11760405de4Skz151634 {
11860405de4Skz151634 	int	err;
11960405de4Skz151634 
12060405de4Skz151634 	if ((err = mod_remove(&modlinkage)) != 0)
12160405de4Skz151634 		return (err);
12260405de4Skz151634 
123d0538f66Scg149915 	mutex_destroy(&drm_inst_list_lock);
12460405de4Skz151634 	return (0);
12560405de4Skz151634 }
12660405de4Skz151634 
12760405de4Skz151634 int
_info(struct modinfo * modinfop)12860405de4Skz151634 _info(struct modinfo *modinfop)
12960405de4Skz151634 {
13060405de4Skz151634 	return (mod_info(&modlinkage, modinfop));
13160405de4Skz151634 }
132d0538f66Scg149915 
133d0538f66Scg149915 void *
drm_supp_register(dev_info_t * dip,drm_device_t * dp)134d0538f66Scg149915 drm_supp_register(dev_info_t *dip, drm_device_t *dp)
135d0538f66Scg149915 {
136d0538f66Scg149915 	int		error;
137d0538f66Scg149915 	char	buf[80];
138d0538f66Scg149915 	int		instance = ddi_get_instance(dip);
139d0538f66Scg149915 	ddi_acc_handle_t	pci_cfg_handle;
140d0538f66Scg149915 	agp_master_softc_t	*agpm;
141d0538f66Scg149915 	drm_inst_state_t	*mstate;
142d0538f66Scg149915 	drm_inst_list_t		*entry;
143d0538f66Scg149915 	gfxp_vgatext_softc_ptr_t gfxp;
144d0538f66Scg149915 	struct dev_ops	*devop;
145d0538f66Scg149915 
146d0538f66Scg149915 	ASSERT(dip != NULL);
147d0538f66Scg149915 
148d0538f66Scg149915 	entry = drm_supp_alloc_drv_entry(dip);
149d0538f66Scg149915 	if (entry == NULL) {
150d0538f66Scg149915 		cmn_err(CE_WARN, "drm_supp_register: failed to get softstate");
151d0538f66Scg149915 		return (NULL);
152d0538f66Scg149915 	}
153d0538f66Scg149915 	mstate = &entry->disl_state;
154d0538f66Scg149915 
155d0538f66Scg149915 	/*
156d0538f66Scg149915 	 * DRM drivers are required to use common cb_ops
157d0538f66Scg149915 	 */
158d0538f66Scg149915 	devop = ddi_get_driver(dip);
159d0538f66Scg149915 	if (devop->devo_cb_ops != &drm_cb_ops) {
160d0538f66Scg149915 		devop->devo_cb_ops = &drm_cb_ops;
161d0538f66Scg149915 	}
162d0538f66Scg149915 
163d0538f66Scg149915 	/* Generic graphics initialization */
164d0538f66Scg149915 	gfxp = gfxp_vgatext_softc_alloc();
165d0538f66Scg149915 	error = gfxp_vgatext_attach(dip, DDI_ATTACH, gfxp);
166d0538f66Scg149915 	if (error != DDI_SUCCESS) {
167d0538f66Scg149915 		DRM_ERROR("drm_supp_regiter: failed to init gfx");
168d0538f66Scg149915 		goto exit1;
169d0538f66Scg149915 	}
170d0538f66Scg149915 
171d0538f66Scg149915 	/* create a minor node for common graphics ops */
172d0538f66Scg149915 	(void) sprintf(buf, "%s%d", GFX_NAME, instance);
173d0538f66Scg149915 	error = ddi_create_minor_node(dip, buf, S_IFCHR,
174d0538f66Scg149915 	    INST2NODE0(instance), DDI_NT_DISPLAY, NULL);
175d0538f66Scg149915 	if (error != DDI_SUCCESS) {
176d0538f66Scg149915 		DRM_ERROR("drm_supp_regiter: "
177d0538f66Scg149915 		    "failed to create minor node for gfx");
178d0538f66Scg149915 		goto exit2;
179d0538f66Scg149915 	}
180d0538f66Scg149915 
181d0538f66Scg149915 	/* setup mapping for later PCI config space access */
182d0538f66Scg149915 	error = pci_config_setup(dip, &pci_cfg_handle);
183d0538f66Scg149915 	if (error != DDI_SUCCESS) {
184d0538f66Scg149915 		DRM_ERROR("drm_supp_regiter: "
185d0538f66Scg149915 		    "PCI configuration space setup failed");
186d0538f66Scg149915 		goto exit2;
187d0538f66Scg149915 	}
188d0538f66Scg149915 
189d0538f66Scg149915 	/* AGP master attach */
190d0538f66Scg149915 	agpm = NULL;
191d0538f66Scg149915 	if (dp->driver->use_agp) {
192d0538f66Scg149915 		DRM_DEBUG("drm_supp_regiter: driver use AGP\n");
193d0538f66Scg149915 		error = agpmaster_attach(dip, &agpm,
194d0538f66Scg149915 		    pci_cfg_handle, INST2NODE1(instance));
195d0538f66Scg149915 		if ((error != DDI_SUCCESS) && (dp->driver->require_agp)) {
196d0538f66Scg149915 			DRM_ERROR("drm_supp_regiter: "
197d0538f66Scg149915 			    "AGP master support not available");
198d0538f66Scg149915 			goto exit3;
199d0538f66Scg149915 		}
200d0538f66Scg149915 	}
201d0538f66Scg149915 
202d0538f66Scg149915 	mutex_enter(&mstate->mis_lock);
203d0538f66Scg149915 	mstate->mis_major = ddi_driver_major(dip);
204d0538f66Scg149915 	mstate->mis_dip = dip;
205d0538f66Scg149915 	mstate->mis_gfxp = gfxp;
206d0538f66Scg149915 	mstate->mis_agpm = agpm;
207d0538f66Scg149915 	mstate->mis_cfg_hdl = pci_cfg_handle;
208d0538f66Scg149915 	mstate->mis_devp = dp;
209d0538f66Scg149915 	mutex_exit(&mstate->mis_lock);
210d0538f66Scg149915 
211d0538f66Scg149915 	/* create minor node for DRM access */
212d0538f66Scg149915 	(void) sprintf(buf, "%s%d", DRM_DEVNODE, instance);
213d0538f66Scg149915 	if (ddi_create_minor_node(dip, buf, S_IFCHR,
214d0538f66Scg149915 	    INST2NODE2(instance), DDI_NT_DISPLAY_DRM, 0)) {
215d0538f66Scg149915 		DRM_ERROR("supp_regiter: faled to create minor node for drm");
216d0538f66Scg149915 		goto exit4;
217d0538f66Scg149915 	}
218d0538f66Scg149915 
219d0538f66Scg149915 	return ((void *)mstate);
220d0538f66Scg149915 
221d0538f66Scg149915 exit4:
222d0538f66Scg149915 	if ((dp->driver->use_agp) && agpm)
223d0538f66Scg149915 		agpmaster_detach(&agpm);
224d0538f66Scg149915 exit3:
225d0538f66Scg149915 	pci_config_teardown(&pci_cfg_handle);
226d0538f66Scg149915 exit2:
227*c1374a13SSurya Prakki 	(void) gfxp_vgatext_detach(dip, DDI_DETACH, gfxp);
228d0538f66Scg149915 exit1:
229d0538f66Scg149915 	gfxp_vgatext_softc_free(gfxp);
230d0538f66Scg149915 	drm_supp_free_drv_entry(dip);
231d0538f66Scg149915 	ddi_remove_minor_node(dip, NULL);
232d0538f66Scg149915 
233d0538f66Scg149915 	return (NULL);
234d0538f66Scg149915 }
235d0538f66Scg149915 
236d0538f66Scg149915 
237d0538f66Scg149915 int
drm_supp_unregister(void * handle)238d0538f66Scg149915 drm_supp_unregister(void *handle)
239d0538f66Scg149915 {
240d0538f66Scg149915 	drm_inst_list_t		*list;
241d0538f66Scg149915 	drm_inst_state_t	*mstate;
242d0538f66Scg149915 
243d0538f66Scg149915 	list = (drm_inst_list_t *)handle;
244d0538f66Scg149915 	mstate = &list->disl_state;
245d0538f66Scg149915 	mutex_enter(&mstate->mis_lock);
246d0538f66Scg149915 
247d0538f66Scg149915 	/* AGP master detach */
248d0538f66Scg149915 	if (mstate->mis_agpm != NULL)
249d0538f66Scg149915 		agpmaster_detach(&mstate->mis_agpm);
250d0538f66Scg149915 
251d0538f66Scg149915 	/* free PCI config access handle */
252d0538f66Scg149915 	if (mstate->mis_cfg_hdl)
253d0538f66Scg149915 		pci_config_teardown(&mstate->mis_cfg_hdl);
254d0538f66Scg149915 
255d0538f66Scg149915 	/* graphics misc module detach */
256d0538f66Scg149915 	if (mstate->mis_gfxp) {
257d0538f66Scg149915 		(void) gfxp_vgatext_detach(mstate->mis_dip, DDI_DETACH,
258d0538f66Scg149915 		    mstate->mis_gfxp);
259d0538f66Scg149915 		gfxp_vgatext_softc_free(mstate->mis_gfxp);
260d0538f66Scg149915 	}
261d0538f66Scg149915 
262d0538f66Scg149915 	mstate->mis_devp = NULL;
263d0538f66Scg149915 
264d0538f66Scg149915 	/* remove all minor nodes */
265d0538f66Scg149915 	ddi_remove_minor_node(mstate->mis_dip, NULL);
266d0538f66Scg149915 	mutex_exit(&mstate->mis_lock);
267d0538f66Scg149915 	drm_supp_free_drv_entry(mstate->mis_dip);
268d0538f66Scg149915 
269d0538f66Scg149915 	return (DDI_SUCCESS);
270d0538f66Scg149915 }
271d0538f66Scg149915 
272d0538f66Scg149915 
273d0538f66Scg149915 /*ARGSUSED*/
274d0538f66Scg149915 static int
drm_sun_open(dev_t * devp,int flag,int otyp,cred_t * credp)275d0538f66Scg149915 drm_sun_open(dev_t *devp, int flag, int otyp, cred_t *credp)
276d0538f66Scg149915 {
277d0538f66Scg149915 	drm_inst_state_t	*mstate;
278fca314aaScg149915 	drm_cminor_t	*mp, *newp;
279d0538f66Scg149915 	drm_device_t	*dp;
280d0538f66Scg149915 	minor_t		minor;
281fca314aaScg149915 	int		newminor;
282fca314aaScg149915 	int		instance;
283d0538f66Scg149915 	int		err;
284d0538f66Scg149915 
285d0538f66Scg149915 	mstate = drm_sup_devt_to_state(*devp);
286d0538f66Scg149915 	/*
287d0538f66Scg149915 	 * return ENXIO for deferred attach so that system can
288d0538f66Scg149915 	 * attach us again.
289d0538f66Scg149915 	 */
290d0538f66Scg149915 	if (mstate == NULL)
291d0538f66Scg149915 		return (ENXIO);
292d0538f66Scg149915 
293fca314aaScg149915 	/*
294fca314aaScg149915 	 * The lest significant 15 bits are used for minor_number, and
295fca314aaScg149915 	 * the mid 3 bits are used for instance number. All minor numbers
296fca314aaScg149915 	 * are used as follows:
297fca314aaScg149915 	 * 0 -- gfx
298fca314aaScg149915 	 * 1 -- agpmaster
299fca314aaScg149915 	 * 2 -- drm
300fca314aaScg149915 	 * (3, MAX_CLONE_MINOR) -- drm minor node for clone open.
301fca314aaScg149915 	 */
302d0538f66Scg149915 	minor = DEV2MINOR(*devp);
303fca314aaScg149915 	instance = DEV2INST(*devp);
304d0538f66Scg149915 	ASSERT(minor <= MAX_CLONE_MINOR);
305fca314aaScg149915 
306fca314aaScg149915 	/*
307fca314aaScg149915 	 * No operations for VGA & AGP mater devices, always return OK.
308fca314aaScg149915 	 */
309d0538f66Scg149915 	if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
310d0538f66Scg149915 		return (0);
311d0538f66Scg149915 
312d0538f66Scg149915 	/*
313d0538f66Scg149915 	 * From here, we start to process drm
314d0538f66Scg149915 	 */
315d0538f66Scg149915 
316d0538f66Scg149915 	dp = mstate->mis_devp;
317d0538f66Scg149915 	if (!dp)
318d0538f66Scg149915 		return (ENXIO);
319d0538f66Scg149915 
320d0538f66Scg149915 	/*
321fca314aaScg149915 	 * Drm driver implements a software lock to serialize access
322fca314aaScg149915 	 * to graphics hardware based on per-process granulation. Before
323fca314aaScg149915 	 * operating graphics hardware, all clients, including kernel
324fca314aaScg149915 	 * and applications, must acquire this lock via DRM_IOCTL_LOCK
325fca314aaScg149915 	 * ioctl, and release it via DRM_IOCTL_UNLOCK after finishing
326fca314aaScg149915 	 * operations. Drm driver will grant r/w permission to the
327fca314aaScg149915 	 * process which acquires this lock (Kernel is assumed to have
328fca314aaScg149915 	 * process ID 0).
329fca314aaScg149915 	 *
330fca314aaScg149915 	 * A process might be terminated without releasing drm lock, in
331fca314aaScg149915 	 * this case, drm driver is responsible for clearing the holding.
332fca314aaScg149915 	 * To be informed of process exiting, drm driver uses clone open
333fca314aaScg149915 	 * to guarantee that each call to open(9e) have one corresponding
334fca314aaScg149915 	 * call to close(9e). In most cases, a process will close drm
335fca314aaScg149915 	 * during process termination, so that drm driver could have a
336fca314aaScg149915 	 * chance to release drm lock.
337fca314aaScg149915 	 *
338fca314aaScg149915 	 * In fact, a driver cannot know exactly when a process exits.
339fca314aaScg149915 	 * Clone open doesn't address this issue completely: Because of
340fca314aaScg149915 	 * inheritance, child processes inherit file descriptors from
341fca314aaScg149915 	 * their parent. As a result, if the parent exits before its
342fca314aaScg149915 	 * children, drm close(9e) entrypoint won't be called until all
343fca314aaScg149915 	 * of its children terminate.
344fca314aaScg149915 	 *
345fca314aaScg149915 	 * Another issue brought up by inhertance is the process PID
346fca314aaScg149915 	 * that calls the drm close() entry point may not be the same
347fca314aaScg149915 	 * as the one who called open(). Per-process struct is allocated
348fca314aaScg149915 	 * when a process first open() drm, and released when the process
349fca314aaScg149915 	 * last close() drm. Since open()/close() may be not the same
350fca314aaScg149915 	 * process, PID cannot be used for key to lookup per-process
351fca314aaScg149915 	 * struct. So, we associate minor number with per-process struct
352fca314aaScg149915 	 * during open()'ing, and find corresponding process struct
353fca314aaScg149915 	 * via minor number when close() is called.
354d0538f66Scg149915 	 */
355fca314aaScg149915 	newp = kmem_zalloc(sizeof (drm_cminor_t), KM_SLEEP);
356d0538f66Scg149915 	mutex_enter(&dp->dev_lock);
357fca314aaScg149915 	for (newminor = DRM_MIN_CLONEMINOR; newminor < MAX_CLONE_MINOR;
358fca314aaScg149915 	    newminor ++) {
359fca314aaScg149915 		TAILQ_FOREACH(mp, &dp->minordevs, link) {
360fca314aaScg149915 			if (mp->minor == newminor)
361d0538f66Scg149915 				break;
362d0538f66Scg149915 		}
363d0538f66Scg149915 		if (mp == NULL)
364d0538f66Scg149915 			goto gotminor;
365d0538f66Scg149915 	}
366d0538f66Scg149915 
367d0538f66Scg149915 	mutex_exit(&dp->dev_lock);
368194eb4bbStao chen - Sun Microsystems - Beijing China 	(void) kmem_free(newp, sizeof (drm_cminor_t));
369d0538f66Scg149915 	return (EMFILE);
370d0538f66Scg149915 
371d0538f66Scg149915 gotminor:
372fca314aaScg149915 	TAILQ_INSERT_TAIL(&dp->minordevs, newp, link);
373fca314aaScg149915 	newp->minor = newminor;
374d0538f66Scg149915 	mutex_exit(&dp->dev_lock);
375fca314aaScg149915 	err = drm_open(dp, newp, flag, otyp, credp);
376fca314aaScg149915 	if (err) {
377fca314aaScg149915 		mutex_enter(&dp->dev_lock);
378fca314aaScg149915 		TAILQ_REMOVE(&dp->minordevs, newp, link);
379194eb4bbStao chen - Sun Microsystems - Beijing China 		(void) kmem_free(newp, sizeof (drm_cminor_t));
380fca314aaScg149915 		mutex_exit(&dp->dev_lock);
381fca314aaScg149915 
382fca314aaScg149915 		return (err);
383fca314aaScg149915 	}
384fca314aaScg149915 
385fca314aaScg149915 	/* return a clone minor */
386fca314aaScg149915 	newminor = newminor | (instance << NBITSMNODE);
387fca314aaScg149915 	*devp = makedevice(getmajor(*devp), newminor);
388d0538f66Scg149915 	return (err);
389d0538f66Scg149915 }
390d0538f66Scg149915 
391d0538f66Scg149915 /*ARGSUSED*/
392d0538f66Scg149915 static int
drm_sun_close(dev_t dev,int flag,int otyp,cred_t * credp)393d0538f66Scg149915 drm_sun_close(dev_t dev, int flag, int otyp, cred_t *credp)
394d0538f66Scg149915 {
395d0538f66Scg149915 	drm_inst_state_t	*mstate;
396d0538f66Scg149915 	drm_device_t		*dp;
397d0538f66Scg149915 	minor_t		minor;
398fca314aaScg149915 	int		ret;
399d0538f66Scg149915 
400d0538f66Scg149915 	mstate = drm_sup_devt_to_state(dev);
401d0538f66Scg149915 	if (mstate == NULL)
402d0538f66Scg149915 		return (EBADF);
403d0538f66Scg149915 
404d0538f66Scg149915 	minor = DEV2MINOR(dev);
405d0538f66Scg149915 	ASSERT(minor <= MAX_CLONE_MINOR);
406d0538f66Scg149915 	if ((minor == GFX_MINOR) || (minor == AGPMASTER_MINOR))
407d0538f66Scg149915 		return (0);
408d0538f66Scg149915 
409d0538f66Scg149915 	dp = mstate->mis_devp;
410d0538f66Scg149915 	if (dp == NULL) {
411d0538f66Scg149915 		DRM_ERROR("drm_sun_close: NULL soft state");
412d0538f66Scg149915 		return (ENXIO);
413d0538f66Scg149915 	}
414d0538f66Scg149915 
415fca314aaScg149915 	ret = drm_close(dp, minor, flag, otyp, credp);
416d0538f66Scg149915 
417fca314aaScg149915 	return (ret);
418d0538f66Scg149915 }
419d0538f66Scg149915 
420d0538f66Scg149915 /*ARGSUSED*/
421d0538f66Scg149915 static int
drm_sun_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)422d0538f66Scg149915 drm_sun_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
423d0538f66Scg149915     cred_t *credp, int *rvalp)
424d0538f66Scg149915 {
425d0538f66Scg149915 	extern drm_ioctl_desc_t drm_ioctls[];
426d0538f66Scg149915 
427d0538f66Scg149915 	drm_inst_state_t	*mstate;
428d0538f66Scg149915 	drm_device_t		*dp;
429d0538f66Scg149915 	drm_ioctl_desc_t	*ioctl;
430d0538f66Scg149915 	drm_ioctl_t		*func;
431d0538f66Scg149915 	drm_file_t		*fpriv;
432d0538f66Scg149915 	minor_t		minor;
433d0538f66Scg149915 	int		retval;
434d0538f66Scg149915 	int		nr;
435d0538f66Scg149915 
436d0538f66Scg149915 	if (cmd == VIS_GETIDENTIFIER) {
437d0538f66Scg149915 		if (ddi_copyout(&text_ident, (void *)arg,
438d0538f66Scg149915 		    sizeof (struct vis_identifier), mode))
439d0538f66Scg149915 			return (EFAULT);
440d0538f66Scg149915 	}
441d0538f66Scg149915 
442d0538f66Scg149915 	mstate = drm_sup_devt_to_state(dev);
443d0538f66Scg149915 	if (mstate == NULL) {
444d0538f66Scg149915 		return (EIO);
445d0538f66Scg149915 	}
446d0538f66Scg149915 
447d0538f66Scg149915 	minor = DEV2MINOR(dev);
448d0538f66Scg149915 	ASSERT(minor <= MAX_CLONE_MINOR);
449d0538f66Scg149915 	switch (minor) {
450d0538f66Scg149915 	case GFX_MINOR:
451d0538f66Scg149915 		retval = gfxp_vgatext_ioctl(dev, cmd, arg,
452d0538f66Scg149915 		    mode, credp, rvalp, mstate->mis_gfxp);
453d0538f66Scg149915 		return (retval);
454d0538f66Scg149915 
455d0538f66Scg149915 	case AGPMASTER_MINOR:
456d0538f66Scg149915 		retval = agpmaster_ioctl(dev, cmd, arg, mode,
457d0538f66Scg149915 		    credp, rvalp, mstate->mis_agpm);
458d0538f66Scg149915 		return (retval);
459d0538f66Scg149915 
460d0538f66Scg149915 	case DRM_MINOR:
461d0538f66Scg149915 	default:	/* DRM cloning minor nodes */
462d0538f66Scg149915 		break;
463d0538f66Scg149915 	}
464d0538f66Scg149915 
465d0538f66Scg149915 	dp = mstate->mis_devp;
466d0538f66Scg149915 	ASSERT(dp != NULL);
467d0538f66Scg149915 
468d0538f66Scg149915 	nr = DRM_IOCTL_NR(cmd);
469d0538f66Scg149915 	ioctl = &drm_ioctls[nr];
470d0538f66Scg149915 	atomic_inc_32(&dp->counts[_DRM_STAT_IOCTLS]);
471d0538f66Scg149915 
472d0538f66Scg149915 	/* It's not a core DRM ioctl, try driver-specific. */
473d0538f66Scg149915 	if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) {
474d0538f66Scg149915 		/* The array entries begin at DRM_COMMAND_BASE ioctl nr */
475d0538f66Scg149915 		nr -= DRM_COMMAND_BASE;
476d0538f66Scg149915 		if (nr > dp->driver->max_driver_ioctl) {
477d0538f66Scg149915 			DRM_ERROR("Bad driver ioctl number, 0x%x (of 0x%x)",
478d0538f66Scg149915 			    nr, dp->driver->max_driver_ioctl);
479d0538f66Scg149915 			return (EINVAL);
480d0538f66Scg149915 		}
481d0538f66Scg149915 		ioctl = &dp->driver->driver_ioctls[nr];
482d0538f66Scg149915 	}
483d0538f66Scg149915 
484d0538f66Scg149915 	func = ioctl->func;
485d0538f66Scg149915 	if (func == NULL) {
486d0538f66Scg149915 		return (ENOTSUP);
487d0538f66Scg149915 	}
488d0538f66Scg149915 
489d0538f66Scg149915 	mutex_enter(&dp->dev_lock);
490d0538f66Scg149915 	fpriv = drm_find_file_by_proc(dp, credp);
491d0538f66Scg149915 	mutex_exit(&dp->dev_lock);
492d0538f66Scg149915 	if (fpriv == NULL) {
493d0538f66Scg149915 		DRM_ERROR("drm_sun_ioctl : can't find authenticator");
494d0538f66Scg149915 		return (EACCES);
495d0538f66Scg149915 	}
496d0538f66Scg149915 
497d0538f66Scg149915 	if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(credp)) ||
498d0538f66Scg149915 	    ((ioctl->flags & DRM_AUTH) && !fpriv->authenticated) ||
499d0538f66Scg149915 	    ((ioctl->flags & DRM_MASTER) && !fpriv->master))
500d0538f66Scg149915 		return (EACCES);
501d0538f66Scg149915 
5020035d21cSmiao chen - Sun Microsystems - Beijing China 	fpriv->dev = dev;
5030035d21cSmiao chen - Sun Microsystems - Beijing China 	fpriv->credp = credp;
5040035d21cSmiao chen - Sun Microsystems - Beijing China 
505d0538f66Scg149915 	retval = func(dp, arg, fpriv, mode);
506d0538f66Scg149915 
507d0538f66Scg149915 	return (retval);
508d0538f66Scg149915 }
509d0538f66Scg149915 
510d0538f66Scg149915 /*ARGSUSED*/
511d0538f66Scg149915 static int
drm_sun_devmap(dev_t dev,devmap_cookie_t dhp,offset_t offset,size_t len,size_t * maplen,uint_t model)512d0538f66Scg149915 drm_sun_devmap(dev_t dev, devmap_cookie_t dhp, offset_t offset,
513d0538f66Scg149915     size_t len, size_t *maplen, uint_t model)
514d0538f66Scg149915 {
515d0538f66Scg149915 	extern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *);
516d0538f66Scg149915 
517d0538f66Scg149915 	drm_inst_state_t	*mstate;
518d0538f66Scg149915 	drm_device_t		*dp;
519d0538f66Scg149915 	ddi_umem_cookie_t	cookie;
5200035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_local_map_t		*map = NULL;
521d0538f66Scg149915 	unsigned long	aperbase;
522d0538f66Scg149915 	u_offset_t		handle;
523d0538f66Scg149915 	offset_t		koff;
524d0538f66Scg149915 	caddr_t			kva;
525d0538f66Scg149915 	minor_t			minor;
526d0538f66Scg149915 	size_t			length;
527d0538f66Scg149915 	int			ret;
528d0538f66Scg149915 
529d0538f66Scg149915 	static ddi_device_acc_attr_t dev_attr = {
530d0538f66Scg149915 		DDI_DEVICE_ATTR_V0,
531d0538f66Scg149915 		DDI_NEVERSWAP_ACC,
532d0538f66Scg149915 		DDI_STRICTORDER_ACC,
533d0538f66Scg149915 	};
5340035d21cSmiao chen - Sun Microsystems - Beijing China 	static ddi_device_acc_attr_t gem_dev_attr = {
5350035d21cSmiao chen - Sun Microsystems - Beijing China 		DDI_DEVICE_ATTR_V0,
5360035d21cSmiao chen - Sun Microsystems - Beijing China 		DDI_NEVERSWAP_ACC,
5370035d21cSmiao chen - Sun Microsystems - Beijing China 		DDI_MERGING_OK_ACC
5380035d21cSmiao chen - Sun Microsystems - Beijing China 	};
539d0538f66Scg149915 
540d0538f66Scg149915 	mstate = drm_sup_devt_to_state(dev);
541d0538f66Scg149915 	if (mstate == NULL)
542d0538f66Scg149915 		return (ENXIO);
543d0538f66Scg149915 
544d0538f66Scg149915 	minor = DEV2MINOR(dev);
545d0538f66Scg149915 	switch (minor) {
546d0538f66Scg149915 	case GFX_MINOR:
547d0538f66Scg149915 		ret = gfxp_vgatext_devmap(dev, dhp, offset, len, maplen, model,
548d0538f66Scg149915 		    mstate->mis_gfxp);
549d0538f66Scg149915 		return (ret);
550d0538f66Scg149915 
551d0538f66Scg149915 	case AGPMASTER_MINOR:
552d0538f66Scg149915 		return (ENOTSUP);
553d0538f66Scg149915 
554d0538f66Scg149915 	case DRM_MINOR:
555d0538f66Scg149915 		break;
556d0538f66Scg149915 
557d0538f66Scg149915 	default:
558d0538f66Scg149915 		/* DRM cloning nodes */
559d0538f66Scg149915 		if (minor > MAX_CLONE_MINOR)
560d0538f66Scg149915 			return (EBADF);
561d0538f66Scg149915 		break;
562d0538f66Scg149915 	}
563d0538f66Scg149915 
564d0538f66Scg149915 
565d0538f66Scg149915 	dp = mstate->mis_devp;
566d0538f66Scg149915 	if (dp == NULL) {
567d0538f66Scg149915 		DRM_ERROR("drm_sun_devmap: NULL soft state");
568d0538f66Scg149915 		return (EINVAL);
569d0538f66Scg149915 	}
570d0538f66Scg149915 
5710035d21cSmiao chen - Sun Microsystems - Beijing China 	mutex_enter(&dp->dev_lock);
5720035d21cSmiao chen - Sun Microsystems - Beijing China 
5730035d21cSmiao chen - Sun Microsystems - Beijing China 	if (dp->driver->use_gem == 1) {
5740035d21cSmiao chen - Sun Microsystems - Beijing China 		struct idr_list *entry;
5750035d21cSmiao chen - Sun Microsystems - Beijing China 		drm_cminor_t *mp;
5760035d21cSmiao chen - Sun Microsystems - Beijing China 
5770035d21cSmiao chen - Sun Microsystems - Beijing China 		mp = drm_find_file_by_minor(dp, minor);
5780035d21cSmiao chen - Sun Microsystems - Beijing China 		if (!mp) {
5790035d21cSmiao chen - Sun Microsystems - Beijing China 			mutex_exit(&dp->dev_lock);
5800035d21cSmiao chen - Sun Microsystems - Beijing China 			DRM_ERROR("drm_sun_devmap: can't find authenticator");
5810035d21cSmiao chen - Sun Microsystems - Beijing China 			return (EACCES);
5820035d21cSmiao chen - Sun Microsystems - Beijing China 		}
5830035d21cSmiao chen - Sun Microsystems - Beijing China 
5840035d21cSmiao chen - Sun Microsystems - Beijing China 		spin_lock(&dp->struct_mutex);
5850035d21cSmiao chen - Sun Microsystems - Beijing China 		idr_list_for_each(entry, &(mp->fpriv->object_idr)) {
5860035d21cSmiao chen - Sun Microsystems - Beijing China 			if ((uintptr_t)entry->obj == (u_offset_t)offset) {
5870035d21cSmiao chen - Sun Microsystems - Beijing China 				map = entry->obj->map;
5880035d21cSmiao chen - Sun Microsystems - Beijing China 				goto goon;
5890035d21cSmiao chen - Sun Microsystems - Beijing China 			}
5900035d21cSmiao chen - Sun Microsystems - Beijing China 		}
5910035d21cSmiao chen - Sun Microsystems - Beijing China goon:
5920035d21cSmiao chen - Sun Microsystems - Beijing China 		spin_unlock(&dp->struct_mutex);
5930035d21cSmiao chen - Sun Microsystems - Beijing China 	}
5940035d21cSmiao chen - Sun Microsystems - Beijing China 
5950035d21cSmiao chen - Sun Microsystems - Beijing China 	if (map == NULL) {
596d0538f66Scg149915 		/*
597d0538f66Scg149915 		 * We will solve 32-bit application on 64-bit kernel
598d0538f66Scg149915 		 * issue later, now, we just use low 32-bit
599d0538f66Scg149915 		 */
600d0538f66Scg149915 		handle = (u_offset_t)offset;
601d0538f66Scg149915 		handle &= 0xffffffff;
6020035d21cSmiao chen - Sun Microsystems - Beijing China 
603d0538f66Scg149915 		TAILQ_FOREACH(map, &dp->maplist, link) {
604d0538f66Scg149915 			if (handle ==
605d0538f66Scg149915 			    ((u_offset_t)((uintptr_t)map->handle) & 0xffffffff))
606d0538f66Scg149915 				break;
607d0538f66Scg149915 		}
608d0538f66Scg149915 
609d0538f66Scg149915 		/*
610d0538f66Scg149915 		 * Temporarily, because offset is phys_addr for register
611d0538f66Scg149915 		 * and framebuffer, is kernel virtual_addr for others
612d0538f66Scg149915 		 * Maybe we will use hash table to solve this issue later.
613d0538f66Scg149915 		 */
614d0538f66Scg149915 		if (map == NULL) {
615d0538f66Scg149915 			TAILQ_FOREACH(map, &dp->maplist, link) {
616d0538f66Scg149915 				if (handle == (map->offset & 0xffffffff))
617d0538f66Scg149915 					break;
618d0538f66Scg149915 			}
619d0538f66Scg149915 		}
6200035d21cSmiao chen - Sun Microsystems - Beijing China 	}
621d0538f66Scg149915 
622d0538f66Scg149915 	if (map == NULL) {
623d0538f66Scg149915 		u_offset_t	tmp;
624d0538f66Scg149915 
625d0538f66Scg149915 		mutex_exit(&dp->dev_lock);
626d0538f66Scg149915 		cmn_err(CE_WARN, "Can't find map, offset=0x%llx, len=%x\n",
627d0538f66Scg149915 		    offset, (int)len);
628d0538f66Scg149915 		cmn_err(CE_WARN, "Current mapping:\n");
629d0538f66Scg149915 		TAILQ_FOREACH(map, &dp->maplist, link) {
630d0538f66Scg149915 		tmp = (u_offset_t)((uintptr_t)map->handle) & 0xffffffff;
631d0538f66Scg149915 		cmn_err(CE_WARN, "map(handle=0x%p, size=0x%lx,type=%d,"
632d0538f66Scg149915 		    "offset=0x%lx), handle=%llx, tmp=%lld", map->handle,
633d0538f66Scg149915 		    map->size, map->type, map->offset, handle, tmp);
634d0538f66Scg149915 		}
635d0538f66Scg149915 		return (-1);
636d0538f66Scg149915 	}
637d0538f66Scg149915 	if (map->flags & _DRM_RESTRICTED) {
638d0538f66Scg149915 		mutex_exit(&dp->dev_lock);
639d0538f66Scg149915 		cmn_err(CE_WARN, "restricted map\n");
640d0538f66Scg149915 		return (-1);
641d0538f66Scg149915 	}
642d0538f66Scg149915 
643d0538f66Scg149915 	mutex_exit(&dp->dev_lock);
644d0538f66Scg149915 	switch (map->type) {
645d0538f66Scg149915 	case _DRM_FRAME_BUFFER:
646d0538f66Scg149915 	case _DRM_REGISTERS:
647d0538f66Scg149915 		{
648d0538f66Scg149915 			int	regno;
649d0538f66Scg149915 			off_t	regoff;
650d0538f66Scg149915 
651d0538f66Scg149915 			regno = drm_get_pci_index_reg(dp->dip,
652d0538f66Scg149915 			    map->offset, (uint_t)len, &regoff);
653d0538f66Scg149915 			if (regno < 0) {
654d0538f66Scg149915 				DRM_ERROR("devmap: failed to get register"
655d0538f66Scg149915 				    " offset=0x%llx, len=0x%x", handle, len);
656d0538f66Scg149915 				return (EINVAL);
657d0538f66Scg149915 			}
658d0538f66Scg149915 
659d0538f66Scg149915 			ret = devmap_devmem_setup(dhp, dp->dip, NULL,
660d0538f66Scg149915 			    regno, (offset_t)regoff, len, PROT_ALL,
661d0538f66Scg149915 			    0, &dev_attr);
662d0538f66Scg149915 			if (ret != 0) {
663d0538f66Scg149915 				*maplen = 0;
664d0538f66Scg149915 				DRM_ERROR("devmap: failed, regno=%d,type=%d,"
665d0538f66Scg149915 				    " handle=0x%x, offset=0x%llx, len=0x%x",
666d0538f66Scg149915 				    regno, map->type, handle, offset, len);
667d0538f66Scg149915 				return (ret);
668d0538f66Scg149915 			}
669d0538f66Scg149915 			*maplen = len;
670d0538f66Scg149915 			return (ret);
671d0538f66Scg149915 		}
672d0538f66Scg149915 
673d0538f66Scg149915 	case _DRM_SHM:
674d0538f66Scg149915 		if (map->drm_umem_cookie == NULL)
675d0538f66Scg149915 			return (EINVAL);
676d0538f66Scg149915 		length = ptob(btopr(map->size));
677d0538f66Scg149915 		ret = devmap_umem_setup(dhp, dp->dip, NULL,
678d0538f66Scg149915 		    map->drm_umem_cookie, 0, length,
679d0538f66Scg149915 		    PROT_ALL, IOMEM_DATA_CACHED, NULL);
680d0538f66Scg149915 		if (ret != 0) {
681d0538f66Scg149915 			*maplen = 0;
682d0538f66Scg149915 			return (ret);
683d0538f66Scg149915 		}
684d0538f66Scg149915 		*maplen = length;
685d0538f66Scg149915 
686d0538f66Scg149915 		return (DDI_SUCCESS);
687d0538f66Scg149915 
688d0538f66Scg149915 	case _DRM_AGP:
689d0538f66Scg149915 		if (dp->agp == NULL) {
690d0538f66Scg149915 			cmn_err(CE_WARN, "drm_sun_devmap: attempted to mmap AGP"
691d0538f66Scg149915 			    "memory before AGP support is enabled");
692d0538f66Scg149915 			return (DDI_FAILURE);
693d0538f66Scg149915 		}
694d0538f66Scg149915 
695d0538f66Scg149915 		aperbase = dp->agp->base;
696d0538f66Scg149915 		koff = map->offset - aperbase;
697d0538f66Scg149915 		length = ptob(btopr(len));
698d0538f66Scg149915 		kva = map->dev_addr;
699d0538f66Scg149915 		cookie = gfxp_umem_cookie_init(kva, length);
700d0538f66Scg149915 		if (cookie == NULL) {
701d0538f66Scg149915 			cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
702d0538f66Scg149915 			return (DDI_FAILURE);
703d0538f66Scg149915 		}
704d0538f66Scg149915 
705d0538f66Scg149915 		if ((ret = devmap_umem_setup(dhp, dp->dip,
706d0538f66Scg149915 		    &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
707d0538f66Scg149915 		    IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr)) < 0) {
708d0538f66Scg149915 			gfxp_umem_cookie_destroy(cookie);
709d0538f66Scg149915 			cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
710d0538f66Scg149915 			return (DDI_FAILURE);
711d0538f66Scg149915 		}
712d0538f66Scg149915 		*maplen = length;
713d0538f66Scg149915 		break;
714d0538f66Scg149915 
715d0538f66Scg149915 	case _DRM_SCATTER_GATHER:
716d0538f66Scg149915 		koff = map->offset - (unsigned long)(caddr_t)dp->sg->virtual;
717d0538f66Scg149915 		kva = map->dev_addr + koff;
718d0538f66Scg149915 		length = ptob(btopr(len));
719d0538f66Scg149915 		if (length > map->size) {
720d0538f66Scg149915 			cmn_err(CE_WARN, "offset=0x%lx, virtual=0x%p,"
721d0538f66Scg149915 			    "mapsize=0x%lx,len=0x%lx", map->offset,
722d0538f66Scg149915 			    dp->sg->virtual, map->size, len);
723d0538f66Scg149915 			return (DDI_FAILURE);
724d0538f66Scg149915 		}
725d0538f66Scg149915 		cookie = gfxp_umem_cookie_init(kva, length);
726d0538f66Scg149915 		if (cookie == NULL) {
727d0538f66Scg149915 			cmn_err(CE_WARN, "devmap:failed to get umem_cookie");
728d0538f66Scg149915 			return (DDI_FAILURE);
729d0538f66Scg149915 		}
730d0538f66Scg149915 		ret = devmap_umem_setup(dhp, dp->dip,
731d0538f66Scg149915 		    &drm_devmap_callbacks, cookie, 0, length, PROT_ALL,
732d0538f66Scg149915 		    IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr);
733d0538f66Scg149915 		if (ret != 0) {
734d0538f66Scg149915 			cmn_err(CE_WARN, "sun_devmap: umem_setup fail");
735d0538f66Scg149915 			gfxp_umem_cookie_destroy(cookie);
736d0538f66Scg149915 			return (DDI_FAILURE);
737d0538f66Scg149915 		}
738d0538f66Scg149915 		*maplen = length;
739d0538f66Scg149915 		break;
740d0538f66Scg149915 
7410035d21cSmiao chen - Sun Microsystems - Beijing China 	case _DRM_TTM:
7420035d21cSmiao chen - Sun Microsystems - Beijing China 		if (map->drm_umem_cookie == NULL)
7430035d21cSmiao chen - Sun Microsystems - Beijing China 			return (EINVAL);
7440035d21cSmiao chen - Sun Microsystems - Beijing China 
7450035d21cSmiao chen - Sun Microsystems - Beijing China 		if (gfxp_devmap_umem_setup(dhp, dp->dip,
7460035d21cSmiao chen - Sun Microsystems - Beijing China 		    NULL, map->drm_umem_cookie, 0, map->size, PROT_ALL,
7470035d21cSmiao chen - Sun Microsystems - Beijing China 		    IOMEM_DATA_UC_WR_COMBINE | DEVMAP_ALLOW_REMAP,
7480035d21cSmiao chen - Sun Microsystems - Beijing China 		    &gem_dev_attr)) {
7490035d21cSmiao chen - Sun Microsystems - Beijing China 			cmn_err(CE_WARN, "devmap:failed, retval=%d", ret);
7500035d21cSmiao chen - Sun Microsystems - Beijing China 			return (DDI_FAILURE);
7510035d21cSmiao chen - Sun Microsystems - Beijing China 		}
7520035d21cSmiao chen - Sun Microsystems - Beijing China 		*maplen = map->size;
7530035d21cSmiao chen - Sun Microsystems - Beijing China 		return (DDI_SUCCESS);
7540035d21cSmiao chen - Sun Microsystems - Beijing China 
755d0538f66Scg149915 	default:
756d0538f66Scg149915 		return (DDI_FAILURE);
757d0538f66Scg149915 	}
758d0538f66Scg149915 	return (DDI_SUCCESS);
759d0538f66Scg149915 
760d0538f66Scg149915 }
761d0538f66Scg149915 
762d0538f66Scg149915 /*ARGSUSED*/
763d0538f66Scg149915 static int
drm_devmap_map(devmap_cookie_t dhc,dev_t dev,uint_t flags,offset_t offset,size_t len,void ** new_priv)764d0538f66Scg149915 drm_devmap_map(devmap_cookie_t dhc, dev_t dev, uint_t flags,
765d0538f66Scg149915     offset_t offset, size_t len, void **new_priv)
766d0538f66Scg149915 {
767d0538f66Scg149915 	devmap_handle_t			*dhp;
768d0538f66Scg149915 	drm_inst_state_t		*statep;
769d0538f66Scg149915 	struct ddi_umem_cookie 	*cp;
770d0538f66Scg149915 
771d0538f66Scg149915 	statep = drm_sup_devt_to_state(dev);
772d0538f66Scg149915 	ASSERT(statep != NULL);
773d0538f66Scg149915 
774d0538f66Scg149915 	/*
775d0538f66Scg149915 	 * This driver only supports MAP_SHARED,
776d0538f66Scg149915 	 * and doesn't support MAP_PRIVATE
777d0538f66Scg149915 	 */
778d0538f66Scg149915 	if (flags & MAP_PRIVATE) {
779d0538f66Scg149915 		cmn_err(CE_WARN, "!DRM driver doesn't support MAP_PRIVATE");
780d0538f66Scg149915 		return (EINVAL);
781d0538f66Scg149915 	}
782d0538f66Scg149915 
783d0538f66Scg149915 	mutex_enter(&statep->dis_ctxlock);
784d0538f66Scg149915 	dhp = (devmap_handle_t *)dhc;
785d0538f66Scg149915 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
786d0538f66Scg149915 	cp->cook_refcnt = 1;
787d0538f66Scg149915 	mutex_exit(&statep->dis_ctxlock);
788d0538f66Scg149915 	*new_priv = statep;
789d0538f66Scg149915 
790d0538f66Scg149915 	return (0);
791d0538f66Scg149915 }
792d0538f66Scg149915 
793d0538f66Scg149915 /*ARGSUSED*/
794d0538f66Scg149915 static void
drm_devmap_unmap(devmap_cookie_t dhc,void * pvtp,offset_t off,size_t len,devmap_cookie_t new_dhp1,void ** new_pvtp1,devmap_cookie_t new_dhp2,void ** new_pvtp2)795d0538f66Scg149915 drm_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len,
796d0538f66Scg149915     devmap_cookie_t new_dhp1, void **new_pvtp1, devmap_cookie_t new_dhp2,
797d0538f66Scg149915     void **new_pvtp2)
798d0538f66Scg149915 {
799d0538f66Scg149915 	devmap_handle_t		*dhp;
800d0538f66Scg149915 	devmap_handle_t		*ndhp;
801d0538f66Scg149915 	drm_inst_state_t		*statep;
802d0538f66Scg149915 	struct ddi_umem_cookie	*cp;
803d0538f66Scg149915 	struct ddi_umem_cookie	*ncp;
804d0538f66Scg149915 
805d0538f66Scg149915 	dhp = (devmap_handle_t *)dhc;
806d0538f66Scg149915 	statep = (drm_inst_state_t *)pvtp;
807d0538f66Scg149915 
808d0538f66Scg149915 	mutex_enter(&statep->dis_ctxlock);
809d0538f66Scg149915 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
810d0538f66Scg149915 	if (new_dhp1 != NULL) {
811d0538f66Scg149915 		ndhp = (devmap_handle_t *)new_dhp1;
812d0538f66Scg149915 		ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
813d0538f66Scg149915 		ncp->cook_refcnt ++;
814d0538f66Scg149915 		*new_pvtp1 = statep;
815d0538f66Scg149915 		ASSERT(ncp == cp);
816d0538f66Scg149915 	}
817d0538f66Scg149915 
818d0538f66Scg149915 	if (new_dhp2 != NULL) {
819d0538f66Scg149915 		ndhp = (devmap_handle_t *)new_dhp2;
820d0538f66Scg149915 		ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
821d0538f66Scg149915 		ncp->cook_refcnt ++;
822d0538f66Scg149915 		*new_pvtp2 = statep;
823d0538f66Scg149915 		ASSERT(ncp == cp);
824d0538f66Scg149915 	}
825d0538f66Scg149915 
826d0538f66Scg149915 	cp->cook_refcnt --;
827d0538f66Scg149915 	if (cp->cook_refcnt == 0) {
828d0538f66Scg149915 		gfxp_umem_cookie_destroy(dhp->dh_cookie);
829d0538f66Scg149915 		dhp->dh_cookie = NULL;
830d0538f66Scg149915 	}
831d0538f66Scg149915 	mutex_exit(&statep->dis_ctxlock);
832d0538f66Scg149915 }
833d0538f66Scg149915 
834d0538f66Scg149915 
835d0538f66Scg149915 /*ARGSUSED*/
836d0538f66Scg149915 static int
drm_devmap_dup(devmap_cookie_t dhc,void * pvtp,devmap_cookie_t new_dhc,void ** new_pvtp)837d0538f66Scg149915 drm_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhc,
838d0538f66Scg149915     void **new_pvtp)
839d0538f66Scg149915 {
840d0538f66Scg149915 	devmap_handle_t			*dhp;
841d0538f66Scg149915 	drm_inst_state_t    *statep;
842d0538f66Scg149915 	struct ddi_umem_cookie *cp;
843d0538f66Scg149915 
844d0538f66Scg149915 	statep = (drm_inst_state_t *)pvtp;
845d0538f66Scg149915 	mutex_enter(&statep->dis_ctxlock);
846d0538f66Scg149915 	dhp = (devmap_handle_t *)dhc;
847d0538f66Scg149915 	cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
848d0538f66Scg149915 	cp->cook_refcnt ++;
849d0538f66Scg149915 	mutex_exit(&statep->dis_ctxlock);
850d0538f66Scg149915 	*new_pvtp = statep;
851d0538f66Scg149915 
852d0538f66Scg149915 	return (0);
853d0538f66Scg149915 }
854d0538f66Scg149915 
855d0538f66Scg149915 int
drm_dev_to_instance(dev_t dev)856d0538f66Scg149915 drm_dev_to_instance(dev_t dev)
857d0538f66Scg149915 {
858d0538f66Scg149915 	return (DEV2INST(dev));
859d0538f66Scg149915 }
860d0538f66Scg149915 
861d0538f66Scg149915 /*
862d0538f66Scg149915  * drm_supp_alloc_drv_entry()
863d0538f66Scg149915  *
864d0538f66Scg149915  * Description:
865d0538f66Scg149915  *	Create a DRM entry and add it into the instance list (drm_inst_head).
866d0538f66Scg149915  *	Note that we don't allow a duplicated entry
867d0538f66Scg149915  */
868d0538f66Scg149915 static drm_inst_list_t *
drm_supp_alloc_drv_entry(dev_info_t * dip)869d0538f66Scg149915 drm_supp_alloc_drv_entry(dev_info_t *dip)
870d0538f66Scg149915 {
871d0538f66Scg149915 	drm_inst_list_t	**plist;
872d0538f66Scg149915 	drm_inst_list_t	*list;
873d0538f66Scg149915 	drm_inst_list_t	*entry;
874d0538f66Scg149915 
875d0538f66Scg149915 	/* protect the driver list */
876d0538f66Scg149915 	mutex_enter(&drm_inst_list_lock);
877d0538f66Scg149915 	plist = &drm_inst_head;
878d0538f66Scg149915 	list = *plist;
879d0538f66Scg149915 	while (list) {
880d0538f66Scg149915 		if (list->disl_state.mis_dip == dip) {
881d0538f66Scg149915 			mutex_exit(&drm_inst_list_lock);
882d0538f66Scg149915 			cmn_err(CE_WARN, "%s%d already registered",
883d0538f66Scg149915 			    ddi_driver_name(dip), ddi_get_instance(dip));
884d0538f66Scg149915 			return (NULL);
885d0538f66Scg149915 		}
886d0538f66Scg149915 		plist = &list->disl_next;
887d0538f66Scg149915 		list = list->disl_next;
888d0538f66Scg149915 	}
889d0538f66Scg149915 
890d0538f66Scg149915 	/* "dip" is not registered, create new one and add to list */
891d0538f66Scg149915 	entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
892d0538f66Scg149915 	*plist = entry;
893d0538f66Scg149915 	entry->disl_state.mis_dip = dip;
894d0538f66Scg149915 	mutex_init(&entry->disl_state.mis_lock, NULL, MUTEX_DRIVER, NULL);
895d0538f66Scg149915 	mutex_init(&entry->disl_state.dis_ctxlock, NULL, MUTEX_DRIVER, NULL);
896d0538f66Scg149915 	mutex_exit(&drm_inst_list_lock);
897d0538f66Scg149915 
898d0538f66Scg149915 	return (entry);
899d0538f66Scg149915 
900d0538f66Scg149915 }	/* drm_supp_alloc_drv_entry */
901d0538f66Scg149915 
902d0538f66Scg149915 /*
903d0538f66Scg149915  * drm_supp_free_drv_entry()
904d0538f66Scg149915  */
905d0538f66Scg149915 static void
drm_supp_free_drv_entry(dev_info_t * dip)906d0538f66Scg149915 drm_supp_free_drv_entry(dev_info_t *dip)
907d0538f66Scg149915 {
908d0538f66Scg149915 	drm_inst_list_t		*list;
909d0538f66Scg149915 	drm_inst_list_t		**plist;
910d0538f66Scg149915 	drm_inst_state_t	*mstate;
911d0538f66Scg149915 
912d0538f66Scg149915 	/* protect the driver list */
913d0538f66Scg149915 	mutex_enter(&drm_inst_list_lock);
914d0538f66Scg149915 	plist = &drm_inst_head;
915d0538f66Scg149915 	list = *plist;
916d0538f66Scg149915 	while (list) {
917d0538f66Scg149915 		if (list->disl_state.mis_dip == dip) {
918d0538f66Scg149915 			*plist = list->disl_next;
919d0538f66Scg149915 			mstate = &list->disl_state;
920d0538f66Scg149915 			mutex_destroy(&mstate->mis_lock);
921d0538f66Scg149915 			mutex_destroy(&mstate->dis_ctxlock);
922d0538f66Scg149915 			kmem_free(list, sizeof (*list));
923d0538f66Scg149915 			mutex_exit(&drm_inst_list_lock);
924d0538f66Scg149915 			return;
925d0538f66Scg149915 		}
926d0538f66Scg149915 		plist = &list->disl_next;
927d0538f66Scg149915 		list = list->disl_next;
928d0538f66Scg149915 	}
929d0538f66Scg149915 	mutex_exit(&drm_inst_list_lock);
930d0538f66Scg149915 
931d0538f66Scg149915 }	/* drm_supp_free_drv_entry() */
932d0538f66Scg149915 
933d0538f66Scg149915 /*
934d0538f66Scg149915  * drm_sup_devt_to_state()
935d0538f66Scg149915  *
936d0538f66Scg149915  * description:
937d0538f66Scg149915  *	Get the soft state of DRM instance by device number
938d0538f66Scg149915  */
939d0538f66Scg149915 static drm_inst_state_t *
drm_sup_devt_to_state(dev_t dev)940d0538f66Scg149915 drm_sup_devt_to_state(dev_t dev)
941d0538f66Scg149915 {
942d0538f66Scg149915 	drm_inst_list_t	*list;
943d0538f66Scg149915 	drm_inst_state_t	*mstate;
944d0538f66Scg149915 	major_t	major = getmajor(dev);
945d0538f66Scg149915 	int		instance = DEV2INST(dev);
946d0538f66Scg149915 
947d0538f66Scg149915 	mutex_enter(&drm_inst_list_lock);
948d0538f66Scg149915 	list = drm_inst_head;
949d0538f66Scg149915 	while (list) {
950d0538f66Scg149915 		mstate = &list->disl_state;
951d0538f66Scg149915 		mutex_enter(&mstate->mis_lock);
952d0538f66Scg149915 
953d0538f66Scg149915 		if ((mstate->mis_major == major) &&
954d0538f66Scg149915 		    (ddi_get_instance(mstate->mis_dip) == instance)) {
955d0538f66Scg149915 			mutex_exit(&mstate->mis_lock);
956d0538f66Scg149915 			mutex_exit(&drm_inst_list_lock);
957d0538f66Scg149915 			return (mstate);
958d0538f66Scg149915 		}
959d0538f66Scg149915 
960d0538f66Scg149915 		list = list->disl_next;
961d0538f66Scg149915 		mutex_exit(&mstate->mis_lock);
962d0538f66Scg149915 	}
963d0538f66Scg149915 
964d0538f66Scg149915 	mutex_exit(&drm_inst_list_lock);
965d0538f66Scg149915 	return (NULL);
966d0538f66Scg149915 
967d0538f66Scg149915 }	/* drm_sup_devt_to_state() */
968d0538f66Scg149915 
969d0538f66Scg149915 int
drm_supp_get_irq(void * handle)970d0538f66Scg149915 drm_supp_get_irq(void *handle)
971d0538f66Scg149915 {
972d0538f66Scg149915 	drm_inst_list_t *list;
973d0538f66Scg149915 	drm_inst_state_t    *mstate;
974d0538f66Scg149915 	int		irq;
975d0538f66Scg149915 
976d0538f66Scg149915 	list = (drm_inst_list_t *)handle;
977d0538f66Scg149915 	mstate = &list->disl_state;
978d0538f66Scg149915 	ASSERT(mstate != NULL);
979d0538f66Scg149915 	irq = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_ILINE);
980d0538f66Scg149915 	return (irq);
981d0538f66Scg149915 }
982d0538f66Scg149915 
983d0538f66Scg149915 int
drm_supp_device_capability(void * handle,int capid)984d0538f66Scg149915 drm_supp_device_capability(void *handle, int capid)
985d0538f66Scg149915 {
986d0538f66Scg149915 	drm_inst_list_t *list;
987d0538f66Scg149915 	drm_inst_state_t    *mstate;
988d0538f66Scg149915 	uint8_t		cap = 0;
989d0538f66Scg149915 	uint16_t	caps_ptr;
990d0538f66Scg149915 
991d0538f66Scg149915 	list = (drm_inst_list_t *)handle;
992d0538f66Scg149915 	mstate = &list->disl_state;
993d0538f66Scg149915 	ASSERT(mstate != NULL);
994d0538f66Scg149915 
995d0538f66Scg149915 	/* has capabilities list ? */
996d0538f66Scg149915 	if ((pci_config_get16(mstate->mis_cfg_hdl, PCI_CONF_STAT) &
997d0538f66Scg149915 	    PCI_CONF_CAP_MASK) == 0)
998d0538f66Scg149915 		return (NULL);
999d0538f66Scg149915 
1000d0538f66Scg149915 	caps_ptr = pci_config_get8(mstate->mis_cfg_hdl, PCI_CONF_CAP_PTR);
1001d0538f66Scg149915 	while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) {
1002d0538f66Scg149915 		cap = pci_config_get32(mstate->mis_cfg_hdl, caps_ptr);
1003d0538f66Scg149915 		if ((cap & PCI_CONF_CAPID_MASK) == capid)
1004d0538f66Scg149915 			return (cap);
1005d0538f66Scg149915 		caps_ptr = pci_config_get8(mstate->mis_cfg_hdl,
1006d0538f66Scg149915 		    caps_ptr + PCI_CAP_NEXT_PTR);
1007d0538f66Scg149915 	}
1008d0538f66Scg149915 
1009d0538f66Scg149915 	return (0);
1010d0538f66Scg149915 }
1011