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
gfxp_pci_get_bsf(dev_info_t * dip,uint8_t * bus,uint8_t * dev,uint8_t * func)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
gfxp_pci_find_bsf(dev_info_t * dip,void * arg)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
gfxp_pci_init_handle(uint8_t bus,uint8_t slot,uint8_t function,uint16_t * vendor,uint16_t * device)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
gfxp_pci_read_byte(gfxp_acc_handle_t handle,uint16_t offset)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
gfxp_pci_read_word(gfxp_acc_handle_t handle,uint16_t offset)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
gfxp_pci_read_dword(gfxp_acc_handle_t handle,uint16_t offset)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
gfxp_pci_write_byte(gfxp_acc_handle_t handle,uint16_t offset,uint8_t value)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
gfxp_pci_write_word(gfxp_acc_handle_t handle,uint16_t offset,uint16_t value)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
gfxp_pci_write_dword(gfxp_acc_handle_t handle,uint16_t offset,uint32_t value)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
gfxp_pci_find_vd(dev_info_t * dip,void * arg)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
gfxp_pci_device_present(uint16_t vendor,uint16_t device)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