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/kstat.h>
66 #include <sys/callb.h>
67 #include <sys/pci_cfgspace.h>
68 #include <sys/gfx_private.h>
69 
70 typedef struct gfxp_pci_bsf {
71 	uint16_t	vendor;
72 	uint16_t	device;
73 	uint8_t		bus;
74 	uint8_t		slot;
75 	uint8_t		function;
76 	uint8_t		found;
77 	dev_info_t	*dip;
78 } gfxp_pci_bsf_t;
79 
80 /* The use of pci_get?/put?_func() depends on misc/pci_autoconfig */
81 
82 static int
gfxp_pci_get_bsf(dev_info_t * dip,uint8_t * bus,uint8_t * dev,uint8_t * func)83 gfxp_pci_get_bsf(dev_info_t *dip, uint8_t *bus, uint8_t *dev, uint8_t *func)
84 {
85 	pci_regspec_t   *pci_rp;
86 	uint32_t	length;
87 	int	rc;
88 
89 	/* get "reg" property */
90 	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
91 		DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
92 		(uint_t *)&length);
93 	if ((rc != DDI_SUCCESS) || (length <
94 			(sizeof (pci_regspec_t) / sizeof (int)))) {
95 		return (DDI_FAILURE);
96 	}
97 
98 	*bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
99 	*dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
100 	*func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
101 
102 	/*
103 	 * free the memory allocated by ddi_prop_lookup_int_array().
104 	 */
105 	ddi_prop_free(pci_rp);
106 
107 	return (DDI_SUCCESS);
108 }
109 
110 static int
gfxp_pci_find_bsf(dev_info_t * dip,void * arg)111 gfxp_pci_find_bsf(dev_info_t *dip, void *arg)
112 {
113 	int	rc;
114 	uint8_t bus, dev, func;
115 	gfxp_pci_bsf_t    *pci_bsf;
116 	int vendor_id, device_id, class_code;
117 
118 	/*
119 	 * Look for vendor-id, device-id, class-code to verify
120 	 * this is some type of PCI child node.
121 	 */
122 	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
123 				"vendor-id", -1);
124 	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
125 				"device-id", -1);
126 	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
127 				"class-code", -1);
128 	if ((vendor_id == -1) || (device_id == -1) || (class_code == -1)) {
129 		return (DDI_WALK_CONTINUE);
130 	}
131 
132 	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
133 		return (DDI_WALK_TERMINATE);
134 
135 	pci_bsf = (gfxp_pci_bsf_t *)arg;
136 
137 	if ((bus == pci_bsf->bus) && (dev == pci_bsf->slot) &&
138 		(func == pci_bsf->function)) {
139 		pci_bsf->dip = dip;
140 		pci_bsf->vendor = vendor_id;
141 		pci_bsf->device = device_id;
142 		pci_bsf->found = 1;
143 		rc = DDI_WALK_TERMINATE;
144 	} else {
145 		rc = DDI_WALK_CONTINUE;
146 	}
147 
148 	return (rc);
149 }
150 
151 gfxp_acc_handle_t
gfxp_pci_init_handle(uint8_t bus,uint8_t slot,uint8_t function,uint16_t * vendor,uint16_t * device)152 gfxp_pci_init_handle(uint8_t bus, uint8_t slot, uint8_t function,
153 	uint16_t *vendor, uint16_t *device)
154 {
155 	dev_info_t	*dip;
156 	gfxp_pci_bsf_t	*pci_bsf;
157 
158 	/*
159 	 * Find a PCI device based on its address, and return a unique handle
160 	 * to be used in subsequent calls to read from or write to the config
161 	 * space of this device.
162 	 */
163 
164 	if ((pci_bsf = kmem_zalloc(sizeof (gfxp_pci_bsf_t), KM_SLEEP))
165 			== NULL) {
166 		return (NULL);
167 	}
168 
169 	pci_bsf->bus = bus;
170 	pci_bsf->slot = slot;
171 	pci_bsf->function = function;
172 
173 	ddi_walk_devs(ddi_root_node(), gfxp_pci_find_bsf, pci_bsf);
174 
175 	if (pci_bsf->found) {
176 		dip = pci_bsf->dip;
177 
178 		if (vendor) *vendor = pci_bsf->vendor;
179 		if (device) *device = pci_bsf->device;
180 	} else {
181 		dip = NULL;
182 		if (vendor) *vendor = 0x0000;
183 		if (device) *device = 0x0000;
184 	}
185 
186 	kmem_free(pci_bsf, sizeof (gfxp_pci_bsf_t));
187 
188 	return ((gfxp_acc_handle_t)dip);
189 }
190 
191 uint8_t
gfxp_pci_read_byte(gfxp_acc_handle_t handle,uint16_t offset)192 gfxp_pci_read_byte(gfxp_acc_handle_t handle, uint16_t offset)
193 {
194 	dev_info_t	*dip = (dev_info_t *)handle;
195 	uint8_t	val;
196 	uint8_t	bus, dev, func;
197 
198 	if (dip == NULL)
199 		return ((uint8_t)~0);
200 
201 	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
202 		return ((uint8_t)~0);
203 
204 	val = (*pci_getb_func)(bus, dev, func, offset);
205 	return (val);
206 }
207 
208 uint16_t
gfxp_pci_read_word(gfxp_acc_handle_t handle,uint16_t offset)209 gfxp_pci_read_word(gfxp_acc_handle_t handle, uint16_t offset)
210 {
211 	dev_info_t	*dip = (dev_info_t *)handle;
212 	uint16_t	val;
213 	uint8_t 	bus, dev, func;
214 
215 	if (dip == NULL)
216 		return ((uint16_t)~0);
217 
218 	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
219 		return ((uint16_t)~0);
220 
221 	val = (*pci_getw_func)(bus, dev, func, offset);
222 	return (val);
223 }
224 
225 uint32_t
gfxp_pci_read_dword(gfxp_acc_handle_t handle,uint16_t offset)226 gfxp_pci_read_dword(gfxp_acc_handle_t handle, uint16_t offset)
227 {
228 	dev_info_t	*dip = (dev_info_t *)handle;
229 	uint32_t	val;
230 	uint8_t		bus, dev, func;
231 
232 	if (dip == NULL)
233 		return ((uint32_t)~0);
234 
235 	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
236 		return ((uint32_t)~0);
237 
238 	val = (*pci_getl_func)(bus, dev, func, offset);
239 	return (val);
240 }
241 
242 void
gfxp_pci_write_byte(gfxp_acc_handle_t handle,uint16_t offset,uint8_t value)243 gfxp_pci_write_byte(gfxp_acc_handle_t handle, uint16_t offset, uint8_t value)
244 {
245 	dev_info_t	*dip = (dev_info_t *)handle;
246 	uint8_t		bus, dev, func;
247 
248 	if (dip == NULL)
249 		return;
250 
251 	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
252 		return;
253 
254 	(*pci_putb_func)(bus, dev, func, offset, value);
255 }
256 
257 void
gfxp_pci_write_word(gfxp_acc_handle_t handle,uint16_t offset,uint16_t value)258 gfxp_pci_write_word(gfxp_acc_handle_t handle, uint16_t offset, uint16_t value)
259 {
260 	dev_info_t	*dip = (dev_info_t *)handle;
261 	uint8_t		bus, dev, func;
262 
263 	if (dip == NULL)
264 		return;
265 
266 	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
267 		return;
268 
269 	(*pci_putw_func)(bus, dev, func, offset, value);
270 }
271 
272 void
gfxp_pci_write_dword(gfxp_acc_handle_t handle,uint16_t offset,uint32_t value)273 gfxp_pci_write_dword(gfxp_acc_handle_t handle, uint16_t offset, uint32_t value)
274 {
275 	dev_info_t	*dip = (dev_info_t *)handle;
276 	uint8_t		bus, dev, func;
277 
278 	if (dip == NULL)
279 		return;
280 
281 	if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
282 		return;
283 
284 	(*pci_putl_func)(bus, dev, func, offset, value);
285 }
286 
287 static int
gfxp_pci_find_vd(dev_info_t * dip,void * arg)288 gfxp_pci_find_vd(dev_info_t *dip, void *arg)
289 {
290 	int		rc;
291 	gfxp_pci_bsf_t	*pci_bsf;
292 	int		vendor_id, device_id, class_code;
293 
294 	/*
295 	 * Look for vendor-id, device-id, class-code to verify
296 	 * this is some type of PCI child node.
297 	 */
298 	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
299 			"vendor-id", -1);
300 	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
301 			"device-id", -1);
302 	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
303 			"class-code", -1);
304 	if ((vendor_id == -1) || (device_id == -1) || (class_code == -1)) {
305 		return (DDI_WALK_CONTINUE);
306 	}
307 
308 	pci_bsf = (gfxp_pci_bsf_t *)arg;
309 
310 	if ((vendor_id == pci_bsf->vendor) && (device_id == pci_bsf->device)) {
311 		pci_bsf->found = 1;
312 		rc = DDI_WALK_TERMINATE;
313 	} else {
314 		rc = DDI_WALK_CONTINUE;
315 	}
316 
317 	return (rc);
318 }
319 
320 int
gfxp_pci_device_present(uint16_t vendor,uint16_t device)321 gfxp_pci_device_present(uint16_t vendor, uint16_t device)
322 {
323 	gfxp_pci_bsf_t	*pci_bsf;
324 	int		rv;
325 
326 	/*
327 	 * Find a PCI device based on its device and vendor id.
328 	 */
329 
330 	if ((pci_bsf = kmem_zalloc(sizeof (gfxp_pci_bsf_t), KM_SLEEP)) == NULL)
331 	    return (0);
332 
333 	pci_bsf->vendor = vendor;
334 	pci_bsf->device = device;
335 	ddi_walk_devs(ddi_root_node(), gfxp_pci_find_vd, pci_bsf);
336 
337 	if (pci_bsf->found) {
338 		rv = 1;
339 	} else {
340 		rv = 0;
341 	}
342 
343 	kmem_free(pci_bsf, sizeof (gfxp_pci_bsf_t));
344 
345 	return (rv);
346 }
347