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 }