aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/agp/intel-agp.c174
1 files changed, 162 insertions, 12 deletions
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 21983456d672..20fe82b99fdb 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -10,6 +10,16 @@
10#include <linux/agp_backend.h> 10#include <linux/agp_backend.h>
11#include "agp.h" 11#include "agp.h"
12 12
13/*
14 * If we have Intel graphics, we're not going to have anything other than
15 * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
16 * on the Intel IOMMU support (CONFIG_DMAR).
17 * Only newer chipsets need to bother with this, of course.
18 */
19#ifdef CONFIG_DMAR
20#define USE_PCI_DMA_API 1
21#endif
22
13#define PCI_DEVICE_ID_INTEL_E7221_HB 0x2588 23#define PCI_DEVICE_ID_INTEL_E7221_HB 0x2588
14#define PCI_DEVICE_ID_INTEL_E7221_IG 0x258a 24#define PCI_DEVICE_ID_INTEL_E7221_IG 0x258a
15#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970 25#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970
@@ -170,6 +180,131 @@ static struct _intel_private {
170 int resource_valid; 180 int resource_valid;
171} intel_private; 181} intel_private;
172 182
183#ifdef USE_PCI_DMA_API
184static int intel_agp_map_page(void *addr, dma_addr_t *ret)
185{
186 *ret = pci_map_single(intel_private.pcidev, addr,
187 PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
188 if (pci_dma_mapping_error(intel_private.pcidev, *ret))
189 return -EINVAL;
190 return 0;
191}
192
193static void intel_agp_unmap_page(void *addr, dma_addr_t dma)
194{
195 pci_unmap_single(intel_private.pcidev, dma,
196 PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
197}
198
199static int intel_agp_map_memory(struct agp_memory *mem)
200{
201 struct scatterlist *sg;
202 int i;
203
204 DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
205
206 if ((mem->page_count * sizeof(*mem->sg_list)) < 2*PAGE_SIZE)
207 mem->sg_list = kcalloc(mem->page_count, sizeof(*mem->sg_list),
208 GFP_KERNEL);
209
210 if (mem->sg_list == NULL) {
211 mem->sg_list = vmalloc(mem->page_count * sizeof(*mem->sg_list));
212 mem->sg_vmalloc_flag = 1;
213 }
214
215 if (!mem->sg_list) {
216 mem->sg_vmalloc_flag = 0;
217 return -ENOMEM;
218 }
219 sg_init_table(mem->sg_list, mem->page_count);
220
221 sg = mem->sg_list;
222 for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
223 sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
224
225 mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
226 mem->page_count, PCI_DMA_BIDIRECTIONAL);
227 if (!mem->num_sg) {
228 if (mem->sg_vmalloc_flag)
229 vfree(mem->sg_list);
230 else
231 kfree(mem->sg_list);
232 mem->sg_list = NULL;
233 mem->sg_vmalloc_flag = 0;
234 return -ENOMEM;
235 }
236 return 0;
237}
238
239static void intel_agp_unmap_memory(struct agp_memory *mem)
240{
241 DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
242
243 pci_unmap_sg(intel_private.pcidev, mem->sg_list,
244 mem->page_count, PCI_DMA_BIDIRECTIONAL);
245 if (mem->sg_vmalloc_flag)
246 vfree(mem->sg_list);
247 else
248 kfree(mem->sg_list);
249 mem->sg_vmalloc_flag = 0;
250 mem->sg_list = NULL;
251 mem->num_sg = 0;
252}
253
254static void intel_agp_insert_sg_entries(struct agp_memory *mem,
255 off_t pg_start, int mask_type)
256{
257 struct scatterlist *sg;
258 int i, j;
259
260 j = pg_start;
261
262 WARN_ON(!mem->num_sg);
263
264 if (mem->num_sg == mem->page_count) {
265 for_each_sg(mem->sg_list, sg, mem->page_count, i) {
266 writel(agp_bridge->driver->mask_memory(agp_bridge,
267 sg_dma_address(sg), mask_type),
268 intel_private.gtt+j);
269 j++;
270 }
271 } else {
272 /* sg may merge pages, but we have to seperate
273 * per-page addr for GTT */
274 unsigned int len, m;
275
276 for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
277 len = sg_dma_len(sg) / PAGE_SIZE;
278 for (m = 0; m < len; m++) {
279 writel(agp_bridge->driver->mask_memory(agp_bridge,
280 sg_dma_address(sg) + m * PAGE_SIZE,
281 mask_type),
282 intel_private.gtt+j);
283 j++;
284 }
285 }
286 }
287 readl(intel_private.gtt+j-1);
288}
289
290#else
291
292static void intel_agp_insert_sg_entries(struct agp_memory *mem,
293 off_t pg_start, int mask_type)
294{
295 int i, j;
296
297 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
298 writel(agp_bridge->driver->mask_memory(agp_bridge,
299 phys_to_gart(page_to_phys(mem->pages[i])), mask_type),
300 intel_private.gtt+j);
301 }
302
303 readl(intel_private.gtt+j-1);
304}
305
306#endif
307
173static int intel_i810_fetch_size(void) 308static int intel_i810_fetch_size(void)
174{ 309{
175 u32 smram_miscc; 310 u32 smram_miscc;
@@ -1003,9 +1138,13 @@ static int intel_i915_configure(void)
1003 writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); 1138 writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
1004 readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ 1139 readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
1005 1140
1141#ifndef USE_PCI_DMA_API
1142 agp_bridge->scratch_page_dma = agp_bridge->scratch_page;
1143#endif
1144
1006 if (agp_bridge->driver->needs_scratch_page) { 1145 if (agp_bridge->driver->needs_scratch_page) {
1007 for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) { 1146 for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
1008 writel(agp_bridge->scratch_page, intel_private.gtt+i); 1147 writel(agp_bridge->scratch_page_dma, intel_private.gtt+i);
1009 } 1148 }
1010 readl(intel_private.gtt+i-1); /* PCI Posting. */ 1149 readl(intel_private.gtt+i-1); /* PCI Posting. */
1011 } 1150 }
@@ -1038,7 +1177,7 @@ static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
1038static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, 1177static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
1039 int type) 1178 int type)
1040{ 1179{
1041 int i, j, num_entries; 1180 int num_entries;
1042 void *temp; 1181 void *temp;
1043 int ret = -EINVAL; 1182 int ret = -EINVAL;
1044 int mask_type; 1183 int mask_type;
@@ -1062,7 +1201,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
1062 if ((pg_start + mem->page_count) > num_entries) 1201 if ((pg_start + mem->page_count) > num_entries)
1063 goto out_err; 1202 goto out_err;
1064 1203
1065 /* The i915 can't check the GTT for entries since its read only, 1204 /* The i915 can't check the GTT for entries since it's read only;
1066 * depend on the caller to make the correct offset decisions. 1205 * depend on the caller to make the correct offset decisions.
1067 */ 1206 */
1068 1207
@@ -1078,14 +1217,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
1078 if (!mem->is_flushed) 1217 if (!mem->is_flushed)
1079 global_cache_flush(); 1218 global_cache_flush();
1080 1219
1081 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 1220 intel_agp_insert_sg_entries(mem, pg_start, mask_type);
1082 writel(agp_bridge->driver->mask_memory(agp_bridge,
1083 phys_to_gart(page_to_phys(mem->pages[i])),
1084 mask_type),
1085 intel_private.gtt+j);
1086 }
1087
1088 readl(intel_private.gtt+j-1);
1089 agp_bridge->driver->tlb_flush(mem); 1221 agp_bridge->driver->tlb_flush(mem);
1090 1222
1091 out: 1223 out:
@@ -1110,7 +1242,7 @@ static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
1110 } 1242 }
1111 1243
1112 for (i = pg_start; i < (mem->page_count + pg_start); i++) 1244 for (i = pg_start; i < (mem->page_count + pg_start); i++)
1113 writel(agp_bridge->scratch_page, intel_private.gtt+i); 1245 writel(agp_bridge->scratch_page_dma, intel_private.gtt+i);
1114 1246
1115 readl(intel_private.gtt+i-1); 1247 readl(intel_private.gtt+i-1);
1116 1248
@@ -2003,6 +2135,12 @@ static const struct agp_bridge_driver intel_915_driver = {
2003 .agp_destroy_pages = agp_generic_destroy_pages, 2135 .agp_destroy_pages = agp_generic_destroy_pages,
2004 .agp_type_to_mask_type = intel_i830_type_to_mask_type, 2136 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
2005 .chipset_flush = intel_i915_chipset_flush, 2137 .chipset_flush = intel_i915_chipset_flush,
2138#ifdef USE_PCI_DMA_API
2139 .agp_map_page = intel_agp_map_page,
2140 .agp_unmap_page = intel_agp_unmap_page,
2141 .agp_map_memory = intel_agp_map_memory,
2142 .agp_unmap_memory = intel_agp_unmap_memory,
2143#endif
2006}; 2144};
2007 2145
2008static const struct agp_bridge_driver intel_i965_driver = { 2146static const struct agp_bridge_driver intel_i965_driver = {
@@ -2031,6 +2169,12 @@ static const struct agp_bridge_driver intel_i965_driver = {
2031 .agp_destroy_pages = agp_generic_destroy_pages, 2169 .agp_destroy_pages = agp_generic_destroy_pages,
2032 .agp_type_to_mask_type = intel_i830_type_to_mask_type, 2170 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
2033 .chipset_flush = intel_i915_chipset_flush, 2171 .chipset_flush = intel_i915_chipset_flush,
2172#ifdef USE_PCI_DMA_API
2173 .agp_map_page = intel_agp_map_page,
2174 .agp_unmap_page = intel_agp_unmap_page,
2175 .agp_map_memory = intel_agp_map_memory,
2176 .agp_unmap_memory = intel_agp_unmap_memory,
2177#endif
2034}; 2178};
2035 2179
2036static const struct agp_bridge_driver intel_7505_driver = { 2180static const struct agp_bridge_driver intel_7505_driver = {
@@ -2085,6 +2229,12 @@ static const struct agp_bridge_driver intel_g33_driver = {
2085 .agp_destroy_pages = agp_generic_destroy_pages, 2229 .agp_destroy_pages = agp_generic_destroy_pages,
2086 .agp_type_to_mask_type = intel_i830_type_to_mask_type, 2230 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
2087 .chipset_flush = intel_i915_chipset_flush, 2231 .chipset_flush = intel_i915_chipset_flush,
2232#ifdef USE_PCI_DMA_API
2233 .agp_map_page = intel_agp_map_page,
2234 .agp_unmap_page = intel_agp_unmap_page,
2235 .agp_map_memory = intel_agp_map_memory,
2236 .agp_unmap_memory = intel_agp_unmap_memory,
2237#endif
2088}; 2238};
2089 2239
2090static int find_gmch(u16 device) 2240static int find_gmch(u16 device)