lx_memory.c revision c744f008
1/* Copyright (c) 2008 Advanced Micro Devices, Inc. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 * 21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its 22 * contributors may be used to endorse or promote products derived from this 23 * software without specific prior written permission. 24 */ 25#if HAVE_CONFIG_H 26#include "config.h" 27#endif 28 29#include "xorg-server.h" 30 31#include "xf86.h" 32#include "geode.h" 33#include "cim/cim_regs.h" 34 35#define ALIGN(x,y) (((x) + (y) - 1) / (y) * (y)) 36#define LX_CB_PITCH 544 37 38/* Geode offscreen memory allocation functions. This is 39 overengineered for the simple hardware that we have, but 40 there are multiple functions that may want to independently 41 allocate and free memory (crtc->shadow_alloc and Xv). This 42 provides a semi-robust mechanism for doing that. 43*/ 44 45/* Return the number of free bytes */ 46 47unsigned int 48GeodeOffscreenFreeSize(GeodeRec * pGeode) 49{ 50 GeodeMemPtr ptr = pGeode->offscreenList; 51 52 if (ptr == NULL) 53 return pGeode->offscreenSize; 54 55 for (; ptr->next; ptr = ptr->next); 56 return (pGeode->offscreenStart + pGeode->offscreenSize) 57 - (ptr->offset + ptr->size); 58} 59 60void 61GeodeFreeOffscreen(GeodeRec * pGeode, GeodeMemPtr ptr) 62{ 63 /* There is a clear memory leak here, but 64 * but it is unlikely that the first block of 65 * "allocated" memory is going to be released 66 * individually. 67 */ 68 69 if (ptr->prev == NULL) 70 pGeode->offscreenList = ptr->next; 71 else 72 ptr->prev->next = ptr->next; 73 74 if (ptr->next) 75 ptr->next->prev = ptr->prev; 76 77 free(ptr); 78} 79 80/* Allocate the "rest" of the offscreen memory - this is for 81 situations where we have very little video memory, and we 82 want to take as much of it as we can for EXA 83*/ 84 85static GeodeMemPtr 86GeodeAllocRemainder(GeodeRec * pGeode) 87{ 88 GeodeMemPtr nptr, ptr = pGeode->offscreenList; 89 90 if (!pGeode->offscreenList) { 91 pGeode->offscreenList = calloc(1, sizeof(*nptr)); 92 pGeode->offscreenList->offset = pGeode->offscreenStart; 93 pGeode->offscreenList->size = pGeode->offscreenSize; 94 pGeode->offscreenList->next = NULL; 95 pGeode->offscreenList->prev = NULL; 96 97 return pGeode->offscreenList; 98 } 99 100 /* Go to the end of the list of allocated stuff */ 101 for (; ptr->next; ptr = ptr->next); 102 103 nptr = calloc(1, sizeof(*nptr)); 104 nptr->offset = ptr->offset + ptr->size; 105 nptr->size = pGeode->offscreenSize - 106 (nptr->offset - pGeode->offscreenStart); 107 108 nptr->next = ptr->next; 109 nptr->prev = ptr; 110 ptr->next = nptr; 111 112 return nptr; 113} 114 115/* Allocate 'size' bytes of offscreen memory. 116*/ 117 118GeodeMemPtr 119GeodeAllocOffscreen(GeodeRec * pGeode, int size, int align) 120{ 121 GeodeMemPtr ptr = pGeode->offscreenList; 122 GeodeMemPtr nptr; 123 124 unsigned int offset; 125 126 if (!pGeode->offscreenList) { 127 128 if (size > pGeode->offscreenSize) 129 return NULL; 130 131 offset = ALIGN(pGeode->offscreenStart, align); 132 133 pGeode->offscreenList = calloc(1, sizeof(*nptr)); 134 pGeode->offscreenList->offset = offset; 135 pGeode->offscreenList->size = size; 136 pGeode->offscreenList->next = NULL; 137 138 return pGeode->offscreenList; 139 } 140 141 while (ptr) { 142 unsigned int gap; 143 144 if (ptr->next == NULL) 145 gap = pGeode->offscreenSize + pGeode->offscreenStart; 146 147 else 148 gap = ptr->next->offset; 149 150 gap = gap - (ptr->offset + ptr->size); 151 gap = ALIGN(gap, align); 152 153 if (size < gap) { 154 offset = ptr->offset + ptr->size; 155 offset = ALIGN(ptr->offset + ptr->size, align); 156 157 nptr = calloc(1, sizeof(*nptr)); 158 nptr->offset = offset; 159 nptr->size = size; 160 nptr->next = ptr->next; 161 nptr->prev = ptr; 162 ptr->next = nptr; 163 164 return nptr; 165 } 166 167 ptr = ptr->next; 168 } 169 170 return NULL; 171} 172 173/* Carve out the space for the visible screen, and carve out 174 the usual suspects that need offscreen memory 175*/ 176 177#define MAX(a,b) ((a) > (b) ? (a) : (b)) 178 179void 180LXInitOffscreen(ScrnInfoPtr pScrni) 181{ 182 GeodeRec *pGeode = GEODEPTR(pScrni); 183 unsigned int fbavail; 184 GeodeMemPtr ptr; 185 186 /* The scratch buffer is always used */ 187 fbavail = pGeode->FBAvail - GP3_SCRATCH_BUFFER_SIZE; 188 189 pGeode->displaySize = MAX(pScrni->virtualX, pScrni->virtualY) 190 * pGeode->Pitch; 191 192 pGeode->offscreenStart = pGeode->displaySize; 193 pGeode->offscreenSize = fbavail - pGeode->displaySize; 194 195 /* Allocate the usual memory suspects */ 196 if (pGeode->tryCompression) { 197 int size = pScrni->virtualY * LX_CB_PITCH; 198 199 /* The compression buffer needs to be 16 byte aligned */ 200 ptr = GeodeAllocOffscreen(pGeode, size, 16); 201 202 if (ptr != NULL) { 203 pGeode->CBData.compression_offset = ptr->offset; 204 pGeode->CBData.size = LX_CB_PITCH; 205 pGeode->CBData.pitch = LX_CB_PITCH; 206 207 pGeode->Compression = TRUE; 208 } 209 else { 210 xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 211 "Not enough memory for compression\n"); 212 pGeode->Compression = FALSE; 213 } 214 } 215 216 if (pGeode->tryHWCursor) { 217 ptr = GeodeAllocOffscreen(pGeode, 218 LX_CURSOR_HW_WIDTH * 4 * LX_CURSOR_HW_HEIGHT, 219 4); 220 221 if (ptr != NULL) { 222 pGeode->CursorStartOffset = ptr->offset; 223 pGeode->HWCursor = TRUE; 224 } 225 else { 226 xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 227 "Not enough memory for the hardware cursor\n"); 228 pGeode->HWCursor = FALSE; 229 } 230 } 231 232 if (!pGeode->NoAccel && pGeode->pExa) { 233 int size; 234 235 /* Try to get the scratch buffer for blending */ 236 pGeode->exaBfrOffset = 0; 237 238 if (pGeode->exaBfrSz > 0) { 239 ptr = GeodeAllocOffscreen(pGeode, pGeode->exaBfrSz, 4); 240 if (ptr != NULL) 241 pGeode->exaBfrOffset = ptr->offset; 242 } 243 244 pGeode->pExa->offScreenBase = 0; 245 pGeode->pExa->memorySize = 0; 246 247 /* This might cause complaints - in order to avoid using 248 xorg.conf as much as possible, we make assumptions about 249 what a "default" memory map would look like. After 250 discussion, we agreed that the default driver should assume 251 the user will want to use rotation and video overlays, and 252 EXA will get whatever is leftover. 253 */ 254 255 /* Get the amount of offscreen memory still left */ 256 size = GeodeOffscreenFreeSize(pGeode); 257 258 /* Align the size to a K boundary */ 259 size &= ~1023; 260 261 /* Allocate the EXA offscreen space */ 262 ptr = GeodeAllocOffscreen(pGeode, size, 4); 263 264 if (ptr == NULL) { 265 /* If we couldn't allocate what we wanted, 266 * then allocate what's left */ 267 268 ptr = GeodeAllocRemainder(pGeode); 269 } 270 271 if (ptr != NULL) { 272 pGeode->pExa->offScreenBase = ptr->offset; 273 pGeode->pExa->memorySize = ptr->offset + ptr->size; 274 } 275 } 276 277 /* Show the memory map for diagnostic purposes */ 278 279 xf86DrvMsg(pScrni->scrnIndex, X_INFO, "LX video memory:\n"); 280 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " Display: 0x%x bytes\n", 281 pGeode->displaySize); 282 283 if (pGeode->Compression) 284 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " Compression: 0x%x bytes\n", 285 pScrni->virtualY * LX_CB_PITCH); 286 287 if (pGeode->HWCursor) 288 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " Cursor: 0x%x bytes\n", 289 LX_CURSOR_HW_WIDTH * 4 * LX_CURSOR_HW_HEIGHT); 290 291 if (pGeode->exaBfrSz) 292 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " ExaBfrSz: 0x%x bytes\n", 293 pGeode->exaBfrSz); 294 295 if (pGeode->pExa && pGeode->pExa->offScreenBase) 296 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " EXA: 0x%x bytes\n", 297 (unsigned int) (pGeode->pExa->memorySize - 298 pGeode->pExa->offScreenBase)); 299 300 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " FREE: 0x%x bytes\n", 301 GeodeOffscreenFreeSize(pGeode)); 302} 303 304/* Called as we go down, so blitz everybody */ 305 306void 307GeodeCloseOffscreen(ScrnInfoPtr pScrni) 308{ 309 GeodeRec *pGeode = GEODEPTR(pScrni); 310 GeodeMemPtr ptr = pGeode->offscreenList; 311 GeodeMemPtr nptr; 312 313 while (ptr) { 314 nptr = ptr->next; 315 free(ptr); 316 ptr = nptr; 317 } 318 319 pGeode->offscreenList = NULL; 320} 321