Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41c2e75e authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Dave Airlie
Browse files

drm: Make drm_local_map use a resource_size_t offset



This changes drm_local_map to use a resource_size for its "offset"
member instead of an unsigned long, thus allowing 32-bit machines
with a >32-bit physical address space to be able to store there
their register or framebuffer addresses when those are above 4G,
such as when using a PCI video card on a recent AMCC 440 SoC.

This patch isn't as "trivial" as it sounds: A few functions needed
to have some unsigned long/int changed to resource_size_t and a few
printk's had to be adjusted.

But also, because userspace isn't capable of passing such offsets,
I had to modify drm_find_matching_map() to ignore the offset passed
in for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS.

If we ever support multiple _DRM_FRAMEBUFFER or _DRM_REGISTERS maps
for a given device, we might have to change that trick, but I don't
think that happens on any current driver.

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent f77d390c
Loading
Loading
Loading
Loading
+28 −9
Original line number Diff line number Diff line
@@ -54,11 +54,29 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
{
	struct drm_map_list *entry;
	list_for_each_entry(entry, &dev->maplist, head) {
		if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) &&
		    ((entry->map->offset == map->offset) ||
		     ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {
		/*
		 * Because the kernel-userspace ABI is fixed at a 32-bit offset
		 * while PCI resources may live above that, we ignore the map
		 * offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS.
		 * It is assumed that each driver will have only one resource of
		 * each type.
		 */
		if (!entry->map ||
		    map->type != entry->map->type ||
		    entry->master != dev->primary->master)
			continue;
		switch (map->type) {
		case _DRM_SHM:
			if (map->flags != _DRM_CONTAINS_LOCK)
				break;
		case _DRM_REGISTERS:
		case _DRM_FRAME_BUFFER:
			return entry;
		default: /* Make gcc happy */
			;
		}
		if (entry->map->offset == map->offset)
			return entry;
	}

	return NULL;
@@ -96,7 +114,7 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
 * type.  Adds the map to the map list drm_device::maplist. Adds MTRR's where
 * applicable and if supported by the kernel.
 */
static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
			   unsigned int size, enum drm_map_type type,
			   enum drm_map_flags flags,
			   struct drm_map_list ** maplist)
@@ -124,9 +142,9 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
		return -EINVAL;
	}
	DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
		  map->offset, map->size, map->type);
	if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
	DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n",
		  (unsigned long long)map->offset, map->size, map->type);
	if ((map->offset & (~(resource_size_t)PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
		return -EINVAL;
	}
@@ -254,7 +272,8 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
			return -EPERM;
		}
		DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
		DRM_DEBUG("AGP offset = 0x%08llx, size = 0x%08lx\n",
			  (unsigned long long)map->offset, map->size);

		break;
	case _DRM_GEM:
@@ -322,7 +341,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
	return 0;
	}

int drm_addmap(struct drm_device * dev, unsigned int offset,
int drm_addmap(struct drm_device * dev, resource_size_t offset,
	       unsigned int size, enum drm_map_type type,
	       enum drm_map_flags flags, struct drm_local_map ** map_ptr)
{
+2 −2
Original line number Diff line number Diff line
@@ -276,9 +276,9 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
			type = "??";
		else
			type = types[map->type];
		DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
		DRM_PROC_PRINT("%4d 0x%08llx 0x%08lx %4.4s  0x%02x 0x%08lx ",
			       i,
			       map->offset,
			       (unsigned long long)map->offset,
			       map->size, type, map->flags,
			       (unsigned long) r_list->user_token);
		if (map->mtrr < 0) {
+12 −10
Original line number Diff line number Diff line
@@ -115,9 +115,9 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
		 * Using vm_pgoff as a selector forces us to use this unusual
		 * addressing scheme.
		 */
		unsigned long offset = (unsigned long)vmf->virtual_address -
		resource_size_t offset = (unsigned long)vmf->virtual_address -
			vma->vm_start;
		unsigned long baddr = map->offset + offset;
		resource_size_t baddr = map->offset + offset;
		struct drm_agp_mem *agpmem;
		struct page *page;

@@ -149,8 +149,10 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
		vmf->page = page;

		DRM_DEBUG
		    ("baddr = 0x%lx page = 0x%p, offset = 0x%lx, count=%d\n",
		     baddr, __va(agpmem->memory->memory[offset]), offset,
		    ("baddr = 0x%llx page = 0x%p, offset = 0x%llx, count=%d\n",
		     (unsigned long long)baddr,
		     __va(agpmem->memory->memory[offset]),
		     (unsigned long long)offset,
		     page_count(page));
		return 0;
	}
@@ -512,14 +514,14 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
	return 0;
}

unsigned long drm_core_get_map_ofs(struct drm_local_map * map)
resource_size_t drm_core_get_map_ofs(struct drm_local_map * map)
{
	return map->offset;
}

EXPORT_SYMBOL(drm_core_get_map_ofs);

unsigned long drm_core_get_reg_ofs(struct drm_device *dev)
resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
{
#ifdef __alpha__
	return dev->hose->dense_mem_base - dev->hose->mem_space->start;
@@ -548,7 +550,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
	struct drm_file *priv = filp->private_data;
	struct drm_device *dev = priv->minor->dev;
	struct drm_local_map *map = NULL;
	unsigned long offset = 0;
	resource_size_t offset = 0;
	struct drm_hash_item *hash;

	DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
@@ -623,9 +625,9 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
				       vma->vm_page_prot))
			return -EAGAIN;
		DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx,"
			  " offset = 0x%lx\n",
			  " offset = 0x%llx\n",
			  map->type,
			  vma->vm_start, vma->vm_end, map->offset + offset);
			  vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset));
		vma->vm_ops = &drm_vm_ops;
		break;
	case _DRM_CONSISTENT:
+9 −8
Original line number Diff line number Diff line
@@ -148,8 +148,8 @@ void mga_do_dma_flush(drm_mga_private_t * dev_priv)
		primary->space = head - tail;
	}

	DRM_DEBUG("   head = 0x%06lx\n", head - dev_priv->primary->offset);
	DRM_DEBUG("   tail = 0x%06lx\n", tail - dev_priv->primary->offset);
	DRM_DEBUG("   head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
	DRM_DEBUG("   tail = 0x%06lx\n", (unsigned long)(tail - dev_priv->primary->offset));
	DRM_DEBUG("  space = 0x%06x\n", primary->space);

	mga_flush_write_combine();
@@ -187,7 +187,7 @@ void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv)
		primary->space = head - dev_priv->primary->offset;
	}

	DRM_DEBUG("   head = 0x%06lx\n", head - dev_priv->primary->offset);
	DRM_DEBUG("   head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
	DRM_DEBUG("   tail = 0x%06x\n", primary->tail);
	DRM_DEBUG("   wrap = %d\n", primary->last_wrap);
	DRM_DEBUG("  space = 0x%06x\n", primary->space);
@@ -239,7 +239,7 @@ static void mga_freelist_print(struct drm_device * dev)
	for (entry = dev_priv->head->next; entry; entry = entry->next) {
		DRM_INFO("   %p   idx=%2d  age=0x%x 0x%06lx\n",
			 entry, entry->buf->idx, entry->age.head,
			 entry->age.head - dev_priv->primary->offset);
			 (unsigned long)(entry->age.head - dev_priv->primary->offset));
	}
	DRM_INFO("\n");
}
@@ -340,10 +340,10 @@ static struct drm_buf *mga_freelist_get(struct drm_device * dev)

	DRM_DEBUG("   tail=0x%06lx %d\n",
		  tail->age.head ?
		  tail->age.head - dev_priv->primary->offset : 0,
		  (unsigned long)(tail->age.head - dev_priv->primary->offset) : 0,
		  tail->age.wrap);
	DRM_DEBUG("   head=0x%06lx %d\n",
		  head - dev_priv->primary->offset, wrap);
		  (unsigned long)(head - dev_priv->primary->offset), wrap);

	if (TEST_AGE(&tail->age, head, wrap)) {
		prev = dev_priv->tail->prev;
@@ -366,8 +366,9 @@ int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf)
	drm_mga_freelist_t *head, *entry, *prev;

	DRM_DEBUG("age=0x%06lx wrap=%d\n",
		  buf_priv->list_entry->age.head -
		  dev_priv->primary->offset, buf_priv->list_entry->age.wrap);
		  (unsigned long)(buf_priv->list_entry->age.head -
				  dev_priv->primary->offset),
		  buf_priv->list_entry->age.wrap);

	entry = buf_priv->list_entry;
	head = dev_priv->head;
+2 −2
Original line number Diff line number Diff line
@@ -317,8 +317,8 @@ do { \
		DRM_INFO( "\n" );					\
		DRM_INFO( "   tail=0x%06x head=0x%06lx\n",		\
			  dev_priv->prim.tail,				\
			  MGA_READ( MGA_PRIMADDRESS ) -			\
			  dev_priv->primary->offset );			\
			  (unsigned long)(MGA_READ(MGA_PRIMADDRESS) -	\
					  dev_priv->primary->offset));	\
	}								\
	if ( !test_bit( 0, &dev_priv->prim.wrapped ) ) {		\
		if ( dev_priv->prim.space <				\
Loading