Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+164 -65
+9 -6
drivers/char/drm/r300_cmdbuf.c
··· 242 242 return 0; 243 243 } 244 244 245 - /* we expect offsets passed to the framebuffer to be either within video memory or 246 - within AGP space */ 245 + /* 246 + * we expect offsets passed to the framebuffer to be either within video 247 + * memory or within AGP space 248 + */ 247 249 static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv, 248 250 u32 offset) 249 251 { ··· 253 251 but this value is not being kept. 254 252 This code is correct for now (does the same thing as the 255 253 code that sets MC_FB_LOCATION) in radeon_cp.c */ 256 - if ((offset >= dev_priv->fb_location) && 257 - (offset < dev_priv->gart_vm_start)) 254 + if (offset >= dev_priv->fb_location && 255 + offset < (dev_priv->fb_location + dev_priv->fb_size)) 258 256 return 0; 259 - if ((offset >= dev_priv->gart_vm_start) && 260 - (offset < dev_priv->gart_vm_start + dev_priv->gart_size)) 257 + if (offset >= dev_priv->gart_vm_start && 258 + offset < (dev_priv->gart_vm_start + dev_priv->gart_size)) 261 259 return 0; 262 260 return 1; 263 261 } ··· 492 490 493 491 return 0; 494 492 } 493 + 495 494 static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, 496 495 drm_radeon_kcmd_buffer_t *cmdbuf) 497 496 {
+101 -44
drivers/char/drm/radeon_cp.c
··· 1118 1118 { 1119 1119 u32 ring_start, cur_read_ptr; 1120 1120 u32 tmp; 1121 - 1122 - /* Initialize the memory controller */ 1123 - RADEON_WRITE(RADEON_MC_FB_LOCATION, 1124 - ((dev_priv->gart_vm_start - 1) & 0xffff0000) 1125 - | (dev_priv->fb_location >> 16)); 1121 + 1122 + /* Initialize the memory controller. With new memory map, the fb location 1123 + * is not changed, it should have been properly initialized already. Part 1124 + * of the problem is that the code below is bogus, assuming the GART is 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 1132 #if __OS_HAS_AGP 1128 1133 if (dev_priv->flags & CHIP_IS_AGP) { 1134 + RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); 1129 1135 RADEON_WRITE(RADEON_MC_AGP_LOCATION, 1130 1136 (((dev_priv->gart_vm_start - 1 + 1131 1137 dev_priv->gart_size) & 0xffff0000) | ··· 1159 1153 1160 1154 #if __OS_HAS_AGP 1161 1155 if (dev_priv->flags & CHIP_IS_AGP) { 1162 - /* set RADEON_AGP_BASE here instead of relying on X from user space */ 1163 - RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); 1164 1156 RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, 1165 1157 dev_priv->ring_rptr->offset 1166 1158 - dev->agp->base + dev_priv->gart_vm_start); ··· 1178 1174 entry->handle + tmp_ofs); 1179 1175 } 1180 1176 1177 + /* Set ring buffer size */ 1178 + #ifdef __BIG_ENDIAN 1179 + RADEON_WRITE(RADEON_CP_RB_CNTL, 1180 + dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT); 1181 + #else 1182 + RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw); 1183 + #endif 1184 + 1185 + /* Start with assuming that writeback doesn't work */ 1186 + dev_priv->writeback_works = 0; 1187 + 1181 1188 /* Initialize the scratch register pointer. This will cause 1182 1189 * the scratch register values to be written out to memory 1183 1190 * whenever they are updated. ··· 1205 1190 1206 1191 RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7); 1207 1192 1208 - /* Writeback doesn't seem to work everywhere, test it first */ 1193 + /* Turn on bus mastering */ 1194 + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; 1195 + RADEON_WRITE(RADEON_BUS_CNTL, tmp); 1196 + 1197 + dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; 1198 + RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); 1199 + 1200 + dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0; 1201 + RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 1202 + dev_priv->sarea_priv->last_dispatch); 1203 + 1204 + dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; 1205 + RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); 1206 + 1207 + radeon_do_wait_for_idle(dev_priv); 1208 + 1209 + /* Sync everything up */ 1210 + RADEON_WRITE(RADEON_ISYNC_CNTL, 1211 + (RADEON_ISYNC_ANY2D_IDLE3D | 1212 + RADEON_ISYNC_ANY3D_IDLE2D | 1213 + RADEON_ISYNC_WAIT_IDLEGUI | 1214 + RADEON_ISYNC_CPSCRATCH_IDLEGUI)); 1215 + 1216 + } 1217 + 1218 + static void radeon_test_writeback(drm_radeon_private_t * dev_priv) 1219 + { 1220 + u32 tmp; 1221 + 1222 + /* Writeback doesn't seem to work everywhere, test it here and possibly 1223 + * enable it if it appears to work 1224 + */ 1209 1225 DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0); 1210 1226 RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef); 1211 1227 ··· 1249 1203 1250 1204 if (tmp < dev_priv->usec_timeout) { 1251 1205 dev_priv->writeback_works = 1; 1252 - DRM_DEBUG("writeback test succeeded, tmp=%d\n", tmp); 1206 + DRM_INFO("writeback test succeeded in %d usecs\n", tmp); 1253 1207 } else { 1254 1208 dev_priv->writeback_works = 0; 1255 - DRM_DEBUG("writeback test failed\n"); 1209 + DRM_INFO("writeback test failed\n"); 1256 1210 } 1257 1211 if (radeon_no_wb == 1) { 1258 1212 dev_priv->writeback_works = 0; 1259 - DRM_DEBUG("writeback forced off\n"); 1213 + DRM_INFO("writeback forced off\n"); 1260 1214 } 1261 - 1262 - dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; 1263 - RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); 1264 - 1265 - dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0; 1266 - RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 1267 - dev_priv->sarea_priv->last_dispatch); 1268 - 1269 - dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; 1270 - RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); 1271 - 1272 - /* Set ring buffer size */ 1273 - #ifdef __BIG_ENDIAN 1274 - RADEON_WRITE(RADEON_CP_RB_CNTL, 1275 - dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT); 1276 - #else 1277 - RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw); 1278 - #endif 1279 - 1280 - radeon_do_wait_for_idle(dev_priv); 1281 - 1282 - /* Turn on bus mastering */ 1283 - tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; 1284 - RADEON_WRITE(RADEON_BUS_CNTL, tmp); 1285 - 1286 - /* Sync everything up */ 1287 - RADEON_WRITE(RADEON_ISYNC_CNTL, 1288 - (RADEON_ISYNC_ANY2D_IDLE3D | 1289 - RADEON_ISYNC_ANY3D_IDLE2D | 1290 - RADEON_ISYNC_WAIT_IDLEGUI | 1291 - RADEON_ISYNC_CPSCRATCH_IDLEGUI)); 1292 1215 } 1293 1216 1294 1217 /* Enable or disable PCI-E GART on the chip */ ··· 1511 1496 1512 1497 dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION) 1513 1498 & 0xffff) << 16; 1499 + dev_priv->fb_size = 1500 + ((RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff0000u) + 0x10000) 1501 + - dev_priv->fb_location; 1514 1502 1515 1503 dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) | 1516 1504 ((dev_priv->front_offset ··· 1528 1510 + dev_priv->fb_location) >> 10)); 1529 1511 1530 1512 dev_priv->gart_size = init->gart_size; 1531 - dev_priv->gart_vm_start = dev_priv->fb_location 1532 - + RADEON_READ(RADEON_CONFIG_APER_SIZE); 1513 + 1514 + /* New let's set the memory map ... */ 1515 + if (dev_priv->new_memmap) { 1516 + u32 base = 0; 1517 + 1518 + DRM_INFO("Setting GART location based on new memory map\n"); 1519 + 1520 + /* If using AGP, try to locate the AGP aperture at the same 1521 + * location in the card and on the bus, though we have to 1522 + * align it down. 1523 + */ 1524 + #if __OS_HAS_AGP 1525 + if (dev_priv->flags & CHIP_IS_AGP) { 1526 + base = dev->agp->base; 1527 + /* Check if valid */ 1528 + if ((base + dev_priv->gart_size) > dev_priv->fb_location && 1529 + base < (dev_priv->fb_location + dev_priv->fb_size)) { 1530 + DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n", 1531 + dev->agp->base); 1532 + base = 0; 1533 + } 1534 + } 1535 + #endif 1536 + /* If not or if AGP is at 0 (Macs), try to put it elsewhere */ 1537 + if (base == 0) { 1538 + base = dev_priv->fb_location + dev_priv->fb_size; 1539 + if (((base + dev_priv->gart_size) & 0xfffffffful) 1540 + < base) 1541 + base = dev_priv->fb_location 1542 + - dev_priv->gart_size; 1543 + } 1544 + dev_priv->gart_vm_start = base & 0xffc00000u; 1545 + if (dev_priv->gart_vm_start != base) 1546 + DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n", 1547 + base, dev_priv->gart_vm_start); 1548 + } else { 1549 + DRM_INFO("Setting GART location based on old memory map\n"); 1550 + dev_priv->gart_vm_start = dev_priv->fb_location + 1551 + RADEON_READ(RADEON_CONFIG_APER_SIZE); 1552 + } 1533 1553 1534 1554 #if __OS_HAS_AGP 1535 1555 if (dev_priv->flags & CHIP_IS_AGP) ··· 1652 1596 dev_priv->last_buf = 0; 1653 1597 1654 1598 radeon_do_engine_reset(dev); 1599 + radeon_test_writeback(dev_priv); 1655 1600 1656 1601 return 0; 1657 1602 }
+1
drivers/char/drm/radeon_drm.h
··· 697 697 #define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ 698 698 #define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */ 699 699 #define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */ 700 + #define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */ 700 701 701 702 /* 1.14: Clients can allocate/free a surface 702 703 */
+7 -3
drivers/char/drm/radeon_drv.h
··· 38 38 39 39 #define DRIVER_NAME "radeon" 40 40 #define DRIVER_DESC "ATI Radeon" 41 - #define DRIVER_DATE "20051229" 41 + #define DRIVER_DATE "20060225" 42 42 43 43 /* Interface history: 44 44 * ··· 91 91 * 1.20- Add support for r300 texrect 92 92 * 1.21- Add support for card type getparam 93 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 96 #define DRIVER_MAJOR 1 96 - #define DRIVER_MINOR 22 97 + #define DRIVER_MINOR 23 97 98 #define DRIVER_PATCHLEVEL 0 98 99 99 100 /* ··· 139 138 CHIP_IS_PCIE = 0x00200000UL, 140 139 }; 141 140 142 - #define GET_RING_HEAD(dev_priv) DRM_READ32( (dev_priv)->ring_rptr, 0 ) 141 + #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ 142 + DRM_READ32( (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR)) 143 143 #define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) 144 144 145 145 typedef struct drm_radeon_freelist { ··· 201 199 drm_radeon_sarea_t *sarea_priv; 202 200 203 201 u32 fb_location; 202 + u32 fb_size; 203 + int new_memmap; 204 204 205 205 int gart_size; 206 206 u32 gart_vm_start;
+46 -12
drivers/char/drm/radeon_state.c
··· 45 45 u32 off = *offset; 46 46 struct drm_radeon_driver_file_fields *radeon_priv; 47 47 48 - if (off >= dev_priv->fb_location && 49 - off < (dev_priv->gart_vm_start + dev_priv->gart_size)) 48 + /* Hrm ... the story of the offset ... So this function converts 49 + * the various ideas of what userland clients might have for an 50 + * offset in the card address space into an offset into the card 51 + * address space :) So with a sane client, it should just keep 52 + * the value intact and just do some boundary checking. However, 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 + */ 61 + 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))) 50 69 return 0; 51 70 52 - radeon_priv = filp_priv->driver_priv; 53 - off += radeon_priv->radeon_fb_delta; 71 + /* Ok, that didn't happen... now check if we have a zero based 72 + * offset that fits in the framebuffer + gart space, apply the 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 + } 54 79 55 - DRM_DEBUG("offset fixed up to 0x%x\n", 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; 56 84 57 - if (off < dev_priv->fb_location || 58 - off >= (dev_priv->gart_vm_start + dev_priv->gart_size)) 59 - return DRM_ERR(EINVAL); 60 - 61 - *offset = off; 62 - 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 97 static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * ··· 3042 3011 break; 3043 3012 case RADEON_SETPARAM_PCIGART_LOCATION: 3044 3013 dev_priv->pcigart_offset = sp.value; 3014 + break; 3015 + case RADEON_SETPARAM_NEW_MEMMAP: 3016 + dev_priv->new_memmap = sp.value; 3045 3017 break; 3046 3018 default: 3047 3019 DRM_DEBUG("Invalid parameter %d\n", sp.param);