1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <sys/debug.h>
28#include <sys/types.h>
29#include <sys/param.h>
30#include <sys/time.h>
31#include <sys/buf.h>
32#include <sys/errno.h>
33#include <sys/systm.h>
34#include <sys/conf.h>
35#include <sys/signal.h>
36#include <sys/file.h>
37#include <sys/uio.h>
38#include <sys/ioctl.h>
39#include <sys/map.h>
40#include <sys/proc.h>
41#include <sys/user.h>
42#include <sys/mman.h>
43#include <sys/cred.h>
44#include <sys/open.h>
45#include <sys/stat.h>
46#include <sys/utsname.h>
47#include <sys/kmem.h>
48#include <sys/cmn_err.h>
49#include <sys/vnode.h>
50#include <vm/page.h>
51#include <vm/as.h>
52#include <vm/hat.h>
53#include <vm/seg.h>
54#include <sys/ddi.h>
55#include <sys/devops.h>
56#include <sys/sunddi.h>
57#include <sys/ddi_impldefs.h>
58#include <sys/fs/snode.h>
59#include <sys/pci.h>
60#include <sys/modctl.h>
61#include <sys/uio.h>
62#include <sys/visual_io.h>
63#include <sys/fbio.h>
64#include <sys/ddidmareq.h>
65#include <sys/tnf_probe.h>
66#include <sys/kstat.h>
67#include <sys/callb.h>
68#include <sys/pci_cfgspace.h>
69#include <sys/gfx_private.h>
70
71typedef struct gfxp_pci_bsf {
72	uint16_t	vendor;
73	uint16_t	device;
74	uint8_t		bus;
75	uint8_t		slot;
76	uint8_t		function;
77	uint8_t		found;
78	dev_info_t	*dip;
79} gfxp_pci_bsf_t;
80
81/* The use of pci_get?/put?_func() depends on misc/pci_autoconfig */
82
83static int
84gfxp_pci_get_bsf(dev_info_t *dip, uint8_t *bus, uint8_t *dev, uint8_t *func)
85{
86	pci_regspec_t   *pci_rp;
87	uint32_t	length;
88	int	rc;
89
90	/* get "reg" property */
91	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
92		DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
93		(uint_t *)&length);
94	if ((rc != DDI_SUCCESS) || (length <
95			(sizeof (pci_regspec_t) / sizeof (int)))) {
96		return (DDI_FAILURE);
97	}
98
99	*bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
100	*dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
101	*func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
102
103	/*
104	 * free the memory allocated by ddi_prop_lookup_int_array().
105	 */
106	ddi_prop_free(pci_rp);
107
108	return (DDI_SUCCESS);
109}
110
111static int
112gfxp_pci_find_bsf(dev_info_t *dip, void *arg)
113{
114	int	rc;
115	uint8_t bus, dev, func;
116	gfxp_pci_bsf_t    *pci_bsf;
117	int vendor_id, device_id, class_code;
118
119	/*
120	 * Look for vendor-id, device-id, class-code to verify
121	 * this is some type of PCI child node.
122	 */
123	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
124				"vendor-id", -1);
125	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
126				"device-id", -1);
127	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
128				"class-code", -1);
129	if ((vendor_id == -1) || (device_id == -1) || (class_code == -1)) {
130		return (DDI_WALK_CONTINUE);
131	}
132
133	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
134		return (DDI_WALK_TERMINATE);
135
136	pci_bsf = (gfxp_pci_bsf_t *)arg;
137
138	if ((bus == pci_bsf->bus) && (dev == pci_bsf->slot) &&
139		(func == pci_bsf->function)) {
140		pci_bsf->dip = dip;
141		pci_bsf->vendor = vendor_id;
142		pci_bsf->device = device_id;
143		pci_bsf->found = 1;
144		rc = DDI_WALK_TERMINATE;
145	} else {
146		rc = DDI_WALK_CONTINUE;
147	}
148
149	return (rc);
150}
151
152gfxp_acc_handle_t
153gfxp_pci_init_handle(uint8_t bus, uint8_t slot, uint8_t function,
154	uint16_t *vendor, uint16_t *device)
155{
156	dev_info_t	*dip;
157	gfxp_pci_bsf_t	*pci_bsf;
158
159	/*
160	 * Find a PCI device based on its address, and return a unique handle
161	 * to be used in subsequent calls to read from or write to the config
162	 * space of this device.
163	 */
164
165	if ((pci_bsf = kmem_zalloc(sizeof (gfxp_pci_bsf_t), KM_SLEEP))
166			== NULL) {
167		return (NULL);
168	}
169
170	pci_bsf->bus = bus;
171	pci_bsf->slot = slot;
172	pci_bsf->function = function;
173
174	ddi_walk_devs(ddi_root_node(), gfxp_pci_find_bsf, pci_bsf);
175
176	if (pci_bsf->found) {
177		dip = pci_bsf->dip;
178
179		if (vendor) *vendor = pci_bsf->vendor;
180		if (device) *device = pci_bsf->device;
181	} else {
182		dip = NULL;
183		if (vendor) *vendor = 0x0000;
184		if (device) *device = 0x0000;
185	}
186
187	kmem_free(pci_bsf, sizeof (gfxp_pci_bsf_t));
188
189	return ((gfxp_acc_handle_t)dip);
190}
191
192uint8_t
193gfxp_pci_read_byte(gfxp_acc_handle_t handle, uint16_t offset)
194{
195	dev_info_t	*dip = (dev_info_t *)handle;
196	uint8_t	val;
197	uint8_t	bus, dev, func;
198
199	if (dip == NULL)
200		return ((uint8_t)~0);
201
202	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
203		return ((uint8_t)~0);
204
205	val = (*pci_getb_func)(bus, dev, func, offset);
206	return (val);
207}
208
209uint16_t
210gfxp_pci_read_word(gfxp_acc_handle_t handle, uint16_t offset)
211{
212	dev_info_t	*dip = (dev_info_t *)handle;
213	uint16_t	val;
214	uint8_t 	bus, dev, func;
215
216	if (dip == NULL)
217		return ((uint16_t)~0);
218
219	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
220		return ((uint16_t)~0);
221
222	val = (*pci_getw_func)(bus, dev, func, offset);
223	return (val);
224}
225
226uint32_t
227gfxp_pci_read_dword(gfxp_acc_handle_t handle, uint16_t offset)
228{
229	dev_info_t	*dip = (dev_info_t *)handle;
230	uint32_t	val;
231	uint8_t		bus, dev, func;
232
233	if (dip == NULL)
234		return ((uint32_t)~0);
235
236	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
237		return ((uint32_t)~0);
238
239	val = (*pci_getl_func)(bus, dev, func, offset);
240	return (val);
241}
242
243void
244gfxp_pci_write_byte(gfxp_acc_handle_t handle, uint16_t offset, uint8_t value)
245{
246	dev_info_t	*dip = (dev_info_t *)handle;
247	uint8_t		bus, dev, func;
248
249	if (dip == NULL)
250		return;
251
252	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
253		return;
254
255	(*pci_putb_func)(bus, dev, func, offset, value);
256}
257
258void
259gfxp_pci_write_word(gfxp_acc_handle_t handle, uint16_t offset, uint16_t value)
260{
261	dev_info_t	*dip = (dev_info_t *)handle;
262	uint8_t		bus, dev, func;
263
264	if (dip == NULL)
265		return;
266
267	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
268		return;
269
270	(*pci_putw_func)(bus, dev, func, offset, value);
271}
272
273void
274gfxp_pci_write_dword(gfxp_acc_handle_t handle, uint16_t offset, uint32_t value)
275{
276	dev_info_t	*dip = (dev_info_t *)handle;
277	uint8_t		bus, dev, func;
278
279	if (dip == NULL)
280		return;
281
282	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
283		return;
284
285	(*pci_putl_func)(bus, dev, func, offset, value);
286}
287
288static int
289gfxp_pci_find_vd(dev_info_t *dip, void *arg)
290{
291	int		rc;
292	gfxp_pci_bsf_t	*pci_bsf;
293	int		vendor_id, device_id, class_code;
294
295	/*
296	 * Look for vendor-id, device-id, class-code to verify
297	 * this is some type of PCI child node.
298	 */
299	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
300			"vendor-id", -1);
301	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
302			"device-id", -1);
303	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
304			"class-code", -1);
305	if ((vendor_id == -1) || (device_id == -1) || (class_code == -1)) {
306		return (DDI_WALK_CONTINUE);
307	}
308
309	pci_bsf = (gfxp_pci_bsf_t *)arg;
310
311	if ((vendor_id == pci_bsf->vendor) && (device_id == pci_bsf->device)) {
312		pci_bsf->found = 1;
313		rc = DDI_WALK_TERMINATE;
314	} else {
315		rc = DDI_WALK_CONTINUE;
316	}
317
318	return (rc);
319}
320
321int
322gfxp_pci_device_present(uint16_t vendor, uint16_t device)
323{
324	gfxp_pci_bsf_t	*pci_bsf;
325	int		rv;
326
327	/*
328	 * Find a PCI device based on its device and vendor id.
329	 */
330
331	if ((pci_bsf = kmem_zalloc(sizeof (gfxp_pci_bsf_t), KM_SLEEP)) == NULL)
332	    return (0);
333
334	pci_bsf->vendor = vendor;
335	pci_bsf->device = device;
336	ddi_walk_devs(ddi_root_node(), gfxp_pci_find_vd, pci_bsf);
337
338	if (pci_bsf->found) {
339		rv = 1;
340	} else {
341		rv = 0;
342	}
343
344	kmem_free(pci_bsf, sizeof (gfxp_pci_bsf_t));
345
346	return (rv);
347}
348