v2.4.9.9 -> v2.4.9.10
[opensuse:kernel.git] / drivers / char / drm / ati_pcigart.h
1 /* ati_pcigart.h -- ATI PCI GART support -*- linux-c -*-
2  * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com
3  *
4  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Authors:
27  *   Gareth Hughes <gareth@valinux.com>
28  */
29
30 #define __NO_VERSION__
31 #include "drmP.h"
32
33 #if PAGE_SIZE == 8192
34 # define ATI_PCIGART_TABLE_ORDER        2
35 # define ATI_PCIGART_TABLE_PAGES        (1 << 2)
36 #elif PAGE_SIZE == 4096
37 # define ATI_PCIGART_TABLE_ORDER        3
38 # define ATI_PCIGART_TABLE_PAGES        (1 << 3)
39 #elif
40 # error - PAGE_SIZE not 8K or 4K
41 #endif
42
43 # define ATI_MAX_PCIGART_PAGES          8192    /* 32 MB aperture, 4K pages */
44 # define ATI_PCIGART_PAGE_SIZE          4096    /* PCI GART page size */
45
46 static unsigned long DRM(ati_alloc_pcigart_table)( void )
47 {
48         unsigned long address;
49         struct page *page;
50         int i;
51         DRM_DEBUG( "%s\n", __FUNCTION__ );
52
53         address = __get_free_pages( GFP_KERNEL, ATI_PCIGART_TABLE_ORDER );
54         if ( address == 0UL ) {
55                 return 0;
56         }
57
58         page = virt_to_page( address );
59
60         for ( i = 0 ; i <= ATI_PCIGART_TABLE_PAGES ; i++, page++ ) {
61                 atomic_inc( &page->count );
62                 SetPageReserved( page );
63         }
64
65         DRM_DEBUG( "%s: returning 0x%08lx\n", __FUNCTION__, address );
66         return address;
67 }
68
69 static void DRM(ati_free_pcigart_table)( unsigned long address )
70 {
71         struct page *page;
72         int i;
73         DRM_DEBUG( "%s\n", __FUNCTION__ );
74
75         page = virt_to_page( address );
76
77         for ( i = 0 ; i <= ATI_PCIGART_TABLE_PAGES ; i++, page++ ) {
78                 atomic_dec( &page->count );
79                 ClearPageReserved( page );
80         }
81
82         free_pages( address, ATI_PCIGART_TABLE_ORDER );
83 }
84
85 int DRM(ati_pcigart_init)( drm_device_t *dev,
86                            unsigned long *addr,
87                            dma_addr_t *bus_addr)
88 {
89         drm_sg_mem_t *entry = dev->sg;
90         unsigned long address = 0;
91         unsigned long pages;
92         u32 *pci_gart, page_base, bus_address = 0;
93         int i, j, ret = 0;
94
95         if ( !entry ) {
96                 DRM_ERROR( "no scatter/gather memory!\n" );
97                 goto done;
98         }
99
100         address = DRM(ati_alloc_pcigart_table)();
101         if ( !address ) {
102                 DRM_ERROR( "cannot allocate PCI GART page!\n" );
103                 goto done;
104         }
105
106         if ( !dev->pdev ) {
107                 DRM_ERROR( "PCI device unknown!\n" );
108                 goto done;
109         }
110
111         bus_address = pci_map_single(dev->pdev, (void *)address,
112                                   ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
113                                   PCI_DMA_TODEVICE);
114         if (bus_address == 0) {
115                 DRM_ERROR( "unable to map PCIGART pages!\n" );
116                 DRM(ati_free_pcigart_table)( address );
117                 address = 0;
118                 goto done;
119         }
120
121         pci_gart = (u32 *)address;
122
123         pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES )
124                 ? entry->pages : ATI_MAX_PCIGART_PAGES;
125
126         memset( pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32) );
127
128         for ( i = 0 ; i < pages ; i++ ) {
129                 /* we need to support large memory configurations */
130                 entry->busaddr[i] = pci_map_single(dev->pdev,
131                                            page_address( entry->pagelist[i] ),
132                                            PAGE_SIZE,
133                                            PCI_DMA_TODEVICE);
134                 if (entry->busaddr[i] == 0) {
135                         DRM_ERROR( "unable to map PCIGART pages!\n" );
136                         DRM(ati_pcigart_cleanup)( dev, address, bus_address );
137                         address = 0;
138                         bus_address = 0;
139                         goto done;
140                 }
141                 page_base = (u32) entry->busaddr[i];
142
143                 for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
144                         *pci_gart++ = cpu_to_le32( page_base );
145                         page_base += ATI_PCIGART_PAGE_SIZE;
146                 }
147         }
148
149         ret = 1;
150
151 #if defined(__i386__) || defined(__x86_64__)
152         asm volatile ( "wbinvd" ::: "memory" );
153 #else
154         mb();
155 #endif
156
157 done:
158         *addr = address;
159         *bus_addr = bus_address;
160         return ret;
161 }
162
163 int DRM(ati_pcigart_cleanup)( drm_device_t *dev,
164                               unsigned long addr,
165                               dma_addr_t bus_addr)
166 {
167         drm_sg_mem_t *entry = dev->sg;
168         unsigned long pages;
169         int i;
170
171         /* we need to support large memory configurations */
172         if ( !entry ) {
173                 DRM_ERROR( "no scatter/gather memory!\n" );
174                 return 0;
175         }
176
177         if ( bus_addr ) {
178                 pci_unmap_single(dev->pdev, bus_addr,
179                                  ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
180                                  PCI_DMA_TODEVICE);
181
182                 pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES )
183                         ? entry->pages : ATI_MAX_PCIGART_PAGES;
184
185                 for ( i = 0 ; i < pages ; i++ ) {
186                         if ( !entry->busaddr[i] ) break;
187                         pci_unmap_single(dev->pdev, entry->busaddr[i],
188                                          PAGE_SIZE, PCI_DMA_TODEVICE);
189                 }
190         }
191
192         if ( addr ) {
193                 DRM(ati_free_pcigart_table)( addr );
194         }
195
196         return 1;
197 }