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