0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <linux/export.h>
0037 #include <linux/highmem.h>
0038 #include <linux/pci.h>
0039 #include <linux/vmalloc.h>
0040
0041 #include <drm/drm_cache.h>
0042 #include <drm/drm_device.h>
0043
0044 #include "drm_legacy.h"
0045
0046 #if IS_ENABLED(CONFIG_AGP)
0047
0048 #ifdef HAVE_PAGE_AGP
0049 # include <asm/agp.h>
0050 #else
0051 # ifdef __powerpc__
0052 # define PAGE_AGP pgprot_noncached_wc(PAGE_KERNEL)
0053 # else
0054 # define PAGE_AGP PAGE_KERNEL
0055 # endif
0056 #endif
0057
0058 static void *agp_remap(unsigned long offset, unsigned long size,
0059 struct drm_device *dev)
0060 {
0061 unsigned long i, num_pages =
0062 PAGE_ALIGN(size) / PAGE_SIZE;
0063 struct drm_agp_mem *agpmem;
0064 struct page **page_map;
0065 struct page **phys_page_map;
0066 void *addr;
0067
0068 size = PAGE_ALIGN(size);
0069
0070 #ifdef __alpha__
0071 offset -= dev->hose->mem_space->start;
0072 #endif
0073
0074 list_for_each_entry(agpmem, &dev->agp->memory, head)
0075 if (agpmem->bound <= offset
0076 && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >=
0077 (offset + size))
0078 break;
0079 if (&agpmem->head == &dev->agp->memory)
0080 return NULL;
0081
0082
0083
0084
0085
0086
0087
0088 page_map = vmalloc(array_size(num_pages, sizeof(struct page *)));
0089 if (!page_map)
0090 return NULL;
0091
0092 phys_page_map = (agpmem->memory->pages + (offset - agpmem->bound) / PAGE_SIZE);
0093 for (i = 0; i < num_pages; ++i)
0094 page_map[i] = phys_page_map[i];
0095 addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP);
0096 vfree(page_map);
0097
0098 return addr;
0099 }
0100
0101 #else
0102 static inline void *agp_remap(unsigned long offset, unsigned long size,
0103 struct drm_device *dev)
0104 {
0105 return NULL;
0106 }
0107
0108 #endif
0109
0110 void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev)
0111 {
0112 if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
0113 map->handle = agp_remap(map->offset, map->size, dev);
0114 else
0115 map->handle = ioremap(map->offset, map->size);
0116 }
0117 EXPORT_SYMBOL(drm_legacy_ioremap);
0118
0119 void drm_legacy_ioremap_wc(struct drm_local_map *map, struct drm_device *dev)
0120 {
0121 if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
0122 map->handle = agp_remap(map->offset, map->size, dev);
0123 else
0124 map->handle = ioremap_wc(map->offset, map->size);
0125 }
0126 EXPORT_SYMBOL(drm_legacy_ioremap_wc);
0127
0128 void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
0129 {
0130 if (!map->handle || !map->size)
0131 return;
0132
0133 if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
0134 vunmap(map->handle);
0135 else
0136 iounmap(map->handle);
0137 }
0138 EXPORT_SYMBOL(drm_legacy_ioremapfree);