First check in for DRM that splits core from personality modules
[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 #include <linux/pci.h>
42 #include "drmP.h"
43
44 /**********************************************************************/
45 /** \name PCI memory */
46 /*@{*/
47
48
49 /**
50  * \brief Allocate a PCI consistent memory block, for DMA.
51  */
52 void *
53 drm_pci_alloc(drm_device_t *dev, size_t size, size_t align, 
54                dma_addr_t maxaddr, dma_addr_t *busaddr)
55 {
56         void *address;
57 #if 0
58         unsigned long addr;
59         size_t sz;
60 #endif
61 #if DRM_DEBUG_MEMORY
62         int area = DRM_MEM_DMA;
63
64         spin_lock(&drm_mem_lock);
65         if ((drm_ram_used >> PAGE_SHIFT)
66             > (DRM_RAM_PERCENT * drm_ram_available) / 100) {
67                 spin_unlock(&drm_mem_lock);
68                 return 0;
69         }
70         spin_unlock(&drm_mem_lock);
71 #endif
72
73         /* pci_alloc_consistent only guarantees alignment to the smallest 
74          * PAGE_SIZE order which is greater than or equal to the requested size.
75          * Return NULL here for now to make sure nobody tries for larger alignment
76          */
77         if (align > size)
78                 return NULL;
79
80         if (pci_set_dma_mask( dev->pdev, maxaddr ) != 0) {
81                 DRM_ERROR( "Setting pci dma mask failed\n" );
82                 return NULL;
83         }
84
85         address = pci_alloc_consistent( dev->pdev, size, busaddr );
86
87 #if DRM_DEBUG_MEMORY
88         if (address == NULL) {
89                 spin_lock(&drm_mem_lock);
90                 ++drm_mem_stats[area].fail_count;
91                 spin_unlock(&drm_mem_lock);
92                 return NULL;
93         }
94
95         spin_lock(&drm_mem_lock);
96         ++drm_mem_stats[area].succeed_count;
97         drm_mem_stats[area].bytes_allocated += size;
98         drm_ram_used                         += size;
99         spin_unlock(&drm_mem_lock);
100 #else
101         if (address == NULL)
102                 return NULL;
103 #endif
104
105         memset(address, 0, size);
106
107 #if 0
108         /* XXX - Is virt_to_page() legal for consistent mem? */
109                                 /* Reserve */
110         for (addr = (unsigned long)address, sz = size;
111              sz > 0;
112              addr += PAGE_SIZE, sz -= PAGE_SIZE) {
113                 SetPageReserved(virt_to_page(addr));
114         }
115 #endif
116
117         return address;
118 }
119 EXPORT_SYMBOL(drm_pci_alloc);
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 EXPORT_SYMBOL(drm_pci_free);
170
171 /*@}*/