/* * Copyright (c) 1997-2003 by The XFree86 Project, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of the copyright holder(s) * and author(s) shall not be used in advertising or otherwise to promote * the sale, use or other dealings in this Software without prior written * authorization from the copyright holder(s) and author(s). */ /* * This file contains the interfaces to the bus-specific code */ #ifdef HAVE_XORG_CONFIG_H #include #endif #include #include #include #include #include "os.h" #include "xf86.h" #include "xf86Priv.h" #include "xf86Resources.h" /* Bus-specific headers */ #include "xf86Bus.h" #define XF86_OS_PRIVS #define NEED_OS_RAC_PROTOS #include "xf86_OSproc.h" #include "xf86RAC.h" #include "Pci.h" /* Entity data */ EntityPtr *xf86Entities = NULL; /* Bus slots claimed by drivers */ int xf86NumEntities = 0; static int xf86EntityPrivateCount = 0; BusAccPtr xf86BusAccInfo = NULL; static void noopEnableDisable(void *arg) { } xf86AccessRec AccessNULL = { noopEnableDisable, noopEnableDisable, NULL }; xf86CurrentAccessRec xf86CurrentAccess = {NULL,NULL}; BusRec primaryBus = { BUS_NONE, {{0}}}; static Bool xf86ResAccessEnter = FALSE; /* resource lists */ resPtr Acc = NULL; /* predefined special resources */ _X_EXPORT resRange resVgaExclusive[] = {_VGA_EXCLUSIVE, _END}; _X_EXPORT resRange resVgaShared[] = {_VGA_SHARED, _END}; _X_EXPORT resRange resVgaMemShared[] = {_VGA_SHARED_MEM,_END}; _X_EXPORT resRange resVgaIoShared[] = {_VGA_SHARED_IO,_END}; _X_EXPORT resRange resVgaUnusedExclusive[] = {_VGA_EXCLUSIVE_UNUSED, _END}; _X_EXPORT resRange resVgaUnusedShared[] = {_VGA_SHARED_UNUSED, _END}; _X_EXPORT resRange resVgaSparseExclusive[] = {_VGA_EXCLUSIVE_SPARSE, _END}; _X_EXPORT resRange resVgaSparseShared[] = {_VGA_SHARED_SPARSE, _END}; _X_EXPORT resRange res8514Exclusive[] = {_8514_EXCLUSIVE, _END}; _X_EXPORT resRange res8514Shared[] = {_8514_SHARED, _END}; /* Flag: do we need RAC ? */ static Bool needRAC = FALSE; static Bool doFramebufferMode = FALSE; /* state change notification callback list */ static StateChangeNotificationPtr StateChangeNotificationList; static void notifyStateChange(xf86NotifyState state); /* * Call the bus probes relevant to the architecture. * * The only one available so far is for PCI and SBUS. */ void xf86BusProbe(void) { xf86PciProbe(); #if (defined(__sparc__) || defined(__sparc)) xf86SbusProbe(); #endif } /* * Determine what bus type the busID string represents. The start of the * bus-dependent part of the string is returned as retID. */ BusType StringToBusType(const char* busID, const char **retID) { char *p, *s; BusType ret = BUS_NONE; /* If no type field, Default to PCI */ if (isdigit(busID[0])) { if (retID) *retID = busID; return BUS_PCI; } s = xstrdup(busID); p = strtok(s, ":"); if (p == NULL || *p == 0) { xfree(s); return BUS_NONE; } if (!xf86NameCmp(p, "pci") || !xf86NameCmp(p, "agp")) ret = BUS_PCI; if (!xf86NameCmp(p, "sbus")) ret = BUS_SBUS; if (ret != BUS_NONE) if (retID) *retID = busID + strlen(p) + 1; xfree(s); return ret; } /* * Entity related code. */ void xf86EntityInit(void) { int i; xf86AccessPtr pacc; for (i = 0; i < xf86NumEntities; i++) if (xf86Entities[i]->entityInit) { if (xf86Entities[i]->access->busAcc) ((BusAccPtr)xf86Entities[i]->access->busAcc)->set_f (xf86Entities[i]->access->busAcc); pacc = xf86Entities[i]->access->fallback; pacc->AccessEnable(pacc->arg); xf86Entities[i]->entityInit(i,xf86Entities[i]->private); pacc->AccessDisable(pacc->arg); } } int xf86AllocateEntity(void) { xf86NumEntities++; xf86Entities = xnfrealloc(xf86Entities, sizeof(EntityPtr) * xf86NumEntities); xf86Entities[xf86NumEntities - 1] = xnfcalloc(1,sizeof(EntityRec)); xf86Entities[xf86NumEntities - 1]->entityPrivates = xnfcalloc(sizeof(DevUnion) * xf86EntityPrivateCount, 1); return (xf86NumEntities - 1); } static void EntityEnter(void) { int i; xf86AccessPtr pacc; for (i = 0; i < xf86NumEntities; i++) if (xf86Entities[i]->entityEnter) { if (xf86Entities[i]->access->busAcc) ((BusAccPtr)xf86Entities[i]->access->busAcc)->set_f (xf86Entities[i]->access->busAcc); pacc = xf86Entities[i]->access->fallback; pacc->AccessEnable(pacc->arg); xf86Entities[i]->entityEnter(i,xf86Entities[i]->private); pacc->AccessDisable(pacc->arg); } } static void EntityLeave(void) { int i; xf86AccessPtr pacc; for (i = 0; i < xf86NumEntities; i++) if (xf86Entities[i]->entityLeave) { if (xf86Entities[i]->access->busAcc) ((BusAccPtr)xf86Entities[i]->access->busAcc)->set_f (xf86Entities[i]->access->busAcc); pacc = xf86Entities[i]->access->fallback; pacc->AccessEnable(pacc->arg); xf86Entities[i]->entityLeave(i,xf86Entities[i]->private); pacc->AccessDisable(pacc->arg); } } _X_EXPORT Bool xf86IsEntityPrimary(int entityIndex) { EntityPtr pEnt = xf86Entities[entityIndex]; if (primaryBus.type != pEnt->busType) return FALSE; switch (pEnt->busType) { case BUS_PCI: return (pEnt->bus.id.pci == primaryBus.id.pci); case BUS_SBUS: return (pEnt->sbusBusId.fbNum == primaryBus.id.sbus.fbNum); default: return FALSE; } } Bool xf86SetEntityFuncs(int entityIndex, EntityProc init, EntityProc enter, EntityProc leave, pointer private) { if (entityIndex >= xf86NumEntities) return FALSE; xf86Entities[entityIndex]->entityInit = init; xf86Entities[entityIndex]->entityEnter = enter; xf86Entities[entityIndex]->entityLeave = leave; xf86Entities[entityIndex]->private = private; return TRUE; } Bool xf86DriverHasEntities(DriverPtr drvp) { int i; for (i = 0; i < xf86NumEntities; i++) { if (xf86Entities[i]->driver == drvp) return TRUE; } return FALSE; } _X_EXPORT void xf86AddEntityToScreen(ScrnInfoPtr pScrn, int entityIndex) { if (entityIndex == -1) return; if (xf86Entities[entityIndex]->inUse && !(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL)) { ErrorF("Requested Entity already in use!\n"); return; } pScrn->numEntities++; pScrn->entityList = xnfrealloc(pScrn->entityList, pScrn->numEntities * sizeof(int)); pScrn->entityList[pScrn->numEntities - 1] = entityIndex; xf86Entities[entityIndex]->access->next = pScrn->access; pScrn->access = xf86Entities[entityIndex]->access; xf86Entities[entityIndex]->inUse = TRUE; pScrn->entityInstanceList = xnfrealloc(pScrn->entityInstanceList, pScrn->numEntities * sizeof(int)); pScrn->entityInstanceList[pScrn->numEntities - 1] = 0; pScrn->domainIOBase = xf86Entities[entityIndex]->domainIO; } _X_EXPORT void xf86SetEntityInstanceForScreen(ScrnInfoPtr pScrn, int entityIndex, int instance) { int i; if (entityIndex == -1 || entityIndex >= xf86NumEntities) return; for (i = 0; i < pScrn->numEntities; i++) { if (pScrn->entityList[i] == entityIndex) { pScrn->entityInstanceList[i] = instance; break; } } } /* * XXX This needs to be updated for the case where a single entity may have * instances associated with more than one screen. */ _X_EXPORT ScrnInfoPtr xf86FindScreenForEntity(int entityIndex) { int i,j; if (entityIndex == -1) return NULL; if (xf86Screens) { for (i = 0; i < xf86NumScreens; i++) { for (j = 0; j < xf86Screens[i]->numEntities; j++) { if ( xf86Screens[i]->entityList[j] == entityIndex ) return (xf86Screens[i]); } } } return NULL; } _X_EXPORT void xf86RemoveEntityFromScreen(ScrnInfoPtr pScrn, int entityIndex) { int i; EntityAccessPtr *ptr = (EntityAccessPtr *)&pScrn->access; EntityAccessPtr peacc; for (i = 0; i < pScrn->numEntities; i++) { if (pScrn->entityList[i] == entityIndex) { peacc = xf86Entities[pScrn->entityList[i]]->access; (*ptr) = peacc->next; /* disable entity: call disable func */ if (peacc->pAccess) peacc->pAccess->AccessDisable(peacc->pAccess->arg); /* also disable fallback - just in case */ if (peacc->fallback) peacc->fallback->AccessDisable(peacc->fallback->arg); for (i++; i < pScrn->numEntities; i++) pScrn->entityList[i-1] = pScrn->entityList[i]; pScrn->numEntities--; xf86Entities[entityIndex]->inUse = FALSE; break; } ptr = &(xf86Entities[pScrn->entityList[i]]->access->next); } } /* * xf86ClearEntitiesForScreen() - called when a screen is deleted * to mark it's entities unused. Called by xf86DeleteScreen(). */ void xf86ClearEntityListForScreen(int scrnIndex) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; EntityAccessPtr peacc; int i, entityIndex; if (pScrn->entityList == NULL || pScrn->numEntities == 0) return; for (i = 0; i < pScrn->numEntities; i++) { entityIndex = pScrn->entityList[i]; xf86Entities[entityIndex]->inUse = FALSE; /* disable resource: call the disable function */ peacc = xf86Entities[entityIndex]->access; if (peacc->pAccess) peacc->pAccess->AccessDisable(peacc->pAccess->arg); /* and the fallback function */ if (peacc->fallback) peacc->fallback->AccessDisable(peacc->fallback->arg); /* shared resources are only needed when entity is active: remove */ xf86DeallocateResourcesForEntity(entityIndex, ResShared); } xfree(pScrn->entityList); xfree(pScrn->entityInstanceList); if (pScrn->CurrentAccess->pIoAccess == (EntityAccessPtr)pScrn->access) pScrn->CurrentAccess->pIoAccess = NULL; if (pScrn->CurrentAccess->pMemAccess == (EntityAccessPtr)pScrn->access) pScrn->CurrentAccess->pMemAccess = NULL; pScrn->entityList = NULL; pScrn->entityInstanceList = NULL; } void xf86DeallocateResourcesForEntity(int entityIndex, unsigned long type) { resPtr *pprev_next = &Acc; resPtr res = Acc; while (res) { if (res->entityIndex == entityIndex && (type & ResAccMask & res->res_type)) { (*pprev_next) = res->next; xfree(res); } else pprev_next = &(res->next); res = (*pprev_next); } } /* * Add an extra device section (GDevPtr) to an entity. */ void xf86AddDevToEntity(int entityIndex, GDevPtr dev) { EntityPtr pEnt; if (entityIndex >= xf86NumEntities) return; pEnt = xf86Entities[entityIndex]; pEnt->numInstances++; pEnt->devices = xnfrealloc(pEnt->devices, pEnt->numInstances * sizeof(GDevPtr)); pEnt->devices[pEnt->numInstances - 1] = dev; dev->claimed = TRUE; } /* * xf86GetEntityInfo() -- This function hands information from the * EntityRec struct to the drivers. The EntityRec structure itself * remains invisible to the driver. */ _X_EXPORT EntityInfoPtr xf86GetEntityInfo(int entityIndex) { EntityInfoPtr pEnt; int i; if (entityIndex >= xf86NumEntities) return NULL; pEnt = xnfcalloc(1,sizeof(EntityInfoRec)); pEnt->index = entityIndex; pEnt->location = xf86Entities[entityIndex]->bus; pEnt->active = xf86Entities[entityIndex]->active; pEnt->chipset = xf86Entities[entityIndex]->chipset; pEnt->resources = xf86Entities[entityIndex]->resources; pEnt->driver = xf86Entities[entityIndex]->driver; if ( (xf86Entities[entityIndex]->devices) && (xf86Entities[entityIndex]->devices[0]) ) { for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++) if (xf86Entities[entityIndex]->devices[i]->screen == 0) break; pEnt->device = xf86Entities[entityIndex]->devices[i]; } else pEnt->device = NULL; return pEnt; } _X_EXPORT int xf86GetNumEntityInstances(int entityIndex) { if (entityIndex >= xf86NumEntities) return -1; return xf86Entities[entityIndex]->numInstances; } _X_EXPORT GDevPtr xf86GetDevFromEntity(int entityIndex, int instance) { int i; /* We might not use AddDevtoEntity */ if ( (!xf86Entities[entityIndex]->devices) || (!xf86Entities[entityIndex]->devices[0]) ) return NULL; if (entityIndex >= xf86NumEntities || instance >= xf86Entities[entityIndex]->numInstances) return NULL; for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++) if (xf86Entities[entityIndex]->devices[i]->screen == instance) break; return xf86Entities[entityIndex]->devices[i]; } /* * general generic disable function. */ static void disableAccess(void) { int i; xf86AccessPtr pacc; EntityAccessPtr peacc; /* call disable funcs and reset current access pointer */ /* the entity specific access funcs are in an enabled */ /* state - driver must restore their state explicitely */ for (i = 0; i < xf86NumScreens; i++) { peacc = xf86Screens[i]->CurrentAccess->pIoAccess; while (peacc) { if (peacc->pAccess) peacc->pAccess->AccessDisable(peacc->pAccess->arg); peacc = peacc->next; } xf86Screens[i]->CurrentAccess->pIoAccess = NULL; peacc = xf86Screens[i]->CurrentAccess->pMemAccess; while (peacc) { if (peacc->pAccess) peacc->pAccess->AccessDisable(peacc->pAccess->arg); peacc = peacc->next; } xf86Screens[i]->CurrentAccess->pMemAccess = NULL; } /* then call the generic entity disable funcs */ for (i = 0; i < xf86NumEntities; i++) { pacc = xf86Entities[i]->access->fallback; pacc->AccessDisable(pacc->arg); } } static void clearAccess(void) { int i; /* call disable funcs and reset current access pointer */ /* the entity specific access funcs are in an enabled */ /* state - driver must restore their state explicitely */ for (i = 0; i < xf86NumScreens; i++) { xf86Screens[i]->CurrentAccess->pIoAccess = NULL; xf86Screens[i]->CurrentAccess->pMemAccess = NULL; } } /* * Generic interface to bus specific code - add other buses here */ /* * xf86AccessInit() - set up everything needed for access control * called only once on first server generation. */ void xf86AccessInit(void) { initPciState(); initPciBusState(); DisablePciBusAccess(); DisablePciAccess(); xf86ResAccessEnter = TRUE; } /* * xf86AccessEnter() -- gets called to save the text mode VGA IO * resources when reentering the server after a VT switch. */ void xf86AccessEnter(void) { if (xf86ResAccessEnter) return; /* * on enter we simply disable routing of special resources * to any bus and let the RAC code to "open" the right bridges. */ PciBusStateEnter(); DisablePciBusAccess(); PciStateEnter(); disableAccess(); EntityEnter(); notifyStateChange(NOTIFY_ENTER); xf86EnterServerState(SETUP); xf86ResAccessEnter = TRUE; } /* * xf86AccessLeave() -- prepares access for and calls the * entityLeave() functions. * xf86AccessLeaveState() --- gets called to restore the * access to the VGA IO resources when switching VT or on * server exit. * This was split to call xf86AccessLeaveState() from * ddxGiveUp(). */ void xf86AccessLeave(void) { if (!xf86ResAccessEnter) return; notifyStateChange(NOTIFY_LEAVE); disableAccess(); DisablePciBusAccess(); EntityLeave(); } void xf86AccessLeaveState(void) { if (!xf86ResAccessEnter) return; xf86ResAccessEnter = FALSE; PciStateLeave(); PciBusStateLeave(); } /* * xf86AccessRestoreState() - Restore the access registers to the * state before X was started. This is handy for framebuffers. */ static void xf86AccessRestoreState(void) { if (!xf86ResAccessEnter) return; PciStateLeave(); PciBusStateLeave(); } /* * xf86EnableAccess() -- enable access to controlled resources. * To reduce latency when switching access the ScrnInfoRec has * a linked list of the EntityAccPtr of all screen entities. */ /* * switching access needs to be done in te following oder: * disable * 1. disable old entity * 2. reroute bus * 3. enable new entity * Otherwise resources needed for access control might be shadowed * by other resources! */ _X_EXPORT void xf86EnableAccess(ScrnInfoPtr pScrn) { register EntityAccessPtr peAcc = (EntityAccessPtr) pScrn->access; register EntityAccessPtr pceAcc; register xf86AccessPtr pAcc; EntityAccessPtr tmp; #ifdef DEBUG ErrorF("Enable access %i\n",pScrn->scrnIndex); #endif /* Entity is not under access control or currently enabled */ if (!pScrn->access) { if (pScrn->busAccess) { ((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess); } return; } switch (pScrn->resourceType) { case IO: pceAcc = pScrn->CurrentAccess->pIoAccess; if (peAcc == pceAcc) { return; } if (pScrn->CurrentAccess->pMemAccess == pceAcc) pScrn->CurrentAccess->pMemAccess = NULL; while (pceAcc) { pAcc = pceAcc->pAccess; if (pAcc) pAcc->AccessDisable(pAcc->arg); pceAcc = pceAcc->next; } if (pScrn->busAccess) ((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess); while (peAcc) { pAcc = peAcc->pAccess; if (pAcc) pAcc->AccessEnable(pAcc->arg); peAcc = peAcc->next; } pScrn->CurrentAccess->pIoAccess = (EntityAccessPtr) pScrn->access; return; case MEM_IO: pceAcc = pScrn->CurrentAccess->pIoAccess; if (peAcc != pceAcc) { /* current Io != pAccess */ tmp = pceAcc; while (pceAcc) { pAcc = pceAcc->pAccess; if (pAcc) pAcc->AccessDisable(pAcc->arg); pceAcc = pceAcc->next; } pceAcc = pScrn->CurrentAccess->pMemAccess; if (peAcc != pceAcc /* current Mem != pAccess */ && tmp !=pceAcc) { while (pceAcc) { pAcc = pceAcc->pAccess; if (pAcc) pAcc->AccessDisable(pAcc->arg); pceAcc = pceAcc->next; } } } else { /* current Io == pAccess */ pceAcc = pScrn->CurrentAccess->pMemAccess; if (pceAcc == peAcc) { /* current Mem == pAccess */ return; } while (pceAcc) { /* current Mem != pAccess */ pAcc = pceAcc->pAccess; if (pAcc) pAcc->AccessDisable(pAcc->arg); pceAcc = pceAcc->next; } } if (pScrn->busAccess) ((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess); while (peAcc) { pAcc = peAcc->pAccess; if (pAcc) pAcc->AccessEnable(pAcc->arg); peAcc = peAcc->next; } pScrn->CurrentAccess->pMemAccess = pScrn->CurrentAccess->pIoAccess = (EntityAccessPtr) pScrn->access; return; case MEM: pceAcc = pScrn->CurrentAccess->pMemAccess; if (peAcc == pceAcc) { return; } if (pScrn->CurrentAccess->pIoAccess == pceAcc) pScrn->CurrentAccess->pIoAccess = NULL; while (pceAcc) { pAcc = pceAcc->pAccess; if (pAcc) pAcc->AccessDisable(pAcc->arg); pceAcc = pceAcc->next; } if (pScrn->busAccess) ((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess); while (peAcc) { pAcc = peAcc->pAccess; if (pAcc) pAcc->AccessEnable(pAcc->arg); peAcc = peAcc->next; } pScrn->CurrentAccess->pMemAccess = (EntityAccessPtr) pScrn->access; return; case NONE: if (pScrn->busAccess) { ((BusAccPtr)pScrn->busAccess)->set_f(pScrn->busAccess); } return; } } _X_EXPORT void xf86SetCurrentAccess(Bool Enable, ScrnInfoPtr pScrn) { EntityAccessPtr pceAcc2 = NULL; register EntityAccessPtr pceAcc = NULL; register xf86AccessPtr pAcc; switch(pScrn->resourceType) { case IO: pceAcc = pScrn->CurrentAccess->pIoAccess; break; case MEM: pceAcc = pScrn->CurrentAccess->pMemAccess; break; case MEM_IO: pceAcc = pScrn->CurrentAccess->pMemAccess; pceAcc2 = pScrn->CurrentAccess->pIoAccess; break; default: break; } while (pceAcc) { pAcc = pceAcc->pAccess; if (pAcc) { if (Enable) { pAcc->AccessEnable(pAcc->arg); } else { pAcc->AccessDisable(pAcc->arg); } } pceAcc = pceAcc->next; if (!pceAcc) { pceAcc = pceAcc2; pceAcc2 = NULL; } } } _X_EXPORT void xf86SetAccessFuncs(EntityInfoPtr pEnt, xf86SetAccessFuncPtr funcs, xf86SetAccessFuncPtr oldFuncs) { AccessFuncPtr rac; if (!xf86Entities[pEnt->index]->rac) xf86Entities[pEnt->index]->rac = xnfcalloc(1,sizeof(AccessFuncRec)); rac = xf86Entities[pEnt->index]->rac; rac->mem_new = funcs->mem; rac->io_new = funcs->io; rac->io_mem_new = funcs->io_mem; rac->old = oldFuncs; } /* * Conflict checking */ static memType getMask(memType val) { memType mask = 0; memType tmp = 0; mask=~mask; tmp = ~((~tmp) >> 1); while (!(val & tmp)) { mask = mask >> 1; val = val << 1; } return mask; } /* * checkConflictBlock() -- check for conflicts of a block resource range. * If conflict is found return end of conflicting range. Else return 0. */ static memType checkConflictBlock(resRange *range, resPtr pRes) { memType val,tmp,prev; int i; switch (pRes->res_type & ResExtMask) { case ResBlock: if (range->rBegin < pRes->block_end && range->rEnd > pRes->block_begin) { #ifdef DEBUG ErrorF("b-b conflict w: %lx %lx\n", pRes->block_begin,pRes->block_end); #endif return pRes->block_end < range->rEnd ? pRes->block_end : range->rEnd; } return 0; case ResSparse: if (pRes->sparse_base > range->rEnd) return 0; val = (~pRes->sparse_mask | pRes->sparse_base) & getMask(range->rEnd); #ifdef DEBUG ErrorF("base = 0x%lx, mask = 0x%lx, begin = 0x%lx, end = 0x%lx ," "val = 0x%lx\n", pRes->sparse_base, pRes->sparse_mask, range->rBegin, range->rEnd, val); #endif i = sizeof(memType) * 8; tmp = prev = pRes->sparse_base; while (i) { tmp |= 1<< (--i) & val; if (tmp > range->rEnd) tmp = prev; else prev = tmp; } if (tmp >= range->rBegin) { #ifdef DEBUG ErrorF("conflict found at: 0x%lx\n",tmp); ErrorF("b-d conflict w: %lx %lx\n", pRes->sparse_base,pRes->sparse_mask); #endif return tmp; } else return 0; } return 0; } /* * checkConflictSparse() -- check for conflicts of a sparse resource range. * If conflict is found return base of conflicting region. Else return 0. */ #define mt_max ~(memType)0 #define length sizeof(memType) * 8 static memType checkConflictSparse(resRange *range, resPtr pRes) { memType val, tmp, prev; int i; switch (pRes->res_type & ResExtMask) { case ResSparse: tmp = pRes->sparse_mask & range->rMask; if ((tmp & pRes->sparse_base) == (tmp & range->rBase)) { #ifdef DEBUG ErrorF("s-b conflict w: %lx %lx\n", pRes->sparse_base,pRes->sparse_mask); #endif return pRes->sparse_mask; } return 0; case ResBlock: if (pRes->block_end < range->rBase) return 0; val = (~range->rMask | range->rBase) & getMask(pRes->block_end); i = length; tmp = prev = range->rBase; while (i) { #ifdef DEBUG ErrorF("tmp = 0x%lx\n",tmp); #endif tmp |= 1<< (--i) & val; if (tmp > pRes->block_end) tmp = prev; else prev = tmp; } if (tmp < pRes->block_begin) return 0; else { /* * now we subdivide the block region in sparse regions * with base values = 2^n and find the smallest mask. * This might be done in a simpler way.... */ memType mask, m_mask = 0, base = pRes->block_begin; int i; while (base < pRes->block_end) { for (i = 1; i < length; i++) if ( base != (base & (mt_max << i))) break; mask = mt_max >> (length - i); do mask >>= 1; while ((mask + base + 1) > pRes->block_end); /* m_mask and are _inverted_ sparse masks */ m_mask = mask > m_mask ? mask : m_mask; base = base + mask + 1; } #ifdef DEBUG ErrorF("conflict found at: 0x%lx\n",tmp); ErrorF("b-b conflict w: %lx %lx\n", pRes->block_begin,pRes->block_end); #endif return ~m_mask; } } return 0; } #undef mt_max #undef length /* * needCheck() -- this function decides whether to check for conflicts * depending on the types of the resource ranges and their locations */ static Bool needCheck(resPtr pRes, unsigned long type, int entityIndex, xf86State state) { /* the same entity shouldn't conflict with itself */ ScrnInfoPtr pScrn; int i; BusType loc = BUS_NONE; BusType r_loc = BUS_NONE; if ((pRes->res_type & ResTypeMask) != (type & ResTypeMask)) return FALSE; /* * Resources set by BIOS (ResBios) are allowed to conflict * with resources marked (ResBios). */ if (pRes->res_type & type & ResBios) return FALSE; if (type & pRes->res_type & ResUnused) return FALSE; if (state == OPERATING) { if (type & ResDisableOpr || pRes->res_type & ResDisableOpr) return FALSE; if (type & pRes->res_type & ResUnusedOpr) return FALSE; /* * Maybe we should have ResUnused set The resUnusedOpr * bit, too. This way we could avoid this confusion */ if ((type & ResUnusedOpr && pRes->res_type & ResUnused) || (type & ResUnused && pRes->res_type & ResUnusedOpr)) return FALSE; } if (entityIndex > -1) loc = xf86Entities[entityIndex]->busType; if (pRes->entityIndex > -1) r_loc = xf86Entities[pRes->entityIndex]->busType; if ((type & ResAccMask) == ResShared && (pRes->res_type & ResAccMask) == ResShared) return FALSE; if (pRes->entityIndex == entityIndex) return FALSE; if (pRes->entityIndex > -1 && (pScrn = xf86FindScreenForEntity(entityIndex))) { for (i = 0; i < pScrn->numEntities; i++) if (pScrn->entityList[i] == pRes->entityIndex) return FALSE; } return TRUE; } /* * checkConflict() - main conflict checking function which all other * function call. */ static memType checkConflict(resRange *rgp, resPtr pRes, int entityIndex, xf86State state, Bool ignoreIdentical) { memType ret; while(pRes) { if (!needCheck(pRes,rgp->type, entityIndex ,state)) { pRes = pRes->next; continue; } switch (rgp->type & ResExtMask) { case ResBlock: if (rgp->rEnd < rgp->rBegin) { xf86Msg(X_ERROR,"end of block range 0x%lx < begin 0x%lx\n", (long)rgp->rEnd, (long)rgp->rBegin); return 0; } if ((ret = checkConflictBlock(rgp, pRes))) { if (!ignoreIdentical || (rgp->rBegin != pRes->block_begin) || (rgp->rEnd != pRes->block_end)) return ret; } break; case ResSparse: if ((rgp->rBase & rgp->rMask) != rgp->rBase) { xf86Msg(X_ERROR,"sparse io range (base: 0x%lx mask: 0x%lx)" "doesn't satisfy (base & mask = mask)\n", (long)rgp->rBase, (long)rgp->rMask); return 0; } if ((ret = checkConflictSparse(rgp, pRes))) { if (!ignoreIdentical || (rgp->rBase != pRes->sparse_base) || (rgp->rMask != pRes->sparse_mask)) return ret; } break; } pRes = pRes->next; } return 0; } /* * xf86ChkConflict() - This function is the low level interface to * the resource broker that gets exported. Tests all resources ie. * performs test with SETUP flag. */ static memType xf86ChkConflict(resRange *rgp, int entityIndex) { return checkConflict(rgp, Acc, entityIndex, SETUP, FALSE); } /* * Resources List handling */ static resPtr xf86JoinResLists(resPtr rlist1, resPtr rlist2) { resPtr pRes; if (!rlist1) return rlist2; if (!rlist2) return rlist1; for (pRes = rlist1; pRes->next; pRes = pRes->next) ; pRes->next = rlist2; return rlist1; } resPtr xf86AddResToList(resPtr rlist, resRange *range, int entityIndex) { resPtr new; switch (range->type & ResExtMask) { case ResBlock: if (range->rEnd < range->rBegin) { xf86Msg(X_ERROR,"end of block range 0x%lx < begin 0x%lx\n", (long)range->rEnd, (long)range->rBegin); return rlist; } break; case ResSparse: if ((range->rBase & range->rMask) != range->rBase) { xf86Msg(X_ERROR,"sparse io range (base: 0x%lx mask: 0x%lx)" "doesn't satisfy (base & mask = mask)\n", (long)range->rBase, (long)range->rMask); return rlist; } break; } new = xnfalloc(sizeof(resRec)); /* * Only background resources may be registered with ResBios * and ResEstimated set. Other resources only set it for * testing. */ if (entityIndex != (-1)) range->type &= ~(ResBios | ResEstimated); new->val = *range; new->entityIndex = entityIndex; new->next = rlist; return new; } _X_EXPORT void xf86FreeResList(resPtr rlist) { resPtr pRes; if (!rlist) return; for (pRes = rlist->next; pRes; rlist = pRes, pRes = pRes->next) xfree(rlist); xfree(rlist); } static resPtr xf86DupResList(const resPtr rlist) { resPtr pRes, ret, prev, new; if (!rlist) return NULL; ret = xnfalloc(sizeof(resRec)); *ret = *rlist; prev = ret; for (pRes = rlist->next; pRes; pRes = pRes->next) { new = xnfalloc(sizeof(resRec)); *new = *pRes; prev->next = new; prev = new; } return ret; } static void xf86PrintResList(int verb, resPtr list) { int i = 0; const char *s, *r; resPtr tmp = list; unsigned long type; if (!list) return; type = ResMem; r = "M"; while (1) { while (list) { if ((list->res_type & ResPhysMask) == type) { switch (list->res_type & ResExtMask) { case ResBlock: xf86ErrorFVerb(verb, "\t[%d] %d\t%ld\t0x%08lx - 0x%08lx (0x%lx)", i, list->entityIndex, (list->res_type & ResDomain) >> 24, (long)list->block_begin, (long)list->block_end, (long)(list->block_end - list->block_begin + 1)); break; case ResSparse: xf86ErrorFVerb(verb, "\t[%d] %d\t%ld\t0x%08lx - 0x%08lx ", i, list->entityIndex, (list->res_type & ResDomain) >> 24, (long)list->sparse_base, (long)list->sparse_mask); break; default: list = list->next; continue; } xf86ErrorFVerb(verb, " %s", r); switch (list->res_type & ResAccMask) { case ResExclusive: if (list->res_type & ResUnused) s = "x"; else s = "X"; break; case ResShared: if (list->res_type & ResUnused) s = "s"; else s = "S"; break; default: s = "?"; } xf86ErrorFVerb(verb, "%s", s); switch (list->res_type & ResExtMask) { case ResBlock: s = "[B]"; break; case ResSparse: s = "[S]"; break; default: s = "[?]"; } xf86ErrorFVerb(verb, "%s", s); if (list->res_type & ResInit) xf86ErrorFVerb(verb, "t"); if (list->res_type & ResBios) xf86ErrorFVerb(verb, "(B)"); if (list->res_type & ResBus) xf86ErrorFVerb(verb, "(b)"); if (list->res_type & ResOprMask) { switch (list->res_type & ResOprMask) { case ResUnusedOpr: s = "(OprU)"; break; case ResDisableOpr: s = "(OprD)"; break; default: s = "(Opr?)"; break; } xf86ErrorFVerb(verb, "%s", s); } xf86ErrorFVerb(verb, "\n"); i++; } list = list->next; } if (type == ResIo) break; type = ResIo; r = "I"; list = tmp; } } resPtr xf86AddRangesToList(resPtr list, resRange *pRange, int entityIndex) { while(pRange && pRange->type != ResEnd) { list = xf86AddResToList(list,pRange,entityIndex); pRange++; } return list; } void xf86ResourceBrokerInit(void) { Acc = NULL; /* Get the ranges used exclusively by the system */ Acc = xf86AccResFromOS(Acc); xf86MsgVerb(X_INFO, 3, "System resource ranges:\n"); xf86PrintResList(3, Acc); } /* * Resource registration */ static void convertRange2Host(int entityIndex, resRange *pRange) { if (pRange->type & ResBus) { switch (xf86Entities[entityIndex]->busType) { case BUS_PCI: pciConvertRange2Host(entityIndex,pRange); break; default: break; } pRange->type &= ~ResBus; } } static void xf86ConvertListToHost(int entityIndex, resPtr list) { while (list) { convertRange2Host(entityIndex, &list->val); list = list->next; } } /* * xf86RegisterResources() -- attempts to register listed resources. * Returns a resPtr listing all resources not successfully registered, by * which we mean, NULL. */ _X_EXPORT resPtr xf86RegisterResources(int entityIndex, resList list, unsigned long access) { resRange range; resList list_f = NULL; if (!list) return NULL; while(list->type != ResEnd) { range = *list; convertRange2Host(entityIndex,&range); if ((access != ResNone) && (access & ResAccMask)) { range.type = (range.type & ~ResAccMask) | (access & ResAccMask); } range.type &= ~ResEstimated; /* Not allowed for drivers */ Acc = xf86AddResToList(Acc,&range,entityIndex); list++; } if (list_f) xfree(list_f); #ifdef DEBUG xf86MsgVerb(X_INFO, 3,"Resources after driver initialization\n"); xf86PrintResList(3, Acc); #endif return NULL; } static void busTypeSpecific(EntityPtr pEnt, xf86AccessPtr *acc_mem, xf86AccessPtr *acc_io, xf86AccessPtr *acc_mem_io) { switch (pEnt->bus.type) { case BUS_SBUS: *acc_mem = *acc_io = *acc_mem_io = &AccessNULL; break; case BUS_PCI: { struct pci_device *const dev = pEnt->bus.id.pci; if ((dev != NULL) && ((void *)dev->user_data != NULL)) { pciAccPtr const paccp = (pciAccPtr) dev->user_data; *acc_io = & paccp->ioAccess; *acc_mem = & paccp->memAccess; *acc_mem_io = & paccp->io_memAccess; } else { /* FIXME: This is an error path. We should probably have an * FIXME: assertion here or something. */ *acc_io = NULL; *acc_mem = NULL; *acc_mem_io = NULL; } break; } default: *acc_mem = *acc_io = *acc_mem_io = NULL; break; } return; } static void setAccess(EntityPtr pEnt, xf86State state) { xf86AccessPtr acc_mem, acc_io, acc_mem_io; xf86AccessPtr org_mem = NULL, org_io = NULL, org_mem_io = NULL; int prop; busTypeSpecific(pEnt, &acc_mem, &acc_io, &acc_mem_io); /* The replacement function needs to handle _all_ shared resources */ /* unless they are handeled locally and disabled otherwise */ if (pEnt->rac) { if (pEnt->rac->io_new) { org_io = acc_io; acc_io = pEnt->rac->io_new; } if (pEnt->rac->mem_new) { org_mem = acc_mem; acc_mem = pEnt->rac->mem_new; } if (pEnt->rac->io_mem_new) { org_mem_io = acc_mem_io; acc_mem_io = pEnt->rac->io_mem_new; } } if (state == OPERATING) { prop = pEnt->entityProp; switch(pEnt->entityProp & NEED_SHARED) { case NEED_SHARED: pEnt->access->rt = MEM_IO; break; case NEED_IO_SHARED: pEnt->access->rt = IO; break; case NEED_MEM_SHARED: pEnt->access->rt = MEM; break; default: pEnt->access->rt = NONE; } } else { prop = NEED_SHARED | NEED_MEM | NEED_IO; pEnt->access->rt = MEM_IO; } switch(pEnt->access->rt) { case IO: pEnt->access->pAccess = acc_io; break; case MEM: pEnt->access->pAccess = acc_mem; break; case MEM_IO: pEnt->access->pAccess = acc_mem_io; break; default: /* no conflicts at all */ pEnt->access->pAccess = NULL; /* remove from RAC */ break; } if (org_io) { /* does the driver want the old access func? */ if (pEnt->rac->old) { /* give it to the driver, leave state disabled */ pEnt->rac->old->io = org_io; } else { /* driver doesn't want it - enable generic access */ org_io->AccessEnable(org_io->arg); } } if (org_mem_io) { /* does the driver want the old access func? */ if (pEnt->rac->old) { /* give it to the driver, leave state disabled */ pEnt->rac->old->io_mem = org_mem_io; } else { /* driver doesn't want it - enable generic access */ org_mem_io->AccessEnable(org_mem_io->arg); } } if (org_mem) { /* does the driver want the old access func? */ if (pEnt->rac->old) { /* give it to the driver, leave state disabled */ pEnt->rac->old->mem = org_mem; } else { /* driver doesn't want it - enable generic access */ org_mem->AccessEnable(org_mem->arg); } } if (!(prop & NEED_MEM_SHARED)){ if (prop & NEED_MEM) { if (acc_mem) acc_mem->AccessEnable(acc_mem->arg); } else { if (acc_mem) acc_mem->AccessDisable(acc_mem->arg); } } if (!(prop & NEED_IO_SHARED)) { if (prop & NEED_IO) { if (acc_io) acc_io->AccessEnable(acc_io->arg); } else { if (acc_io) acc_io->AccessDisable(acc_io->arg); } } /* disable shared resources */ if (pEnt->access->pAccess) pEnt->access->pAccess->AccessDisable(pEnt->access->pAccess->arg); /* * If device is not under access control it is enabled. * If it needs bus routing do it here as it isn't bus * type specific. Any conflicts should be checked at this * stage */ if (!pEnt->access->pAccess && (pEnt->entityProp & (state == SETUP ? NEED_VGA_ROUTED_SETUP : NEED_VGA_ROUTED))) ((BusAccPtr)pEnt->busAcc)->set_f(pEnt->busAcc); } /* * xf86EnterServerState() -- set state the server is in. */ typedef enum { TRI_UNSET, TRI_TRUE, TRI_FALSE } TriState; static void SetSIGIOForState(xf86State state) { static int sigio_state; static TriState sigio_blocked = TRI_UNSET; if ((state == SETUP) && (sigio_blocked != TRI_TRUE)) { sigio_state = xf86BlockSIGIO(); sigio_blocked = TRI_TRUE; } else if ((state == OPERATING) && (sigio_blocked != TRI_UNSET)) { xf86UnblockSIGIO(sigio_state); sigio_blocked = TRI_FALSE; } } void xf86EnterServerState(xf86State state) { EntityPtr pEnt; ScrnInfoPtr pScrn; int i,j; int needVGA = 0; resType rt; /* * This is a good place to block SIGIO during SETUP state. * SIGIO should be blocked in SETUP state otherwise (u)sleep() * might get interrupted early. * We take care not to call xf86BlockSIGIO() twice. */ SetSIGIOForState(state); #ifdef DEBUG if (state == SETUP) ErrorF("Entering SETUP state\n"); else ErrorF("Entering OPERATING state\n"); #endif /* When servicing a dumb framebuffer we don't need to do anything */ if (doFramebufferMode) return; for (i=0; ientityList[pScrn->numEntities - 1]; pScrn->access = xf86Entities[j]->access; for (j = 0; jnumEntities; j++) { pEnt = xf86Entities[xf86Screens[i]->entityList[j]]; if (pEnt->entityProp & (state == SETUP ? NEED_VGA_ROUTED_SETUP : NEED_VGA_ROUTED)) xf86Screens[i]->busAccess = pEnt->busAcc; } if (xf86Screens[i]->busAccess) needVGA ++; } /* * if we just have one screen we don't have RAC. * Therefore just enable the screen and return. */ if (!needRAC) { xf86EnableAccess(xf86Screens[0]); notifyStateChange(NOTIFY_ENABLE); return; } if (state == SETUP) notifyStateChange(NOTIFY_SETUP_TRANSITION); else notifyStateChange(NOTIFY_OPERATING_TRANSITION); clearAccess(); for (i=0; inumEntities; j++) { pEnt = xf86Entities[xf86Screens[i]->entityList[j]]; setAccess(pEnt,state); if (pEnt->access->rt != NONE) { if (rt != NONE && rt != pEnt->access->rt) rt = MEM_IO; else rt = pEnt->access->rt; } } xf86Screens[i]->resourceType = rt; if (rt == NONE) { xf86Screens[i]->access = NULL; if (needVGA < 2) xf86Screens[i]->busAccess = NULL; } #ifdef DEBUG if (xf86Screens[i]->busAccess) ErrorF("Screen %i setting vga route\n",i); #endif switch (rt) { case MEM_IO: xf86MsgVerb(X_INFO, 3, "Screen %i shares mem & io resources\n",i); break; case IO: xf86MsgVerb(X_INFO, 3, "Screen %i shares io resources\n",i); break; case MEM: xf86MsgVerb(X_INFO, 3, "Screen %i shares mem resources\n",i); break; default: xf86MsgVerb(X_INFO, 3, "Entity %i shares no resources\n",i); break; } } if (state == SETUP) notifyStateChange(NOTIFY_SETUP); else notifyStateChange(NOTIFY_OPERATING); } /* * xf86SetOperatingState() -- Set ResOperMask for resources listed. */ _X_EXPORT resPtr xf86SetOperatingState(resList list, int entityIndex, int mask) { resPtr acc; resPtr r_fail = NULL; resRange range; while (list->type != ResEnd) { range = *list; convertRange2Host(entityIndex,&range); acc = Acc; while (acc) { #define MASK (ResTypeMask | ResExtMask) if ((acc->entityIndex == entityIndex) && (acc->val.a == range.a) && (acc->val.b == range.b) && ((acc->val.type & MASK) == (range.type & MASK))) break; #undef MASK acc = acc->next; } if (acc) acc->val.type = (acc->val.type & ~ResOprMask) | (mask & ResOprMask); else { r_fail = xf86AddResToList(r_fail,&range,entityIndex); } list ++; } return r_fail; } /* * Stage specific code */ /* * xf86ClaimFixedResources() is used to allocate non-relocatable resources. * This should only be done by a driver's Probe() function. */ _X_EXPORT void xf86ClaimFixedResources(resList list, int entityIndex) { resPtr ptr = NULL; resRange range; if (!list) return; while (list->type !=ResEnd) { range = *list; convertRange2Host(entityIndex,&range); range.type &= ~ResEstimated; /* Not allowed for drivers */ switch (range.type & ResAccMask) { case ResExclusive: if (!xf86ChkConflict(&range, entityIndex)) { Acc = xf86AddResToList(Acc, &range, entityIndex); } else FatalError("xf86ClaimFixedResources conflict\n"); break; case ResShared: /* at this stage the resources are just added to the * EntityRec. After the Probe() phase this list is checked by * xf86PostProbe(). All resources which don't * conflict with already allocated ones are allocated * and removed from the EntityRec. Thus a non-empty resource * list in the EntityRec indicates resource conflicts the * driver should either handle or fail. */ if (xf86Entities[entityIndex]->active) ptr = xf86AddResToList(ptr,&range,entityIndex); break; } list++; } xf86Entities[entityIndex]->resources = xf86JoinResLists(xf86Entities[entityIndex]->resources,ptr); xf86MsgVerb(X_INFO, 3, "resource ranges after xf86ClaimFixedResources() call:\n"); xf86PrintResList(3,Acc); #ifdef DEBUG if (ptr) { xf86MsgVerb(X_INFO, 3, "to be registered later:\n"); xf86PrintResList(3,ptr); } #endif } static void checkRoutingForScreens(xf86State state) { resList list = resVgaUnusedExclusive; resPtr pResVGA = NULL; resPtr pResVGAHost; pointer vga = NULL; int i,j; int entityIndex; EntityPtr pEnt; resPtr pAcc; resRange range; /* * find devices that need VGA routed: ie the ones that have * registered VGA resources without ResUnused. ResUnused * doesn't conflict with itself therefore use it here. */ while (list->type != ResEnd) { /* create resPtr from resList for VGA */ range = *list; range.type &= ~(ResBios | ResEstimated); /* if set remove them */ pResVGA = xf86AddResToList(pResVGA, &range, -1); list++; } for (i = 0; i < xf86NumScreens; i++) { for (j = 0; j < xf86Screens[i]->numEntities; j++) { entityIndex = xf86Screens[i]->entityList[j]; pEnt = xf86Entities[entityIndex]; pAcc = Acc; vga = NULL; pResVGAHost = xf86DupResList(pResVGA); xf86ConvertListToHost(entityIndex,pResVGAHost); while (pAcc) { if (pAcc->entityIndex == entityIndex) if (checkConflict(&pAcc->val, pResVGAHost, entityIndex, state, FALSE)) { if (vga && vga != pEnt->busAcc) { xf86Msg(X_ERROR, "Screen %i needs vga routed to" "different buses - deleting\n",i); xf86DeleteScreen(i--,0); } #ifdef DEBUG { resPtr rlist = xf86AddResToList(NULL,&pAcc->val, pAcc->entityIndex); xf86MsgVerb(X_INFO,3,"====== %s\n", state == OPERATING ? "OPERATING" : "SETUP"); xf86MsgVerb(X_INFO,3,"%s Resource:\n", (pAcc->val.type) & ResMem ? "Mem" :"Io"); xf86PrintResList(3,rlist); xf86FreeResList(rlist); xf86MsgVerb(X_INFO,3,"Conflicts with:\n"); xf86PrintResList(3,pResVGAHost); xf86MsgVerb(X_INFO,3,"=====\n"); } #endif vga = pEnt->busAcc; pEnt->entityProp |= (state == SETUP ? NEED_VGA_ROUTED_SETUP : NEED_VGA_ROUTED); if (state == OPERATING) { if (pAcc->val.type & ResMem) pEnt->entityProp |= NEED_VGA_MEM; else pEnt->entityProp |= NEED_VGA_IO; } } pAcc = pAcc->next; } if (vga) xf86MsgVerb(X_INFO, 3,"Setting vga for screen %i.\n",i); xf86FreeResList(pResVGAHost); } } xf86FreeResList(pResVGA); } /* * xf86PostProbe() -- Allocate all non conflicting resources * This function gets called by xf86Init(). */ void xf86PostProbe(void) { memType val; int i,j; resPtr resp, acc, tmp, resp_x; if (fbSlotClaimed) { if (pciSlotClaimed #if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) || sbusSlotClaimed #endif ) { FatalError("Cannot run in framebuffer mode. Please specify busIDs " " for all framebuffer devices\n"); return; } else { xf86Msg(X_INFO,"Running in FRAMEBUFFER Mode\n"); xf86AccessRestoreState(); notifyStateChange(NOTIFY_ENABLE); doFramebufferMode = TRUE; return; } } acc = tmp = xf86DupResList(Acc); for (i=0; iresources; xf86Entities[i]->resources = NULL; resp_x = NULL; while (resp) { if (! (val = checkConflict(&resp->val,acc,i,SETUP,FALSE))) { resp->res_type &= ~(ResBios); /* just used for chkConflict() */ tmp = resp_x; resp_x = resp; resp = resp->next; resp_x->next = tmp; } else { xf86MsgVerb(X_INFO, 3, "Found conflict at: 0x%lx\n", (long)val); resp->res_type &= ~ResEstimated; tmp = xf86Entities[i]->resources; xf86Entities[i]->resources = resp; resp = resp->next; xf86Entities[i]->resources->next = tmp; } } xf86JoinResLists(Acc,resp_x); } xf86FreeResList(acc); xf86MsgVerb(X_INFO, 3, "resource ranges after probing:\n"); xf86PrintResList(3, Acc); checkRoutingForScreens(SETUP); for (i = 0; i < xf86NumScreens; i++) { for (j = 0; jnumEntities; j++) { EntityPtr pEnt = xf86Entities[xf86Screens[i]->entityList[j]]; if ((pEnt->entityProp & NEED_VGA_ROUTED_SETUP) && ((xf86Screens[i]->busAccess = pEnt->busAcc))) break; } } } static void checkRequiredResources(int entityIndex) { resRange range; resPtr pAcc = Acc; const EntityPtr pEnt = xf86Entities[entityIndex]; while (pAcc) { if (pAcc->entityIndex == entityIndex) { range = pAcc->val; /* ResAny to find conflicts with anything. */ range.type = (range.type & ~ResAccMask) | ResAny | ResBios; if (checkConflict(&range,Acc,entityIndex,OPERATING,FALSE)) switch (pAcc->res_type & ResPhysMask) { case ResMem: pEnt->entityProp |= NEED_MEM_SHARED; break; case ResIo: pEnt->entityProp |= NEED_IO_SHARED; break; } if (!(pAcc->res_type & ResOprMask)) { switch (pAcc->res_type & ResPhysMask) { case ResMem: pEnt->entityProp |= NEED_MEM; break; case ResIo: pEnt->entityProp |= NEED_IO; break; } } } pAcc = pAcc->next; } /* * After we have checked all resources of an entity agains any * other resource we know if the entity need this resource type * (ie. mem/io) at all. if not we can disable this type completely, * so no need to share it either. */ if ((pEnt->entityProp & NEED_MEM_SHARED) && (!(pEnt->entityProp & NEED_MEM))) pEnt->entityProp &= ~(unsigned long)NEED_MEM_SHARED; if ((pEnt->entityProp & NEED_IO_SHARED) && (!(pEnt->entityProp & NEED_IO))) pEnt->entityProp &= ~(unsigned long)NEED_IO_SHARED; } void xf86PostPreInit() { if (doFramebufferMode) return; if (xf86NumScreens > 1) needRAC = TRUE; xf86MsgVerb(X_INFO, 3, "do I need RAC?"); if (needRAC) { xf86ErrorFVerb(3, " Yes, I do.\n"); } else { xf86ErrorFVerb(3, " No, I don't.\n"); } xf86MsgVerb(X_INFO, 3, "resource ranges after preInit:\n"); xf86PrintResList(3, Acc); } void xf86PostScreenInit(void) { int i,j; ScreenPtr pScreen; unsigned int flags; int nummem = 0, numio = 0; if (doFramebufferMode) { SetSIGIOForState(OPERATING); return; } #ifdef DEBUG ErrorF("PostScreenInit generation: %i\n",serverGeneration); #endif if (serverGeneration == 1) { checkRoutingForScreens(OPERATING); for (i=0; ientityProp & NEED_MEM_SHARED) nummem++; if (xf86Entities[i]->entityProp & NEED_IO_SHARED) numio++; } for (i = 0; i < xf86NumEntities; i++) { if (nummem < 2) xf86Entities[i]->entityProp &= ~NEED_MEM_SHARED; if (numio < 2) xf86Entities[i]->entityProp &= ~NEED_IO_SHARED; } } if (xf86Screens && needRAC) { int needRACforVga = 0; for (i = 0; i < xf86NumScreens; i++) { for (j = 0; j < xf86Screens[i]->numEntities; j++) { if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp & NEED_VGA_ROUTED) { needRACforVga ++; break; /* only count each screen once */ } } } for (i = 0; i < xf86NumScreens; i++) { Bool needRACforMem = FALSE, needRACforIo = FALSE; for (j = 0; j < xf86Screens[i]->numEntities; j++) { if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp & NEED_MEM_SHARED) needRACforMem = TRUE; if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp & NEED_IO_SHARED) needRACforIo = TRUE; /* * We may need RAC although we don't share any resources * as we need to route VGA to the correct bus. This can * only be done simultaniously for MEM and IO. */ if (needRACforVga > 1) { if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp & NEED_VGA_MEM) needRACforMem = TRUE; if (xf86Entities[xf86Screens[i]->entityList[j]]->entityProp & NEED_VGA_IO) needRACforIo = TRUE; } } pScreen = xf86Screens[i]->pScreen; flags = 0; if (needRACforMem) { flags |= xf86Screens[i]->racMemFlags; xf86ErrorFVerb(3, "Screen %d is using RAC for mem\n", i); } if (needRACforIo) { flags |= xf86Screens[i]->racIoFlags; xf86ErrorFVerb(3, "Screen %d is using RAC for io\n", i); } xf86RACInit(pScreen,flags); } } xf86EnterServerState(OPERATING); } /* * Sets */ static resPtr decomposeSparse(resRange range) { resRange new; resPtr ret = NULL; memType val = range.rBegin; int i = 0; new.type = (range.type & ~ResExtMask) | ResSparse; while (1) { if (val & 0x01) { new.rBase = (val << i); new.rMask = ~((1 << i) - 1); ret = xf86AddResToList(ret,&new,-1); val ++; } i++; val >>= 1; if ((((val + 1) << i) - 1) > range.rEnd) break; } i--; val <<= 1; while (1) { if((((val + 1) << i) - 1)> range.rEnd) { if (--i < 0) break; val <<= 1; } else { new.rBase = (val << i); new.rMask = ~((1 << i) - 1); val++; ret = xf86AddResToList(ret,&new,-1); } } return ret; } static Bool x_isSubsetOf(resRange range, resPtr list1, resPtr list2) { resRange range1, range2; memType m1_A_m2; Bool ret; resPtr list; if (list1) { list = list1; if ((range.type & ResTypeMask) == (list->res_type & ResTypeMask)) { switch (range.type & ResExtMask) { case ResBlock: if ((list->res_type & ResExtMask) == ResBlock) { if (range.rBegin >= list->block_begin && range.rEnd <= list->block_end) return TRUE; else if (range.rBegin < list->block_begin && range.rEnd > list->block_end) { RANGE(range1, range.rBegin, list->block_begin - 1, range.type); RANGE(range2, list->block_end + 1, range.rEnd, range.type); return (x_isSubsetOf(range1,list->next,list2) && x_isSubsetOf(range2,list->next,list2)); } else if (range.rBegin >= list->block_begin && range.rBegin <= list->block_end) { RANGE(range1, list->block_end + 1, range.rEnd, range.type); return (x_isSubsetOf(range1,list->next,list2)); } else if (range.rEnd >= list->block_begin && range.rEnd <= list->block_end) { RANGE(range1,range.rBegin, list->block_begin - 1, range.type); return (x_isSubsetOf(range1,list->next,list2)); } } break; case ResSparse: if ((list->res_type & ResExtMask) == ResSparse) { memType test; int i; m1_A_m2 = range.rMask & list->sparse_mask; if ((range.rBase ^ list->sparse_base) & m1_A_m2) break; /* * We use the following system: * let 0 ^= mask:1 base:0, 1 ^= mask:1 base:1, * X mask:0 ; S: set TSS: test set for subset * NTSS: new test set after test * S: 1 0 1 0 X X 0 1 X * TSS: 1 0 0 1 1 0 X X X * T: 0 0 1 1 0 0 0 0 0 * NTSS: 1 0 0/X 1/X 1 0 1 0 X * R: 0 0 0 0 0 0 1 1 0 * If R != 0 TSS and S are disjunct * If R == 0 TSS is subset of S * If R != 0 NTSS contains elements from TSS * which are not also members of S. * If a T is set one of the correspondig bits * in NTSS must be set to the specified value * all other are X */ test = list->sparse_mask & ~range.rMask; if (test == 0) return TRUE; for (i = 0; i < sizeof(memType); i++) { if ((test >> i) & 0x1) { RANGE(range1, ((range.rBase & list->sparse_base) | (range.rBase & ~list->sparse_mask) | ((~list->sparse_base & list->sparse_mask) & ~range.rMask)) & range1.rMask, ((range.rMask | list->sparse_mask) & ~test) | (1 << i), range.type); return (x_isSubsetOf(range1,list->next,list2)); } } } break; } } return (x_isSubsetOf(range,list->next,list2)); } else if (list2) { resPtr tmpList = NULL; switch (range.type & ResExtMask) { case ResBlock: tmpList = decomposeSparse(range); while (tmpList) { if (!x_isSubsetOf(tmpList->val,list2,NULL)) { xf86FreeResList(tmpList); return FALSE; } tmpList = tmpList->next; } xf86FreeResList(tmpList); return TRUE; break; case ResSparse: while (list2) { tmpList = xf86JoinResLists(tmpList,decomposeSparse(list2->val)); list2 = list2->next; } ret = x_isSubsetOf(range,tmpList,NULL); xf86FreeResList(tmpList); return ret; break; } } else return FALSE; return FALSE; } Bool xf86IsSubsetOf(resRange range, resPtr list) { resPtr dup = xf86DupResList(list); resPtr r_sp = NULL, r = NULL, tmp = NULL; Bool ret = FALSE; while (dup) { tmp = dup; dup = dup->next; switch (tmp->res_type & ResExtMask) { case ResBlock: tmp->next = r; r = tmp; break; case ResSparse: tmp->next = r_sp; r_sp = tmp; break; } } switch (range.type & ResExtMask) { case ResBlock: ret = x_isSubsetOf(range,r,r_sp); break; case ResSparse: ret = x_isSubsetOf(range,r_sp,r); break; } xf86FreeResList(r); xf86FreeResList(r_sp); return ret; } static resPtr findIntersect(resRange Range, resPtr list) { resRange range; resPtr new = NULL; while (list) { if ((Range.type & ResTypeMask) == (list->res_type & ResTypeMask)) { switch (Range.type & ResExtMask) { case ResBlock: switch (list->res_type & ResExtMask) { case ResBlock: if (Range.rBegin >= list->block_begin) range.rBegin = Range.rBegin; else range.rBegin = list->block_begin; if (Range.rEnd <= list->block_end) range.rEnd = Range.rEnd; else range.rEnd = list->block_end; if (range.rEnd > range.rBegin) { range.type = Range.type; new = xf86AddResToList(new,&range,-1); } break; case ResSparse: new = xf86JoinResLists(new,xf86FindIntersectOfLists(new,decomposeSparse(list->val))); break; } break; case ResSparse: switch (list->res_type & ResExtMask) { case ResSparse: if (!((~(range.rBase ^ list->sparse_base) & (range.rMask & list->sparse_mask)))) { RANGE(range, (range.rBase & list->sparse_base) | (~range.rMask & list->sparse_base) | (~list->sparse_mask & range.rBase), range.rMask | list->sparse_mask, Range.type); new = xf86AddResToList(new,&range,-1); } break; case ResBlock: new = xf86JoinResLists(new,xf86FindIntersectOfLists( decomposeSparse(range),list)); break; } } } list = list->next; } return new; } resPtr xf86FindIntersectOfLists(resPtr l1, resPtr l2) { resPtr ret = NULL; while (l1) { ret = xf86JoinResLists(ret,findIntersect(l1->val,l2)); l1 = l1->next; } return ret; } #if 0 /* Not used */ static resPtr xf86FindComplement(resRange Range) { resRange range; memType tmp; resPtr new = NULL; int i; switch (Range.type & ResExtMask) { case ResBlock: if (Range.rBegin > 0) { RANGE(range, 0, Range.rBegin - 1, Range.type); new = xf86AddResToList(new,&range,-1); } if (Range.rEnd < (memType)~0) { RANGE(range,Range.rEnd + 1, (memType)~0, Range.type); new = xf86AddResToList(new,&range,-1); } break; case ResSparse: tmp = Range.rMask; for (i = 0; i < sizeof(memType); i++) { if (tmp & 0x1) { RANGE(range,(~Range.rMask & range.rMask),(1 << i), Range.type); new = xf86AddResToList(new,&range,-1); } } break; default: break; } return new; } #endif resPtr xf86ExtractTypeFromList(resPtr list, unsigned long type) { resPtr ret = NULL; while (list) { if ((list->res_type & ResTypeMask) == type) ret = xf86AddResToList(ret,&(list->val),list->entityIndex); list = list->next; } return ret; } /* * xf86FindPrimaryDevice() - Find the display device which * was active when the server was started. */ void xf86FindPrimaryDevice() { if (primaryBus.type != BUS_NONE) { char *bus; char loc[16]; switch (primaryBus.type) { case BUS_PCI: bus = "PCI"; snprintf(loc, sizeof(loc), " %2.2x@%2.2x:%2.2x:%1.1x", primaryBus.id.pci->bus, primaryBus.id.pci->domain, primaryBus.id.pci->dev, primaryBus.id.pci->func); break; case BUS_SBUS: bus = "SBUS"; snprintf(loc, sizeof(loc), " %2.2x", primaryBus.id.sbus.fbNum); break; default: bus = ""; loc[0] = '\0'; } xf86MsgVerb(X_INFO, 2, "Primary Device is: %s%s\n",bus,loc); } } Bool xf86NoSharedResources(int screenIndex,resType res) { int j; if (screenIndex > xf86NumScreens) return TRUE; for (j = 0; j < xf86Screens[screenIndex]->numEntities; j++) { switch (res) { case IO: if ( xf86Entities[xf86Screens[screenIndex]->entityList[j]]->entityProp & NEED_IO_SHARED) return FALSE; break; case MEM: if ( xf86Entities[xf86Screens[screenIndex]->entityList[j]]->entityProp & NEED_MEM_SHARED) return FALSE; break; case MEM_IO: if ( xf86Entities[xf86Screens[screenIndex]->entityList[j]]->entityProp & NEED_SHARED) return FALSE; break; case NONE: break; } } return TRUE; } _X_EXPORT void xf86RegisterStateChangeNotificationCallback(xf86StateChangeNotificationCallbackFunc func, pointer arg) { StateChangeNotificationPtr ptr = (StateChangeNotificationPtr)xnfalloc(sizeof(StateChangeNotificationRec)); ptr->func = func; ptr->arg = arg; ptr->next = StateChangeNotificationList; StateChangeNotificationList = ptr; } _X_EXPORT Bool xf86DeregisterStateChangeNotificationCallback(xf86StateChangeNotificationCallbackFunc func) { StateChangeNotificationPtr *ptr = &StateChangeNotificationList; StateChangeNotificationPtr tmp; while (*ptr) { if ((*ptr)->func == func) { tmp = (*ptr); (*ptr) = (*ptr)->next; xfree(tmp); return TRUE; } ptr = &((*ptr)->next); } return FALSE; } static void notifyStateChange(xf86NotifyState state) { StateChangeNotificationPtr ptr = StateChangeNotificationList; while (ptr) { ptr->func(state,ptr->arg); ptr = ptr->next; } } /* Multihead accel sharing accessor functions and entity Private handling */ _X_EXPORT int xf86GetLastScrnFlag(int entityIndex) { if(entityIndex < xf86NumEntities) { return(xf86Entities[entityIndex]->lastScrnFlag); } else { return -1; } } _X_EXPORT void xf86SetLastScrnFlag(int entityIndex, int scrnIndex) { if(entityIndex < xf86NumEntities) { xf86Entities[entityIndex]->lastScrnFlag = scrnIndex; } } _X_EXPORT Bool xf86IsEntityShared(int entityIndex) { if(entityIndex < xf86NumEntities) { if(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL) { return TRUE; } } return FALSE; } _X_EXPORT void xf86SetEntityShared(int entityIndex) { if(entityIndex < xf86NumEntities) { xf86Entities[entityIndex]->entityProp |= IS_SHARED_ACCEL; } } _X_EXPORT Bool xf86IsEntitySharable(int entityIndex) { if(entityIndex < xf86NumEntities) { if(xf86Entities[entityIndex]->entityProp & ACCEL_IS_SHARABLE) { return TRUE; } } return FALSE; } _X_EXPORT void xf86SetEntitySharable(int entityIndex) { if(entityIndex < xf86NumEntities) { xf86Entities[entityIndex]->entityProp |= ACCEL_IS_SHARABLE; } } _X_EXPORT Bool xf86IsPrimInitDone(int entityIndex) { if(entityIndex < xf86NumEntities) { if(xf86Entities[entityIndex]->entityProp & SA_PRIM_INIT_DONE) { return TRUE; } } return FALSE; } _X_EXPORT void xf86SetPrimInitDone(int entityIndex) { if(entityIndex < xf86NumEntities) { xf86Entities[entityIndex]->entityProp |= SA_PRIM_INIT_DONE; } } _X_EXPORT void xf86ClearPrimInitDone(int entityIndex) { if(entityIndex < xf86NumEntities) { xf86Entities[entityIndex]->entityProp &= ~SA_PRIM_INIT_DONE; } } /* * Allocate a private in the entities. */ _X_EXPORT int xf86AllocateEntityPrivateIndex(void) { int idx, i; EntityPtr pEnt; DevUnion *nprivs; idx = xf86EntityPrivateCount++; for (i = 0; i < xf86NumEntities; i++) { pEnt = xf86Entities[i]; nprivs = xnfrealloc(pEnt->entityPrivates, xf86EntityPrivateCount * sizeof(DevUnion)); /* Zero the new private */ bzero(&nprivs[idx], sizeof(DevUnion)); pEnt->entityPrivates = nprivs; } return idx; } _X_EXPORT DevUnion * xf86GetEntityPrivate(int entityIndex, int privIndex) { if (entityIndex >= xf86NumEntities || privIndex >= xf86EntityPrivateCount) return NULL; return &(xf86Entities[entityIndex]->entityPrivates[privIndex]); }