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