lx_memory.c revision 7f419768
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 "xf86.h" 30#include "geode.h" 31#include "cim/cim_regs.h" 32 33#define ALIGN(x,y) (((x) + (y) - 1) / (y) * (y)) 34#define LX_CB_PITCH 544 35 36/* Geode offscreen memory allocation functions. This is 37 overengineered for the simple hardware that we have, but 38 there are multiple functions that may want to independently 39 allocate and free memory (crtc->shadow_alloc and Xv). This 40 provides a semi-robust mechanism for doing that. 41*/ 42 43/* Return the number of free bytes */ 44 45unsigned int 46GeodeOffscreenFreeSize(GeodeRec * pGeode) 47{ 48 GeodeMemPtr ptr = pGeode->offscreenList; 49 50 if (ptr == NULL) 51 return pGeode->offscreenSize; 52 53 for (; ptr->next; ptr = ptr->next); 54 return (pGeode->offscreenStart + pGeode->offscreenSize) 55 - (ptr->offset + ptr->size); 56} 57 58void 59GeodeFreeOffscreen(GeodeRec * pGeode, GeodeMemPtr ptr) 60{ 61 /* There is a clear memory leak here, but 62 * but it is unlikely that the first block of 63 * "allocated" memory is going to be released 64 * individually. 65 */ 66 67 if (ptr->prev == NULL) 68 pGeode->offscreenList = ptr->next; 69 else 70 ptr->prev->next = ptr->next; 71 72 if (ptr->next) 73 ptr->next->prev = ptr->prev; 74 75 free(ptr); 76} 77 78/* Allocate the "rest" of the offscreen memory - this is for 79 situations where we have very little video memory, and we 80 want to take as much of it as we can for EXA 81*/ 82 83static GeodeMemPtr 84GeodeAllocRemainder(GeodeRec * pGeode) 85{ 86 GeodeMemPtr nptr, ptr = pGeode->offscreenList; 87 88 if (!pGeode->offscreenList) { 89 pGeode->offscreenList = calloc(1, sizeof(*nptr)); 90 pGeode->offscreenList->offset = pGeode->offscreenStart; 91 pGeode->offscreenList->size = pGeode->offscreenSize; 92 pGeode->offscreenList->next = NULL; 93 pGeode->offscreenList->prev = NULL; 94 95 return pGeode->offscreenList; 96 } 97 98 /* Go to the end of the list of allocated stuff */ 99 for (; ptr->next; ptr = ptr->next); 100 101 nptr = calloc(1, sizeof(*nptr)); 102 nptr->offset = ptr->offset + ptr->size; 103 nptr->size = pGeode->offscreenSize - 104 (nptr->offset - pGeode->offscreenStart); 105 106 nptr->next = ptr->next; 107 nptr->prev = ptr; 108 ptr->next = nptr; 109 110 return nptr; 111} 112 113/* Allocate 'size' bytes of offscreen memory. 114*/ 115 116GeodeMemPtr 117GeodeAllocOffscreen(GeodeRec * pGeode, int size, int align) 118{ 119 GeodeMemPtr ptr = pGeode->offscreenList; 120 GeodeMemPtr nptr; 121 122 unsigned int offset; 123 124 if (!pGeode->offscreenList) { 125 126 if (size > pGeode->offscreenSize) 127 return NULL; 128 129 offset = ALIGN(pGeode->offscreenStart, align); 130 131 pGeode->offscreenList = calloc(1, sizeof(*nptr)); 132 pGeode->offscreenList->offset = offset; 133 pGeode->offscreenList->size = size; 134 pGeode->offscreenList->next = NULL; 135 136 return pGeode->offscreenList; 137 } 138 139 while (ptr) { 140 unsigned int gap; 141 142 if (ptr->next == NULL) 143 gap = pGeode->offscreenSize + pGeode->offscreenStart; 144 145 else 146 gap = ptr->next->offset; 147 148 gap = gap - (ptr->offset + ptr->size); 149 gap = ALIGN(gap, align); 150 151 if (size < gap) { 152 offset = ptr->offset + ptr->size; 153 offset = ALIGN(ptr->offset + ptr->size, align); 154 155 nptr = calloc(1, sizeof(*nptr)); 156 nptr->offset = offset; 157 nptr->size = size; 158 nptr->next = ptr->next; 159 nptr->prev = ptr; 160 ptr->next = nptr; 161 162 return nptr; 163 } 164 165 ptr = ptr->next; 166 } 167 168 return NULL; 169} 170 171/* Carve out the space for the visible screen, and carve out 172 the usual suspects that need offscreen memory 173*/ 174 175#define MAX(a,b) ((a) > (b) ? (a) : (b)) 176 177void 178LXInitOffscreen(ScrnInfoPtr pScrni) 179{ 180 GeodeRec *pGeode = GEODEPTR(pScrni); 181 unsigned int fbavail; 182 GeodeMemPtr ptr; 183 184 /* The scratch buffer is always used */ 185 fbavail = pGeode->FBAvail - GP3_SCRATCH_BUFFER_SIZE; 186 187 pGeode->displaySize = MAX(pScrni->virtualX, pScrni->virtualY) 188 * pGeode->Pitch; 189 190 pGeode->offscreenStart = pGeode->displaySize; 191 pGeode->offscreenSize = fbavail - pGeode->displaySize; 192 193 /* Allocate the usual memory suspects */ 194 if (pGeode->tryCompression) { 195 int size = pScrni->virtualY * LX_CB_PITCH; 196 197 /* The compression buffer needs to be 16 byte aligned */ 198 ptr = GeodeAllocOffscreen(pGeode, size, 16); 199 200 if (ptr != NULL) { 201 pGeode->CBData.compression_offset = ptr->offset; 202 pGeode->CBData.size = LX_CB_PITCH; 203 pGeode->CBData.pitch = LX_CB_PITCH; 204 205 pGeode->Compression = TRUE; 206 } 207 else { 208 xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 209 "Not enough memory for compression\n"); 210 pGeode->Compression = FALSE; 211 } 212 } 213 214 if (pGeode->tryHWCursor) { 215 ptr = GeodeAllocOffscreen(pGeode, 216 LX_CURSOR_HW_WIDTH * 4 * LX_CURSOR_HW_HEIGHT, 217 4); 218 219 if (ptr != NULL) { 220 pGeode->CursorStartOffset = ptr->offset; 221 pGeode->HWCursor = TRUE; 222 } 223 else { 224 xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 225 "Not enough memory for the hardware cursor\n"); 226 pGeode->HWCursor = FALSE; 227 } 228 } 229 230 if (!pGeode->NoAccel && pGeode->pExa) { 231 int size; 232 233 /* Try to get the scratch buffer for blending */ 234 pGeode->exaBfrOffset = 0; 235 236 if (pGeode->exaBfrSz > 0) { 237 ptr = GeodeAllocOffscreen(pGeode, pGeode->exaBfrSz, 4); 238 if (ptr != NULL) 239 pGeode->exaBfrOffset = ptr->offset; 240 } 241 242 pGeode->pExa->offScreenBase = 0; 243 pGeode->pExa->memorySize = 0; 244 245 /* This might cause complaints - in order to avoid using 246 xorg.conf as much as possible, we make assumptions about 247 what a "default" memory map would look like. After 248 discussion, we agreed that the default driver should assume 249 the user will want to use rotation and video overlays, and 250 EXA will get whatever is leftover. 251 */ 252 253 /* Get the amount of offscreen memory still left */ 254 size = GeodeOffscreenFreeSize(pGeode); 255 256 /* Align the size to a K boundary */ 257 size &= ~1023; 258 259 /* Allocate the EXA offscreen space */ 260 ptr = GeodeAllocOffscreen(pGeode, size, 4); 261 262 if (ptr == NULL) { 263 /* If we couldn't allocate what we wanted, 264 * then allocate whats left */ 265 266 ptr = GeodeAllocRemainder(pGeode); 267 } 268 269 if (ptr != NULL) { 270 pGeode->pExa->offScreenBase = ptr->offset; 271 pGeode->pExa->memorySize = ptr->offset + ptr->size; 272 } 273 } 274 275 /* Show the memory map for diagnostic purposes */ 276 277 xf86DrvMsg(pScrni->scrnIndex, X_INFO, "LX video memory:\n"); 278 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " Display: 0x%x bytes\n", 279 pGeode->displaySize); 280 281 if (pGeode->Compression) 282 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " Compression: 0x%x bytes\n", 283 pScrni->virtualY * LX_CB_PITCH); 284 285 if (pGeode->HWCursor) 286 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " Cursor: 0x%x bytes\n", 287 LX_CURSOR_HW_WIDTH * 4 * LX_CURSOR_HW_HEIGHT); 288 289 if (pGeode->exaBfrSz) 290 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " ExaBfrSz: 0x%x bytes\n", 291 pGeode->exaBfrSz); 292 293 if (pGeode->pExa && pGeode->pExa->offScreenBase) 294 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " EXA: 0x%x bytes\n", 295 (unsigned int) (pGeode->pExa->memorySize - 296 pGeode->pExa->offScreenBase)); 297 298 xf86DrvMsg(pScrni->scrnIndex, X_INFO, " FREE: 0x%x bytes\n", 299 GeodeOffscreenFreeSize(pGeode)); 300} 301 302/* Called as we go down, so blitz everybody */ 303 304void 305GeodeCloseOffscreen(ScrnInfoPtr pScrni) 306{ 307 GeodeRec *pGeode = GEODEPTR(pScrni); 308 GeodeMemPtr ptr = pGeode->offscreenList; 309 GeodeMemPtr nptr; 310 311 while (ptr) { 312 nptr = ptr->next; 313 free(ptr); 314 ptr = nptr; 315 } 316 317 pGeode->offscreenList = NULL; 318} 319