diff options
-rw-r--r-- | linux-core/drmP.h | 1 | ||||
-rw-r--r-- | linux-core/drm_compat.c | 133 | ||||
-rw-r--r-- | linux-core/drm_drv.c | 1 | ||||
-rw-r--r-- | linux-core/drm_fops.c | 7 | ||||
-rw-r--r-- | linux-core/drm_ttm.c | 77 | ||||
-rw-r--r-- | linux-core/drm_ttm.h | 1 |
6 files changed, 29 insertions, 191 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f17a3421..089059c8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -874,6 +874,7 @@ typedef struct drm_device { drm_open_hash_t map_hash; /**< User token hash table for maps */ drm_mm_t offset_manager; /**< User token manager */ drm_open_hash_t object_hash; /**< User token hash table for objects */ + struct address_space *dev_mapping; /**< For unmap_mapping_range() */ /** \name Context handle management */ /*@{ */ diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 8dbc636a..81a2bd84 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -26,139 +26,6 @@ */ #include "drmP.h" -#include <asm/pgtable.h> -#include <asm/cacheflush.h> -#include <asm/tlbflush.h> - -#ifdef MODULE -void pgd_clear_bad(pgd_t * pgd) -{ - pgd_ERROR(*pgd); - pgd_clear(pgd); -} - -void pud_clear_bad(pud_t * pud) -{ - pud_ERROR(*pud); - pud_clear(pud); -} - -void pmd_clear_bad(pmd_t * pmd) -{ - pmd_ERROR(*pmd); - pmd_clear(pmd); -} -#endif - -static inline void change_pte_range(struct mm_struct *mm, pmd_t * pmd, - unsigned long addr, unsigned long end) -{ - pte_t *pte; - struct page *page; - unsigned long pfn; - - pte = pte_offset_map(pmd, addr); - do { - if (pte_present(*pte)) { - pte_t ptent; - pfn = pte_pfn(*pte); - ptent = *pte; - ptep_get_and_clear(mm, addr, pte); - if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (atomic_add_negative(-1, &page->_mapcount)) { - if (page_test_and_clear_dirty(page)) - set_page_dirty(page); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) - dec_zone_page_state(page, NR_FILE_MAPPED); -#else - dec_page_state(nr_mapped); -#endif - } - - put_page(page); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) - dec_mm_counter(mm, file_rss); -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) - dec_mm_counter(mm, rss); -#else - --mm->rss; -#endif - } - } - } while (pte++, addr += PAGE_SIZE, addr != end); - pte_unmap(pte - 1); -} - -static inline void change_pmd_range(struct mm_struct *mm, pud_t * pud, - unsigned long addr, unsigned long end) -{ - pmd_t *pmd; - unsigned long next; - - pmd = pmd_offset(pud, addr); - do { - next = pmd_addr_end(addr, end); - if (pmd_none_or_clear_bad(pmd)) - continue; - change_pte_range(mm, pmd, addr, next); - } while (pmd++, addr = next, addr != end); -} - -static inline void change_pud_range(struct mm_struct *mm, pgd_t * pgd, - unsigned long addr, unsigned long end) -{ - pud_t *pud; - unsigned long next; - - pud = pud_offset(pgd, addr); - do { - next = pud_addr_end(addr, end); - if (pud_none_or_clear_bad(pud)) - continue; - change_pmd_range(mm, pud, addr, next); - } while (pud++, addr = next, addr != end); -} - -/* - * This function should be called with all relevant spinlocks held. - */ - -#if 1 -void drm_clear_vma(struct vm_area_struct *vma, - unsigned long addr, unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - pgd_t *pgd; - unsigned long next; -#if defined(flush_tlb_mm) || !defined(MODULE) - unsigned long start = addr; -#endif - BUG_ON(addr >= end); - pgd = pgd_offset(mm, addr); - flush_cache_range(vma, addr, end); - do { - next = pgd_addr_end(addr, end); - if (pgd_none_or_clear_bad(pgd)) - continue; - change_pud_range(mm, pgd, addr, next); - } while (pgd++, addr = next, addr != end); -#if defined(flush_tlb_mm) || !defined(MODULE) - flush_tlb_range(vma, addr, end); -#endif -} -#else - -void drm_clear_vma(struct vm_area_struct *vma, - unsigned long addr, unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - - spin_unlock(&mm->page_table_lock); - (void) zap_page_range(vma, addr, end - addr, NULL); - spin_lock(&mm->page_table_lock); -} -#endif #if defined(CONFIG_X86) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) int drm_map_page_into_agp(struct page *page) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index ae0c37a5..4cbe035f 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -263,6 +263,7 @@ int drm_lastclose(drm_device_t * dev) dev->lock.filp = NULL; wake_up_interruptible(&dev->lock.lock_queue); } + dev->dev_mapping = NULL; mutex_unlock(&dev->struct_mutex); if (drm_bo_clean_mm(dev)) { diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 5593e55c..b60ced34 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -158,6 +158,12 @@ int drm_open(struct inode *inode, struct file *filp) } spin_unlock(&dev->count_lock); } + mutex_lock(&dev->struct_mutex); + BUG_ON((dev->dev_mapping != NULL) && + (dev->dev_mapping != inode->i_mapping)); + if (dev->dev_mapping == NULL) + dev->dev_mapping = inode->i_mapping; + mutex_unlock(&dev->struct_mutex); return retcode; } @@ -465,6 +471,7 @@ int drm_release(struct inode *inode, struct file *filp) drm_fasync(-1, filp, 0); mutex_lock(&dev->ctxlist_mutex); + if (dev->ctxlist && (!list_empty(&dev->ctxlist->head))) { drm_ctx_list_t *pos, *n; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 311c57fa..ed50da90 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -123,31 +123,12 @@ void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm) BUG_ON(1); } -static void drm_ttm_lock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) +static void drm_ttm_unlock_mm(drm_ttm_t * ttm) { p_mm_entry_t *entry; list_for_each_entry(entry, &ttm->p_mm_list, head) { - if (mm_sem) { - down_write(&entry->mm->mmap_sem); - } - if (page_table) { - spin_lock(&entry->mm->page_table_lock); - } - } -} - -static void drm_ttm_unlock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) -{ - p_mm_entry_t *entry; - - list_for_each_entry(entry, &ttm->p_mm_list, head) { - if (page_table) { - spin_unlock(&entry->mm->page_table_lock); - } - if (mm_sem) { - up_write(&entry->mm->mmap_sem); - } + up_write(&entry->mm->mmap_sem); } } @@ -180,30 +161,13 @@ static int ioremap_vmas(drm_ttm_t * ttm, unsigned long page_offset, static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, unsigned long num_pages) { - struct list_head *list; - -#if !defined(flush_tlb_mm) && defined(MODULE) - int flush_tlb = 0; -#endif - list_for_each(list, &ttm->vma_list->head) { - drm_ttm_vma_list_t *entry = - list_entry(list, drm_ttm_vma_list_t, head); - - drm_clear_vma(entry->vma, - entry->vma->vm_start + - (page_offset << PAGE_SHIFT), - entry->vma->vm_start + - ((page_offset + num_pages) << PAGE_SHIFT)); - -#if !defined(flush_tlb_mm) && defined(MODULE) - flush_tlb = 1; -#endif - } -#if !defined(flush_tlb_mm) && defined(MODULE) - if (flush_tlb) - global_flush_tlb(); -#endif + drm_device_t *dev = ttm->dev; + loff_t offset = ((loff_t) ttm->mapping_offset + page_offset) + << PAGE_SHIFT; + loff_t holelen = num_pages << PAGE_SHIFT; + + unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); return 0; } @@ -437,15 +401,16 @@ static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) } /* - * Change caching policy for range of pages in a ttm. + * Change caching policy for the linear kernel map + * for range of pages in a ttm. */ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, - unsigned long num_pages, int noncached, - int do_tlbflush) + unsigned long num_pages, int noncached) { int i, cur; struct page **cur_page; + int do_tlbflush = 0; for (i = 0; i < num_pages; ++i) { cur = page_offset + i; @@ -467,6 +432,7 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, } else { unmap_page_from_agp(*cur_page); } + do_tlbflush = 1; } } } @@ -492,16 +458,14 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; - drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); } be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, - entry->num_pages, 0, 1); - drm_ttm_unlock_mm(ttm, 1, 0); + entry->num_pages, 0); + drm_ttm_unlock_mm(ttm); } break; default: @@ -653,20 +617,17 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, if (ret) return ret; - drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, region->page_offset, region->num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); - drm_set_caching(ttm, region->page_offset, region->num_pages, - DRM_TTM_PAGE_UNCACHED, 1); + DRM_TTM_PAGE_UNCACHED); } else { DRM_DEBUG("Binding cached\n"); } if ((ret = be->bind(be, aper_offset))) { if (ttm && be->needs_cache_adjust(be)) - drm_ttm_unlock_mm(ttm, 1, 0); + drm_ttm_unlock_mm(ttm); drm_unbind_ttm_region(region); DRM_ERROR("Couldn't bind backend.\n"); return ret; @@ -682,7 +643,7 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, if (ttm && be->needs_cache_adjust(be)) { ioremap_vmas(ttm, region->page_offset, region->num_pages, aper_offset); - drm_ttm_unlock_mm(ttm, 1, 0); + drm_ttm_unlock_mm(ttm); } region->state = ttm_bound; @@ -924,7 +885,7 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, } list->user_token = ((drm_u64_t) list->hash.key) << PAGE_SHIFT; - + ttm->mapping_offset = list->hash.key; atomic_set(&object->usage, 1); *ttm_object = object; return 0; diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index d65b17de..53afe792 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -100,6 +100,7 @@ typedef struct drm_ttm { atomic_t vma_count; int mmap_sem_locked; int destroy; + uint32_t mapping_offset; } drm_ttm_t; typedef struct drm_ttm_object { |