blob: 37a02a1d9590c9a7729ef9adef745f51fbbc256b [file] [log] [blame]
kz15163460405de2006-09-28 01:41:18 -07001/*
cg149915d0538f62008-01-09 19:45:15 -08002 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
kz15163460405de2006-09-28 01:41:18 -07003 * 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"
cg149915d0538f62008-01-09 19:45:15 -080045#include <vm/seg_kmem.h>
kz15163460405de2006-09-28 01:41:18 -070046
47#define PCI_DEVICE(x) (((x)>>11) & 0x1f)
48#define PCI_FUNCTION(x) (((x) & 0x700) >> 8)
49#define PCI_BUS(x) (((x) & 0xff0000) >> 16)
50
kz15163460405de2006-09-28 01:41:18 -070051typedef struct drm_pci_resource {
52 uint_t regnum;
53 unsigned long offset;
54 unsigned long size;
55} drm_pci_resource_t;
56
kz15163460405de2006-09-28 01:41:18 -070057int
cg149915d0538f62008-01-09 19:45:15 -080058pci_get_info(drm_device_t *softstate, int *bus, int *slot, int *func)
kz15163460405de2006-09-28 01:41:18 -070059{
60 int *regs_list;
61 uint_t nregs = 0;
62
63 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, softstate->dip,
64 DDI_PROP_DONTPASS, "reg", (int **)&regs_list, &nregs)
65 != DDI_PROP_SUCCESS) {
66 DRM_ERROR("pci_get_info: get pci function bus device failed");
67 goto error;
68 }
69 *bus = (int)PCI_BUS(regs_list[0]);
70 *slot = (int)PCI_DEVICE(regs_list[0]);
71 *func = (int)PCI_FUNCTION(regs_list[0]);
72
73 if (nregs > 0) {
74 ddi_prop_free(regs_list);
75 }
76 return (DDI_SUCCESS);
77error:
78 if (nregs > 0) {
79 ddi_prop_free(regs_list);
80 }
81 return (DDI_FAILURE);
82}
83
84int
cg149915d0538f62008-01-09 19:45:15 -080085pci_get_irq(drm_device_t *statep)
kz15163460405de2006-09-28 01:41:18 -070086{
cg149915d0538f62008-01-09 19:45:15 -080087 int irq;
kz15163460405de2006-09-28 01:41:18 -070088
cg149915d0538f62008-01-09 19:45:15 -080089 extern int drm_supp_get_irq(void *);
kz15163460405de2006-09-28 01:41:18 -070090
cg149915d0538f62008-01-09 19:45:15 -080091 irq = ddi_prop_get_int(DDI_DEV_T_ANY,
92 statep->dip, DDI_PROP_DONTPASS, "interrupts", -1);
93
94 if (irq > 0) {
95 irq = drm_supp_get_irq(statep->drm_handle);
96 }
97
98 return (irq);
kz15163460405de2006-09-28 01:41:18 -070099}
100
101int
cg149915d0538f62008-01-09 19:45:15 -0800102pci_get_vendor(drm_device_t *statep)
kz15163460405de2006-09-28 01:41:18 -0700103{
cg149915d0538f62008-01-09 19:45:15 -0800104 int vendorid;
kz15163460405de2006-09-28 01:41:18 -0700105
cg149915d0538f62008-01-09 19:45:15 -0800106 vendorid = ddi_prop_get_int(DDI_DEV_T_ANY,
107 statep->dip, DDI_PROP_DONTPASS, "vendor-id", 0);
kz15163460405de2006-09-28 01:41:18 -0700108
cg149915d0538f62008-01-09 19:45:15 -0800109 return (vendorid);
kz15163460405de2006-09-28 01:41:18 -0700110}
111
112int
cg149915d0538f62008-01-09 19:45:15 -0800113pci_get_device(drm_device_t *statep)
kz15163460405de2006-09-28 01:41:18 -0700114{
cg149915d0538f62008-01-09 19:45:15 -0800115 int deviceid;
kz15163460405de2006-09-28 01:41:18 -0700116
cg149915d0538f62008-01-09 19:45:15 -0800117 deviceid = ddi_prop_get_int(DDI_DEV_T_ANY,
118 statep->dip, DDI_PROP_DONTPASS, "device-id", 0);
kz15163460405de2006-09-28 01:41:18 -0700119
cg149915d0538f62008-01-09 19:45:15 -0800120 return (deviceid);
kz15163460405de2006-09-28 01:41:18 -0700121}
122
123void
cg149915d0538f62008-01-09 19:45:15 -0800124drm_core_ioremap(struct drm_local_map *map, drm_device_t *dev)
kz15163460405de2006-09-28 01:41:18 -0700125{
cg149915d0538f62008-01-09 19:45:15 -0800126 if ((map->type == _DRM_AGP) && dev->agp) {
127 /*
128 * During AGP mapping initialization, we map AGP aperture
129 * into kernel space. So, when we access the memory which
130 * managed by agp gart in kernel space, we have to go
131 * through two-level address translation: kernel virtual
132 * address --> aperture address --> physical address. For
133 * improving this, here in opensourced code, agp_remap()
134 * gets invoking to dispose the mapping between agp aperture
135 * and kernel space, and directly map the actual physical
136 * memory which is allocated to agp gart to kernel space.
137 * After that, access to physical memory managed by agp gart
138 * hardware in kernel space doesn't go through agp hardware,
139 * it will be: kernel virtual ---> physical address.
140 * Obviously, it is more efficient. But in solaris operating
141 * system, the ioctl AGPIOC_ALLOCATE of apggart driver does
142 * not return physical address. We are unable to create the
143 * direct mapping between kernel space and agp memory. So,
144 * we remove the calling to agp_remap().
145 */
146 DRM_DEBUG("drm_core_ioremap: skipping agp_remap\n");
147 } else {
148 (void) drm_ioremap(dev, map);
kz15163460405de2006-09-28 01:41:18 -0700149
cg149915d0538f62008-01-09 19:45:15 -0800150 }
kz15163460405de2006-09-28 01:41:18 -0700151}
152
153/*ARGSUSED*/
154void
cg149915d0538f62008-01-09 19:45:15 -0800155drm_core_ioremapfree(struct drm_local_map *map, drm_device_t *dev)
kz15163460405de2006-09-28 01:41:18 -0700156{
cg149915d0538f62008-01-09 19:45:15 -0800157 if (map->type != _DRM_AGP) {
kz15163460405de2006-09-28 01:41:18 -0700158 if (map->handle && map->size)
159 drm_ioremapfree(map);
160 } else {
cg149915d0538f62008-01-09 19:45:15 -0800161 /*
162 * Refer to the comments in drm_core_ioremap() where we removed
163 * the calling to agp_remap(), correspondingly, we remove the
164 * calling to agp_remap_free(dev, map);
165 */
166 DRM_DEBUG("drm_core_ioremap: skipping agp_remap_free\n");
kz15163460405de2006-09-28 01:41:18 -0700167 }
168}
169
170struct drm_local_map *
cg149915d0538f62008-01-09 19:45:15 -0800171drm_core_findmap(drm_device_t *dev, unsigned long handle)
kz15163460405de2006-09-28 01:41:18 -0700172{
173 drm_local_map_t *map;
174
175 DRM_SPINLOCK_ASSERT(&dev->dev_lock);
cg149915d0538f62008-01-09 19:45:15 -0800176
177/*
178 * For the time being, we compare the low 32 bit only,
179 * We will hash handle to 32-bit to solve this issue later.
180 */
kz15163460405de2006-09-28 01:41:18 -0700181 TAILQ_FOREACH(map, &dev->maplist, link) {
cg149915d0538f62008-01-09 19:45:15 -0800182 if ((((unsigned long)map->handle) & 0x00000000ffffffff)
183 == (handle & 0x00000000ffffffff))
kz15163460405de2006-09-28 01:41:18 -0700184 return (map);
185 }
cg149915d0538f62008-01-09 19:45:15 -0800186
kz15163460405de2006-09-28 01:41:18 -0700187 return (NULL);
188}
189
190/*
191 * pci_alloc_consistent()
192 */
cg149915d0538f62008-01-09 19:45:15 -0800193static ddi_dma_attr_t hw_dma_attr = {
194 DMA_ATTR_V0, /* version */
195 0, /* addr_lo */
196 0xffffffff, /* addr_hi */
197 0xffffffff, /* count_max */
198 4096, /* alignment */
199 0xfff, /* burstsize */
200 1, /* minxfer */
201 0xffffffff, /* maxxfer */
202 0xffffffff, /* seg */
203 1, /* sgllen */
204 4, /* granular */
205 0 /* flags */
kz15163460405de2006-09-28 01:41:18 -0700206};
207
208static ddi_device_acc_attr_t hw_acc_attr = {
209 DDI_DEVICE_ATTR_V0,
210 DDI_NEVERSWAP_ACC,
211 DDI_STRICTORDER_ACC
212};
213
cg149915d0538f62008-01-09 19:45:15 -0800214
kz15163460405de2006-09-28 01:41:18 -0700215void *
cg149915d0538f62008-01-09 19:45:15 -0800216drm_pci_alloc(drm_device_t *dev, size_t size,
217 size_t align, dma_addr_t maxaddr, int segments)
kz15163460405de2006-09-28 01:41:18 -0700218{
cg149915d0538f62008-01-09 19:45:15 -0800219 drm_dma_handle_t *dmah;
220 uint_t count;
kz15163460405de2006-09-28 01:41:18 -0700221 int ret = DDI_FAILURE;
kz15163460405de2006-09-28 01:41:18 -0700222
223 /* allocat continous physical memory for hw status page */
cg149915d0538f62008-01-09 19:45:15 -0800224 if (align == 0)
225 hw_dma_attr.dma_attr_align = 1;
226 else
227 hw_dma_attr.dma_attr_align = align;
kz15163460405de2006-09-28 01:41:18 -0700228
cg149915d0538f62008-01-09 19:45:15 -0800229 hw_dma_attr.dma_attr_addr_hi = maxaddr;
230 hw_dma_attr.dma_attr_sgllen = segments;
231
232 dmah = kmem_zalloc(sizeof (drm_dma_handle_t), KM_SLEEP);
233 if (ret = ddi_dma_alloc_handle(dev->dip, &hw_dma_attr,
234 DDI_DMA_SLEEP, NULL, &dmah->dma_hdl)) {
kz15163460405de2006-09-28 01:41:18 -0700235 DRM_ERROR("drm_pci_alloc:ddi_dma_alloc_handle failed\n");
236 goto err3;
237 }
238
cg149915d0538f62008-01-09 19:45:15 -0800239 if (ret = ddi_dma_mem_alloc(dmah->dma_hdl, size, &hw_acc_attr,
240 DDI_DMA_CONSISTENT | IOMEM_DATA_UNCACHED,
241 DDI_DMA_SLEEP, NULL, (caddr_t *)&dmah->vaddr,
242 &dmah->real_sz, &dmah->acc_hdl)) {
kz15163460405de2006-09-28 01:41:18 -0700243 DRM_ERROR("drm_pci_alloc: ddi_dma_mem_alloc failed\n");
244 goto err2;
245 }
246
cg149915d0538f62008-01-09 19:45:15 -0800247 ret = ddi_dma_addr_bind_handle(dmah->dma_hdl, NULL,
248 (caddr_t)dmah->vaddr, dmah->real_sz,
249 DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
250 DDI_DMA_SLEEP, NULL, &dmah->cookie, &count);
251 if (ret != DDI_DMA_MAPPED) {
252 DRM_ERROR("drm_pci_alloc: alloc phys memory failed");
kz15163460405de2006-09-28 01:41:18 -0700253 goto err1;
254 }
cg149915d0538f62008-01-09 19:45:15 -0800255
256 if (count > segments) {
257 (void) ddi_dma_unbind_handle(dmah->dma_hdl);
258 goto err1;
259 }
260
261 dmah->cookie_num = count;
262 if (count == 1)
263 dmah->paddr = dmah->cookie.dmac_address;
264
265 return (dmah);
kz15163460405de2006-09-28 01:41:18 -0700266
267err1:
cg149915d0538f62008-01-09 19:45:15 -0800268 ddi_dma_mem_free(&dmah->acc_hdl);
kz15163460405de2006-09-28 01:41:18 -0700269err2:
cg149915d0538f62008-01-09 19:45:15 -0800270 ddi_dma_free_handle(&dmah->dma_hdl);
kz15163460405de2006-09-28 01:41:18 -0700271err3:
cg149915d0538f62008-01-09 19:45:15 -0800272 kmem_free(dmah, sizeof (*dmah));
kz15163460405de2006-09-28 01:41:18 -0700273 return (NULL);
274}
275
276/*
277 * pci_free_consistent()
278 */
279/*ARGSUSED*/
280void
cg149915d0538f62008-01-09 19:45:15 -0800281drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah)
kz15163460405de2006-09-28 01:41:18 -0700282{
cg149915d0538f62008-01-09 19:45:15 -0800283 ASSERT(dmah != NULL);
284 (void) ddi_dma_unbind_handle(dmah->dma_hdl);
285 ddi_dma_mem_free(&dmah->acc_hdl);
286 ddi_dma_free_handle(&dmah->dma_hdl);
287 kmem_free(dmah, sizeof (drm_dma_handle_t));
kz15163460405de2006-09-28 01:41:18 -0700288}
289
290int
cg149915d0538f62008-01-09 19:45:15 -0800291do_get_pci_res(drm_device_t *dev, drm_pci_resource_t *resp)
kz15163460405de2006-09-28 01:41:18 -0700292{
293 int length;
294 pci_regspec_t *regs;
295
296 if (ddi_getlongprop(
cg149915d0538f62008-01-09 19:45:15 -0800297 DDI_DEV_T_ANY, dev->dip, DDI_PROP_DONTPASS,
kz15163460405de2006-09-28 01:41:18 -0700298 "assigned-addresses", (caddr_t)&regs, &length) !=
299 DDI_PROP_SUCCESS) {
300 DRM_ERROR("do_get_pci_res: ddi_getlongprop failed!\n");
cg149915d0538f62008-01-09 19:45:15 -0800301 return (EFAULT);
kz15163460405de2006-09-28 01:41:18 -0700302 }
303 resp->offset =
304 (unsigned long)regs[resp->regnum].pci_phys_low;
305 resp->size =
306 (unsigned long)regs[resp->regnum].pci_size_low;
307 kmem_free(regs, (size_t)length);
308
cg149915d0538f62008-01-09 19:45:15 -0800309 return (0);
kz15163460405de2006-09-28 01:41:18 -0700310}
311
312/*ARGSUSED*/
313unsigned long
cg149915d0538f62008-01-09 19:45:15 -0800314drm_get_resource_start(drm_device_t *softstate, unsigned int regnum)
kz15163460405de2006-09-28 01:41:18 -0700315{
316 drm_pci_resource_t res;
317 int ret;
318
319 res.regnum = regnum;
320
321 ret = do_get_pci_res(softstate, &res);
322
cg149915d0538f62008-01-09 19:45:15 -0800323 if (ret != 0) {
324 DRM_ERROR("drm_get_resource_start: ioctl failed");
kz15163460405de2006-09-28 01:41:18 -0700325 return (0);
326 }
327
328 return (res.offset);
329
330}
331
332/*ARGSUSED*/
333unsigned long
cg149915d0538f62008-01-09 19:45:15 -0800334drm_get_resource_len(drm_device_t *softstate, unsigned int regnum)
kz15163460405de2006-09-28 01:41:18 -0700335{
336 drm_pci_resource_t res;
337 int ret;
338
339 res.regnum = regnum;
340
341 ret = do_get_pci_res(softstate, &res);
342
cg149915d0538f62008-01-09 19:45:15 -0800343 if (ret != 0) {
344 DRM_ERROR("drm_get_resource_len: ioctl failed");
kz15163460405de2006-09-28 01:41:18 -0700345 return (0);
346 }
347
348 return (res.size);
349}