more files for mach64
[platform/upstream/libdrm.git] / linux-core / drm_pci.c
1 /* drm_pci.h -- PCI DMA memory management wrappers for DRM -*- linux-c -*- */
2 /**
3  * \file drm_pci.h
4  * \brief Functions and ioctls to manage PCI memory
5  * 
6  * \warning These interfaces aren't stable yet.
7  * 
8  * \todo Implement the remaining ioctl's for the PCI pools.
9  * \todo Add support to map these buffers.
10  * \todo The wrappers here are so thin that they would be better off inlined..
11  *
12  * \author José Fonseca <jrfonseca@tungstengraphics.com>
13  * \author Leif Delgass <ldelgass@retinalburn.net>
14  */
15
16 /*
17  * Copyright 2003 José Fonseca.
18  * Copyright 2003 Leif Delgass.
19  * All Rights Reserved.
20  *
21  * Permission is hereby granted, free of charge, to any person obtaining a
22  * copy of this software and associated documentation files (the "Software"),
23  * to deal in the Software without restriction, including without limitation
24  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
25  * and/or sell copies of the Software, and to permit persons to whom the
26  * Software is furnished to do so, subject to the following conditions:
27  *
28  * The above copyright notice and this permission notice (including the next
29  * paragraph) shall be included in all copies or substantial portions of the
30  * Software.
31  *
32  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
35  * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
36  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40
41 #define __NO_VERSION__
42 #include <linux/pci.h>
43 #include "drmP.h"
44
45 /**********************************************************************/
46 /** \name PCI memory */
47 /*@{*/
48
49
50 /**
51  * \brief Allocate a PCI consistent memory block, for DMA.
52  */
53 void *
54 DRM(pci_alloc)(drm_device_t *dev, size_t size, size_t align, 
55                dma_addr_t maxaddr, dma_addr_t *busaddr)
56 {
57         void *address;
58 #if 0
59         unsigned long addr;
60         size_t sz;
61 #endif
62 #if DRM_DEBUG_MEMORY
63         int area = DRM_MEM_DMA;
64
65         spin_lock(&DRM(mem_lock));
66         if ((DRM(ram_used) >> PAGE_SHIFT)
67             > (DRM_RAM_PERCENT * DRM(ram_available)) / 100) {
68                 spin_unlock(&DRM(mem_lock));
69                 return 0;
70         }
71         spin_unlock(&DRM(mem_lock));
72 #endif
73
74         /* pci_alloc_consistent only guarantees alignment to the smallest 
75          * PAGE_SIZE order which is greater than or equal to the requested size.
76          * Return NULL here for now to make sure nobody tries for larger alignment
77          */
78         if (align > size)
79                 return NULL;
80
81         if (pci_set_dma_mask( dev->pdev, maxaddr ) != 0) {
82                 DRM_ERROR( "Setting pci dma mask failed\n" );
83                 return NULL;
84         }
85
86         address = pci_alloc_consistent( dev->pdev, size, busaddr );
87
88 #if DRM_DEBUG_MEMORY
89         if (address == NULL) {
90                 spin_lock(&DRM(mem_lock));
91                 ++DRM(mem_stats)[area].fail_count;
92                 spin_unlock(&DRM(mem_lock));
93                 return NULL;
94         }
95
96         spin_lock(&DRM(mem_lock));
97         ++DRM(mem_stats)[area].succeed_count;
98         DRM(mem_stats)[area].bytes_allocated += size;
99         DRM(ram_used)                        += size;
100         spin_unlock(&DRM(mem_lock));
101 #else
102         if (address == NULL)
103                 return NULL;
104 #endif
105
106         memset(address, 0, size);
107
108 #if 0
109         /* XXX - Is virt_to_page() legal for consistent mem? */
110                                 /* Reserve */
111         for (addr = (unsigned long)address, sz = size;
112              sz > 0;
113              addr += PAGE_SIZE, sz -= PAGE_SIZE) {
114                 SetPageReserved(virt_to_page(addr));
115         }
116 #endif
117
118         return address;
119 }
120
121 /**
122  * \brief Free a PCI consistent memory block.
123  */
124 void
125 DRM(pci_free)(drm_device_t *dev, size_t size, void *vaddr, dma_addr_t busaddr)
126 {
127 #if 0
128         unsigned long addr;
129         size_t sz;
130 #endif
131 #if DRM_DEBUG_MEMORY
132         int area = DRM_MEM_DMA;
133         int alloc_count;
134         int free_count;
135 #endif
136
137         if (!vaddr) {
138 #if DRM_DEBUG_MEMORY
139                 DRM_MEM_ERROR(area, "Attempt to free address 0\n");
140 #endif
141         } else {
142 #if 0
143                 /* XXX - Is virt_to_page() legal for consistent mem? */
144                                 /* Unreserve */
145                 for (addr = (unsigned long)vaddr, sz = size;
146                      sz > 0;
147                      addr += PAGE_SIZE, sz -= PAGE_SIZE) {
148                         ClearPageReserved(virt_to_page(addr));
149                 }
150 #endif
151                 pci_free_consistent( dev->pdev, size, vaddr, busaddr );
152         }
153
154 #if DRM_DEBUG_MEMORY
155         spin_lock(&DRM(mem_lock));
156         free_count  = ++DRM(mem_stats)[area].free_count;
157         alloc_count =   DRM(mem_stats)[area].succeed_count;
158         DRM(mem_stats)[area].bytes_freed += size;
159         DRM(ram_used)                    -= size;
160         spin_unlock(&DRM(mem_lock));
161         if (free_count > alloc_count) {
162                 DRM_MEM_ERROR(area,
163                               "Excess frees: %d frees, %d allocs\n",
164                               free_count, alloc_count);
165         }
166 #endif
167
168 }
169
170 /*@}*/