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 | |
| 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>
| -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); |
