1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* BEGIN CSTYLED */ 7 /** 8 * \file drm_pci.h 9 * \brief PCI consistent, DMA-accessible memory functions. 10 * 11 * \author Eric Anholt <anholt@FreeBSD.org> 12 */ 13 14 /*- 15 * Copyright 2003 Eric Anholt. 16 * All Rights Reserved. 17 * 18 * Permission is hereby granted, free of charge, to any person obtaining a 19 * copy of this software and associated documentation files (the "Software"), 20 * to deal in the Software without restriction, including without limitation 21 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 22 * and/or sell copies of the Software, and to permit persons to whom the 23 * Software is furnished to do so, subject to the following conditions: 24 * 25 * The above copyright notice and this permission notice (including the next 26 * paragraph) shall be included in all copies or substantial portions of the 27 * Software. 28 * 29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 33 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 34 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 35 */ 36 37 /**********************************************************************/ 38 /** \name PCI memory */ 39 /*@{*/ 40 /* END CSTYLED */ 41 42 #pragma ident "%Z%%M% %I% %E% SMI" 43 44 #include "drmP.h" 45 46 #define PCI_DEVICE(x) (((x)>>11) & 0x1f) 47 #define PCI_FUNCTION(x) (((x) & 0x700) >> 8) 48 #define PCI_BUS(x) (((x) & 0xff0000) >> 16) 49 50 /* Device info struct */ 51 typedef struct drm_device_info { 52 uint16_t drm_venid; /* drm devcie's vendor id */ 53 uint16_t drm_devid; /* drm device's device id */ 54 uint8_t drm_irq; /* drm device's interrupt line */ 55 } drm_device_info_t; 56 57 typedef struct drm_pci_resource { 58 uint_t regnum; 59 unsigned long offset; 60 unsigned long size; 61 } drm_pci_resource_t; 62 63 /* Get IRQ line */ 64 static int device_get_info(drm_device_info_t *data, ddi_acc_handle_t pch) 65 { 66 uint8_t irq; 67 68 if (!pch) 69 return (DRM_ERR(EINVAL)); 70 71 data->drm_venid = 72 pci_config_get16(pch, PCI_CONF_VENID); 73 data->drm_devid = 74 pci_config_get16(pch, PCI_CONF_DEVID); 75 irq = pci_config_get8(pch, PCI_CONF_IPIN); 76 DRM_DEBUG("!drm: device_get_info: \ 77 venid is %x, devid is %x,irq is %x \n", 78 data->drm_venid, data->drm_devid, irq); 79 80 if (irq) 81 irq = pci_config_get8(pch, PCI_CONF_ILINE); 82 data->drm_irq = irq; 83 84 return (0); 85 } 86 87 int 88 pci_get_info(drm_softstate_t *softstate, int *bus, int *slot, int *func) 89 { 90 int *regs_list; 91 uint_t nregs = 0; 92 93 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, softstate->dip, 94 DDI_PROP_DONTPASS, "reg", (int **)®s_list, &nregs) 95 != DDI_PROP_SUCCESS) { 96 DRM_ERROR("pci_get_info: get pci function bus device failed"); 97 goto error; 98 } 99 *bus = (int)PCI_BUS(regs_list[0]); 100 *slot = (int)PCI_DEVICE(regs_list[0]); 101 *func = (int)PCI_FUNCTION(regs_list[0]); 102 103 if (nregs > 0) { 104 ddi_prop_free(regs_list); 105 } 106 return (DDI_SUCCESS); 107 error: 108 if (nregs > 0) { 109 ddi_prop_free(regs_list); 110 } 111 return (DDI_FAILURE); 112 } 113 114 int 115 pci_get_irq(drm_softstate_t *softstate) 116 { 117 drm_device_info_t drm_info; 118 int ret; 119 120 bzero(&drm_info, sizeof (drm_device_info_t)); 121 ret = device_get_info(&drm_info, softstate->pci_cfg_hdl); 122 if (ret) 123 return (-1); 124 125 return (drm_info.drm_irq); 126 } 127 128 int 129 pci_get_vendor(drm_softstate_t *softstate) 130 { 131 drm_device_info_t drm_info; 132 int ret; 133 134 bzero(&drm_info, sizeof (drm_device_info_t)); 135 136 ret = device_get_info(&drm_info, softstate->pci_cfg_hdl); 137 if (ret) 138 return (DDI_FAILURE); 139 140 return (drm_info.drm_venid); 141 } 142 143 int 144 pci_get_device(drm_softstate_t *softstate) 145 { 146 drm_device_info_t drm_info; 147 int ret; 148 149 bzero(&drm_info, sizeof (drm_device_info_t)); 150 151 ret = device_get_info(&drm_info, softstate->pci_cfg_hdl); 152 if (ret) 153 return (DDI_FAILURE); 154 155 return (drm_info.drm_devid); 156 157 } 158 159 void 160 agp_remap(struct drm_softstate *softstate, struct drm_local_map *map) 161 { 162 DRM_DEBUG( 163 "agp_remap: map->handle:%lx map->offset %llx, map->size %lx\n", 164 (unsigned long)map->handle, map->offset.off, 165 (unsigned long)map->size); 166 167 map->handle = (void *)((softstate->agp_umem_kvaddr) + 168 (unsigned long)(map->offset.off - softstate->agp->base)); 169 map->dev_addr = (caddr_t)map->handle; 170 DRM_DEBUG("agp_remap: map->dev_addr is %lx", 171 (unsigned long) map->dev_addr); 172 173 } 174 175 /*ARGSUSED*/ 176 void 177 agp_remap_free(struct drm_softstate *softstate, struct drm_local_map *map) 178 {} 179 180 void 181 drm_core_ioremap(struct drm_local_map *map, struct drm_softstate *softstate) 182 { 183 if (map->type != _DRM_AGP_UMEM) { 184 (void) drm_ioremap(softstate, map); 185 } else { 186 (void) agp_remap(softstate, map); 187 } 188 } 189 190 void 191 drm_core_ioremapfree(struct drm_local_map *map, struct drm_softstate *softstate) 192 { 193 if (map->type != _DRM_AGP_UMEM) { 194 if (map->handle && map->size) 195 drm_ioremapfree(map); 196 } else { 197 (void) agp_remap_free(softstate, map); 198 } 199 } 200 201 struct drm_local_map * 202 drm_core_findmap(struct drm_softstate *dev, unsigned long offset) 203 { 204 drm_local_map_t *map; 205 206 DRM_SPINLOCK_ASSERT(&dev->dev_lock); 207 TAILQ_FOREACH(map, &dev->maplist, link) { 208 if ((unsigned long)map->offset.off == offset) 209 return (map); 210 } 211 return (NULL); 212 } 213 214 /* 215 * pci_alloc_consistent() 216 */ 217 218 static ddi_dma_attr_t hw_dma_attr = { 219 DMA_ATTR_V0, 220 (unsigned long long)0, 221 (unsigned long long)0xffffffff, 222 (unsigned long long)0xffffffff, 223 (unsigned long long)4096, 224 1, 225 1, 226 (unsigned long long)0xffffffff, 227 (unsigned long long)0xffffffff, 228 1, 229 4, 230 0 231 }; 232 233 static ddi_device_acc_attr_t hw_acc_attr = { 234 DDI_DEVICE_ATTR_V0, 235 DDI_NEVERSWAP_ACC, 236 DDI_STRICTORDER_ACC 237 }; 238 239 void * 240 drm_pci_alloc(drm_softstate_t *dev, uint32_t size, 241 dma_addr_t *physaddr) 242 { 243 int ret = DDI_FAILURE; 244 uint32_t num_cookies; 245 ddi_dma_cookie_t cookie; 246 247 /* allocat continous physical memory for hw status page */ 248 hw_dma_attr.dma_attr_sgllen = 1; 249 250 if (ret = ddi_dma_alloc_handle(dev->dip, 251 &hw_dma_attr, 252 DDI_DMA_SLEEP, 253 NULL, &dev->hw_dma_handle)) { 254 DRM_ERROR("drm_pci_alloc:ddi_dma_alloc_handle failed\n"); 255 goto err3; 256 } 257 258 if (ret = ddi_dma_mem_alloc(dev->hw_dma_handle, 259 size, 260 &hw_acc_attr, 261 DDI_DMA_CONSISTENT, 262 DDI_DMA_SLEEP, NULL, 263 &dev->hw_vbase, 264 &dev->hw_size, 265 &dev->hw_dma_acc_handle)) { 266 DRM_ERROR("drm_pci_alloc: ddi_dma_mem_alloc failed\n"); 267 goto err2; 268 } 269 270 ret = ddi_dma_addr_bind_handle(dev->hw_dma_handle, 271 NULL, dev->hw_vbase, 272 size, 273 DDI_DMA_RDWR|DDI_DMA_CONSISTENT, 274 DDI_DMA_SLEEP, NULL, 275 &cookie, &num_cookies); 276 dev->hw_pbase = cookie.dmac_address; 277 278 if ((ret != DDI_DMA_MAPPED) || (num_cookies != 1)) { 279 if (num_cookies > 1) 280 (void) ddi_dma_unbind_handle(dev->hw_dma_handle); 281 DRM_ERROR("drm_pci_alloc: alloc contiguous phys memory failed"); 282 goto err1; 283 } 284 *physaddr = dev->hw_pbase; 285 return (dev->hw_vbase); 286 287 err1: 288 ddi_dma_mem_free(&dev->hw_dma_acc_handle); 289 dev->hw_dma_acc_handle = NULL; 290 err2: 291 ddi_dma_free_handle(&dev->hw_dma_handle); 292 dev->hw_dma_handle = NULL; 293 err3: 294 dev->hw_pbase = 0; 295 dev->hw_vbase = 0; 296 dev->hw_size = 0; 297 *physaddr = NULL; 298 return (NULL); 299 } 300 301 /* 302 * pci_free_consistent() 303 */ 304 /*ARGSUSED*/ 305 void 306 drm_pci_free(drm_softstate_t *dev) 307 { 308 if (dev->hw_dma_handle == NULL) 309 return; 310 (void) ddi_dma_unbind_handle(dev->hw_dma_handle); 311 ddi_dma_mem_free(&dev->hw_dma_acc_handle); 312 dev->hw_dma_acc_handle = NULL; 313 ddi_dma_free_handle(&dev->hw_dma_handle); 314 dev->hw_dma_handle = NULL; 315 dev->hw_pbase = NULL; 316 dev->hw_vbase = NULL; 317 dev->hw_size = 0; 318 319 320 } 321 322 int 323 do_get_pci_res(drm_softstate_t *softstate, drm_pci_resource_t *resp) 324 { 325 int length; 326 pci_regspec_t *regs; 327 328 if (ddi_getlongprop( 329 DDI_DEV_T_ANY, softstate->dip, DDI_PROP_DONTPASS, 330 "assigned-addresses", (caddr_t)®s, &length) != 331 DDI_PROP_SUCCESS) { 332 DRM_ERROR("do_get_pci_res: ddi_getlongprop failed!\n"); 333 return (DRM_ERR(EFAULT)); 334 } 335 resp->offset = 336 (unsigned long)regs[resp->regnum].pci_phys_low; 337 resp->size = 338 (unsigned long)regs[resp->regnum].pci_size_low; 339 kmem_free(regs, (size_t)length); 340 341 return (DDI_SUCCESS); 342 } 343 344 /*ARGSUSED*/ 345 unsigned long 346 drm_get_resource_start(drm_softstate_t *softstate, unsigned int regnum) 347 { 348 drm_pci_resource_t res; 349 int ret; 350 351 res.regnum = regnum; 352 353 ret = do_get_pci_res(softstate, &res); 354 355 if (ret != DDI_SUCCESS) { 356 DRM_ERROR( 357 "drm_get_resource_start: " 358 "DRM_GET_PCI_RESOURCE ioctl failed"); 359 return (0); 360 } 361 362 return (res.offset); 363 364 } 365 366 /*ARGSUSED*/ 367 unsigned long 368 drm_get_resource_len(drm_softstate_t *softstate, unsigned int regnum) 369 { 370 drm_pci_resource_t res; 371 int ret; 372 373 res.regnum = regnum; 374 375 ret = do_get_pci_res(softstate, &res); 376 377 if (ret != DDI_SUCCESS) { 378 DRM_ERROR( 379 "drm_get_resource_len: " 380 "DRM_GET_PCI_RESOURCE ioctl failed"); 381 return (0); 382 } 383 384 return (res.size); 385 } 386