v2.4.8 -> v2.4.8.1
[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         if ( !address ) return;
76
77         page = virt_to_page( address );
78
79         for ( i = 0 ; i <= ATI_PCIGART_TABLE_PAGES ; i++, page++ ) {
80                 atomic_dec( &page->count );
81                 ClearPageReserved( page );
82         }
83
84         free_pages( address, ATI_PCIGART_TABLE_ORDER );
85 }
86
87 unsigned long DRM(ati_pcigart_init)( drm_device_t *dev )
88 {
89         drm_sg_mem_t *entry = dev->sg;
90         unsigned long address;
91         unsigned long pages;
92         u32 *pci_gart, page_base;
93         int i, j;
94
95         if ( !entry ) {
96                 DRM_ERROR( "no scatter/gather memory!\n" );
97                 return 0;
98         }
99
100         address = DRM(ati_alloc_pcigart_table)();
101         if ( !address ) {
102                 DRM_ERROR( "cannot allocate PCI GART page!\n" );
103                 return 0;
104         }
105
106         pci_gart = (u32 *)address;
107
108         pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES )
109                 ? entry->pages : ATI_MAX_PCIGART_PAGES;
110
111         memset( pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32) );
112
113         for ( i = 0 ; i < pages ; i++ ) {
114                 page_base = page_to_bus( entry->pagelist[i] );
115                 for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
116                         *pci_gart++ = cpu_to_le32( page_base );
117                         page_base += ATI_PCIGART_PAGE_SIZE;
118                 }
119         }
120
121 #if __i386__
122         asm volatile ( "wbinvd" ::: "memory" );
123 #else
124         mb();
125 #endif
126
127         return address;
128 }
129
130 int DRM(ati_pcigart_cleanup)( unsigned long address )
131 {
132
133         if ( address ) {
134                 DRM(ati_free_pcigart_table)( address );
135         }
136
137         return 0;
138 }