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