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-02-10 16:39:32.000000000 +1100 @@ -1118,14 +1118,20 @@ { 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) { + RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); RADEON_WRITE(RADEON_MC_AGP_LOCATION, (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & 0xffff0000) | @@ -1152,8 +1158,6 @@ #if __OS_HAS_AGP if (dev_priv->flags & CHIP_IS_AGP) { - /* set RADEON_AGP_BASE here instead of relying on X from user space */ - RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset - dev->agp->base + dev_priv->gart_vm_start); @@ -1172,6 +1176,17 @@ entry->handle + tmp_ofs); } + /* Set ring buffer size */ +#ifdef __BIG_ENDIAN + RADEON_WRITE(RADEON_CP_RB_CNTL, + dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT); +#else + RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw); +#endif + + /* Start with assuming that writeback doesn't work */ + dev_priv->writeback_works = 0; + /* Initialize the scratch register pointer. This will cause * the scratch register values to be written out to memory * whenever they are updated. @@ -1188,28 +1203,9 @@ RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7); - /* Writeback doesn't seem to work everywhere, test it first */ - DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0); - RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef); - - for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) { - if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) == - 0xdeadbeef) - break; - DRM_UDELAY(1); - } - - if (tmp < dev_priv->usec_timeout) { - dev_priv->writeback_works = 1; - DRM_DEBUG("writeback test succeeded, tmp=%d\n", tmp); - } else { - dev_priv->writeback_works = 0; - DRM_DEBUG("writeback test failed\n"); - } - if (radeon_no_wb == 1) { - dev_priv->writeback_works = 0; - DRM_DEBUG("writeback forced off\n"); - } + /* Turn on bus mastering */ + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + RADEON_WRITE(RADEON_BUS_CNTL, tmp); dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); @@ -1221,26 +1217,45 @@ dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); - /* Set ring buffer size */ -#ifdef __BIG_ENDIAN - RADEON_WRITE(RADEON_CP_RB_CNTL, - dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT); -#else - RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw); -#endif - radeon_do_wait_for_idle(dev_priv); - /* Turn on bus mastering */ - tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; - RADEON_WRITE(RADEON_BUS_CNTL, tmp); - /* Sync everything up */ RADEON_WRITE(RADEON_ISYNC_CNTL, (RADEON_ISYNC_ANY2D_IDLE3D | RADEON_ISYNC_ANY3D_IDLE2D | RADEON_ISYNC_WAIT_IDLEGUI | RADEON_ISYNC_CPSCRATCH_IDLEGUI)); + +} + +static void radeon_test_writeback(drm_radeon_private_t * dev_priv) +{ + u32 tmp; + + /* Writeback doesn't seem to work everywhere, test it here and possibly + * enable it if it appears to work + */ + DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0); + RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef); + + for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) { + if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) == + 0xdeadbeef) + break; + DRM_UDELAY(1); + } + + if (tmp < dev_priv->usec_timeout) { + dev_priv->writeback_works = 1; + DRM_INFO("writeback test succeeded, tmp=%d\n", tmp); + } else { + dev_priv->writeback_works = 0; + DRM_INFO("writeback test failed\n"); + } + if (radeon_no_wb == 1) { + dev_priv->writeback_works = 0; + DRM_INFO("writeback forced off\n"); + } } /* Enable or disable PCI-E GART on the chip */ @@ -1489,6 +1504,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 +1522,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) @@ -1580,6 +1630,7 @@ dev_priv->last_buf = 0; radeon_do_engine_reset(dev); + radeon_test_writeback(dev_priv); return 0; } 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-02-10 16:20:08.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 { @@ -135,7 +135,8 @@ CHIP_IS_PCIE = 0x00200000UL, }; -#define GET_RING_HEAD(dev_priv) DRM_READ32( (dev_priv)->ring_rptr, 0 ) +#define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ + DRM_READ32( (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR)) #define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) typedef struct drm_radeon_freelist { @@ -197,6 +198,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);