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 }