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, ®off);
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