aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/agp
diff options
context:
space:
mode:
authorZhenyu Wang <zhenyu.z.wang@intel.com>2009-07-27 07:59:57 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-08-03 04:04:50 -0400
commit176616814d700f19914d8509d9f65dec51a6ebf7 (patch)
tree535417a2e6ce311d7016ca15c303e4ded40f6852 /drivers/char/agp
parentff663cf8705bea101d5f73cf471855c85242575e (diff)
intel_agp: Use PCI DMA API correctly on chipsets new enough to have IOMMU
When graphics dma remapping engine is active, we must fill gart table with dma address from dmar engine, as now graphics device access to graphics memory must go through dma remapping table to get real physical address. Add this support to all drivers which use intel_i915_insert_entries() Signed-off-by: Zhenyu Wang <zhenyu.z.wang@intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/char/agp')
-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)