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 "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
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
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
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 pci_bsf = kmem_zalloc(sizeof (gfxp_pci_bsf_t), KM_SLEEP);
166
167 pci_bsf->bus = bus;
168 pci_bsf->slot = slot;
169 pci_bsf->function = function;
170
171 ddi_walk_devs(ddi_root_node(), gfxp_pci_find_bsf, pci_bsf);
172
173 if (pci_bsf->found) {
174 dip = pci_bsf->dip;
175
176 if (vendor) *vendor = pci_bsf->vendor;
177 if (device) *device = pci_bsf->device;
178 } else {
179 dip = NULL;
180 if (vendor) *vendor = 0x0000;
181 if (device) *device = 0x0000;
182 }
183
184 kmem_free(pci_bsf, sizeof (gfxp_pci_bsf_t));
185
186 return ((gfxp_acc_handle_t)dip);
187 }
188
189 uint8_t
190 gfxp_pci_read_byte(gfxp_acc_handle_t handle, uint16_t offset)
191 {
192 dev_info_t *dip = (dev_info_t *)handle;
193 uint8_t val;
194 uint8_t bus, dev, func;
195
196 if (dip == NULL)
197 return ((uint8_t)~0);
198
199 if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
200 return ((uint8_t)~0);
201
202 val = (*pci_getb_func)(bus, dev, func, offset);
203 return (val);
204 }
205
206 uint16_t
207 gfxp_pci_read_word(gfxp_acc_handle_t handle, uint16_t offset)
208 {
209 dev_info_t *dip = (dev_info_t *)handle;
210 uint16_t val;
211 uint8_t bus, dev, func;
212
213 if (dip == NULL)
214 return ((uint16_t)~0);
215
216 if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
217 return ((uint16_t)~0);
218
219 val = (*pci_getw_func)(bus, dev, func, offset);
220 return (val);
221 }
222
223 uint32_t
224 gfxp_pci_read_dword(gfxp_acc_handle_t handle, uint16_t offset)
225 {
226 dev_info_t *dip = (dev_info_t *)handle;
227 uint32_t val;
228 uint8_t bus, dev, func;
229
230 if (dip == NULL)
231 return ((uint32_t)~0);
232
233 if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
234 return ((uint32_t)~0);
235
236 val = (*pci_getl_func)(bus, dev, func, offset);
237 return (val);
238 }
239
240 void
241 gfxp_pci_write_byte(gfxp_acc_handle_t handle, uint16_t offset, uint8_t value)
242 {
243 dev_info_t *dip = (dev_info_t *)handle;
244 uint8_t bus, dev, func;
245
246 if (dip == NULL)
247 return;
248
249 if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
250 return;
251
252 (*pci_putb_func)(bus, dev, func, offset, value);
253 }
254
255 void
256 gfxp_pci_write_word(gfxp_acc_handle_t handle, uint16_t offset, uint16_t value)
257 {
258 dev_info_t *dip = (dev_info_t *)handle;
259 uint8_t bus, dev, func;
260
261 if (dip == NULL)
262 return;
263
264 if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
265 return;
266
267 (*pci_putw_func)(bus, dev, func, offset, value);
268 }
269
270 void
271 gfxp_pci_write_dword(gfxp_acc_handle_t handle, uint16_t offset, uint32_t value)
272 {
273 dev_info_t *dip = (dev_info_t *)handle;
274 uint8_t bus, dev, func;
275
276 if (dip == NULL)
277 return;
278
279 if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS)
280 return;
281
282 (*pci_putl_func)(bus, dev, func, offset, value);
283 }
284
285 static int
286 gfxp_pci_find_vd(dev_info_t *dip, void *arg)
287 {
288 int rc;
289 gfxp_pci_bsf_t *pci_bsf;
290 int vendor_id, device_id, class_code;
291
292 /*
293 * Look for vendor-id, device-id, class-code to verify
294 * this is some type of PCI child node.
295 */
296 vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
297 "vendor-id", -1);
298 device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
299 "device-id", -1);
300 class_code = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
301 "class-code", -1);
302 if ((vendor_id == -1) || (device_id == -1) || (class_code == -1)) {
303 return (DDI_WALK_CONTINUE);
304 }
305
306 pci_bsf = (gfxp_pci_bsf_t *)arg;
307
308 if ((vendor_id == pci_bsf->vendor) && (device_id == pci_bsf->device)) {
309 pci_bsf->found = 1;
310 rc = DDI_WALK_TERMINATE;
311 } else {
312 rc = DDI_WALK_CONTINUE;
313 }
314
315 return (rc);
316 }
317
318 int
319 gfxp_pci_device_present(uint16_t vendor, uint16_t device)
320 {
321 gfxp_pci_bsf_t *pci_bsf;
322 int rv;
323
324 /*
325 * Find a PCI device based on its device and vendor id.
326 */
327
328 pci_bsf = kmem_zalloc(sizeof (gfxp_pci_bsf_t), KM_SLEEP);
329
330 pci_bsf->vendor = vendor;
331 pci_bsf->device = device;
332 ddi_walk_devs(ddi_root_node(), gfxp_pci_find_vd, pci_bsf);
333
334 if (pci_bsf->found) {
335 rv = 1;
336 } else {
337 rv = 0;
338 }
339
340 kmem_free(pci_bsf, sizeof (gfxp_pci_bsf_t));
341
342 return (rv);
343 }