diff options
author | Dave Airlie <airlied@linux.ie> | 2006-03-19 03:37:55 -0500 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2006-03-19 03:37:55 -0500 |
commit | d5ea702f1e8e3edeea6b673a58281bf99f3dbec5 (patch) | |
tree | dae329419620db61ccfaa9a50394e07c31f21d1f /drivers/char/drm | |
parent | 45f17100bfd18c99d6479e94598f4e533bbe30d8 (diff) |
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: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/char/drm')
-rw-r--r-- | drivers/char/drm/r300_cmdbuf.c | 15 | ||||
-rw-r--r-- | drivers/char/drm/radeon_cp.c | 143 | ||||
-rw-r--r-- | drivers/char/drm/radeon_drm.h | 1 | ||||
-rw-r--r-- | drivers/char/drm/radeon_drv.h | 10 | ||||
-rw-r--r-- | drivers/char/drm/radeon_state.c | 58 |
5 files changed, 163 insertions, 64 deletions
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c index 9fbadb965858..20b6cb39213d 100644 --- a/drivers/char/drm/r300_cmdbuf.c +++ b/drivers/char/drm/r300_cmdbuf.c | |||
@@ -242,8 +242,10 @@ static __inline__ int r300_check_range(unsigned reg, int count) | |||
242 | return 0; | 242 | return 0; |
243 | } | 243 | } |
244 | 244 | ||
245 | /* we expect offsets passed to the framebuffer to be either within video memory or | 245 | /* |
246 | within AGP space */ | 246 | * we expect offsets passed to the framebuffer to be either within video |
247 | * memory or within AGP space | ||
248 | */ | ||
247 | static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv, | 249 | static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv, |
248 | u32 offset) | 250 | u32 offset) |
249 | { | 251 | { |
@@ -251,11 +253,11 @@ static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv, | |||
251 | but this value is not being kept. | 253 | but this value is not being kept. |
252 | This code is correct for now (does the same thing as the | 254 | This code is correct for now (does the same thing as the |
253 | code that sets MC_FB_LOCATION) in radeon_cp.c */ | 255 | code that sets MC_FB_LOCATION) in radeon_cp.c */ |
254 | if ((offset >= dev_priv->fb_location) && | 256 | if (offset >= dev_priv->fb_location && |
255 | (offset < dev_priv->gart_vm_start)) | 257 | offset < (dev_priv->fb_location + dev_priv->fb_size)) |
256 | return 0; | 258 | return 0; |
257 | if ((offset >= dev_priv->gart_vm_start) && | 259 | if (offset >= dev_priv->gart_vm_start && |
258 | (offset < dev_priv->gart_vm_start + dev_priv->gart_size)) | 260 | offset < (dev_priv->gart_vm_start + dev_priv->gart_size)) |
259 | return 0; | 261 | return 0; |
260 | return 1; | 262 | return 1; |
261 | } | 263 | } |
@@ -490,6 +492,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, | |||
490 | 492 | ||
491 | return 0; | 493 | return 0; |
492 | } | 494 | } |
495 | |||
493 | static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, | 496 | static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, |
494 | drm_radeon_kcmd_buffer_t *cmdbuf) | 497 | drm_radeon_kcmd_buffer_t *cmdbuf) |
495 | { | 498 | { |
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 9bb8ae0c1c27..cc4942a112cb 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c | |||
@@ -1118,14 +1118,20 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, | |||
1118 | { | 1118 | { |
1119 | u32 ring_start, cur_read_ptr; | 1119 | u32 ring_start, cur_read_ptr; |
1120 | u32 tmp; | 1120 | u32 tmp; |
1121 | 1121 | ||
1122 | /* Initialize the memory controller */ | 1122 | /* Initialize the memory controller. With new memory map, the fb location |
1123 | RADEON_WRITE(RADEON_MC_FB_LOCATION, | 1123 | * is not changed, it should have been properly initialized already. Part |
1124 | ((dev_priv->gart_vm_start - 1) & 0xffff0000) | 1124 | * of the problem is that the code below is bogus, assuming the GART is |
1125 | | (dev_priv->fb_location >> 16)); | 1125 | * always appended to the fb which is not necessarily the case |
1126 | */ | ||
1127 | if (!dev_priv->new_memmap) | ||
1128 | RADEON_WRITE(RADEON_MC_FB_LOCATION, | ||
1129 | ((dev_priv->gart_vm_start - 1) & 0xffff0000) | ||
1130 | | (dev_priv->fb_location >> 16)); | ||
1126 | 1131 | ||
1127 | #if __OS_HAS_AGP | 1132 | #if __OS_HAS_AGP |
1128 | if (dev_priv->flags & CHIP_IS_AGP) { | 1133 | if (dev_priv->flags & CHIP_IS_AGP) { |
1134 | RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); | ||
1129 | RADEON_WRITE(RADEON_MC_AGP_LOCATION, | 1135 | RADEON_WRITE(RADEON_MC_AGP_LOCATION, |
1130 | (((dev_priv->gart_vm_start - 1 + | 1136 | (((dev_priv->gart_vm_start - 1 + |
1131 | dev_priv->gart_size) & 0xffff0000) | | 1137 | dev_priv->gart_size) & 0xffff0000) | |
@@ -1153,8 +1159,6 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, | |||
1153 | 1159 | ||
1154 | #if __OS_HAS_AGP | 1160 | #if __OS_HAS_AGP |
1155 | if (dev_priv->flags & CHIP_IS_AGP) { | 1161 | if (dev_priv->flags & CHIP_IS_AGP) { |
1156 | /* set RADEON_AGP_BASE here instead of relying on X from user space */ | ||
1157 | RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); | ||
1158 | RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, | 1162 | RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, |
1159 | dev_priv->ring_rptr->offset | 1163 | dev_priv->ring_rptr->offset |
1160 | - dev->agp->base + dev_priv->gart_vm_start); | 1164 | - dev->agp->base + dev_priv->gart_vm_start); |
@@ -1174,6 +1178,17 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, | |||
1174 | entry->handle + tmp_ofs); | 1178 | entry->handle + tmp_ofs); |
1175 | } | 1179 | } |
1176 | 1180 | ||
1181 | /* Set ring buffer size */ | ||
1182 | #ifdef __BIG_ENDIAN | ||
1183 | RADEON_WRITE(RADEON_CP_RB_CNTL, | ||
1184 | dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT); | ||
1185 | #else | ||
1186 | RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw); | ||
1187 | #endif | ||
1188 | |||
1189 | /* Start with assuming that writeback doesn't work */ | ||
1190 | dev_priv->writeback_works = 0; | ||
1191 | |||
1177 | /* Initialize the scratch register pointer. This will cause | 1192 | /* Initialize the scratch register pointer. This will cause |
1178 | * the scratch register values to be written out to memory | 1193 | * the scratch register values to be written out to memory |
1179 | * whenever they are updated. | 1194 | * whenever they are updated. |
@@ -1190,28 +1205,9 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, | |||
1190 | 1205 | ||
1191 | RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7); | 1206 | RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7); |
1192 | 1207 | ||
1193 | /* Writeback doesn't seem to work everywhere, test it first */ | 1208 | /* Turn on bus mastering */ |
1194 | DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0); | 1209 | tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; |
1195 | RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef); | 1210 | RADEON_WRITE(RADEON_BUS_CNTL, tmp); |
1196 | |||
1197 | for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) { | ||
1198 | if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) == | ||
1199 | 0xdeadbeef) | ||
1200 | break; | ||
1201 | DRM_UDELAY(1); | ||
1202 | } | ||
1203 | |||
1204 | if (tmp < dev_priv->usec_timeout) { | ||
1205 | dev_priv->writeback_works = 1; | ||
1206 | DRM_DEBUG("writeback test succeeded, tmp=%d\n", tmp); | ||
1207 | } else { | ||
1208 | dev_priv->writeback_works = 0; | ||
1209 | DRM_DEBUG("writeback test failed\n"); | ||
1210 | } | ||
1211 | if (radeon_no_wb == 1) { | ||
1212 | dev_priv->writeback_works = 0; | ||
1213 | DRM_DEBUG("writeback forced off\n"); | ||
1214 | } | ||
1215 | 1211 | ||
1216 | dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; | 1212 | dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; |
1217 | RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); | 1213 | 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, | |||
1223 | dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; | 1219 | dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; |
1224 | RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); | 1220 | RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); |
1225 | 1221 | ||
1226 | /* Set ring buffer size */ | ||
1227 | #ifdef __BIG_ENDIAN | ||
1228 | RADEON_WRITE(RADEON_CP_RB_CNTL, | ||
1229 | dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT); | ||
1230 | #else | ||
1231 | RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw); | ||
1232 | #endif | ||
1233 | |||
1234 | radeon_do_wait_for_idle(dev_priv); | 1222 | radeon_do_wait_for_idle(dev_priv); |
1235 | 1223 | ||
1236 | /* Turn on bus mastering */ | ||
1237 | tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; | ||
1238 | RADEON_WRITE(RADEON_BUS_CNTL, tmp); | ||
1239 | |||
1240 | /* Sync everything up */ | 1224 | /* Sync everything up */ |
1241 | RADEON_WRITE(RADEON_ISYNC_CNTL, | 1225 | RADEON_WRITE(RADEON_ISYNC_CNTL, |
1242 | (RADEON_ISYNC_ANY2D_IDLE3D | | 1226 | (RADEON_ISYNC_ANY2D_IDLE3D | |
1243 | RADEON_ISYNC_ANY3D_IDLE2D | | 1227 | RADEON_ISYNC_ANY3D_IDLE2D | |
1244 | RADEON_ISYNC_WAIT_IDLEGUI | | 1228 | RADEON_ISYNC_WAIT_IDLEGUI | |
1245 | RADEON_ISYNC_CPSCRATCH_IDLEGUI)); | 1229 | RADEON_ISYNC_CPSCRATCH_IDLEGUI)); |
1230 | |||
1231 | } | ||
1232 | |||
1233 | static void radeon_test_writeback(drm_radeon_private_t * dev_priv) | ||
1234 | { | ||
1235 | u32 tmp; | ||
1236 | |||
1237 | /* Writeback doesn't seem to work everywhere, test it here and possibly | ||
1238 | * enable it if it appears to work | ||
1239 | */ | ||
1240 | DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0); | ||
1241 | RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef); | ||
1242 | |||
1243 | for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) { | ||
1244 | if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) == | ||
1245 | 0xdeadbeef) | ||
1246 | break; | ||
1247 | DRM_UDELAY(1); | ||
1248 | } | ||
1249 | |||
1250 | if (tmp < dev_priv->usec_timeout) { | ||
1251 | dev_priv->writeback_works = 1; | ||
1252 | DRM_INFO("writeback test succeeded in %d usecs\n", tmp); | ||
1253 | } else { | ||
1254 | dev_priv->writeback_works = 0; | ||
1255 | DRM_INFO("writeback test failed\n"); | ||
1256 | } | ||
1257 | if (radeon_no_wb == 1) { | ||
1258 | dev_priv->writeback_works = 0; | ||
1259 | DRM_INFO("writeback forced off\n"); | ||
1260 | } | ||
1246 | } | 1261 | } |
1247 | 1262 | ||
1248 | /* Enable or disable PCI-E GART on the chip */ | 1263 | /* 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) | |||
1496 | 1511 | ||
1497 | dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION) | 1512 | dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION) |
1498 | & 0xffff) << 16; | 1513 | & 0xffff) << 16; |
1514 | dev_priv->fb_size = | ||
1515 | ((RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff0000u) + 0x10000) | ||
1516 | - dev_priv->fb_location; | ||
1499 | 1517 | ||
1500 | dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) | | 1518 | dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) | |
1501 | ((dev_priv->front_offset | 1519 | ((dev_priv->front_offset |
@@ -1510,8 +1528,46 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) | |||
1510 | + dev_priv->fb_location) >> 10)); | 1528 | + dev_priv->fb_location) >> 10)); |
1511 | 1529 | ||
1512 | dev_priv->gart_size = init->gart_size; | 1530 | dev_priv->gart_size = init->gart_size; |
1513 | dev_priv->gart_vm_start = dev_priv->fb_location | 1531 | |
1514 | + RADEON_READ(RADEON_CONFIG_APER_SIZE); | 1532 | /* New let's set the memory map ... */ |
1533 | if (dev_priv->new_memmap) { | ||
1534 | u32 base = 0; | ||
1535 | |||
1536 | DRM_INFO("Setting GART location based on new memory map\n"); | ||
1537 | |||
1538 | /* If using AGP, try to locate the AGP aperture at the same | ||
1539 | * location in the card and on the bus, though we have to | ||
1540 | * align it down. | ||
1541 | */ | ||
1542 | #if __OS_HAS_AGP | ||
1543 | if (dev_priv->flags & CHIP_IS_AGP) { | ||
1544 | base = dev->agp->base; | ||
1545 | /* Check if valid */ | ||
1546 | if ((base + dev_priv->gart_size) > dev_priv->fb_location && | ||
1547 | base < (dev_priv->fb_location + dev_priv->fb_size)) { | ||
1548 | DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n", | ||
1549 | dev->agp->base); | ||
1550 | base = 0; | ||
1551 | } | ||
1552 | } | ||
1553 | #endif | ||
1554 | /* If not or if AGP is at 0 (Macs), try to put it elsewhere */ | ||
1555 | if (base == 0) { | ||
1556 | base = dev_priv->fb_location + dev_priv->fb_size; | ||
1557 | if (((base + dev_priv->gart_size) & 0xfffffffful) | ||
1558 | < base) | ||
1559 | base = dev_priv->fb_location | ||
1560 | - dev_priv->gart_size; | ||
1561 | } | ||
1562 | dev_priv->gart_vm_start = base & 0xffc00000u; | ||
1563 | if (dev_priv->gart_vm_start != base) | ||
1564 | DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n", | ||
1565 | base, dev_priv->gart_vm_start); | ||
1566 | } else { | ||
1567 | DRM_INFO("Setting GART location based on old memory map\n"); | ||
1568 | dev_priv->gart_vm_start = dev_priv->fb_location + | ||
1569 | RADEON_READ(RADEON_CONFIG_APER_SIZE); | ||
1570 | } | ||
1515 | 1571 | ||
1516 | #if __OS_HAS_AGP | 1572 | #if __OS_HAS_AGP |
1517 | if (dev_priv->flags & CHIP_IS_AGP) | 1573 | 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) | |||
1596 | dev_priv->last_buf = 0; | 1652 | dev_priv->last_buf = 0; |
1597 | 1653 | ||
1598 | radeon_do_engine_reset(dev); | 1654 | radeon_do_engine_reset(dev); |
1655 | radeon_test_writeback(dev_priv); | ||
1599 | 1656 | ||
1600 | return 0; | 1657 | return 0; |
1601 | } | 1658 | } |
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h index 9c177a6b2a4c..bb63e6806fd1 100644 --- a/drivers/char/drm/radeon_drm.h +++ b/drivers/char/drm/radeon_drm.h | |||
@@ -697,6 +697,7 @@ typedef struct drm_radeon_setparam { | |||
697 | #define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ | 697 | #define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ |
698 | #define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */ | 698 | #define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */ |
699 | #define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */ | 699 | #define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */ |
700 | #define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */ | ||
700 | 701 | ||
701 | /* 1.14: Clients can allocate/free a surface | 702 | /* 1.14: Clients can allocate/free a surface |
702 | */ | 703 | */ |
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 1f7d2ab8c4fc..a0c198895a27 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h | |||
@@ -38,7 +38,7 @@ | |||
38 | 38 | ||
39 | #define DRIVER_NAME "radeon" | 39 | #define DRIVER_NAME "radeon" |
40 | #define DRIVER_DESC "ATI Radeon" | 40 | #define DRIVER_DESC "ATI Radeon" |
41 | #define DRIVER_DATE "20051229" | 41 | #define DRIVER_DATE "20060225" |
42 | 42 | ||
43 | /* Interface history: | 43 | /* Interface history: |
44 | * | 44 | * |
@@ -91,9 +91,10 @@ | |||
91 | * 1.20- Add support for r300 texrect | 91 | * 1.20- Add support for r300 texrect |
92 | * 1.21- Add support for card type getparam | 92 | * 1.21- Add support for card type getparam |
93 | * 1.22- Add support for texture cache flushes (R300_TX_CNTL) | 93 | * 1.22- Add support for texture cache flushes (R300_TX_CNTL) |
94 | * 1.23- Add new radeon memory map work from benh | ||
94 | */ | 95 | */ |
95 | #define DRIVER_MAJOR 1 | 96 | #define DRIVER_MAJOR 1 |
96 | #define DRIVER_MINOR 22 | 97 | #define DRIVER_MINOR 23 |
97 | #define DRIVER_PATCHLEVEL 0 | 98 | #define DRIVER_PATCHLEVEL 0 |
98 | 99 | ||
99 | /* | 100 | /* |
@@ -138,7 +139,8 @@ enum radeon_chip_flags { | |||
138 | CHIP_IS_PCIE = 0x00200000UL, | 139 | CHIP_IS_PCIE = 0x00200000UL, |
139 | }; | 140 | }; |
140 | 141 | ||
141 | #define GET_RING_HEAD(dev_priv) DRM_READ32( (dev_priv)->ring_rptr, 0 ) | 142 | #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ |
143 | DRM_READ32( (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR)) | ||
142 | #define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) | 144 | #define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) |
143 | 145 | ||
144 | typedef struct drm_radeon_freelist { | 146 | typedef struct drm_radeon_freelist { |
@@ -199,6 +201,8 @@ typedef struct drm_radeon_private { | |||
199 | drm_radeon_sarea_t *sarea_priv; | 201 | drm_radeon_sarea_t *sarea_priv; |
200 | 202 | ||
201 | u32 fb_location; | 203 | u32 fb_location; |
204 | u32 fb_size; | ||
205 | int new_memmap; | ||
202 | 206 | ||
203 | int gart_size; | 207 | int gart_size; |
204 | u32 gart_vm_start; | 208 | u32 gart_vm_start; |
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 7bc27516d425..56e56b873616 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c | |||
@@ -45,22 +45,53 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * | |||
45 | u32 off = *offset; | 45 | u32 off = *offset; |
46 | struct drm_radeon_driver_file_fields *radeon_priv; | 46 | struct drm_radeon_driver_file_fields *radeon_priv; |
47 | 47 | ||
48 | if (off >= dev_priv->fb_location && | 48 | /* Hrm ... the story of the offset ... So this function converts |
49 | off < (dev_priv->gart_vm_start + dev_priv->gart_size)) | 49 | * the various ideas of what userland clients might have for an |
50 | return 0; | 50 | * offset in the card address space into an offset into the card |
51 | 51 | * address space :) So with a sane client, it should just keep | |
52 | radeon_priv = filp_priv->driver_priv; | 52 | * the value intact and just do some boundary checking. However, |
53 | off += radeon_priv->radeon_fb_delta; | 53 | * not all clients are sane. Some older clients pass us 0 based |
54 | * offsets relative to the start of the framebuffer and some may | ||
55 | * assume the AGP aperture it appended to the framebuffer, so we | ||
56 | * try to detect those cases and fix them up. | ||
57 | * | ||
58 | * Note: It might be a good idea here to make sure the offset lands | ||
59 | * in some "allowed" area to protect things like the PCIE GART... | ||
60 | */ | ||
54 | 61 | ||
55 | DRM_DEBUG("offset fixed up to 0x%x\n", off); | 62 | /* First, the best case, the offset already lands in either the |
63 | * framebuffer or the GART mapped space | ||
64 | */ | ||
65 | if ((off >= dev_priv->fb_location && | ||
66 | off < (dev_priv->fb_location + dev_priv->fb_size)) || | ||
67 | (off >= dev_priv->gart_vm_start && | ||
68 | off < (dev_priv->gart_vm_start + dev_priv->gart_size))) | ||
69 | return 0; | ||
56 | 70 | ||
57 | if (off < dev_priv->fb_location || | 71 | /* Ok, that didn't happen... now check if we have a zero based |
58 | off >= (dev_priv->gart_vm_start + dev_priv->gart_size)) | 72 | * offset that fits in the framebuffer + gart space, apply the |
59 | return DRM_ERR(EINVAL); | 73 | * magic offset we get from SETPARAM or calculated from fb_location |
74 | */ | ||
75 | if (off < (dev_priv->fb_size + dev_priv->gart_size)) { | ||
76 | radeon_priv = filp_priv->driver_priv; | ||
77 | off += radeon_priv->radeon_fb_delta; | ||
78 | } | ||
60 | 79 | ||
61 | *offset = off; | 80 | /* Finally, assume we aimed at a GART offset if beyond the fb */ |
81 | if (off > (dev_priv->fb_location + dev_priv->fb_size)) | ||
82 | off = off - (dev_priv->fb_location + dev_priv->fb_size) + | ||
83 | dev_priv->gart_vm_start; | ||
62 | 84 | ||
63 | return 0; | 85 | /* Now recheck and fail if out of bounds */ |
86 | if ((off >= dev_priv->fb_location && | ||
87 | off < (dev_priv->fb_location + dev_priv->fb_size)) || | ||
88 | (off >= dev_priv->gart_vm_start && | ||
89 | off < (dev_priv->gart_vm_start + dev_priv->gart_size))) { | ||
90 | DRM_DEBUG("offset fixed up to 0x%x\n", off); | ||
91 | *offset = off; | ||
92 | return 0; | ||
93 | } | ||
94 | return DRM_ERR(EINVAL); | ||
64 | } | 95 | } |
65 | 96 | ||
66 | static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * | 97 | static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * |
@@ -3012,6 +3043,9 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) | |||
3012 | case RADEON_SETPARAM_PCIGART_LOCATION: | 3043 | case RADEON_SETPARAM_PCIGART_LOCATION: |
3013 | dev_priv->pcigart_offset = sp.value; | 3044 | dev_priv->pcigart_offset = sp.value; |
3014 | break; | 3045 | break; |
3046 | case RADEON_SETPARAM_NEW_MEMMAP: | ||
3047 | dev_priv->new_memmap = sp.value; | ||
3048 | break; | ||
3015 | default: | 3049 | default: |
3016 | DRM_DEBUG("Invalid parameter %d\n", sp.param); | 3050 | DRM_DEBUG("Invalid parameter %d\n", sp.param); |
3017 | return DRM_ERR(EINVAL); | 3051 | return DRM_ERR(EINVAL); |