diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-09-26 11:17:16 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-09-26 11:17:16 +0000 |
commit | eb9889ae7bdf7b2c58943a9a96d5b9a9e4ae88ff (patch) | |
tree | 4e593ce2f43d7e6e2ab4d65edfaa9408d319ec39 /sys/dev/pci | |
parent | 506d75ea2fb0e7fb26f0589cb5d50ad12495dc43 (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.c | 30 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_linux.h | 47 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915/i915_drv.h | 8 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915/i915_gem_gtt.c | 82 |
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) |