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 }