2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
9 * \brief PCI consistent, DMA-accessible memory functions.
11 * \author Eric Anholt <anholt@FreeBSD.org>
15 * Copyright 2003 Eric Anholt.
16 * All Rights Reserved.
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:
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
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.
37 /**********************************************************************/
38 /** \name PCI memory */
42 #pragma ident "%Z%%M% %I% %E% SMI"
45 #include <vm/seg_kmem.h>
47 #define PCI_DEVICE(x) (((x)>>11) & 0x1f)
48 #define PCI_FUNCTION(x) (((x) & 0x700) >> 8)
49 #define PCI_BUS(x) (((x) & 0xff0000) >> 16)
51 typedef struct drm_pci_resource
{
58 pci_get_info(drm_device_t
*softstate
, int *bus
, int *slot
, int *func
)
63 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, softstate
->dip
,
64 DDI_PROP_DONTPASS
, "reg", (int **)®s_list
, &nregs
)
65 != DDI_PROP_SUCCESS
) {
66 DRM_ERROR("pci_get_info: get pci function bus device failed");
69 *bus
= (int)PCI_BUS(regs_list
[0]);
70 *slot
= (int)PCI_DEVICE(regs_list
[0]);
71 *func
= (int)PCI_FUNCTION(regs_list
[0]);
74 ddi_prop_free(regs_list
);
79 ddi_prop_free(regs_list
);
85 pci_get_irq(drm_device_t
*statep
)
89 extern int drm_supp_get_irq(void *);
91 irq
= ddi_prop_get_int(DDI_DEV_T_ANY
,
92 statep
->dip
, DDI_PROP_DONTPASS
, "interrupts", -1);
95 irq
= drm_supp_get_irq(statep
->drm_handle
);
102 pci_get_vendor(drm_device_t
*statep
)
106 vendorid
= ddi_prop_get_int(DDI_DEV_T_ANY
,
107 statep
->dip
, DDI_PROP_DONTPASS
, "vendor-id", 0);
113 pci_get_device(drm_device_t
*statep
)
117 deviceid
= ddi_prop_get_int(DDI_DEV_T_ANY
,
118 statep
->dip
, DDI_PROP_DONTPASS
, "device-id", 0);
124 drm_core_ioremap(struct drm_local_map
*map
, drm_device_t
*dev
)
126 if ((map
->type
== _DRM_AGP
) && dev
->agp
) {
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().
146 DRM_DEBUG("drm_core_ioremap: skipping agp_remap\n");
148 (void) drm_ioremap(dev
, map
);
155 drm_core_ioremapfree(struct drm_local_map
*map
, drm_device_t
*dev
)
157 if (map
->type
!= _DRM_AGP
) {
158 if (map
->handle
&& map
->size
)
159 drm_ioremapfree(map
);
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);
166 DRM_DEBUG("drm_core_ioremap: skipping agp_remap_free\n");
170 struct drm_local_map
*
171 drm_core_findmap(drm_device_t
*dev
, unsigned long handle
)
173 drm_local_map_t
*map
;
175 DRM_SPINLOCK_ASSERT(&dev
->dev_lock
);
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.
181 TAILQ_FOREACH(map
, &dev
->maplist
, link
) {
182 if ((((unsigned long)map
->handle
) & 0x00000000ffffffff)
183 == (handle
& 0x00000000ffffffff))
191 * pci_alloc_consistent()
193 static ddi_dma_attr_t hw_dma_attr
= {
194 DMA_ATTR_V0
, /* version */
196 0xffffffff, /* addr_hi */
197 0xffffffff, /* count_max */
198 4096, /* alignment */
199 0xfff, /* burstsize */
201 0xffffffff, /* maxxfer */
202 0xffffffff, /* seg */
208 static ddi_device_acc_attr_t hw_acc_attr
= {
216 drm_pci_alloc(drm_device_t
*dev
, size_t size
,
217 size_t align
, dma_addr_t maxaddr
, int segments
)
219 drm_dma_handle_t
*dmah
;
221 int ret
= DDI_FAILURE
;
223 /* allocat continous physical memory for hw status page */
225 hw_dma_attr
.dma_attr_align
= 1;
227 hw_dma_attr
.dma_attr_align
= align
;
229 hw_dma_attr
.dma_attr_addr_hi
= maxaddr
;
230 hw_dma_attr
.dma_attr_sgllen
= segments
;
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
)) {
235 DRM_ERROR("drm_pci_alloc:ddi_dma_alloc_handle failed\n");
239 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
)) {
243 DRM_ERROR("drm_pci_alloc: ddi_dma_mem_alloc failed\n");
247 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");
256 if (count
> segments
) {
257 (void) ddi_dma_unbind_handle(dmah
->dma_hdl
);
261 dmah
->cookie_num
= count
;
263 dmah
->paddr
= dmah
->cookie
.dmac_address
;
268 ddi_dma_mem_free(&dmah
->acc_hdl
);
270 ddi_dma_free_handle(&dmah
->dma_hdl
);
272 kmem_free(dmah
, sizeof (*dmah
));
277 * pci_free_consistent()
281 drm_pci_free(drm_device_t
*dev
, drm_dma_handle_t
*dmah
)
283 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
));
291 do_get_pci_res(drm_device_t
*dev
, drm_pci_resource_t
*resp
)
297 DDI_DEV_T_ANY
, dev
->dip
, DDI_PROP_DONTPASS
,
298 "assigned-addresses", (caddr_t
)®s
, &length
) !=
300 DRM_ERROR("do_get_pci_res: ddi_getlongprop failed!\n");
304 (unsigned long)regs
[resp
->regnum
].pci_phys_low
;
306 (unsigned long)regs
[resp
->regnum
].pci_size_low
;
307 kmem_free(regs
, (size_t)length
);
314 drm_get_resource_start(drm_device_t
*softstate
, unsigned int regnum
)
316 drm_pci_resource_t res
;
321 ret
= do_get_pci_res(softstate
, &res
);
324 DRM_ERROR("drm_get_resource_start: ioctl failed");
334 drm_get_resource_len(drm_device_t
*softstate
, unsigned int regnum
)
336 drm_pci_resource_t res
;
341 ret
= do_get_pci_res(softstate
, &res
);
344 DRM_ERROR("drm_get_resource_len: ioctl failed");