[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20071218051302.GD12564@zhen-devel.sh.intel.com>
Date: Tue, 18 Dec 2007 13:13:02 +0800
From: Zhenyu Wang <zhenyu.z.wang@...el.com>
To: Dave Airlie <airlied@...ux.ie>
Cc: LKML <linux-kernel@...r.kernel.org>,
Keith Packard <keithp@...thp.com>,
Eric Anholt <eric@...olt.net>,
"Gross, Mark" <mark.gross@...el.com>
Subject: [RFC][PATCH 3/4][AGP] intel_agp: add support for graphics dma remapping on G33
[PATCH] [AGP] intel_agp: add support for graphics dma remapping on G33
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 support on G33 chipset, which has graphics device specific
dmar engine avaiable.
Signed-off-by: Zhenyu Wang <zhenyu.z.wang@...el.com>
---
drivers/char/agp/Kconfig | 12 +++-
drivers/char/agp/intel-agp.c | 134 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 141 insertions(+), 5 deletions(-)
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index ccb1fa8..e60c2b0 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -74,8 +74,16 @@ config AGP_INTEL
on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875,
E7205 and E7505 chipsets and full support for the 810, 815, 830M,
845G, 852GM, 855GM, 865G and I915 integrated graphics chipsets.
-
-
+
+config AGP_INTEL_DMAR
+ bool
+ depends on AGP_INTEL && DMAR && !DMAR_GFX_WA
+ default y
+ help
+ This option will enable graphics address remapping with Intel
+ DMAR engine aka VT-d if you don't select graphics workaround on
+ Intel DMAR. The graphics address filled to gart table will be
+ changed by remapping within graphics DMAR engine for domain.
config AGP_NVIDIA
tristate "NVIDIA nForce/nForce2 chipset support"
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index d879619..7424667 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -9,6 +9,9 @@
#include <linux/pagemap.h>
#include <linux/agp_backend.h>
#include "agp.h"
+#ifdef CONFIG_AGP_INTEL_DMAR
+#include <linux/dmar.h>
+#endif
#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970
#define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972
@@ -115,6 +118,97 @@ static struct _intel_private {
int gtt_entries; /* i830+ */
} intel_private;
+static int intel_agp_require_remapping(void)
+{
+#ifdef CONFIG_AGP_INTEL_DMAR
+ return intel_iommu_gfx_remapping();
+#else
+ return 0;
+#endif
+}
+
+#ifdef CONFIG_AGP_INTEL_DMAR
+static int intel_agp_map_pages(struct agp_memory *mem, void *virt, dma_addr_t *ret, int is_single)
+{
+ int i;
+ struct scatterlist *sg;
+
+ if (is_single) {
+ *ret = pci_map_single(intel_private.pcidev, virt, PAGE_SIZE,
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(*ret))
+ return -EINVAL;
+ return 0;
+ }
+
+ DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
+
+ if ((mem->page_count * sizeof(*mem->sg_list)) < 2*PAGE_SIZE)
+ mem->sg_list = kcalloc(mem->page_count, sizeof(*mem->sg_list), GFP_KERNEL);
+
+ if (mem->sg_list == NULL) {
+ mem->sg_list = vmalloc(mem->page_count * sizeof(*mem->sg_list));
+ mem->sg_vmalloc_flag = 1;
+ }
+
+ if (!mem->sg_list) {
+ mem->sg_vmalloc_flag = 0;
+ return -ENOMEM;
+ }
+ sg_init_table(mem->sg_list, mem->page_count);
+
+ sg = mem->sg_list;
+ for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
+ sg_set_buf(sg, gart_to_virt(mem->memory[i]), PAGE_SIZE);
+
+ mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
+ mem->page_count, PCI_DMA_BIDIRECTIONAL);
+ if (mem->num_sg == 0) {
+ if (mem->sg_vmalloc_flag)
+ vfree(mem->sg_list);
+ else
+ kfree(mem->sg_list);
+ mem->sg_list = NULL;
+ mem->sg_vmalloc_flag = 0;
+ return -ENOMEM;
+ }
+ mem->is_mapped = TRUE;
+ return 0;
+}
+
+static void intel_agp_unmap_pages(struct agp_memory *mem, dma_addr_t addr, int is_single)
+{
+ if (is_single) {
+ pci_unmap_single(intel_private.pcidev, addr, PAGE_SIZE,
+ PCI_DMA_BIDIRECTIONAL);
+ return;
+ }
+ DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
+
+ if (!mem->is_mapped)
+ return;
+
+ if (mem->num_sg)
+ pci_unmap_sg(intel_private.pcidev, mem->sg_list, mem->page_count,
+ PCI_DMA_BIDIRECTIONAL);
+ if (mem->sg_vmalloc_flag)
+ vfree(mem->sg_list);
+ else
+ kfree(mem->sg_list);
+ mem->sg_vmalloc_flag = 0;
+ mem->sg_list = NULL;
+ mem->num_sg = 0;
+}
+#else
+static int intel_agp_map_pages(struct agp_memory *mem, void *virt, dma_addr_t *ret, int is_single)
+{
+ return 0;
+}
+static void intel_agp_unmap_pages(struct agp_memory *mem, dma_addr_t addr, int is_single)
+{
+}
+#endif
+
static int intel_i810_fetch_size(void)
{
u32 smram_miscc;
@@ -847,9 +941,40 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
if (!mem->is_flushed)
global_cache_flush();
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mask_type), intel_private.gtt+j);
+ /* map mem if current graphics dmar engine is active
+ * and workaround is not applied. */
+ if (mem->is_mapped) {
+ struct scatterlist *sg;
+
+ j = pg_start;
+ if (mem->num_sg == mem->page_count) {
+ for_each_sg(mem->sg_list, sg, mem->page_count, i) {
+ writel(agp_bridge->driver->mask_memory(agp_bridge,
+ sg_dma_address(sg),
+ mask_type),
+ intel_private.gtt+j);
+ j++;
+ }
+ } else {
+ /* sg may merge pages, but we have to seperate
+ * per-page addr for GTT */
+ unsigned int len, m;
+ for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
+ len = sg_dma_len(sg) / PAGE_SIZE;
+ for (m = 0; m < len; m++) {
+ writel(agp_bridge->driver->mask_memory(agp_bridge,
+ sg_dma_address(sg) + m * PAGE_SIZE, mask_type),
+ intel_private.gtt+j);
+ j++;
+ }
+ }
+ }
+ } else {
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+ writel(agp_bridge->driver->mask_memory(agp_bridge,
+ mem->memory[i], mask_type),
+ intel_private.gtt+j);
+ }
}
readl(intel_private.gtt+j-1);
@@ -1796,6 +1921,9 @@ static const struct agp_bridge_driver intel_g33_driver = {
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
+ .agp_require_remapping = intel_agp_require_remapping,
+ .agp_map_page = intel_agp_map_pages,
+ .agp_unmap_page = intel_agp_unmap_pages,
};
static int find_gmch(u16 device)
--
1.5.3.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists