summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2015-09-26 11:17:16 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2015-09-26 11:17:16 +0000
commiteb9889ae7bdf7b2c58943a9a96d5b9a9e4ae88ff (patch)
tree4e593ce2f43d7e6e2ab4d65edfaa9408d319ec39 /sys/dev/pci
parent506d75ea2fb0e7fb26f0589cb5d50ad12495dc43 (diff)
Make the PPGTT code work. Seems to fix the caching issues on Broadwell.
Comments on some of the later Broadwell-related commits in the Linux tree seem to say that the PPAT flags in for the (global) GTT are simply broken in the hardware.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/drm/drm_linux.c30
-rw-r--r--sys/dev/pci/drm/drm_linux.h47
-rw-r--r--sys/dev/pci/drm/i915/i915_drv.h8
-rw-r--r--sys/dev/pci/drm/i915/i915_gem_gtt.c82
4 files changed, 151 insertions, 16 deletions
diff --git a/sys/dev/pci/drm/drm_linux.c b/sys/dev/pci/drm/drm_linux.c
index 97aaa90c0a1..4dcca39fdec 100644
--- a/sys/dev/pci/drm/drm_linux.c
+++ b/sys/dev/pci/drm/drm_linux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_linux.c,v 1.4 2015/04/08 15:01:33 jsg Exp $ */
+/* $OpenBSD: drm_linux.c,v 1.5 2015/09/26 11:17:15 kettenis Exp $ */
/*
* Copyright (c) 2013 Jonathan Gray <jsg@openbsd.org>
*
@@ -118,6 +118,34 @@ dmi_check_system(const struct dmi_system_id *sysid)
return (num);
}
+struct vm_page *
+alloc_pages(unsigned int gfp_mask, unsigned int order)
+{
+ int flags = (gfp_mask & M_NOWAIT) ? UVM_PLA_NOWAIT : UVM_PLA_WAITOK;
+ struct pglist mlist;
+
+ if (gfp_mask & M_CANFAIL)
+ flags |= UVM_PLA_FAILOK;
+
+ TAILQ_INIT(&mlist);
+ if (uvm_pglistalloc(PAGE_SIZE << order, 0, -1, PAGE_SIZE, 0,
+ &mlist, 1, flags))
+ return NULL;
+ return TAILQ_FIRST(&mlist);
+}
+
+void
+__free_pages(struct vm_page *page, unsigned int order)
+{
+ struct pglist mlist;
+ int i;
+
+ TAILQ_INIT(&mlist);
+ for (i = 0; i < (1 << order); i++)
+ TAILQ_INSERT_TAIL(&mlist, &page[i], pageq);
+ uvm_pglistfree(&mlist);
+}
+
void *
kmap(struct vm_page *pg)
{
diff --git a/sys/dev/pci/drm/drm_linux.h b/sys/dev/pci/drm/drm_linux.h
index e12188455d8..0819de601c2 100644
--- a/sys/dev/pci/drm/drm_linux.h
+++ b/sys/dev/pci/drm/drm_linux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_linux.h,v 1.36 2015/09/25 20:27:52 kettenis Exp $ */
+/* $OpenBSD: drm_linux.h,v 1.37 2015/09/26 11:17:15 kettenis Exp $ */
/*
* Copyright (c) 2013, 2014, 2015 Mark Kettenis
*
@@ -934,6 +934,29 @@ typedef enum {
PCI_D3cold
} pci_power_t;
+#if defined(__amd64__) || defined(__i386__)
+
+#define PCI_DMA_BIDIRECTIONAL 0
+
+static inline dma_addr_t
+pci_map_page(struct pci_dev *pdev, struct vm_page *page, unsigned long offset, size_t size, int direction)
+{
+ return VM_PAGE_TO_PHYS(page);
+}
+
+static inline void
+pci_unmap_page(struct pci_dev *pdev, dma_addr_t dma_address, size_t size, int direction)
+{
+}
+
+static inline int
+pci_dma_mapping_error(struct pci_dev *pdev, dma_addr_t dma_addr)
+{
+ return 0;
+}
+
+#endif
+
#define memcpy_toio(d, s, n) memcpy(d, s, n)
#define memcpy_fromio(d, s, n) memcpy(d, s, n)
#define memset_io(d, b, n) memset(d, b, n)
@@ -957,6 +980,7 @@ iowrite32(u32 val, volatile void __iomem *addr)
}
#define readl(p) ioread32(p)
+#define writel(v, p) iowrite32(v, p)
#define readq(p) ioread64(p)
#define page_to_phys(page) (VM_PAGE_TO_PHYS(page))
@@ -1096,6 +1120,27 @@ of_machine_is_compatible(const char *model)
}
#endif
+struct vm_page *alloc_pages(unsigned int, unsigned int);
+void __free_pages(struct vm_page *, unsigned int);
+
+static inline struct vm_page *
+alloc_page(unsigned int gfp_mask)
+{
+ return alloc_pages(gfp_mask, 0);
+}
+
+static inline void
+__free_page(struct vm_page *page)
+{
+ return __free_pages(page, 0);
+}
+
+static inline unsigned int
+get_order(size_t size)
+{
+ return flsl((size - 1) >> PAGE_SHIFT);
+}
+
#if defined(__i386__) || defined(__amd64__)
static inline void
diff --git a/sys/dev/pci/drm/i915/i915_drv.h b/sys/dev/pci/drm/i915/i915_drv.h
index 9084c6ee487..da813eef5c8 100644
--- a/sys/dev/pci/drm/i915/i915_drv.h
+++ b/sys/dev/pci/drm/i915/i915_drv.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: i915_drv.h,v 1.67 2015/09/23 23:12:12 kettenis Exp $ */
+/* $OpenBSD: i915_drv.h,v 1.68 2015/09/26 11:17:15 kettenis Exp $ */
/* i915_drv.h -- Private header for the I915 driver -*- linux-c -*-
*/
/*
@@ -710,10 +710,10 @@ struct i915_hw_ppgtt {
struct i915_address_space base;
unsigned num_pd_entries;
union {
- struct page **pt_pages;
- struct page *gen8_pt_pages;
+ struct vm_page **pt_pages;
+ struct vm_page *gen8_pt_pages;
};
- struct page *pd_pages;
+ struct vm_page *pd_pages;
int num_pd_pages;
int num_pt_pages;
union {
diff --git a/sys/dev/pci/drm/i915/i915_gem_gtt.c b/sys/dev/pci/drm/i915/i915_gem_gtt.c
index 836d20ee5af..537b50f9fb4 100644
--- a/sys/dev/pci/drm/i915/i915_gem_gtt.c
+++ b/sys/dev/pci/drm/i915/i915_gem_gtt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i915_gem_gtt.c,v 1.11 2015/09/25 16:15:19 jsg Exp $ */
+/* $OpenBSD: i915_gem_gtt.c,v 1.12 2015/09/26 11:17:15 kettenis Exp $ */
/*
* Copyright © 2010 Daniel Vetter
*
@@ -207,7 +207,6 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
return pte;
}
-#ifdef notyet
/* Broadwell Page Directory Pointer Descriptors */
static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry,
uint64_t val)
@@ -279,7 +278,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
I915_CACHE_LLC, use_scratch);
while (num_entries) {
- struct page *page_table = &ppgtt->gen8_pt_pages[act_pt];
+ struct vm_page *page_table = &ppgtt->gen8_pt_pages[act_pt];
last_pte = first_pte + num_entries;
if (last_pte > GEN8_PTES_PER_PAGE)
@@ -298,6 +297,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
}
}
+#ifdef __linux__
static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
struct sg_table *pages,
unsigned first_entry,
@@ -328,6 +328,39 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
if (pt_vaddr)
kunmap_atomic(pt_vaddr);
}
+#else
+static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
+ struct vm_page **pages,
+ unsigned int num_entries,
+ unsigned first_entry,
+ enum i915_cache_level cache_level)
+{
+ struct i915_hw_ppgtt *ppgtt =
+ container_of(vm, struct i915_hw_ppgtt, base);
+ gen8_gtt_pte_t *pt_vaddr;
+ unsigned act_pt = first_entry / GEN8_PTES_PER_PAGE;
+ unsigned act_pte = first_entry % GEN8_PTES_PER_PAGE;
+ int i;
+
+ pt_vaddr = NULL;
+ for (i = 0; i < num_entries; i++) {
+ if (pt_vaddr == NULL)
+ pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]);
+
+ pt_vaddr[act_pte] =
+ gen8_pte_encode(VM_PAGE_TO_PHYS(pages[i]),
+ cache_level, true);
+ if (++act_pte == GEN8_PTES_PER_PAGE) {
+ kunmap_atomic(pt_vaddr);
+ pt_vaddr = NULL;
+ act_pt++;
+ act_pte = 0;
+ }
+ }
+ if (pt_vaddr)
+ kunmap_atomic(pt_vaddr);
+}
+#endif
static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
{
@@ -371,7 +404,7 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
{
struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
- struct page *pt_pages;
+ struct vm_page *pt_pages;
int i, j, ret = -ENOMEM;
const int max_pdp = DIV_ROUND_UP(size, 1 << 30);
const int num_pt_pages = GEN8_PDES_PER_PAGE * max_pdp;
@@ -428,7 +461,7 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
goto err_out;
for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
- struct page *p = &pt_pages[i * GEN8_PDES_PER_PAGE + j];
+ struct vm_page *p = &pt_pages[i * GEN8_PDES_PER_PAGE + j];
temp = pci_map_page(ppgtt->base.dev->pdev,
p, 0, PAGE_SIZE,
PCI_DMA_BIDIRECTIONAL);
@@ -584,6 +617,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
}
}
+#ifdef __linux__
static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
struct sg_table *pages,
unsigned first_entry,
@@ -614,6 +648,39 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
if (pt_vaddr)
kunmap_atomic(pt_vaddr);
}
+#else
+static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
+ struct vm_page **pages,
+ unsigned int num_entries,
+ unsigned first_entry,
+ enum i915_cache_level cache_level)
+{
+ struct i915_hw_ppgtt *ppgtt =
+ container_of(vm, struct i915_hw_ppgtt, base);
+ gen6_gtt_pte_t *pt_vaddr;
+ unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
+ unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+ int i;
+
+ pt_vaddr = NULL;
+ for (i = 0; i < num_entries; i++) {
+ if (pt_vaddr == NULL)
+ pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
+
+ pt_vaddr[act_pte] =
+ vm->pte_encode(VM_PAGE_TO_PHYS(pages[i]),
+ cache_level, true);
+ if (++act_pte == I915_PPGTT_PT_ENTRIES) {
+ kunmap_atomic(pt_vaddr);
+ pt_vaddr = NULL;
+ act_pt++;
+ act_pte = 0;
+ }
+ }
+ if (pt_vaddr)
+ kunmap_atomic(pt_vaddr);
+}
+#endif
static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
{
@@ -712,11 +779,9 @@ err_pt_alloc:
return ret;
}
-#endif
static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
{
-#ifdef notyet
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_hw_ppgtt *ppgtt;
int ret;
@@ -743,9 +808,6 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
}
return ret;
-#else
- return 0;
-#endif
}
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)