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

Commit d5ea702f authored by Dave Airlie's avatar Dave Airlie
Browse files

drm: rework radeon memory map (radeon 1.23)



This code reworks the radeon memory map so it works better
for newer r300 chips and for a lot of older PCI chips.

It really requires a new X driver in order to take advantage of this code.

From: Ben Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 45f17100
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -242,8 +242,10 @@ static __inline__ int r300_check_range(unsigned reg, int count)
	return 0;
}

  /* we expect offsets passed to the framebuffer to be either within video memory or
     within AGP space */
/*
 * we expect offsets passed to the framebuffer to be either within video 
 * memory or within AGP space 
 */
static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
					u32 offset)
{
@@ -251,11 +253,11 @@ static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
	   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) &&
	    (offset < dev_priv->gart_vm_start))
	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))
	if (offset >= dev_priv->gart_vm_start &&
	    offset < (dev_priv->gart_vm_start + dev_priv->gart_size))
		return 0;
	return 1;
}
@@ -490,6 +492,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,

	return 0;
}

static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
					     drm_radeon_kcmd_buffer_t *cmdbuf)
{
+100 −43
Original line number Diff line number Diff line
@@ -1119,13 +1119,19 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
	u32 ring_start, cur_read_ptr;
	u32 tmp;
	
	/* Initialize the memory controller */
	/* 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) |
@@ -1153,8 +1159,6 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,

#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);
@@ -1174,6 +1178,17 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
			  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.
@@ -1190,28 +1205,9 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,

	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);
@@ -1223,26 +1219,45 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
	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 in %d usecs\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 */
@@ -1496,6 +1511,9 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)

	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
@@ -1510,8 +1528,46 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
					  + dev_priv->fb_location) >> 10));

	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_INFO("Setting GART 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)) {
				DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
					 dev->agp->base);
				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;
		if (dev_priv->gart_vm_start != base)
			DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n",
				 base, dev_priv->gart_vm_start);
	} else {
		DRM_INFO("Setting GART 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)
@@ -1596,6 +1652,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
	dev_priv->last_buf = 0;

	radeon_do_engine_reset(dev);
	radeon_test_writeback(dev_priv);

	return 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -697,6 +697,7 @@ typedef struct drm_radeon_setparam {
#define RADEON_SETPARAM_FB_LOCATION    1	/* determined framebuffer location */
#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
 */
+7 −3
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@

#define DRIVER_NAME		"radeon"
#define DRIVER_DESC		"ATI Radeon"
#define DRIVER_DATE		"20051229"
#define DRIVER_DATE		"20060225"

/* Interface history:
 *
@@ -91,9 +91,10 @@
 * 1.20- Add support for r300 texrect
 * 1.21- Add support for card type getparam
 * 1.22- Add support for texture cache flushes (R300_TX_CNTL)
 * 1.23- Add new radeon memory map work from benh
 */
#define DRIVER_MAJOR		1
#define DRIVER_MINOR		22
#define DRIVER_MINOR		23
#define DRIVER_PATCHLEVEL	0

/*
@@ -138,7 +139,8 @@ enum radeon_chip_flags {
	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 {
@@ -199,6 +201,8 @@ typedef struct drm_radeon_private {
	drm_radeon_sarea_t *sarea_priv;

	u32 fb_location;
	u32 fb_size;
	int new_memmap;

	int gart_size;
	u32 gart_vm_start;
+46 −12
Original line number Diff line number Diff line
@@ -45,23 +45,54 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
	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;

	/* 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;
	}

	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);
	/* 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 *
						     dev_priv,
@@ -3012,6 +3043,9 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
	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);