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 
71 typedef 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 
83 static int
gfxp_pci_get_bsf(dev_info_t * dip,uint8_t * bus,uint8_t * dev,uint8_t * func)84 gfxp_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 
111 static int
gfxp_pci_find_bsf(dev_info_t * dip,void * arg)112 gfxp_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 
152 gfxp_acc_handle_t
gfxp_pci_init_handle(uint8_t bus,uint8_t slot,uint8_t function,uint16_t * vendor,uint16_t * device)153 gfxp_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 
192 uint8_t
gfxp_pci_read_byte(gfxp_acc_handle_t handle,uint16_t offset)193 gfxp_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 
209 uint16_t
gfxp_pci_read_word(gfxp_acc_handle_t handle,uint16_t offset)210 gfxp_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 
226 uint32_t
gfxp_pci_read_dword(gfxp_acc_handle_t handle,uint16_t offset)227 gfxp_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 
243 void
gfxp_pci_write_byte(gfxp_acc_handle_t handle,uint16_t offset,uint8_t value)244 gfxp_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 
258 void
gfxp_pci_write_word(gfxp_acc_handle_t handle,uint16_t offset,uint16_t value)259 gfxp_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 
273 void
gfxp_pci_write_dword(gfxp_acc_handle_t handle,uint16_t offset,uint32_t value)274 gfxp_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 
288 static int
gfxp_pci_find_vd(dev_info_t * dip,void * arg)289 gfxp_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 
321 int
gfxp_pci_device_present(uint16_t vendor,uint16_t device)322 gfxp_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