1 /*
   2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 /*
   7  * drm_memory.h -- Memory management wrappers for DRM -*- linux-c -*-
   8  * Created: Thu Feb  4 14:00:34 1999 by faith@valinux.com
   9  */
  10 /*
  11  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
  12  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  13  * Copyright (c) 2009, Intel Corporation.
  14  * All Rights Reserved.
  15  *
  16  * Permission is hereby granted, free of charge, to any person obtaining a
  17  * copy of this software and associated documentation files (the "Software"),
  18  * to deal in the Software without restriction, including without limitation
  19  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  20  * and/or sell copies of the Software, and to permit persons to whom the
  21  * Software is furnished to do so, subject to the following conditions:
  22  *
  23  * The above copyright notice and this permission notice (including the next
  24  * paragraph) shall be included in all copies or substantial portions of the
  25  * Software.
  26  *
  27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  30  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  31  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  32  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  33  * OTHER DEALINGS IN THE SOFTWARE.
  34  *
  35  * Authors:
  36  *    Rickard E. (Rik) Faith <faith@valinux.com>
  37  *    Gareth Hughes <gareth@valinux.com>
  38  *
  39  */
  40 
  41 #include "drmP.h"
  42 
  43 /* Device memory access structure */
  44 typedef struct drm_device_iomap {
  45         uint_t                  physical;       /* physical address */
  46         uint_t                  size;           /* size of mapping */
  47         uint_t                  drm_regnum;     /* register number */
  48         caddr_t                 drm_base;       /* kernel virtual address */
  49         ddi_acc_handle_t        drm_handle;     /* data access handle */
  50 } drm_device_iomap_t;
  51 
  52 void
  53 drm_mem_init(void)
  54 {
  55 }
  56 
  57 void
  58 drm_mem_uninit(void)
  59 {
  60 }
  61 
  62 /*ARGSUSED*/
  63 void *
  64 drm_alloc(size_t size, int area)
  65 {
  66         return (kmem_zalloc(1 * size, KM_NOSLEEP));
  67 }
  68 
  69 /*ARGSUSED*/
  70 void *
  71 drm_calloc(size_t nmemb, size_t size, int area)
  72 {
  73         return (kmem_zalloc(size * nmemb, KM_NOSLEEP));
  74 }
  75 
  76 /*ARGSUSED*/
  77 void *
  78 drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
  79 {
  80         void *pt;
  81 
  82         pt = kmem_zalloc(1 * size, KM_NOSLEEP);
  83         if (pt == NULL) {
  84                 DRM_ERROR("pt is NULL strange");
  85                 return (NULL);
  86         }
  87         if (oldpt && oldsize) {
  88                 bcopy(pt, oldpt, oldsize);
  89                 kmem_free(oldpt, oldsize);
  90         }
  91         return (pt);
  92 }
  93 
  94 /*ARGSUSED*/
  95 void
  96 drm_free(void *pt, size_t size, int area)
  97 {
  98         kmem_free(pt, size);
  99 }
 100 
 101 /*ARGSUSED*/
 102 int
 103 drm_get_pci_index_reg(dev_info_t *devi, uint_t physical, uint_t size,
 104     off_t *off)
 105 {
 106         int             length;
 107         pci_regspec_t   *regs;
 108         int             n_reg, i;
 109         int             regnum;
 110         uint_t          base, regsize;
 111 
 112         regnum = -1;
 113 
 114         if (ddi_dev_nregs(devi, &n_reg) == DDI_FAILURE) {
 115                 DRM_ERROR("drm_get_pci_index_reg:ddi_dev_nregs failed\n");
 116                 n_reg = 0;
 117                 return (-1);
 118         }
 119 
 120         if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
 121             "assigned-addresses", (caddr_t)&regs, &length) !=
 122             DDI_PROP_SUCCESS) {
 123                 DRM_ERROR("drm_get_pci_index_reg: ddi_getlongprop failed!\n");
 124                 goto error;
 125         }
 126 
 127         for (i = 0; i < n_reg; i ++) {
 128                 base = (uint_t)regs[i].pci_phys_low;
 129                 regsize = (uint_t)regs[i].pci_size_low;
 130                 if ((uint_t)physical >= base &&
 131                     (uint_t)physical < (base + regsize)) {
 132                         regnum = i + 1;
 133                         *off = (off_t)(physical - base);
 134                         break;
 135                 }
 136         }
 137 
 138         kmem_free(regs, (size_t)length);
 139         return (regnum);
 140 error:
 141         kmem_free(regs, (size_t)length);
 142         return (-1);
 143 }
 144 
 145 /* data access attributes structure for register access */
 146 static ddi_device_acc_attr_t dev_attr = {
 147         DDI_DEVICE_ATTR_V0,
 148         DDI_NEVERSWAP_ACC,
 149         DDI_STRICTORDER_ACC,
 150 };
 151 
 152 int
 153 do_ioremap(dev_info_t *devi, drm_device_iomap_t *iomap)
 154 {
 155         int regnum;
 156         off_t offset;
 157         int ret;
 158 
 159         regnum =  drm_get_pci_index_reg(devi, iomap->physical,
 160             iomap->size, &offset);
 161         if (regnum < 0) {
 162                 DRM_ERROR("do_ioremap: can not find regster entry,"
 163                     " start=0x%x, size=0x%x", iomap->physical, iomap->size);
 164                 return (ENXIO);
 165         }
 166 
 167         iomap->drm_regnum = regnum;
 168 
 169         ret = ddi_regs_map_setup(devi, iomap->drm_regnum,
 170             (caddr_t *)&(iomap->drm_base), (offset_t)offset,
 171             (offset_t)iomap->size, &dev_attr, &iomap->drm_handle);
 172         if (ret < 0) {
 173                 DRM_ERROR("do_ioremap: failed to map regs: regno=%d,"
 174                     " offset=0x%x", regnum, offset);
 175                 iomap->drm_handle = NULL;
 176                 return (EFAULT);
 177         }
 178 
 179         return (0);
 180 }
 181 
 182 int
 183 drm_ioremap(drm_device_t *softstate, drm_local_map_t *map)
 184 {
 185         drm_device_iomap_t iomap;
 186         int ret;
 187 
 188         DRM_DEBUG("drm_ioremap called\n");
 189 
 190         bzero(&iomap, sizeof (drm_device_iomap_t));
 191         iomap.physical = map->offset;
 192         iomap.size = map->size;
 193         ret = do_ioremap(softstate->dip, &iomap);
 194 
 195         if (ret) {
 196                 DRM_ERROR("drm_ioremap: failed, physaddr=0x%x, size=0x%x",
 197                     map->offset, map->size);
 198                 return (ret);
 199         }
 200 
 201         /* ddi_acc_handle_t */
 202         map->dev_handle = iomap.drm_handle;
 203         map->handle = (void *)iomap.drm_base;
 204         map->dev_addr = iomap.drm_base;
 205 
 206         DRM_DEBUG(
 207             "map->handle is %p map->dev_addr is %lx map->size %x",
 208             (void *)map->handle, (unsigned long)map->dev_addr, map->size);
 209 
 210         return (0);
 211 }
 212 
 213 void
 214 drm_ioremapfree(drm_local_map_t *map)
 215 {
 216         if (map->dev_handle == NULL) {
 217                 DRM_ERROR("drm_ioremapfree: handle is NULL");
 218                 return;
 219         }
 220         ddi_regs_map_free(&map->dev_handle);
 221 }