xfree86: Remove {set,undo}WC from VidMemInfo
Now that mapMem is gone this can never actually get called. Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
		
							parent
							
								
									9db2af6f75
								
							
						
					
					
						commit
						ec0e29ed5b
					
				|  | @ -86,15 +86,8 @@ static int devMemFd = -1; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef HAS_MTRR_SUPPORT | #ifdef HAS_MTRR_SUPPORT | ||||||
| static void *setWC(int, unsigned long, unsigned long, Bool, MessageType); |  | ||||||
| static void undoWC(int, void *); |  | ||||||
| static Bool cleanMTRR(void); | static Bool cleanMTRR(void); | ||||||
| #endif | #endif | ||||||
| #if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) |  | ||||||
| static void *NetBSDsetWC(int, unsigned long, unsigned long, Bool, |  | ||||||
|                            MessageType); |  | ||||||
| static void NetBSDundoWC(int, void *); |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Check if /dev/mem can be mmap'd.  If it can't print a warning when |  * Check if /dev/mem can be mmap'd.  If it can't print a warning when | ||||||
|  | @ -192,15 +185,8 @@ xf86OSInitVidMem(VidMemInfoPtr pVidMem) | ||||||
| 
 | 
 | ||||||
| #ifdef HAS_MTRR_SUPPORT | #ifdef HAS_MTRR_SUPPORT | ||||||
|     if (useDevMem) { |     if (useDevMem) { | ||||||
|         if (cleanMTRR()) { |         cleanMTRR(); | ||||||
|             pVidMem->setWC = setWC; |  | ||||||
|             pVidMem->undoWC = undoWC; |  | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| #if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) |  | ||||||
|     pVidMem->setWC = NetBSDsetWC; |  | ||||||
|     pVidMem->undoWC = NetBSDundoWC; |  | ||||||
| #endif | #endif | ||||||
|     pVidMem->initialised = TRUE; |     pVidMem->initialised = TRUE; | ||||||
| } | } | ||||||
|  | @ -503,334 +489,4 @@ cleanMTRR() | ||||||
|     return TRUE; |     return TRUE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| typedef struct x_RangeRec { |  | ||||||
|     struct mem_range_desc mrd; |  | ||||||
|     Bool wasWC; |  | ||||||
|     struct x_RangeRec *next; |  | ||||||
| } RangeRec, *RangePtr; |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| freeRangeList(RangePtr range) |  | ||||||
| { |  | ||||||
|     RangePtr rp; |  | ||||||
| 
 |  | ||||||
|     while (range) { |  | ||||||
|         rp = range; |  | ||||||
|         range = rp->next; |  | ||||||
|         free(rp); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static RangePtr |  | ||||||
| dupRangeList(RangePtr list) |  | ||||||
| { |  | ||||||
|     RangePtr new = NULL, rp, p; |  | ||||||
| 
 |  | ||||||
|     rp = list; |  | ||||||
|     while (rp) { |  | ||||||
|         p = xnfalloc(sizeof(RangeRec)); |  | ||||||
|         *p = *rp; |  | ||||||
|         p->next = new; |  | ||||||
|         new = p; |  | ||||||
|         rp = rp->next; |  | ||||||
|     } |  | ||||||
|     return new; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static RangePtr |  | ||||||
| sortRangeList(RangePtr list) |  | ||||||
| { |  | ||||||
|     RangePtr rp1, rp2, copy, sorted = NULL, minp, prev, minprev; |  | ||||||
|     unsigned long minBase; |  | ||||||
| 
 |  | ||||||
|     /* Sort by base address */ |  | ||||||
|     rp1 = copy = dupRangeList(list); |  | ||||||
|     while (rp1) { |  | ||||||
|         minBase = rp1->mrd.mr_base; |  | ||||||
|         minp = rp1; |  | ||||||
|         minprev = NULL; |  | ||||||
|         prev = rp1; |  | ||||||
|         rp2 = rp1->next; |  | ||||||
|         while (rp2) { |  | ||||||
|             if (rp2->mrd.mr_base < minBase) { |  | ||||||
|                 minBase = rp2->mrd.mr_base; |  | ||||||
|                 minp = rp2; |  | ||||||
|                 minprev = prev; |  | ||||||
|             } |  | ||||||
|             prev = rp2; |  | ||||||
|             rp2 = rp2->next; |  | ||||||
|         } |  | ||||||
|         if (minprev) { |  | ||||||
|             minprev->next = minp->next; |  | ||||||
|             rp1 = copy; |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             rp1 = minp->next; |  | ||||||
|         } |  | ||||||
|         minp->next = sorted; |  | ||||||
|         sorted = minp; |  | ||||||
|     } |  | ||||||
|     return sorted; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * findRanges returns a list of ranges that overlap the specified range. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| findRanges(unsigned long base, unsigned long size, RangePtr * ucp, |  | ||||||
|            RangePtr * wcp) |  | ||||||
| { |  | ||||||
|     struct mem_range_desc *mrd; |  | ||||||
|     int nmr, i; |  | ||||||
|     RangePtr rp, *p; |  | ||||||
| 
 |  | ||||||
|     if (!(mrd = getAllRanges(&nmr))) |  | ||||||
|         return; |  | ||||||
| 
 |  | ||||||
|     for (i = 0; i < nmr; i++) { |  | ||||||
|         if ((mrd[i].mr_flags & MDF_ACTIVE) && |  | ||||||
|             mrd[i].mr_base < base + size && |  | ||||||
|             mrd[i].mr_base + mrd[i].mr_len > base) { |  | ||||||
|             if (mrd[i].mr_flags & MDF_WRITECOMBINE) |  | ||||||
|                 p = wcp; |  | ||||||
|             else if (mrd[i].mr_flags & MDF_UNCACHEABLE) |  | ||||||
|                 p = ucp; |  | ||||||
|             else |  | ||||||
|                 continue; |  | ||||||
|             rp = xnfalloc(sizeof(RangeRec)); |  | ||||||
|             rp->mrd = mrd[i]; |  | ||||||
|             rp->next = *p; |  | ||||||
|             *p = rp; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     free(mrd); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * This checks if the existing overlapping ranges fully cover the requested |  | ||||||
|  * range.  Is this overkill? |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| static Bool |  | ||||||
| fullCoverage(unsigned long base, unsigned long size, RangePtr overlap) |  | ||||||
| { |  | ||||||
|     RangePtr rp1, sorted = NULL; |  | ||||||
|     unsigned long end; |  | ||||||
| 
 |  | ||||||
|     sorted = sortRangeList(overlap); |  | ||||||
|     /* Look for gaps */ |  | ||||||
|     rp1 = sorted; |  | ||||||
|     end = base + size; |  | ||||||
|     while (rp1) { |  | ||||||
|         if (rp1->mrd.mr_base > base) { |  | ||||||
|             freeRangeList(sorted); |  | ||||||
|             return FALSE; |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             base = rp1->mrd.mr_base + rp1->mrd.mr_len; |  | ||||||
|         } |  | ||||||
|         if (base >= end) { |  | ||||||
|             freeRangeList(sorted); |  | ||||||
|             return TRUE; |  | ||||||
|         } |  | ||||||
|         rp1 = rp1->next; |  | ||||||
|     } |  | ||||||
|     freeRangeList(sorted); |  | ||||||
|     return FALSE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void * |  | ||||||
| addWC(int screenNum, unsigned long base, unsigned long size, MessageType from) |  | ||||||
| { |  | ||||||
|     RangePtr uc = NULL, wc = NULL, retlist = NULL; |  | ||||||
|     struct mem_range_desc mrd; |  | ||||||
|     struct mem_range_op mro; |  | ||||||
| 
 |  | ||||||
|     findRanges(base, size, &uc, &wc); |  | ||||||
| 
 |  | ||||||
|     /* See of the full range is already WC */ |  | ||||||
|     if (!uc && fullCoverage(base, size, wc)) { |  | ||||||
|         xf86DrvMsg(screenNum, from, |  | ||||||
|                    "Write-combining range (0x%lx,0x%lx) was already set\n", |  | ||||||
|                    base, size); |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* Otherwise, try to add the new range */ |  | ||||||
|     mrd.mr_base = base; |  | ||||||
|     mrd.mr_len = size; |  | ||||||
|     strcpy(mrd.mr_owner, X_MTRR_ID); |  | ||||||
|     mrd.mr_flags = MDF_WRITECOMBINE; |  | ||||||
|     mro.mo_desc = &mrd; |  | ||||||
|     mro.mo_arg[0] = MEMRANGE_SET_UPDATE; |  | ||||||
|     if (ioctl(devMemFd, MEMRANGE_SET, &mro)) { |  | ||||||
|         xf86DrvMsg(screenNum, X_WARNING, |  | ||||||
|                    "Failed to set write-combining range " |  | ||||||
|                    "(0x%lx,0x%lx)\n", base, size); |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         xf86DrvMsg(screenNum, from, |  | ||||||
|                    "Write-combining range (0x%lx,0x%lx)\n", base, size); |  | ||||||
|         retlist = xnfalloc(sizeof(RangeRec)); |  | ||||||
|         retlist->mrd = mrd; |  | ||||||
|         retlist->wasWC = FALSE; |  | ||||||
|         retlist->next = NULL; |  | ||||||
|         return retlist; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void * |  | ||||||
| delWC(int screenNum, unsigned long base, unsigned long size, MessageType from) |  | ||||||
| { |  | ||||||
|     RangePtr uc = NULL, wc = NULL, retlist = NULL; |  | ||||||
|     struct mem_range_desc mrd; |  | ||||||
|     struct mem_range_op mro; |  | ||||||
| 
 |  | ||||||
|     findRanges(base, size, &uc, &wc); |  | ||||||
| 
 |  | ||||||
|     /*
 |  | ||||||
|      * See of the full range is already not WC, or if there is full |  | ||||||
|      * coverage from UC ranges. |  | ||||||
|      */ |  | ||||||
|     if (!wc || fullCoverage(base, size, uc)) { |  | ||||||
|         xf86DrvMsg(screenNum, from, |  | ||||||
|                    "Write-combining range (0x%lx,0x%lx) was already clear\n", |  | ||||||
|                    base, size); |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* Otherwise, try to add the new range */ |  | ||||||
|     mrd.mr_base = base; |  | ||||||
|     mrd.mr_len = size; |  | ||||||
|     strcpy(mrd.mr_owner, X_MTRR_ID); |  | ||||||
|     mrd.mr_flags = MDF_UNCACHEABLE; |  | ||||||
|     mro.mo_desc = &mrd; |  | ||||||
|     mro.mo_arg[0] = MEMRANGE_SET_UPDATE; |  | ||||||
|     if (ioctl(devMemFd, MEMRANGE_SET, &mro)) { |  | ||||||
|         xf86DrvMsg(screenNum, X_WARNING, |  | ||||||
|                    "Failed to remove write-combining range " |  | ||||||
|                    "(0x%lx,0x%lx)\n", base, size); |  | ||||||
|         /* XXX Should then remove all of the overlapping WC ranges */ |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         xf86DrvMsg(screenNum, from, |  | ||||||
|                    "Removed Write-combining range (0x%lx,0x%lx)\n", base, size); |  | ||||||
|         retlist = xnfalloc(sizeof(RangeRec)); |  | ||||||
|         retlist->mrd = mrd; |  | ||||||
|         retlist->wasWC = TRUE; |  | ||||||
|         retlist->next = NULL; |  | ||||||
|         return retlist; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void * |  | ||||||
| setWC(int screenNum, unsigned long base, unsigned long size, Bool enable, |  | ||||||
|       MessageType from) |  | ||||||
| { |  | ||||||
|     if (enable) |  | ||||||
|         return addWC(screenNum, base, size, from); |  | ||||||
|     else |  | ||||||
|         return delWC(screenNum, base, size, from); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| undoWC(int screenNum, void *list) |  | ||||||
| { |  | ||||||
|     RangePtr rp; |  | ||||||
|     struct mem_range_op mro; |  | ||||||
|     Bool failed; |  | ||||||
| 
 |  | ||||||
|     rp = list; |  | ||||||
|     while (rp) { |  | ||||||
| #ifdef DEBUG |  | ||||||
|         ErrorF("Undo for (0x%lx,0x%lx), %d\n", |  | ||||||
|                (unsigned long) rp->mrd.mr_base, |  | ||||||
|                (unsigned long) rp->mrd.mr_len, rp->wasWC); |  | ||||||
| #endif |  | ||||||
|         failed = FALSE; |  | ||||||
|         if (rp->wasWC) { |  | ||||||
|             mro.mo_arg[0] = MEMRANGE_SET_UPDATE; |  | ||||||
|             rp->mrd.mr_flags = MDF_WRITECOMBINE; |  | ||||||
|             strcpy(rp->mrd.mr_owner, "unknown"); |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             mro.mo_arg[0] = MEMRANGE_SET_REMOVE; |  | ||||||
|         } |  | ||||||
|         mro.mo_desc = &rp->mrd; |  | ||||||
| 
 |  | ||||||
|         if (ioctl(devMemFd, MEMRANGE_SET, &mro)) { |  | ||||||
|             if (!rp->wasWC) { |  | ||||||
|                 mro.mo_arg[0] = MEMRANGE_SET_UPDATE; |  | ||||||
|                 rp->mrd.mr_flags = MDF_UNCACHEABLE; |  | ||||||
|                 strcpy(rp->mrd.mr_owner, "unknown"); |  | ||||||
|                 if (ioctl(devMemFd, MEMRANGE_SET, &mro)) |  | ||||||
|                     failed = TRUE; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|                 failed = TRUE; |  | ||||||
|         } |  | ||||||
|         if (failed) { |  | ||||||
|             xf86DrvMsg(screenNum, X_WARNING, |  | ||||||
|                        "Failed to restore MTRR range (0x%lx,0x%lx)\n", |  | ||||||
|                        (unsigned long) rp->mrd.mr_base, |  | ||||||
|                        (unsigned long) rp->mrd.mr_len); |  | ||||||
|         } |  | ||||||
|         rp = rp->next; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #endif                          /* HAS_MTRR_SUPPORT */ | #endif                          /* HAS_MTRR_SUPPORT */ | ||||||
| 
 |  | ||||||
| #if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__) |  | ||||||
| static void * |  | ||||||
| NetBSDsetWC(int screenNum, unsigned long base, unsigned long size, Bool enable, |  | ||||||
|             MessageType from) |  | ||||||
| { |  | ||||||
|     struct mtrr *mtrrp; |  | ||||||
|     int n; |  | ||||||
| 
 |  | ||||||
|     xf86DrvMsg(screenNum, X_WARNING, |  | ||||||
|                "%s MTRR %lx - %lx\n", enable ? "set" : "remove", |  | ||||||
|                base, (base + size)); |  | ||||||
| 
 |  | ||||||
|     mtrrp = xnfalloc(sizeof(struct mtrr)); |  | ||||||
|     mtrrp->base = base; |  | ||||||
|     mtrrp->len = size; |  | ||||||
|     mtrrp->type = MTRR_TYPE_WC; |  | ||||||
| 
 |  | ||||||
|     /*
 |  | ||||||
|      * MTRR_PRIVATE will make this MTRR get reset automatically |  | ||||||
|      * if this process exits, so we have no need for an explicit |  | ||||||
|      * cleanup operation when starting a new server. |  | ||||||
|      */ |  | ||||||
| 
 |  | ||||||
|     if (enable) |  | ||||||
|         mtrrp->flags = MTRR_VALID | MTRR_PRIVATE; |  | ||||||
|     else |  | ||||||
|         mtrrp->flags = 0; |  | ||||||
|     n = 1; |  | ||||||
| 
 |  | ||||||
|     if (i386_set_mtrr(mtrrp, &n) < 0) { |  | ||||||
|         free(mtrrp); |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|     return mtrrp; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| NetBSDundoWC(int screenNum, void *list) |  | ||||||
| { |  | ||||||
|     struct mtrr *mtrrp = (struct mtrr *) list; |  | ||||||
|     int n; |  | ||||||
| 
 |  | ||||||
|     if (mtrrp == NULL) |  | ||||||
|         return; |  | ||||||
|     n = 1; |  | ||||||
|     mtrrp->flags &= ~MTRR_VALID; |  | ||||||
|     i386_set_mtrr(mtrrp, &n); |  | ||||||
|     free(mtrrp); |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  | @ -42,10 +42,6 @@ | ||||||
| #include "shared/xf86Axp.h" | #include "shared/xf86Axp.h" | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef HAS_MTRR_SUPPORT |  | ||||||
| #include <asm/mtrr.h> |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| static Bool ExtendedEnabled = FALSE; | static Bool ExtendedEnabled = FALSE; | ||||||
| 
 | 
 | ||||||
| #ifdef __ia64__ | #ifdef __ia64__ | ||||||
|  | @ -95,265 +91,6 @@ static unsigned long hae_mask; | ||||||
| static unsigned long bus_base; | static unsigned long bus_base; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef HAS_MTRR_SUPPORT |  | ||||||
| 
 |  | ||||||
| #define SPLIT_WC_REGIONS 1 |  | ||||||
| 
 |  | ||||||
| static void *setWC(int, unsigned long, unsigned long, Bool, MessageType); |  | ||||||
| static void undoWC(int, void *); |  | ||||||
| 
 |  | ||||||
| /* The file desc for /proc/mtrr. Once opened, left opened, and the mtrr
 |  | ||||||
|    driver will clean up when we exit. */ |  | ||||||
| #define MTRR_FD_UNOPENED (-1)   /* We have yet to open /proc/mtrr */ |  | ||||||
| #define MTRR_FD_PROBLEM (-2)    /* We tried to open /proc/mtrr, but had |  | ||||||
|                                    a problem. */ |  | ||||||
| static int mtrr_fd = MTRR_FD_UNOPENED; |  | ||||||
| 
 |  | ||||||
| /* Open /proc/mtrr. FALSE on failure. Will always fail on Linux 2.0, 
 |  | ||||||
|    and will fail on Linux 2.2 with MTRR support configured out, |  | ||||||
|    so verbosity should be chosen appropriately. */ |  | ||||||
| static Bool |  | ||||||
| mtrr_open(int verbosity) |  | ||||||
| { |  | ||||||
|     /* Only report absence of /proc/mtrr once. */ |  | ||||||
|     static Bool warned = FALSE; |  | ||||||
| 
 |  | ||||||
|     if (mtrr_fd == MTRR_FD_UNOPENED) { |  | ||||||
|         mtrr_fd = open("/proc/mtrr", O_WRONLY); |  | ||||||
| 
 |  | ||||||
|         if (mtrr_fd < 0) |  | ||||||
|             mtrr_fd = MTRR_FD_PROBLEM; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (mtrr_fd == MTRR_FD_PROBLEM) { |  | ||||||
|         /* To make sure we only ever warn once, need to check
 |  | ||||||
|            verbosity outside xf86MsgVerb */ |  | ||||||
|         if (!warned && verbosity <= xf86GetVerbosity()) { |  | ||||||
|             xf86MsgVerb(X_WARNING, verbosity, |  | ||||||
|                         "System lacks support for changing MTRRs\n"); |  | ||||||
|             warned = TRUE; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return FALSE; |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|         return TRUE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * We maintain a list of WC regions for each physical mapping so they can |  | ||||||
|  * be undone when unmapping. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| struct mtrr_wc_region { |  | ||||||
|     struct mtrr_sentry sentry; |  | ||||||
|     Bool added;                 /* added WC or removed it */ |  | ||||||
|     struct mtrr_wc_region *next; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static struct mtrr_wc_region * |  | ||||||
| mtrr_cull_wc_region(int screenNum, unsigned long base, unsigned long size, |  | ||||||
|                     MessageType from) |  | ||||||
| { |  | ||||||
|     /* Some BIOS writers thought that setting wc over the mmio
 |  | ||||||
|        region of a graphics devices was a good idea. Try to fix |  | ||||||
|        it. */ |  | ||||||
| 
 |  | ||||||
|     struct mtrr_gentry gent; |  | ||||||
|     struct mtrr_wc_region *wcreturn = NULL, *wcr; |  | ||||||
|     int count, ret = 0; |  | ||||||
| 
 |  | ||||||
|     /* Linux 2.0 users should not get a warning without -verbose */ |  | ||||||
|     if (!mtrr_open(2)) |  | ||||||
|         return NULL; |  | ||||||
| 
 |  | ||||||
|     for (gent.regnum = 0; |  | ||||||
|          ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; gent.regnum++) { |  | ||||||
|         if (gent.type != MTRR_TYPE_WRCOMB |  | ||||||
|             || gent.base + gent.size <= base || base + size <= gent.base) |  | ||||||
|             continue; |  | ||||||
| 
 |  | ||||||
|         /* Found an overlapping region. Delete it. */ |  | ||||||
| 
 |  | ||||||
|         wcr = malloc(sizeof(*wcr)); |  | ||||||
|         if (!wcr) |  | ||||||
|             return NULL; |  | ||||||
|         wcr->sentry.base = gent.base; |  | ||||||
|         wcr->sentry.size = gent.size; |  | ||||||
|         wcr->sentry.type = MTRR_TYPE_WRCOMB; |  | ||||||
|         wcr->added = FALSE; |  | ||||||
| 
 |  | ||||||
|         count = 3; |  | ||||||
|         while (count-- && |  | ||||||
|                (ret = ioctl(mtrr_fd, MTRRIOC_KILL_ENTRY, &(wcr->sentry))) < 0); |  | ||||||
| 
 |  | ||||||
|         if (ret >= 0) { |  | ||||||
|             xf86DrvMsg(screenNum, from, |  | ||||||
|                        "Removed MMIO write-combining range " |  | ||||||
|                        "(0x%lx,0x%lx)\n", |  | ||||||
|                        (unsigned long) gent.base, (unsigned long) gent.size); |  | ||||||
|             wcr->next = wcreturn; |  | ||||||
|             wcreturn = wcr; |  | ||||||
|             gent.regnum--; |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             free(wcr); |  | ||||||
|             xf86DrvMsgVerb(screenNum, X_WARNING, 0, |  | ||||||
|                            "Failed to remove MMIO " |  | ||||||
|                            "write-combining range (0x%lx,0x%lx)\n", |  | ||||||
|                            (unsigned long)gent.base, (unsigned long) gent.size); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return wcreturn; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static struct mtrr_wc_region * |  | ||||||
| mtrr_remove_offending(int screenNum, unsigned long base, unsigned long size, |  | ||||||
|                       MessageType from) |  | ||||||
| { |  | ||||||
|     struct mtrr_gentry gent; |  | ||||||
|     struct mtrr_wc_region *wcreturn = NULL, **wcr; |  | ||||||
| 
 |  | ||||||
|     if (!mtrr_open(2)) |  | ||||||
|         return NULL; |  | ||||||
| 
 |  | ||||||
|     wcr = &wcreturn; |  | ||||||
|     for (gent.regnum = 0; |  | ||||||
|          ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; gent.regnum++) { |  | ||||||
|         if (gent.type == MTRR_TYPE_WRCOMB |  | ||||||
|             && ((gent.base >= base && gent.base + gent.size < base + size) || |  | ||||||
|                 (gent.base > base && gent.base + gent.size <= base + size))) { |  | ||||||
|             *wcr = mtrr_cull_wc_region(screenNum, gent.base, gent.size, from); |  | ||||||
|             if (*wcr) |  | ||||||
|                 gent.regnum--; |  | ||||||
|             while (*wcr) { |  | ||||||
|                 wcr = &((*wcr)->next); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return wcreturn; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static struct mtrr_wc_region * |  | ||||||
| mtrr_add_wc_region(int screenNum, unsigned long base, unsigned long size, |  | ||||||
|                    MessageType from) |  | ||||||
| { |  | ||||||
|     struct mtrr_wc_region **wcr, *wcreturn, *curwcr; |  | ||||||
| 
 |  | ||||||
|     /*
 |  | ||||||
|      * There can be only one.... |  | ||||||
|      */ |  | ||||||
| 
 |  | ||||||
|     wcreturn = mtrr_remove_offending(screenNum, base, size, from); |  | ||||||
|     wcr = &wcreturn; |  | ||||||
|     while (*wcr) { |  | ||||||
|         wcr = &((*wcr)->next); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* Linux 2.0 should not warn, unless the user explicitly asks for
 |  | ||||||
|        WC. */ |  | ||||||
| 
 |  | ||||||
|     if (!mtrr_open(from == X_CONFIG ? 0 : 2)) |  | ||||||
|         return wcreturn; |  | ||||||
| 
 |  | ||||||
|     *wcr = curwcr = malloc(sizeof(**wcr)); |  | ||||||
|     if (!curwcr) |  | ||||||
|         return wcreturn; |  | ||||||
| 
 |  | ||||||
|     curwcr->sentry.base = base; |  | ||||||
|     curwcr->sentry.size = size; |  | ||||||
|     curwcr->sentry.type = MTRR_TYPE_WRCOMB; |  | ||||||
|     curwcr->added = TRUE; |  | ||||||
|     curwcr->next = NULL; |  | ||||||
| 
 |  | ||||||
| #if SPLIT_WC_REGIONS |  | ||||||
|     /*
 |  | ||||||
|      * Splits up the write-combining region if it is not aligned on a |  | ||||||
|      * size boundary. |  | ||||||
|      */ |  | ||||||
| 
 |  | ||||||
|     { |  | ||||||
|         unsigned long lbase, d_size = 1; |  | ||||||
|         unsigned long n_size = size; |  | ||||||
|         unsigned long n_base = base; |  | ||||||
| 
 |  | ||||||
|         for (lbase = n_base, d_size = 1; !(lbase & 1); |  | ||||||
|              lbase = lbase >> 1, d_size <<= 1); |  | ||||||
|         while (d_size > n_size) |  | ||||||
|             d_size = d_size >> 1; |  | ||||||
|         DebugF("WC_BASE: 0x%lx WC_END: 0x%lx\n", base, base + d_size - 1); |  | ||||||
|         n_base += d_size; |  | ||||||
|         n_size -= d_size; |  | ||||||
|         if (n_size) { |  | ||||||
|             xf86DrvMsgVerb(screenNum, X_INFO, 3, "Splitting WC range: " |  | ||||||
|                            "base: 0x%lx, size: 0x%lx\n", base, size); |  | ||||||
|             curwcr->next = mtrr_add_wc_region(screenNum, n_base, n_size, from); |  | ||||||
|         } |  | ||||||
|         curwcr->sentry.size = d_size; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|         /*****************************************************************/ |  | ||||||
| #endif                          /* SPLIT_WC_REGIONS */ |  | ||||||
| 
 |  | ||||||
|     if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &curwcr->sentry) >= 0) { |  | ||||||
|         /* Avoid printing on every VT switch */ |  | ||||||
|         if (xf86ServerIsInitialising()) { |  | ||||||
|             xf86DrvMsg(screenNum, from, |  | ||||||
|                        "Write-combining range (0x%lx,0x%lx)\n", base, size); |  | ||||||
|         } |  | ||||||
|         return wcreturn; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         *wcr = curwcr->next; |  | ||||||
|         free(curwcr); |  | ||||||
| 
 |  | ||||||
|         /* Don't complain about the VGA region: MTRR fixed
 |  | ||||||
|            regions aren't currently supported, but might be in |  | ||||||
|            the future. */ |  | ||||||
|         if ((unsigned long) base >= 0x100000) { |  | ||||||
|             xf86DrvMsgVerb(screenNum, X_WARNING, 0, |  | ||||||
|                            "Failed to set up write-combining range " |  | ||||||
|                            "(0x%lx,0x%lx)\n", base, size); |  | ||||||
|         } |  | ||||||
|         return wcreturn; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| mtrr_undo_wc_region(int screenNum, struct mtrr_wc_region *wcr) |  | ||||||
| { |  | ||||||
|     struct mtrr_wc_region *p, *prev; |  | ||||||
| 
 |  | ||||||
|     if (mtrr_fd >= 0) { |  | ||||||
|         p = wcr; |  | ||||||
|         while (p) { |  | ||||||
|             if (p->added) |  | ||||||
|                 ioctl(mtrr_fd, MTRRIOC_DEL_ENTRY, &p->sentry); |  | ||||||
|             prev = p; |  | ||||||
|             p = p->next; |  | ||||||
|             free(prev); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void * |  | ||||||
| setWC(int screenNum, unsigned long base, unsigned long size, Bool enable, |  | ||||||
|       MessageType from) |  | ||||||
| { |  | ||||||
|     if (enable) |  | ||||||
|         return mtrr_add_wc_region(screenNum, base, size, from); |  | ||||||
|     else |  | ||||||
|         return mtrr_cull_wc_region(screenNum, base, size, from); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| undoWC(int screenNum, void *regioninfo) |  | ||||||
| { |  | ||||||
|     mtrr_undo_wc_region(screenNum, regioninfo); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #endif                          /* HAS_MTRR_SUPPORT */ |  | ||||||
| 
 |  | ||||||
| void | void | ||||||
| xf86OSInitVidMem(VidMemInfoPtr pVidMem) | xf86OSInitVidMem(VidMemInfoPtr pVidMem) | ||||||
| { | { | ||||||
|  | @ -375,10 +112,6 @@ xf86OSInitVidMem(VidMemInfoPtr pVidMem) | ||||||
|     } |     } | ||||||
| #endif                          /* __alpha__ */ | #endif                          /* __alpha__ */ | ||||||
| 
 | 
 | ||||||
| #ifdef HAS_MTRR_SUPPORT |  | ||||||
|     pVidMem->setWC = setWC; |  | ||||||
|     pVidMem->undoWC = undoWC; |  | ||||||
| #endif |  | ||||||
|     pVidMem->initialised = TRUE; |     pVidMem->initialised = TRUE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -129,7 +129,7 @@ xf86CheckMTRR(int ScreenNum) | ||||||
|      */ |      */ | ||||||
|     checkMtrrOption(vp); |     checkMtrrOption(vp); | ||||||
| 
 | 
 | ||||||
|     if (vp->mtrrEnabled && vidMemInfo.setWC) |     if (vp->mtrrEnabled) | ||||||
|         return TRUE; |         return TRUE; | ||||||
| 
 | 
 | ||||||
|     return FALSE; |     return FALSE; | ||||||
|  |  | ||||||
|  | @ -32,14 +32,8 @@ | ||||||
| #ifndef _XF86OSPRIV_H | #ifndef _XF86OSPRIV_H | ||||||
| #define _XF86OSPRIV_H | #define _XF86OSPRIV_H | ||||||
| 
 | 
 | ||||||
| typedef void *(*SetWCProcPtr) (int, unsigned long, unsigned long, Bool, |  | ||||||
|                                  MessageType); |  | ||||||
| typedef void (*UndoWCProcPtr) (int, void *); |  | ||||||
| 
 |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     Bool initialised; |     Bool initialised; | ||||||
|     SetWCProcPtr setWC; |  | ||||||
|     UndoWCProcPtr undoWC; |  | ||||||
|     Bool linearSupported; |     Bool linearSupported; | ||||||
| } VidMemInfo, *VidMemInfoPtr; | } VidMemInfo, *VidMemInfoPtr; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue