drm: Make drm_local_map use a resource_size_t offset
Benjamin Herrenschmidt [Mon, 2 Feb 2009 05:55:47 +0000 (16:55 +1100)]
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: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Dave Airlie <airlied@linux.ie>

drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_proc.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/mga/mga_dma.c
drivers/gpu/drm/mga/mga_drv.h
drivers/gpu/drm/r128/r128_cce.c
drivers/gpu/drm/radeon/radeon_cp.c
include/drm/drmP.h

index 1b8dbd5..cddea1a 100644 (file)
@@ -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)
 {
index c1959ba..2e3f907 100644 (file)
@@ -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) {
index 0d8bbd7..22f7656 100644 (file)
@@ -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 -
-                                                               vma->vm_start;
-               unsigned long baddr = map->offset + offset;
+               resource_size_t offset = (unsigned long)vmf->virtual_address -
+                       vma->vm_start;
+               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:
index b49c5ff..7a6bf9f 100644 (file)
@@ -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;
index 6bf4de9..3d264f2 100644 (file)
@@ -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 <                             \
index c31afbd..32de4ce 100644 (file)
@@ -525,11 +525,12 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
        } else
 #endif
        {
-               dev_priv->cce_ring->handle = (void *)dev_priv->cce_ring->offset;
+               dev_priv->cce_ring->handle =
+                       (void *)(unsigned long)dev_priv->cce_ring->offset;
                dev_priv->ring_rptr->handle =
-                   (void *)dev_priv->ring_rptr->offset;
+                       (void *)(unsigned long)dev_priv->ring_rptr->offset;
                dev->agp_buffer_map->handle =
-                   (void *)dev->agp_buffer_map->offset;
+                       (void *)(unsigned long)dev->agp_buffer_map->offset;
        }
 
 #if __OS_HAS_AGP
index 92965db..34c0b3f 100644 (file)
@@ -1062,11 +1062,12 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        } else
 #endif
        {
-               dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset;
+               dev_priv->cp_ring->handle =
+                       (void *)(unsigned long)dev_priv->cp_ring->offset;
                dev_priv->ring_rptr->handle =
-                   (void *)dev_priv->ring_rptr->offset;
+                       (void *)(unsigned long)dev_priv->ring_rptr->offset;
                dev->agp_buffer_map->handle =
-                   (void *)dev->agp_buffer_map->offset;
+                       (void *)(unsigned long)dev->agp_buffer_map->offset;
 
                DRM_DEBUG("dev_priv->cp_ring->handle %p\n",
                          dev_priv->cp_ring->handle);
@@ -1177,7 +1178,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
                /* if we have an offset set from userspace */
                if (dev_priv->pcigart_offset_set) {
                        dev_priv->gart_info.bus_addr =
-                           dev_priv->pcigart_offset + dev_priv->fb_location;
+                               (resource_size_t)dev_priv->pcigart_offset + dev_priv->fb_location;
                        dev_priv->gart_info.mapping.offset =
                            dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
                        dev_priv->gart_info.mapping.size =
index 03a7c11..c91fbb6 100644 (file)
@@ -526,7 +526,7 @@ struct drm_mm {
  * Kernel side of a mapping
  */
 struct drm_local_map {
-       unsigned long offset;    /**< Requested physical address (0 for SAREA)*/
+       resource_size_t offset;  /**< Requested physical address (0 for SAREA)*/
        unsigned long size;      /**< Requested physical size (bytes) */
        enum drm_map_type type;  /**< Type of memory to map */
        enum drm_map_flags flags;        /**< Flags */
@@ -760,8 +760,8 @@ struct drm_driver {
                                        struct drm_file *file_priv);
        void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
                                            struct drm_file *file_priv);
-       unsigned long (*get_map_ofs) (struct drm_local_map * map);
-       unsigned long (*get_reg_ofs) (struct drm_device *dev);
+       resource_size_t (*get_map_ofs) (struct drm_local_map * map);
+       resource_size_t (*get_reg_ofs) (struct drm_device *dev);
        void (*set_version) (struct drm_device *dev,
                             struct drm_set_version *sv);
 
@@ -1062,8 +1062,8 @@ extern int drm_release(struct inode *inode, struct file *filp);
 extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
 extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma);
 extern void drm_vm_open_locked(struct vm_area_struct *vma);
-extern unsigned long drm_core_get_map_ofs(struct drm_local_map * map);
-extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
+extern resource_size_t drm_core_get_map_ofs(struct drm_local_map * map);
+extern resource_size_t drm_core_get_reg_ofs(struct drm_device *dev);
 extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
 
                                /* Memory management support (drm_memory.h) */
@@ -1166,7 +1166,7 @@ extern int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv
                                /* Buffer management support (drm_bufs.h) */
 extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request);
 extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request);
-extern int drm_addmap(struct drm_device *dev, unsigned int offset,
+extern 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);
 extern int drm_addmap_ioctl(struct drm_device *dev, void *data,