diff -urN drm-HEAD.orig/shared-core/r300_cmdbuf.c drm-HEAD/shared-core/r300_cmdbuf.c --- drm-HEAD.orig/shared-core/r300_cmdbuf.c 2006-01-25 16:52:09.000000000 +1100 +++ drm-HEAD/shared-core/r300_cmdbuf.c 2006-01-27 06:42:21.000000000 +1100 @@ -243,10 +243,12 @@ but this value is not being kept. This code is correct for now (does the same thing as the code that sets MC_FB_LOCATION) in radeon_cp.c */ - if((offset>=dev_priv->fb_location) && - (offsetgart_vm_start))return 0; - if((offset>=dev_priv->gart_vm_start) && - (offsetgart_vm_start+dev_priv->gart_size))return 0; + if (offset >= dev_priv->fb_location && + offset < (dev_priv->fb_location + dev_priv->fb_size)) + return 0; + if (offset >= dev_priv->gart_vm_start && + offset < (dev_priv->gart_vm_start + dev_priv->gart_size)) + return 0; return 1; } diff -urN drm-HEAD.orig/shared-core/radeon_cp.c drm-HEAD/shared-core/radeon_cp.c --- drm-HEAD.orig/shared-core/radeon_cp.c 2006-01-09 19:18:24.000000000 +1100 +++ drm-HEAD/shared-core/radeon_cp.c 2006-01-26 18:15:53.000000000 +1100 @@ -1118,11 +1118,16 @@ { u32 ring_start, cur_read_ptr; u32 tmp; - - /* Initialize the memory controller */ - RADEON_WRITE(RADEON_MC_FB_LOCATION, - ((dev_priv->gart_vm_start - 1) & 0xffff0000) - | (dev_priv->fb_location >> 16)); + + /* Initialize the memory controller. With new memory map, the fb location + * is not changed, it should have been properly initialized already. Part + * of the problem is that the code below is bogus, assuming the GART is + * always appended to the fb which is not necessarily the case + */ + if (!dev_priv->new_memmap) + RADEON_WRITE(RADEON_MC_FB_LOCATION, + ((dev_priv->gart_vm_start - 1) & 0xffff0000) + | (dev_priv->fb_location >> 16)); #if __OS_HAS_AGP if (dev_priv->flags & CHIP_IS_AGP) { @@ -1489,6 +1494,9 @@ dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff) << 16; + dev_priv->fb_size = + ((RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff0000u) + 0x10000) + - dev_priv->fb_location; dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) | ((dev_priv->front_offset @@ -1504,7 +1512,39 @@ dev_priv->gart_size = init->gart_size; - dev_priv->gart_vm_start = dev_priv->fb_location + RADEON_READ(RADEON_CONFIG_APER_SIZE); + /* New let's set the memory map ... */ + if (dev_priv->new_memmap) { + u32 base = 0; + + DRM_DEBUG("Setting AGP location based on new memory map\n"); + + /* If using AGP, try to locate the AGP aperture at the same + * location in the card and on the bus, though we have to + * align it down. + */ +#if __OS_HAS_AGP + if (dev_priv->flags & CHIP_IS_AGP) { + base = dev->agp->base; + /* Check if valid */ + if ((base + dev_priv->gart_size) > dev_priv->fb_location && + base < (dev_priv->fb_location + dev_priv->fb_size)) + base = 0; + } +#endif + /* If not or if AGP is at 0 (Macs), try to put it elsewhere */ + if (base == 0) { + base = dev_priv->fb_location + dev_priv->fb_size; + if (((base + dev_priv->gart_size) & 0xfffffffful) + < base) + base = dev_priv->fb_location + - dev_priv->gart_size; + } + dev_priv->gart_vm_start = base & 0xffc00000u; + } else { + DRM_DEBUG("Setting AGP location based on old memory map\n"); + dev_priv->gart_vm_start = dev_priv->fb_location + + RADEON_READ(RADEON_CONFIG_APER_SIZE); + } #if __OS_HAS_AGP if (dev_priv->flags & CHIP_IS_AGP) diff -urN drm-HEAD.orig/shared-core/radeon_drm.h drm-HEAD/shared-core/radeon_drm.h --- drm-HEAD.orig/shared-core/radeon_drm.h 2006-01-09 19:18:24.000000000 +1100 +++ drm-HEAD/shared-core/radeon_drm.h 2006-01-25 17:16:15.000000000 +1100 @@ -698,6 +698,8 @@ #define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */ #define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */ +#define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */ + /* 1.14: Clients can allocate/free a surface */ typedef struct drm_radeon_surface_alloc { diff -urN drm-HEAD.orig/shared-core/radeon_drv.h drm-HEAD/shared-core/radeon_drv.h --- drm-HEAD.orig/shared-core/radeon_drv.h 2006-01-25 16:52:10.000000000 +1100 +++ drm-HEAD/shared-core/radeon_drv.h 2006-01-26 18:12:39.000000000 +1100 @@ -93,7 +93,7 @@ */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 22 +#define DRIVER_MINOR 23 #define DRIVER_PATCHLEVEL 0 enum radeon_family { @@ -197,6 +197,8 @@ drm_radeon_sarea_t *sarea_priv; u32 fb_location; + u32 fb_size; + int new_memmap; int gart_size; u32 gart_vm_start; diff -urN drm-HEAD.orig/shared-core/radeon_state.c drm-HEAD/shared-core/radeon_state.c --- drm-HEAD.orig/shared-core/radeon_state.c 2006-01-09 19:18:25.000000000 +1100 +++ drm-HEAD/shared-core/radeon_state.c 2006-01-26 23:18:51.000000000 +1100 @@ -45,23 +45,53 @@ u32 off = *offset; struct drm_radeon_driver_file_fields *radeon_priv; - if (off >= dev_priv->fb_location && - off < (dev_priv->gart_vm_start + dev_priv->gart_size)) + /* Hrm ... the story of the offset ... So this function converts + * the various ideas of what userland clients might have for an + * offset in the card address space into an offset into the card + * address space :) So with a sane client, it should just keep + * the value intact and just do some boundary checking. However, + * not all clients are sane. Some older clients pass us 0 based + * offsets relative to the start of the framebuffer and some may + * assume the AGP aperture it appended to the framebuffer, so we + * try to detect those cases and fix them up. + * + * Note: It might be a good idea here to make sure the offset lands + * in some "allowed" area to protect things like the PCIE GART... + */ + + /* First, the best case, the offset already lands in either the + * framebuffer or the GART mapped space + */ + if ((off >= dev_priv->fb_location && + off < (dev_priv->fb_location + dev_priv->fb_size)) || + (off >= dev_priv->gart_vm_start && + off < (dev_priv->gart_vm_start + dev_priv->gart_size))) return 0; - radeon_priv = filp_priv->driver_priv; - - off += radeon_priv->radeon_fb_delta; - - DRM_DEBUG("offset fixed up to 0x%x\n", off); - - if (off < dev_priv->fb_location || - off >= (dev_priv->gart_vm_start + dev_priv->gart_size)) - return DRM_ERR(EINVAL); - - *offset = off; + /* Ok, that didn't happen... now check if we have a zero based + * offset that fits in the framebuffer + gart space, apply the + * magic offset we get from SETPARAM or calculated from fb_location + */ + if (off < (dev_priv->fb_size + dev_priv->gart_size)) { + radeon_priv = filp_priv->driver_priv; + off += radeon_priv->radeon_fb_delta; + } - return 0; + /* Finally, assume we aimed at a GART offset if beyond the fb */ + if (off > (dev_priv->fb_location + dev_priv->fb_size)) + off = off - (dev_priv->fb_location + dev_priv->fb_size) + + dev_priv->gart_vm_start; + + /* Now recheck and fail if out of bounds */ + if ((off >= dev_priv->fb_location && + off < (dev_priv->fb_location + dev_priv->fb_size)) || + (off >= dev_priv->gart_vm_start && + off < (dev_priv->gart_vm_start + dev_priv->gart_size))) { + DRM_DEBUG("offset fixed up to 0x%x\n", off); + *offset = off; + return 0; + } + return DRM_ERR(EINVAL); } static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * @@ -3014,6 +3044,9 @@ case RADEON_SETPARAM_PCIGART_LOCATION: dev_priv->pcigart_offset = sp.value; break; + case RADEON_SETPARAM_NEW_MEMMAP: + dev_priv->new_memmap = sp.value; + break; default: DRM_DEBUG("Invalid parameter %d\n", sp.param); return DRM_ERR(EINVAL);