Module Name:    src
Committed By:   riastradh
Date:           Wed Mar  5 14:45:00 UTC 2014

Modified Files:
        src/sys/external/bsd/drm2/i915drm [riastradh-drm2]: i915_gem_gtt.c

Log Message:
First draft of i915_gem_gtt.c for pre-Sandy Bridge (gen<6) devices.

These go through the legacy AGP cruft to get at the GTT.


To generate a diff of this commit:
cvs rdiff -u -r1.1.2.8 -r1.1.2.9 \
    src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c
diff -u src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c:1.1.2.8 src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c:1.1.2.9
--- src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c:1.1.2.8	Wed Mar  5 08:45:06 2014
+++ src/sys/external/bsd/drm2/i915drm/i915_gem_gtt.c	Wed Mar  5 14:45:00 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: i915_gem_gtt.c,v 1.1.2.8 2014/03/05 08:45:06 aymeric Exp $	*/
+/*	$NetBSD: i915_gem_gtt.c,v 1.1.2.9 2014/03/05 14:45:00 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i915_gem_gtt.c,v 1.1.2.8 2014/03/05 08:45:06 aymeric Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i915_gem_gtt.c,v 1.1.2.9 2014/03/05 14:45:00 riastradh Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -40,181 +40,119 @@ __KERNEL_RCSID(0, "$NetBSD: i915_gem_gtt
 
 #include <dev/pci/pcivar.h>
 
+#include <dev/pci/agpvar.h>
+#include <dev/pci/agp_i810var.h>
+
 #include <drm/drmP.h>
 
 #include "i915_drv.h"
 
+static int	i915_gem_gtt_init_scratch_page(struct intel_gtt *,
+		    bus_dma_tag_t);
+static void	i915_gem_gtt_fini_scratch_page(struct intel_gtt *,
+		    bus_dma_tag_t);
+
 static void	i915_gtt_color_adjust(struct drm_mm_node *, unsigned long,
 		    unsigned long *, unsigned long *);
 static void	i915_ggtt_clear_range(struct drm_device *, unsigned, unsigned);
+
+static int	agp_gtt_init(struct drm_device *);
+static void	agp_gtt_fini(struct drm_device *);
+static void	agp_ggtt_bind_object(struct drm_i915_gem_object *,
+		    enum i915_cache_level);
+static void	agp_ggtt_clear_range(struct drm_device *, unsigned, unsigned);
+
+static int	gen6_gtt_init(struct drm_device *);
+static void	gen6_gtt_fini(struct drm_device *);
 static void	gen6_ggtt_bind_object(struct drm_i915_gem_object *,
 		    enum i915_cache_level);
 static void	gen6_ggtt_clear_range(struct drm_device *, unsigned, unsigned);
 
-#define	SNB_GMCH_GGMS	(SNB_GMCH_GGMS_MASK << SNB_GMCH_GGMS_SHIFT)
-#define	SNB_GMCH_GMS	(SNB_GMCH_GMS_MASK << SNB_GMCH_GMS_SHIFT)
-#define	IVB_GMCH_GMS	(IVB_GMCH_GMS_MASK << IVB_GMCH_GMS_SHIFT)
-
-typedef uint32_t gtt_pte_t;
-
-#define	GEN6_PTE_VALID		__BIT(0)
-#define	GEN6_PTE_UNCACHED	__BIT(1)
-#define	HSW_PTE_UNCACHED	(0)
-#define	GEN6_PTE_CACHE_LLC	__BIT(2)
-#define	GEN6_PTE_CACHE_LLC_MLC	__BIT(3)
-
-static uint32_t
-gen6_pte_addr_encode(bus_addr_t addr)
-{
-	KASSERT(addr <= __BITS(39, 0));
-	return (addr | ((addr >> 28) & 0xff0));
-}
-
-static gtt_pte_t
-pte_encode(struct drm_device *dev, bus_addr_t addr,
-    enum i915_cache_level level)
-{
-	uint32_t flags = GEN6_PTE_VALID;
-
-	switch (level) {
-	case I915_CACHE_LLC_MLC:
-		flags |= (IS_HASWELL(dev)? GEN6_PTE_CACHE_LLC
-		    : GEN6_PTE_CACHE_LLC_MLC);
-		break;
-
-	case I915_CACHE_LLC:
-		flags |= GEN6_PTE_CACHE_LLC;
-		break;
-
-	case I915_CACHE_NONE:
-		flags |= (IS_HASWELL(dev)? HSW_PTE_UNCACHED
-		    : GEN6_PTE_UNCACHED);
-		break;
-
-	default:
-		panic("invalid i915 GTT cache level: %d", (int)level);
-		break;
-	}
-
-	return (gen6_pte_addr_encode(addr) | flags);
-}
-
 int
 i915_gem_gtt_init(struct drm_device *dev)
 {
 	struct drm_i915_private *const dev_priv = dev->dev_private;
-	struct pci_attach_args *const pa = &dev->pdev->pd_pa;
 	struct intel_gtt *gtt;
-	uint16_t snb_gmch_ctl, ggms, gms;
-	int nsegs;
 	int ret;
 
-	if (INTEL_INFO(dev)->gen < 6) {
-		/* XXX gen<6 */
-		DRM_ERROR("device is too old for drm2 for now!\n");
-		return -ENODEV;
-	}
-
-	gtt = kmem_zalloc(sizeof(*gtt), KM_NOSLEEP);
-
-	/* XXX pci_set_dma_mask?  pci_set_consistent_dma_mask?  */
-	drm_limit_dma_space(dev, 0, 0x0000000fffffffffULL);
+	dev_priv->mm.gtt = gtt = kmem_zalloc(sizeof(*gtt), KM_SLEEP);
+	if (INTEL_INFO(dev)->gen < 6)
+		ret = agp_gtt_init(dev);
+	else
+		ret = gen6_gtt_init(dev);
+	if (ret)
+		goto fail0;
 
-	gtt->gma_bus_addr = dev->bus_maps[2].bm_base;
+	/* Success!  */
+	DRM_INFO("Memory usable by graphics device = %dM\n",
+	    gtt->gtt_total_entries >> 8);
+	DRM_DEBUG_DRIVER("GMADR size = %dM\n", gtt->gtt_mappable_entries >> 8);
+	DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", gtt->stolen_size >> 20);
+	return 0;
 
-	snb_gmch_ctl = pci_conf_read(pa->pa_pc, pa->pa_tag, SNB_GMCH_CTRL);
+fail1: __unused
+	if (INTEL_INFO(dev)->gen < 6)
+		agp_gtt_fini(dev);
+	else
+		gen6_gtt_fini(dev);
+fail0:	kmem_free(gtt, sizeof(*gtt));
+	return ret;
+}
 
-	/* GMS: Graphics Mode Select.  */
-	if (INTEL_INFO(dev)->gen < 7) {
-		gms = __SHIFTOUT(snb_gmch_ctl, SNB_GMCH_GMS);
-		gtt->stolen_size = (gms << 25);
-	} else {
-		gms = __SHIFTOUT(snb_gmch_ctl, IVB_GMCH_GMS);
-		static const unsigned sizes[] = {
-			0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352
-		};
-		gtt->stolen_size = sizes[gms] << 20;
-	}
+void
+i915_gem_gtt_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *const dev_priv = dev->dev_private;
 
-	/* GGMS: GTT Graphics Memory Size.  */
-	ggms = __SHIFTOUT(snb_gmch_ctl, SNB_GMCH_GGMS);
-	gtt->gtt_total_entries = (ggms << 20) / sizeof(gtt_pte_t);
+	if (INTEL_INFO(dev)->gen < 6)
+		agp_gtt_fini(dev);
+	else
+		gen6_gtt_fini(dev);
+	kmem_free(dev_priv->mm.gtt, sizeof(*dev_priv->mm.gtt));
+}
 
-	gtt->gtt_mappable_entries = (dev->bus_maps[2].bm_size >> PAGE_SHIFT);
-	if (((gtt->gtt_mappable_entries >> 8) < 64) ||
-	    (gtt->gtt_total_entries < gtt->gtt_mappable_entries)) {
-		DRM_ERROR("unknown GMADR entries: %d\n",
-		    gtt->gtt_mappable_entries);
-		ret = -ENXIO;
-		goto fail0;
-	}
+static int
+i915_gem_gtt_init_scratch_page(struct intel_gtt *gtt, bus_dma_tag_t dmat)
+{
+	int nsegs;
+	int ret;
 
 	/* XXX errno NetBSD->Linux */
-	ret = -bus_dmamem_alloc(dev->dmat, PAGE_SIZE, PAGE_SIZE, 0,
+	ret = -bus_dmamem_alloc(dmat, PAGE_SIZE, PAGE_SIZE, 0,
 	    &gtt->gtt_scratch_seg, 1, &nsegs, 0);
 	if (ret)
 		goto fail0;
 	KASSERT(nsegs == 1);
 
 	/* XXX errno NetBSD->Linux */
-	ret = -bus_dmamap_create(dev->dmat, PAGE_SIZE, 1, PAGE_SIZE, 0, 0,
+	ret = -bus_dmamap_create(dmat, PAGE_SIZE, 1, PAGE_SIZE, 0, 0,
 	    &gtt->gtt_scratch_map);
 	if (ret)
 		goto fail1;
 
 	/* XXX errno NetBSD->Linux */
-	ret = -bus_dmamap_load_raw(dev->dmat, gtt->gtt_scratch_map,
+	ret = -bus_dmamap_load_raw(dmat, gtt->gtt_scratch_map,
 	    &gtt->gtt_scratch_seg, 1, PAGE_SIZE, BUS_DMA_NOCACHE);
 	if (ret)
 		goto fail2;
 
-	/* Linux sez:  For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */
-	if (dev->bus_maps[0].bm_size < (gtt->gtt_total_entries *
-		sizeof(gtt_pte_t))) {
-		DRM_ERROR("BAR0 too small for GTT: 0x%"PRIxMAX" < 0x%"PRIxMAX
-		    "\n",
-		    dev->bus_maps[0].bm_size,
-		    (gtt->gtt_total_entries * sizeof(gtt_pte_t)));
-		ret = -ENODEV;
-		goto fail3;
-	}
-	if (bus_space_map(dev->bst, (dev->bus_maps[0].bm_base + (2<<20)),
-		(gtt->gtt_total_entries * sizeof(gtt_pte_t)),
-		0,
-		&gtt->gtt_bsh)) {
-		DRM_ERROR("unable to map GTT\n");
-		ret = -ENODEV;
-		goto fail3;
-	}
-
-	DRM_INFO("Memory usable by graphics device = %dM\n",
-	    gtt->gtt_total_entries >> 8);
-	DRM_DEBUG_DRIVER("GMADR size = %dM\n", gtt->gtt_mappable_entries >> 8);
-	DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", gtt->stolen_size >> 20);
-
 	/* Success!  */
-	dev_priv->mm.gtt = gtt;
 	return 0;
 
-fail3:	bus_dmamap_unload(dev->dmat, gtt->gtt_scratch_map);
-fail2:	bus_dmamap_destroy(dev->dmat, gtt->gtt_scratch_map);
-fail1:	bus_dmamem_free(dev->dmat, &gtt->gtt_scratch_seg, 1);
-fail0:	kmem_free(gtt, sizeof(*gtt));
-	return ret;
+fail3: __unused
+	bus_dmamap_unload(dmat, gtt->gtt_scratch_map);
+fail2:	bus_dmamap_destroy(dmat, gtt->gtt_scratch_map);
+fail1:	bus_dmamem_free(dmat, &gtt->gtt_scratch_seg, 1);
+fail0:	return ret;
 }
 
-void
-i915_gem_gtt_fini(struct drm_device *dev)
+static void
+i915_gem_gtt_fini_scratch_page(struct intel_gtt *gtt, bus_dma_tag_t dmat)
 {
-	struct drm_i915_private *const dev_priv = dev->dev_private;
-	struct intel_gtt *const gtt = dev_priv->mm.gtt;
 
-	bus_space_unmap(dev->bst, gtt->gtt_bsh,
-	    (gtt->gtt_total_entries * sizeof(gtt_pte_t)));
-	bus_dmamap_unload(dev->dmat, gtt->gtt_scratch_map);
-	bus_dmamap_destroy(dev->dmat, gtt->gtt_scratch_map);
-	bus_dmamem_free(dev->dmat, &gtt->gtt_scratch_seg, 1);
-	kmem_free(gtt, sizeof(*gtt));
+	bus_dmamap_unload(dmat, gtt->gtt_scratch_map);
+	bus_dmamap_destroy(dmat, gtt->gtt_scratch_map);
+	bus_dmamem_free(dmat, &gtt->gtt_scratch_seg, 1);
 }
 
 void
@@ -329,9 +267,12 @@ void
 i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
     enum i915_cache_level cache_level)
 {
+	struct drm_device *const dev = obj->base.dev;
 
-	KASSERT(6 < INTEL_INFO(obj->base.dev)->gen); /* XXX gen<6 */
-	gen6_ggtt_bind_object(obj, cache_level);
+	if (INTEL_INFO(dev)->gen < 6)
+		agp_ggtt_bind_object(obj, cache_level);
+	else
+		gen6_ggtt_bind_object(obj, cache_level);
 	obj->has_global_gtt_mapping = 1;
 }
 
@@ -345,17 +286,42 @@ i915_gem_gtt_unbind_object(struct drm_i9
 	obj->has_global_gtt_mapping = 0;
 }
 
+static bool
+i915_gem_gtt_idle(struct drm_device *dev)
+{
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	const bool interruptible = dev_priv->mm.interruptible;
+
+	if (__predict_false(dev_priv->mm.gtt->do_idle_maps)) {
+		dev_priv->mm.interruptible = false;
+		if (i915_gpu_idle(dev)) {
+			DRM_ERROR("unable to idle GPU\n");
+			/* XXX Cargo-culted from Linux.  */
+			udelay(10);
+		}
+	}
+
+	return interruptible;
+}
+
+static void
+i915_gem_gtt_unidle(struct drm_device *dev, bool interruptible)
+{
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+
+	dev_priv->mm.interruptible = interruptible;
+}
+
 void
 i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
 {
 	struct drm_device *const dev = obj->base.dev;
+	bool interruptible;
 
-	/* XXX Idle, for gen<6.  */
-
-	if (obj->has_dma_mapping)
-		return;
-
-	bus_dmamap_unload(dev->dmat, obj->igo_dmamap);
+	interruptible = i915_gem_gtt_idle(dev);
+	if (!obj->has_dma_mapping)
+		bus_dmamap_unload(dev->dmat, obj->igo_dmamap);
+	i915_gem_gtt_unidle(dev, interruptible);
 }
 
 void
@@ -380,9 +346,268 @@ i915_ggtt_clear_range(struct drm_device 
     unsigned npages)
 {
 
-	KASSERT(6 <= INTEL_INFO(dev)->gen);
+	if (INTEL_INFO(dev)->gen < 6)
+		agp_ggtt_clear_range(dev, start_page, npages);
+	else
+		gen6_ggtt_clear_range(dev, start_page, npages);
+}
+
+/*
+ * AGP GTT
+ */
+
+/*
+ * XXX This is factored all wrong.  We should merge this gen6+ code
+ * into our agp abstraction like FreeBSD did to clean it up.
+ */
+
+/*
+ * XXX Kludge!  If you implement VT-d stuff, you should fix this.  I
+ * hope you will find this comment, by grepping for the string `VT-d',
+ * when you do.  This has to do with using VT-d to map graphics crap.
+ * I don't understand it -- you will have to see what it means in Linux
+ * to find out.
+ */
+int intel_iommu_gfx_mapped = 0;
+
+static int
+agp_gtt_init(struct drm_device *dev)
+{
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	struct intel_gtt *gtt = dev_priv->mm.gtt;
+	struct agp_i810_softc *isc;
+	uint16_t product;
+	int ret;
+
+	if (agp_i810_sc == NULL) {
+		DRM_ERROR("no i810 agp device for gtt\n");
+		ret = -ENODEV;
+		goto fail0;
+	}
+	isc = agp_i810_sc->as_chipc;
+
+	gtt->gma_bus_addr = agp_i810_sc->as_apaddr;
+	gtt->gtt_mappable_entries = (agp_i810_sc->as_apsize >> AGP_PAGE_SHIFT);
+	gtt->stolen_size = (isc->stolen >> AGP_PAGE_SHIFT);
+	gtt->gtt_total_entries =
+	    (gtt->gtt_mappable_entries + gtt->stolen_size);
+	gtt->gtt_bsh = isc->bsh;
+
+	product = PCI_PRODUCT(dev->pdev->pd_pa.pa_id);
+	if (((product == PCI_PRODUCT_INTEL_IRONLAKE_M_HB) ||
+	     (product == PCI_PRODUCT_INTEL_IRONLAKE_M_HB)) &&
+	    intel_iommu_gfx_mapped)
+		gtt->do_idle_maps = true;
+	else
+		gtt->do_idle_maps = false;
 
-	gen6_ggtt_clear_range(dev, start_page, npages);
+	ret = i915_gem_gtt_init_scratch_page(gtt, agp_i810_sc->as_dmat);
+	if (ret)
+		goto fail0;
+
+	/* Success!  */
+	return 0;
+
+fail1: __unused
+	i915_gem_gtt_fini_scratch_page(gtt, agp_i810_sc->as_dmat);
+fail0:	return ret;
+}
+
+static void
+agp_gtt_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	struct intel_gtt *gtt = dev_priv->mm.gtt;
+
+	i915_gem_gtt_fini_scratch_page(gtt, agp_i810_sc->as_dmat);
+}
+
+static void
+agp_ggtt_bind_object(struct drm_i915_gem_object *obj,
+    enum i915_cache_level cache_level)
+{
+	struct drm_device *const dev = obj->base.dev;
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	const off_t start = obj->gtt_space->start;
+	bus_addr_t addr;
+	bus_size_t len;
+	unsigned int seg, i = 0;
+
+	for (seg = 0; seg < obj->igo_dmamap->dm_nsegs; seg++) {
+		addr = obj->igo_dmamap->dm_segs[seg].ds_addr;
+		len = obj->igo_dmamap->dm_segs[seg].ds_len;
+		do {
+			KASSERT(PAGE_SIZE <= len);
+			KASSERT(0 == (len % PAGE_SIZE));
+			AGP_BIND_PAGE(agp_i810_sc, (start + (i << PAGE_SHIFT)),
+			    addr);
+			addr += PAGE_SIZE;
+			len -= PAGE_SIZE;
+			i += 1;
+		} while (0 < len);
+	}
+
+	KASSERT((start >> PAGE_SHIFT) <= dev_priv->mm.gtt->gtt_total_entries);
+	KASSERT(i <= (dev_priv->mm.gtt->gtt_total_entries -
+		(start >> PAGE_SHIFT)));
+	KASSERT(i == (obj->base.size >> PAGE_SHIFT));
+
+	/*
+	 * XXX Linux does a posting read here of the last PTE, but the
+	 * AGP API provides no way to do that.  Hope it's OK...
+	 */
+}
+
+static void
+agp_ggtt_clear_range(struct drm_device *dev, unsigned start_page,
+    unsigned npages)
+{
+	unsigned page;
+
+	for (page = start_page; npages--; page++)
+		AGP_UNBIND_PAGE(agp_i810_sc, (off_t)page << PAGE_SHIFT);
+
+	/* XXX Posting read!  */
+}
+
+/*
+ * Gen6+ GTT
+ */
+
+#define	SNB_GMCH_GGMS	(SNB_GMCH_GGMS_MASK << SNB_GMCH_GGMS_SHIFT)
+#define	SNB_GMCH_GMS	(SNB_GMCH_GMS_MASK << SNB_GMCH_GMS_SHIFT)
+#define	IVB_GMCH_GMS	(IVB_GMCH_GMS_MASK << IVB_GMCH_GMS_SHIFT)
+
+typedef uint32_t gtt_pte_t;
+
+#define	GEN6_PTE_VALID		__BIT(0)
+#define	GEN6_PTE_UNCACHED	__BIT(1)
+#define	HSW_PTE_UNCACHED	(0)
+#define	GEN6_PTE_CACHE_LLC	__BIT(2)
+#define	GEN6_PTE_CACHE_LLC_MLC	__BIT(3)
+
+static uint32_t
+gen6_pte_addr_encode(bus_addr_t addr)
+{
+	KASSERT(addr <= __BITS(39, 0));
+	return (addr | ((addr >> 28) & 0xff0));
+}
+
+static gtt_pte_t
+gen6_pte_encode(struct drm_device *dev, bus_addr_t addr,
+    enum i915_cache_level level)
+{
+	uint32_t flags = GEN6_PTE_VALID;
+
+	switch (level) {
+	case I915_CACHE_LLC_MLC:
+		flags |= (IS_HASWELL(dev)? GEN6_PTE_CACHE_LLC
+		    : GEN6_PTE_CACHE_LLC_MLC);
+		break;
+
+	case I915_CACHE_LLC:
+		flags |= GEN6_PTE_CACHE_LLC;
+		break;
+
+	case I915_CACHE_NONE:
+		flags |= (IS_HASWELL(dev)? HSW_PTE_UNCACHED
+		    : GEN6_PTE_UNCACHED);
+		break;
+
+	default:
+		panic("invalid i915 GTT cache level: %d", (int)level);
+		break;
+	}
+
+	return (gen6_pte_addr_encode(addr) | flags);
+}
+
+static int
+gen6_gtt_init(struct drm_device *dev)
+{
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	struct pci_attach_args *const pa = &dev->pdev->pd_pa;
+	struct intel_gtt *gtt = dev_priv->mm.gtt;
+	uint16_t snb_gmch_ctl, ggms, gms;
+	int ret;
+
+	gtt->do_idle_maps = false;
+
+	/* XXX pci_set_dma_mask?  pci_set_consistent_dma_mask?  */
+	drm_limit_dma_space(dev, 0, 0x0000000fffffffffULL);
+
+	gtt->gma_bus_addr = dev->bus_maps[2].bm_base;
+
+	snb_gmch_ctl = pci_conf_read(pa->pa_pc, pa->pa_tag, SNB_GMCH_CTRL);
+
+	/* GMS: Graphics Mode Select.  */
+	if (INTEL_INFO(dev)->gen < 7) {
+		gms = __SHIFTOUT(snb_gmch_ctl, SNB_GMCH_GMS);
+		gtt->stolen_size = (gms << 25);
+	} else {
+		gms = __SHIFTOUT(snb_gmch_ctl, IVB_GMCH_GMS);
+		static const unsigned sizes[] = {
+			0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352
+		};
+		gtt->stolen_size = sizes[gms] << 20;
+	}
+
+	/* GGMS: GTT Graphics Memory Size.  */
+	ggms = __SHIFTOUT(snb_gmch_ctl, SNB_GMCH_GGMS);
+	gtt->gtt_total_entries = (ggms << 20) / sizeof(gtt_pte_t);
+
+	gtt->gtt_mappable_entries = (dev->bus_maps[2].bm_size >> PAGE_SHIFT);
+	if (((gtt->gtt_mappable_entries >> 8) < 64) ||
+	    (gtt->gtt_total_entries < gtt->gtt_mappable_entries)) {
+		DRM_ERROR("unknown GMADR entries: %d\n",
+		    gtt->gtt_mappable_entries);
+		ret = -ENXIO;
+		goto fail0;
+	}
+
+	/* Linux sez:  For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */
+	if (dev->bus_maps[0].bm_size < (gtt->gtt_total_entries *
+		sizeof(gtt_pte_t))) {
+		DRM_ERROR("BAR0 too small for GTT: 0x%"PRIxMAX" < 0x%"PRIxMAX
+		    "\n",
+		    dev->bus_maps[0].bm_size,
+		    (gtt->gtt_total_entries * sizeof(gtt_pte_t)));
+		ret = -ENODEV;
+		goto fail0;
+	}
+	if (bus_space_map(dev->bst, (dev->bus_maps[0].bm_base + (2<<20)),
+		(gtt->gtt_total_entries * sizeof(gtt_pte_t)),
+		0,
+		&gtt->gtt_bsh)) {
+		DRM_ERROR("unable to map GTT\n");
+		ret = -ENODEV;
+		goto fail0;
+	}
+
+	ret = i915_gem_gtt_init_scratch_page(gtt, dev->dmat);
+	if (ret)
+		goto fail1;
+
+	/* Success!  */
+	return 0;
+
+fail2: __unused
+	i915_gem_gtt_fini_scratch_page(gtt, dev->dmat);
+fail1:	bus_space_unmap(dev->bst, gtt->gtt_bsh,
+	    (gtt->gtt_total_entries * sizeof(gtt_pte_t)));
+fail0:	/* XXX Undo drm_limit_dma_space?  */
+	return ret;
+}
+
+static void
+gen6_gtt_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	struct intel_gtt *gtt = dev_priv->mm.gtt;
+
+	bus_space_unmap(dev->bst, gtt->gtt_bsh,
+	    (gtt->gtt_total_entries * sizeof(gtt_pte_t)));
+	i915_gem_gtt_fini_scratch_page(gtt, dev->dmat);
 }
 
 static void
@@ -405,7 +630,7 @@ gen6_ggtt_bind_object(struct drm_i915_ge
 			KASSERT(PAGE_SIZE <= len);
 			KASSERT(0 == (len % PAGE_SIZE));
 			bus_space_write_4(bst, bsh, 4*(first_entry + i),
-			    pte_encode(dev, addr, cache_level));
+			    gen6_pte_encode(dev, addr, cache_level));
 			addr += PAGE_SIZE;
 			len -= PAGE_SIZE;
 			i += 1;
@@ -420,8 +645,8 @@ gen6_ggtt_bind_object(struct drm_i915_ge
 	if (0 < i) {
 		/* Posting read and sanity check.  */
 		/* XXX Shouldn't there be a bus_space_sync?  */
-		const uint32_t expected = pte_encode(dev, addr - PAGE_SIZE,
-		    cache_level);
+		const uint32_t expected = gen6_pte_encode(dev,
+		    addr - PAGE_SIZE, cache_level);
 		const uint32_t actual = bus_space_read_4(bst, bsh,
 		    4*(first_entry + i-1));
 		if (actual != expected)
@@ -442,7 +667,7 @@ gen6_ggtt_clear_range(struct drm_device 
 	const bus_space_tag_t bst = dev->bst;
 	const bus_space_handle_t bsh = dev_priv->mm.gtt->gtt_bsh;
 	const unsigned n = (dev_priv->mm.gtt->gtt_total_entries - start_page);
-	const gtt_pte_t scratch_pte = pte_encode(dev,
+	const gtt_pte_t scratch_pte = gen6_pte_encode(dev,
 	    dev_priv->mm.gtt->gtt_scratch_map->dm_segs[0].ds_addr,
 	    I915_CACHE_LLC);
 	unsigned int i;

Reply via email to