diff options
Diffstat (limited to 'drivers/char/drm/ati_pcigart.c')
-rw-r--r-- | drivers/char/drm/ati_pcigart.c | 84 |
1 files changed, 45 insertions, 39 deletions
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index bd7be09ea53d..5b91bc04ea4e 100644 --- a/drivers/char/drm/ati_pcigart.c +++ b/drivers/char/drm/ati_pcigart.c | |||
@@ -33,59 +33,44 @@ | |||
33 | 33 | ||
34 | #include "drmP.h" | 34 | #include "drmP.h" |
35 | 35 | ||
36 | #if PAGE_SIZE == 65536 | ||
37 | # define ATI_PCIGART_TABLE_ORDER 0 | ||
38 | # define ATI_PCIGART_TABLE_PAGES (1 << 0) | ||
39 | #elif PAGE_SIZE == 16384 | ||
40 | # define ATI_PCIGART_TABLE_ORDER 1 | ||
41 | # define ATI_PCIGART_TABLE_PAGES (1 << 1) | ||
42 | #elif PAGE_SIZE == 8192 | ||
43 | # define ATI_PCIGART_TABLE_ORDER 2 | ||
44 | # define ATI_PCIGART_TABLE_PAGES (1 << 2) | ||
45 | #elif PAGE_SIZE == 4096 | ||
46 | # define ATI_PCIGART_TABLE_ORDER 3 | ||
47 | # define ATI_PCIGART_TABLE_PAGES (1 << 3) | ||
48 | #else | ||
49 | # error - PAGE_SIZE not 64K, 16K, 8K or 4K | ||
50 | #endif | ||
51 | |||
52 | # define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */ | ||
53 | # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ | 36 | # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ |
54 | 37 | ||
55 | static void *drm_ati_alloc_pcigart_table(void) | 38 | static void *drm_ati_alloc_pcigart_table(int order) |
56 | { | 39 | { |
57 | unsigned long address; | 40 | unsigned long address; |
58 | struct page *page; | 41 | struct page *page; |
59 | int i; | 42 | int i; |
60 | DRM_DEBUG("%s\n", __FUNCTION__); | 43 | |
44 | DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order); | ||
61 | 45 | ||
62 | address = __get_free_pages(GFP_KERNEL | __GFP_COMP, | 46 | address = __get_free_pages(GFP_KERNEL | __GFP_COMP, |
63 | ATI_PCIGART_TABLE_ORDER); | 47 | order); |
64 | if (address == 0UL) { | 48 | if (address == 0UL) { |
65 | return NULL; | 49 | return NULL; |
66 | } | 50 | } |
67 | 51 | ||
68 | page = virt_to_page(address); | 52 | page = virt_to_page(address); |
69 | 53 | ||
70 | for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) | 54 | for (i = 0; i < order; i++, page++) |
71 | SetPageReserved(page); | 55 | SetPageReserved(page); |
72 | 56 | ||
73 | DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address); | 57 | DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address); |
74 | return (void *)address; | 58 | return (void *)address; |
75 | } | 59 | } |
76 | 60 | ||
77 | static void drm_ati_free_pcigart_table(void *address) | 61 | static void drm_ati_free_pcigart_table(void *address, int order) |
78 | { | 62 | { |
79 | struct page *page; | 63 | struct page *page; |
80 | int i; | 64 | int i; |
65 | int num_pages = 1 << order; | ||
81 | DRM_DEBUG("%s\n", __FUNCTION__); | 66 | DRM_DEBUG("%s\n", __FUNCTION__); |
82 | 67 | ||
83 | page = virt_to_page((unsigned long)address); | 68 | page = virt_to_page((unsigned long)address); |
84 | 69 | ||
85 | for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) | 70 | for (i = 0; i < num_pages; i++, page++) |
86 | ClearPageReserved(page); | 71 | ClearPageReserved(page); |
87 | 72 | ||
88 | free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER); | 73 | free_pages((unsigned long)address, order); |
89 | } | 74 | } |
90 | 75 | ||
91 | int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | 76 | int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) |
@@ -93,6 +78,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | |||
93 | drm_sg_mem_t *entry = dev->sg; | 78 | drm_sg_mem_t *entry = dev->sg; |
94 | unsigned long pages; | 79 | unsigned long pages; |
95 | int i; | 80 | int i; |
81 | int order; | ||
82 | int num_pages, max_pages; | ||
96 | 83 | ||
97 | /* we need to support large memory configurations */ | 84 | /* we need to support large memory configurations */ |
98 | if (!entry) { | 85 | if (!entry) { |
@@ -100,15 +87,19 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | |||
100 | return 0; | 87 | return 0; |
101 | } | 88 | } |
102 | 89 | ||
90 | order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE); | ||
91 | num_pages = 1 << order; | ||
92 | |||
103 | if (gart_info->bus_addr) { | 93 | if (gart_info->bus_addr) { |
104 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { | 94 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { |
105 | pci_unmap_single(dev->pdev, gart_info->bus_addr, | 95 | pci_unmap_single(dev->pdev, gart_info->bus_addr, |
106 | ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, | 96 | num_pages * PAGE_SIZE, |
107 | PCI_DMA_TODEVICE); | 97 | PCI_DMA_TODEVICE); |
108 | } | 98 | } |
109 | 99 | ||
110 | pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) | 100 | max_pages = (gart_info->table_size / sizeof(u32)); |
111 | ? entry->pages : ATI_MAX_PCIGART_PAGES; | 101 | pages = (entry->pages <= max_pages) |
102 | ? entry->pages : max_pages; | ||
112 | 103 | ||
113 | for (i = 0; i < pages; i++) { | 104 | for (i = 0; i < pages; i++) { |
114 | if (!entry->busaddr[i]) | 105 | if (!entry->busaddr[i]) |
@@ -123,13 +114,12 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | |||
123 | 114 | ||
124 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN | 115 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN |
125 | && gart_info->addr) { | 116 | && gart_info->addr) { |
126 | drm_ati_free_pcigart_table(gart_info->addr); | 117 | drm_ati_free_pcigart_table(gart_info->addr, order); |
127 | gart_info->addr = NULL; | 118 | gart_info->addr = NULL; |
128 | } | 119 | } |
129 | 120 | ||
130 | return 1; | 121 | return 1; |
131 | } | 122 | } |
132 | |||
133 | EXPORT_SYMBOL(drm_ati_pcigart_cleanup); | 123 | EXPORT_SYMBOL(drm_ati_pcigart_cleanup); |
134 | 124 | ||
135 | int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | 125 | int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) |
@@ -139,6 +129,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | |||
139 | unsigned long pages; | 129 | unsigned long pages; |
140 | u32 *pci_gart, page_base, bus_address = 0; | 130 | u32 *pci_gart, page_base, bus_address = 0; |
141 | int i, j, ret = 0; | 131 | int i, j, ret = 0; |
132 | int order; | ||
133 | int max_pages; | ||
134 | int num_pages; | ||
142 | 135 | ||
143 | if (!entry) { | 136 | if (!entry) { |
144 | DRM_ERROR("no scatter/gather memory!\n"); | 137 | DRM_ERROR("no scatter/gather memory!\n"); |
@@ -148,7 +141,10 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | |||
148 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { | 141 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { |
149 | DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); | 142 | DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); |
150 | 143 | ||
151 | address = drm_ati_alloc_pcigart_table(); | 144 | order = drm_order((gart_info->table_size + |
145 | (PAGE_SIZE-1)) / PAGE_SIZE); | ||
146 | num_pages = 1 << order; | ||
147 | address = drm_ati_alloc_pcigart_table(order); | ||
152 | if (!address) { | 148 | if (!address) { |
153 | DRM_ERROR("cannot allocate PCI GART page!\n"); | 149 | DRM_ERROR("cannot allocate PCI GART page!\n"); |
154 | goto done; | 150 | goto done; |
@@ -160,11 +156,13 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | |||
160 | } | 156 | } |
161 | 157 | ||
162 | bus_address = pci_map_single(dev->pdev, address, | 158 | bus_address = pci_map_single(dev->pdev, address, |
163 | ATI_PCIGART_TABLE_PAGES * | 159 | num_pages * PAGE_SIZE, |
164 | PAGE_SIZE, PCI_DMA_TODEVICE); | 160 | PCI_DMA_TODEVICE); |
165 | if (bus_address == 0) { | 161 | if (bus_address == 0) { |
166 | DRM_ERROR("unable to map PCIGART pages!\n"); | 162 | DRM_ERROR("unable to map PCIGART pages!\n"); |
167 | drm_ati_free_pcigart_table(address); | 163 | order = drm_order((gart_info->table_size + |
164 | (PAGE_SIZE-1)) / PAGE_SIZE); | ||
165 | drm_ati_free_pcigart_table(address, order); | ||
168 | address = NULL; | 166 | address = NULL; |
169 | goto done; | 167 | goto done; |
170 | } | 168 | } |
@@ -177,10 +175,11 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | |||
177 | 175 | ||
178 | pci_gart = (u32 *) address; | 176 | pci_gart = (u32 *) address; |
179 | 177 | ||
180 | pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) | 178 | max_pages = (gart_info->table_size / sizeof(u32)); |
181 | ? entry->pages : ATI_MAX_PCIGART_PAGES; | 179 | pages = (entry->pages <= max_pages) |
180 | ? entry->pages : max_pages; | ||
182 | 181 | ||
183 | memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32)); | 182 | memset(pci_gart, 0, max_pages * sizeof(u32)); |
184 | 183 | ||
185 | for (i = 0; i < pages; i++) { | 184 | for (i = 0; i < pages; i++) { |
186 | /* we need to support large memory configurations */ | 185 | /* we need to support large memory configurations */ |
@@ -198,10 +197,18 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | |||
198 | page_base = (u32) entry->busaddr[i]; | 197 | page_base = (u32) entry->busaddr[i]; |
199 | 198 | ||
200 | for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { | 199 | for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { |
201 | if (gart_info->is_pcie) | 200 | switch(gart_info->gart_reg_if) { |
201 | case DRM_ATI_GART_IGP: | ||
202 | *pci_gart = cpu_to_le32((page_base) | 0xc); | ||
203 | break; | ||
204 | case DRM_ATI_GART_PCIE: | ||
202 | *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); | 205 | *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); |
203 | else | 206 | break; |
207 | default: | ||
208 | case DRM_ATI_GART_PCI: | ||
204 | *pci_gart = cpu_to_le32(page_base); | 209 | *pci_gart = cpu_to_le32(page_base); |
210 | break; | ||
211 | } | ||
205 | pci_gart++; | 212 | pci_gart++; |
206 | page_base += ATI_PCIGART_PAGE_SIZE; | 213 | page_base += ATI_PCIGART_PAGE_SIZE; |
207 | } | 214 | } |
@@ -220,5 +227,4 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) | |||
220 | gart_info->bus_addr = bus_address; | 227 | gart_info->bus_addr = bus_address; |
221 | return ret; | 228 | return ret; |
222 | } | 229 | } |
223 | |||
224 | EXPORT_SYMBOL(drm_ati_pcigart_init); | 230 | EXPORT_SYMBOL(drm_ati_pcigart_init); |