3476 lines
		
	
	
		
			95 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			3476 lines
		
	
	
		
			95 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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
 | |
|  */
 | |
| #define INCLUDE_DEPRECATED 1
 | |
| 
 | |
| #ifdef HAVE_XORG_CONFIG_H
 | |
| #include <xorg-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <ctype.h>
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| #include <X11/X.h>
 | |
| #include "os.h"
 | |
| #include "Pci.h"
 | |
| #include "xf86.h"
 | |
| #include "xf86Priv.h"
 | |
| #include "xf86Resources.h"
 | |
| 
 | |
| /* Bus-specific headers */
 | |
| #include "xf86PciData.h"
 | |
| 
 | |
| #include "xf86Bus.h"
 | |
| 
 | |
| #define XF86_OS_PRIVS
 | |
| #define NEED_OS_RAC_PROTOS
 | |
| #include "xf86_OSproc.h"
 | |
| 
 | |
| #include "xf86RAC.h"
 | |
| 
 | |
| /* Bus-specific globals */
 | |
| Bool pciSlotClaimed = FALSE;
 | |
| pciConfigPtr *xf86PciInfo = NULL;		/* Full PCI probe info */
 | |
| pciVideoPtr *xf86PciVideoInfo = NULL;		/* PCI probe for video hw */
 | |
| pciAccPtr * xf86PciAccInfo = NULL;              /* PCI access related */
 | |
| 
 | |
| /* pcidata globals */
 | |
| ScanPciSetupProcPtr xf86SetupPciIds = NULL;
 | |
| ScanPciCloseProcPtr xf86ClosePciIds = NULL;
 | |
| ScanPciFindByDeviceProcPtr xf86FindPciNamesByDevice = NULL;
 | |
| ScanPciFindBySubsysProcPtr xf86FindPciNamesBySubsys = NULL;
 | |
| 
 | |
| static resPtr pciAvoidRes = NULL;
 | |
| 
 | |
| /* PCI buses */
 | |
| static PciBusPtr xf86PciBus = NULL;
 | |
| /* Bus-specific probe/sorting functions */
 | |
| 
 | |
| /* PCI classes that get included in xf86PciVideoInfo */
 | |
| #define PCIINFOCLASSES(b,s)						      \
 | |
|     (((b) == PCI_CLASS_PREHISTORIC) ||					      \
 | |
|      ((b) == PCI_CLASS_DISPLAY) ||					      \
 | |
|      ((b) == PCI_CLASS_MULTIMEDIA && (s) == PCI_SUBCLASS_MULTIMEDIA_VIDEO) || \
 | |
|      ((b) == PCI_CLASS_PROCESSOR && (s) == PCI_SUBCLASS_PROCESSOR_COPROC))
 | |
| 
 | |
| /*
 | |
|  * PCI classes that have messages printed always.  The others are only
 | |
|  * have a message printed when the vendor/dev IDs are recognised.
 | |
|  */
 | |
| #define PCIALWAYSPRINTCLASSES(b,s)					      \
 | |
|     (((b) == PCI_CLASS_PREHISTORIC && (s) == PCI_SUBCLASS_PREHISTORIC_VGA) || \
 | |
|      ((b) == PCI_CLASS_DISPLAY) ||					      \
 | |
|      ((b) == PCI_CLASS_MULTIMEDIA && (s) == PCI_SUBCLASS_MULTIMEDIA_VIDEO))
 | |
|  
 | |
| /*
 | |
|  * PCI classes for which potentially destructive checking of the map sizes
 | |
|  * may be done.  Any classes where this may be unsafe should be omitted
 | |
|  * from this list.
 | |
|  */
 | |
| #define PCINONSYSTEMCLASSES(b,s) PCIALWAYSPRINTCLASSES(b,s)
 | |
| 
 | |
| /* 
 | |
|  * PCI classes that use RAC 
 | |
|  */
 | |
| #define PCISHAREDIOCLASSES(b,s)					      \
 | |
|     (((b) == PCI_CLASS_PREHISTORIC && (s) == PCI_SUBCLASS_PREHISTORIC_VGA) || \
 | |
|      ((b) == PCI_CLASS_DISPLAY && (s) == PCI_SUBCLASS_DISPLAY_VGA))
 | |
| 
 | |
| #define PCI_MEM32_LENGTH_MAX 0xFFFFFFFF
 | |
| 
 | |
| #define B2M(tag,base) pciBusAddrToHostAddr(tag,PCI_MEM,base)
 | |
| #define B2I(tag,base) pciBusAddrToHostAddr(tag,PCI_IO,base)
 | |
| #define B2H(tag,base,type) (((type & ResPhysMask) == ResMem) ? \
 | |
| 			B2M(tag, base) : B2I(tag, base))
 | |
| #define M2B(tag,base) pciHostAddrToBusAddr(tag,PCI_MEM,base)
 | |
| #define I2B(tag,base) pciHostAddrToBusAddr(tag,PCI_IO,base)
 | |
| #define H2B(tag,base,type) (((type & ResPhysMask) == ResMem) ? \
 | |
| 			M2B(tag, base) : I2B(tag, base))
 | |
| #define TAG(pvp) (pciTag(pvp->bus,pvp->device,pvp->func))
 | |
| #define SIZE(size) ((1 << size) - 1)
 | |
| #define PCI_SIZE(type,tag,size) (((type & ResPhysMask) == ResMem) \
 | |
|                         ? pciBusAddrToHostAddr(tag,PCI_MEM_SIZE,size) \
 | |
|                         : pciBusAddrToHostAddr(tag,PCI_IO_SIZE,size))
 | |
| #define PCI_M_RANGE(range,tag,begin,end,type) \
 | |
| 	{ \
 | |
| 	    RANGE(range, B2M(tag, begin), B2M(tag, end), \
 | |
| 		  RANGE_TYPE(type, xf86GetPciDomain(tag))); \
 | |
| 	}
 | |
| #define PCI_I_RANGE(range,tag,begin,end,type) \
 | |
| 	{ \
 | |
| 	    RANGE(range, B2I(tag, begin), B2I(tag, end), \
 | |
| 		  RANGE_TYPE(type, xf86GetPciDomain(tag))); \
 | |
| 	}
 | |
| #define PCI_X_RANGE(range,tag,begin,end,type) \
 | |
| { if ((type & ResPhysMask) == ResMem)  PCI_M_RANGE(range,tag,begin,end,type); \
 | |
|                 else PCI_I_RANGE(range,tag,begin,end,type); } 
 | |
| #define P_M_RANGE(range,tag,begin,size,type) \
 | |
|                     PCI_M_RANGE(range,tag,begin,(begin + SIZE(size)),type)
 | |
| #define P_I_RANGE(range,tag,begin,size,type) \
 | |
|                     PCI_I_RANGE(range,tag,begin,(begin + SIZE(size)),type)
 | |
| #define P_X_RANGE(range,tag,begin,size,type) \
 | |
| { if ((type & ResPhysMask) == ResMem)  P_M_RANGE(range,tag,begin,size,type); \
 | |
|                 else P_I_RANGE(range,tag,begin,size,type); }
 | |
| #define PV_M_RANGE(range,pvp,i,type) \
 | |
|                   P_M_RANGE(range,TAG(pvp),pvp->memBase[i],pvp->size[i],type)
 | |
| #define PV_B_RANGE(range,pvp,type) \
 | |
|                   P_M_RANGE(range,TAG(pvp),pvp->biosBase,pvp->biosSize,type)
 | |
| #define PV_I_RANGE(range,pvp,i,type) \
 | |
|                   P_I_RANGE(range,TAG(pvp),pvp->ioBase[i],pvp->size[i],type)
 | |
| 
 | |
| static void pciConvertListToHost(int bus, int dev, int func, resPtr list);
 | |
| static PciBusPtr xf86GetPciBridgeInfo(void);
 | |
| 
 | |
| _X_EXPORT void
 | |
| xf86FormatPciBusNumber(int busnum, char *buffer)
 | |
| {
 | |
|     /* 'buffer' should be at least 8 characters long */
 | |
|     if (busnum < 256)
 | |
| 	sprintf(buffer, "%d", busnum);
 | |
|     else
 | |
| 	sprintf(buffer, "%d@%d", busnum & 0x00ff, busnum >> 8);
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| IsBaseUnassigned(CARD32 base)
 | |
| {
 | |
|     CARD32 mask;
 | |
| 
 | |
|     if (base & PCI_MAP_IO)
 | |
| 	mask = ~PCI_MAP_IO_ATTR_MASK;
 | |
|     else
 | |
| 	mask = ~PCI_MAP_MEMORY_ATTR_MASK;
 | |
| 
 | |
|     base &= mask;
 | |
|     return (!base || (base == mask));
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| IsBaseUnassigned64(CARD32 base0, CARD32 base1)
 | |
| {
 | |
|     base0 &= ~PCI_MAP_MEMORY_ATTR_MASK;
 | |
|     base1 &= 0xffffffff;
 | |
|     
 | |
|     return ((!base0 && !base1)
 | |
| 	    || ((base0 == ~PCI_MAP_MEMORY_ATTR_MASK)
 | |
| 		&& (base1 == 0xffffffff)));
 | |
| }
 | |
| 
 | |
| static void
 | |
| FindPCIVideoInfo(void)
 | |
| {
 | |
|     pciConfigPtr pcrp, *pcrpp;
 | |
|     int i = 0, j, k;
 | |
|     int num = 0;
 | |
|     pciVideoPtr info;
 | |
|     int DoIsolateDeviceCheck = 0;
 | |
| 
 | |
|     if (xf86IsolateDevice.bus || xf86IsolateDevice.device || xf86IsolateDevice.func)
 | |
|         DoIsolateDeviceCheck = 1;
 | |
|     pcrpp = xf86PciInfo = xf86scanpci(0);
 | |
| 
 | |
|     
 | |
|     if (pcrpp == NULL) {
 | |
| 	xf86PciVideoInfo = NULL;
 | |
| 	return;
 | |
|     }
 | |
|     xf86PciBus = xf86GetPciBridgeInfo();
 | |
| 
 | |
|     while ((pcrp = pcrpp[i])) {
 | |
| 	const int baseclass = pcrp->pci_base_class;
 | |
| 	const int subclass = pcrp->pci_sub_class;
 | |
| 	
 | |
| 	if ( PCIINFOCLASSES(baseclass, subclass) &&
 | |
| 	     (!DoIsolateDeviceCheck ||
 | |
| 	      (xf86IsolateDevice.bus == pcrp->busnum &&
 | |
| 	       xf86IsolateDevice.device == pcrp->devnum &&
 | |
| 	       xf86IsolateDevice.func == pcrp->funcnum)) ) {
 | |
| 	    num++;
 | |
| 	    xf86PciVideoInfo = xnfrealloc(xf86PciVideoInfo,
 | |
| 					  sizeof(pciVideoPtr) * (num + 1));
 | |
| 	    xf86PciVideoInfo[num] = NULL;
 | |
| 	    info = xf86PciVideoInfo[num - 1] = xnfalloc(sizeof(pciVideoRec));
 | |
| 	    info->validSize = FALSE;
 | |
| 	    info->vendor = pcrp->pci_vendor;
 | |
| 	    info->chipType = pcrp->pci_device;
 | |
| 	    info->chipRev = pcrp->pci_rev_id;
 | |
| 	    info->subsysVendor = pcrp->pci_subsys_vendor;
 | |
| 	    info->subsysCard = pcrp->pci_subsys_card;
 | |
| 	    info->bus = pcrp->busnum;
 | |
| 	    info->device = pcrp->devnum;
 | |
| 	    info->func = pcrp->funcnum;
 | |
| 	    info->class = baseclass;
 | |
| 	    info->subclass = pcrp->pci_sub_class;
 | |
| 	    info->interface = pcrp->pci_prog_if;
 | |
| 	    info->biosBase = PCIGETROM(pcrp->pci_baserom);
 | |
| 	    info->biosSize = pciGetBaseSize(pcrp->tag, 6, TRUE, NULL);
 | |
| 	    info->thisCard = pcrp;
 | |
| 	    info->validate = FALSE;
 | |
| #ifdef INCLUDE_XF86_NO_DOMAIN
 | |
| 	    if ((PCISHAREDIOCLASSES(baseclass, subclass))
 | |
| 		&& (pcrp->pci_command & PCI_CMD_IO_ENABLE) &&
 | |
| 		(pcrp->pci_prog_if == 0)) {
 | |
| 
 | |
| 		/*
 | |
| 		 * Attempt to ensure that VGA is actually routed to this
 | |
| 		 * adapter on entry.  This needs to be fixed when we finally
 | |
| 		 * grok host bridges (and multiple bus trees).
 | |
| 		 */
 | |
| 		j = info->bus;
 | |
| 		while (TRUE) {
 | |
| 		    PciBusPtr pBus = xf86PciBus;
 | |
| 		    while (pBus && j != pBus->secondary)
 | |
| 			pBus = pBus->next;
 | |
| 		    if (!pBus || !(pBus->brcontrol & PCI_PCI_BRIDGE_VGA_EN))
 | |
| 			break;
 | |
| 		    if (j == pBus->primary) {
 | |
| 			if (primaryBus.type == BUS_NONE) {
 | |
| 			    /* assumption: primary adapter is always VGA */
 | |
| 			    primaryBus.type = BUS_PCI;
 | |
| 			    primaryBus.id.pci.bus = pcrp->busnum;
 | |
| 			    primaryBus.id.pci.device = pcrp->devnum;
 | |
| 			    primaryBus.id.pci.func = pcrp->funcnum;
 | |
| 			} else if (primaryBus.type < BUS_last) {
 | |
| 			    xf86Msg(X_NOTICE,
 | |
| 				    "More than one primary device found\n");
 | |
| 			    primaryBus.type ^= (BusType)(-1);
 | |
| 			}
 | |
| 			break;
 | |
| 		    }
 | |
| 		    j = pBus->primary;
 | |
| 		}
 | |
| 	    }
 | |
| #endif
 | |
| 	    
 | |
| 	    for (j = 0; j < 6; j++) {
 | |
| 		info->memBase[j] = 0;
 | |
| 		info->ioBase[j] = 0;
 | |
| 		if (PCINONSYSTEMCLASSES(baseclass, subclass)) {
 | |
| 		    info->size[j] =
 | |
| 			pciGetBaseSize(pcrp->tag, j, TRUE, &info->validSize);
 | |
| 		    pcrp->minBasesize = info->validSize;
 | |
| 		} else {
 | |
| 		    info->size[j] = pcrp->basesize[j];
 | |
| 		    info->validSize = pcrp->minBasesize;
 | |
| 		}
 | |
| 		info->type[j] = 0;
 | |
| 	    }
 | |
| 
 | |
| 	    if (PCINONSYSTEMCLASSES(baseclass, subclass)) {
 | |
| 		/*
 | |
| 		 * Check of a PCI base is unassigned. If so
 | |
| 		 * attempt to fix it. Validation will determine
 | |
| 		 * if the value was correct later on.
 | |
| 		 */
 | |
| 		CARD32 *base = &pcrp->pci_base0;
 | |
| 
 | |
| 		for (j = 0; j < 6; j++) {
 | |
| 		    if (!PCI_MAP_IS64BITMEM(base[j])) {
 | |
| 			if (info->size[j] && IsBaseUnassigned(base[j])) 
 | |
| 			    base[j] = pciCheckForBrokenBase(pcrp->tag, j);
 | |
| 		    } else {
 | |
| 			if (j == 5) /* bail out */
 | |
| 			    break;
 | |
| 			if (info->size[j]
 | |
| 			    && IsBaseUnassigned64(base[j],base[j+1])) {
 | |
| 			    base[j] = pciCheckForBrokenBase(pcrp->tag, j);
 | |
| 			    j++;
 | |
| 			    base[j] = pciCheckForBrokenBase(pcrp->tag, j);
 | |
| 			}
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	    
 | |
| 	    /*
 | |
| 	     * 64-bit base addresses are checked for and avoided on 32-bit
 | |
| 	     * platforms.
 | |
| 	     */
 | |
| 	    for (j = 0; j < 6; ++j) {
 | |
| 		CARD32  bar = (&pcrp->pci_base0)[j];
 | |
| 
 | |
| 		if (bar != 0) {
 | |
| 		    if (bar & PCI_MAP_IO) {
 | |
| 			info->ioBase[j] = (memType)PCIGETIO(bar);
 | |
| 			info->type[j] = bar & PCI_MAP_IO_ATTR_MASK;
 | |
| 		    } else {
 | |
| 			info->type[j] = bar & PCI_MAP_MEMORY_ATTR_MASK;
 | |
| 			info->memBase[j] = (memType)PCIGETMEMORY(bar);
 | |
| 			if (PCI_MAP_IS64BITMEM(bar)) {
 | |
| 			    if (j == 5) {
 | |
| 				xf86MsgVerb(X_WARNING, 0,
 | |
| 				    "****BAR5 specified as 64-bit wide, "
 | |
| 				    "which is not possible. "
 | |
| 				    "Ignoring BAR5.****\n");
 | |
| 				info->memBase[j] = 0;
 | |
| 			    } else {
 | |
| 				CARD32  bar_hi = PCIGETMEMORY64HIGH((&pcrp->pci_base0)[j]);
 | |
| #if defined(LONG64) || defined(WORD64)
 | |
| 				    /* 64 bit architecture */
 | |
| 				    info->memBase[j] |=
 | |
| 					(memType)bar_hi << 32;
 | |
| #else
 | |
| 				    if (bar_hi != 0)
 | |
| 					info->memBase[j] = 0;
 | |
| #endif
 | |
| 				    ++j;    /* Step over the next BAR */
 | |
| 			    }
 | |
| 			}
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 	i++;
 | |
|     }
 | |
| 
 | |
|     /* If we haven't found a primary device try a different heuristic */
 | |
|     if (primaryBus.type == BUS_NONE && num) {
 | |
| 	for (i = 0;  i < num;  i++) {
 | |
| 	    info = xf86PciVideoInfo[i];
 | |
| 	    pcrp = info->thisCard;
 | |
| 	    
 | |
| 	    if ((pcrp->pci_command & PCI_CMD_MEM_ENABLE) &&
 | |
| 		(num == 1 ||
 | |
| 		 ((info->class == PCI_CLASS_DISPLAY) &&
 | |
| 		  (info->subclass == PCI_SUBCLASS_DISPLAY_VGA)))) {
 | |
| 		if (primaryBus.type == BUS_NONE) {
 | |
| 		    primaryBus.type = BUS_PCI;
 | |
| 		    primaryBus.id.pci.bus = pcrp->busnum;
 | |
| 		    primaryBus.id.pci.device = pcrp->devnum;
 | |
| 		    primaryBus.id.pci.func = pcrp->funcnum;
 | |
| 		} else {
 | |
| 		    xf86Msg(X_NOTICE,
 | |
| 			    "More than one possible primary device found\n");
 | |
| 		    primaryBus.type ^= (BusType)(-1);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|     /* Print a summary of the video devices found */
 | |
|     for (k = 0; k < num; k++) {
 | |
| 	const char *vendorname = NULL, *chipname = NULL;
 | |
| 	const char *prim = " ";
 | |
| 	char busnum[8];
 | |
| 	Bool memdone = FALSE, iodone = FALSE;
 | |
| 
 | |
| 	i = 0; 
 | |
| 	info = xf86PciVideoInfo[k];
 | |
| 	xf86FormatPciBusNumber(info->bus, busnum);
 | |
| 	xf86FindPciNamesByDevice(info->vendor, info->chipType,
 | |
| 				 NOVENDOR, NOSUBSYS,
 | |
| 				 &vendorname, &chipname, NULL, NULL);
 | |
| 	if ((!vendorname || !chipname) &&
 | |
| 	    !PCIALWAYSPRINTCLASSES(info->class, info->subclass))
 | |
| 	    continue;
 | |
| 	if (xf86IsPrimaryPci(info))
 | |
| 	    prim = "*";
 | |
| 
 | |
| 	xf86Msg(X_PROBED, "PCI:%s(%s:%d:%d) ", prim, busnum, info->device,
 | |
| 		info->func);
 | |
| 	if (vendorname)
 | |
| 	    xf86ErrorF("%s ", vendorname);
 | |
| 	else
 | |
| 	    xf86ErrorF("unknown vendor (0x%04x) ", info->vendor);
 | |
| 	if (chipname)
 | |
| 	    xf86ErrorF("%s ", chipname);
 | |
| 	else
 | |
| 	    xf86ErrorF("unknown chipset (0x%04x) ", info->chipType);
 | |
| 	xf86ErrorF("rev %d", info->chipRev);
 | |
| 	for (i = 0; i < 6; i++) {
 | |
| 	    if (info->memBase[i] &&
 | |
| 		(info->memBase[i] < (memType)(-1 << info->size[i]))) {
 | |
| 		if (!memdone) {
 | |
| 		    xf86ErrorF(", Mem @ ");
 | |
| 		    memdone = TRUE;
 | |
| 		} else
 | |
| 		    xf86ErrorF(", ");
 | |
| 		xf86ErrorF("0x%08lx/%d", info->memBase[i], info->size[i]);
 | |
| 	    }
 | |
| 	}
 | |
| 	for (i = 0; i < 6; i++) {
 | |
| 	    if (info->ioBase[i] &&
 | |
| 		(info->ioBase[i] < (memType)(-1 << info->size[i]))) {
 | |
| 		if (!iodone) {
 | |
| 		    xf86ErrorF(", I/O @ ");
 | |
| 		    iodone = TRUE;
 | |
| 		} else
 | |
| 		    xf86ErrorF(", ");
 | |
| 		xf86ErrorF("0x%04lx/%d", info->ioBase[i], info->size[i]);
 | |
| 	    }
 | |
| 	}
 | |
| 	if (info->biosBase &&
 | |
| 	    (info->biosBase < (memType)(-1 << info->biosSize)))
 | |
| 	    xf86ErrorF(", BIOS @ 0x%08lx/%d", info->biosBase, info->biosSize);
 | |
| 	xf86ErrorF("\n");
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * fixPciSizeInfo() -- fix pci size info by testing it destructively
 | |
|  * (if not already done), fix pciVideoInfo and entry in the resource
 | |
|  * list.
 | |
|  */
 | |
| /*
 | |
|  * Note: once we have OS support to read the sizes GetBaseSize() will
 | |
|  * have to be wrapped by the OS layer. fixPciSizeInfo() should also
 | |
|  * be wrapped by the OS layer to do nothing if the size is always
 | |
|  * returned correctly by GetBaseSize(). It should however set validate
 | |
|  * in pciVideoRec if validation is required. ValidatePci() also needs
 | |
|  * to be wrapped by the OS layer. This may do nothing if the OS has
 | |
|  * already taken care of validation. fixPciResource() may be moved to
 | |
|  * OS layer with minimal changes. Once the wrapping layer is in place
 | |
|  * the common level and drivers should not reference these functions
 | |
|  * directly but thru the OS layer.
 | |
|  */
 | |
| 
 | |
| static void
 | |
| fixPciSizeInfo(int entityIndex)
 | |
| {
 | |
|     pciVideoPtr pvp;
 | |
|     resPtr pAcc;
 | |
|     PCITAG tag;
 | |
|     int j;
 | |
|     
 | |
|     if (! (pvp = xf86GetPciInfoForEntity(entityIndex))) return;
 | |
|     if (pvp->validSize) return;
 | |
| 
 | |
|     tag = pciTag(pvp->bus,pvp->device,pvp->func);
 | |
|     
 | |
|     for (j = 0; j < 6; j++) {
 | |
| 	pAcc = Acc;
 | |
| 	if (pvp->memBase[j]) 
 | |
| 	    while (pAcc) {
 | |
| 		if (((pAcc->res_type & (ResPhysMask | ResBlock))
 | |
| 		     == (ResMem | ResBlock))
 | |
| 		    && (pAcc->block_begin == B2M(TAG(pvp),pvp->memBase[j])) 
 | |
| 		    && (pAcc->block_end == B2M(TAG(pvp),pvp->memBase[j]
 | |
| 		    + SIZE(pvp->size[j])))) break;
 | |
| 		pAcc = pAcc->next;
 | |
| 	    }
 | |
| 	else if (pvp->ioBase[j])
 | |
| 	    while (pAcc) {
 | |
| 		if (((pAcc->res_type & (ResPhysMask | ResBlock)) ==
 | |
| 		     (ResIo | ResBlock))
 | |
| 		    && (pAcc->block_begin == B2I(TAG(pvp),pvp->ioBase[j]))
 | |
| 		    && (pAcc->block_end == B2I(TAG(pvp),pvp->ioBase[j]
 | |
| 		    + SIZE(pvp->size[j])))) break;
 | |
| 		pAcc = pAcc->next;
 | |
| 	    }
 | |
| 	else continue;
 | |
| 	pvp->size[j]  = pciGetBaseSize(tag, j, TRUE, &pvp->validSize);
 | |
| 	if (pAcc) {
 | |
| 	    pAcc->block_end = pvp->memBase[j] ?
 | |
| 		B2M(TAG(pvp),pvp->memBase[j] + SIZE(pvp->size[j]))
 | |
| 		: B2I(TAG(pvp),pvp->ioBase[j] + SIZE(pvp->size[j]));
 | |
| 	    pAcc->res_type &= ~ResEstimated;
 | |
| 	    pAcc->res_type |= ResBios;
 | |
| 	}
 | |
|     }
 | |
|     if (pvp->biosBase) {
 | |
| 	pAcc = Acc;
 | |
| 	while (pAcc) {
 | |
| 	    if (((pAcc->res_type & (ResPhysMask | ResBlock)) ==
 | |
| 		 (ResMem | ResBlock))
 | |
| 		&& (pAcc->block_begin == B2M(TAG(pvp),pvp->biosBase))
 | |
| 		    && (pAcc->block_end == B2M(TAG(pvp),pvp->biosBase
 | |
| 		    + SIZE(pvp->biosSize)))) break;
 | |
| 	    pAcc = pAcc->next;
 | |
| 	}
 | |
| 	pvp->biosSize = pciGetBaseSize(tag, 6, TRUE, &pvp->validSize);
 | |
| 	if (pAcc) {
 | |
| 	    pAcc->block_end = B2M(TAG(pvp),pvp->biosBase+SIZE(pvp->biosSize));
 | |
| 	    pAcc->res_type &= ~ResEstimated;
 | |
| 	    pAcc->res_type |= ResBios;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * IO enable/disable related routines for PCI
 | |
|  */
 | |
| #define pArg ((pciArg*)arg)
 | |
| #define SETBITS PCI_CMD_IO_ENABLE
 | |
| static void
 | |
| pciIoAccessEnable(void* arg)
 | |
| {
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciIoAccessEnable: 0x%05lx\n", *(PCITAG *)arg);
 | |
| #endif
 | |
|     pArg->ctrl |= SETBITS | PCI_CMD_MASTER_ENABLE;
 | |
|     pciWriteLong(pArg->tag, PCI_CMD_STAT_REG, pArg->ctrl);
 | |
| }
 | |
| 
 | |
| static void
 | |
| pciIoAccessDisable(void* arg)
 | |
| {
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciIoAccessDisable: 0x%05lx\n", *(PCITAG *)arg);
 | |
| #endif
 | |
|     pArg->ctrl &= ~SETBITS;
 | |
|     pciWriteLong(pArg->tag, PCI_CMD_STAT_REG, pArg->ctrl);
 | |
| }
 | |
| 
 | |
| #undef SETBITS
 | |
| #define SETBITS (PCI_CMD_IO_ENABLE | PCI_CMD_MEM_ENABLE)
 | |
| static void
 | |
| pciIo_MemAccessEnable(void* arg)
 | |
| {
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciIo_MemAccessEnable: 0x%05lx\n", *(PCITAG *)arg);
 | |
| #endif
 | |
|     pArg->ctrl |= SETBITS | PCI_CMD_MASTER_ENABLE;
 | |
|     pciWriteLong(pArg->tag, PCI_CMD_STAT_REG, pArg->ctrl);
 | |
| }
 | |
| 
 | |
| static void
 | |
| pciIo_MemAccessDisable(void* arg)
 | |
| {
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciIo_MemAccessDisable: 0x%05lx\n", *(PCITAG *)arg);
 | |
| #endif
 | |
|     pArg->ctrl &= ~SETBITS;
 | |
|     pciWriteLong(pArg->tag, PCI_CMD_STAT_REG, pArg->ctrl);
 | |
| }
 | |
| 
 | |
| #undef SETBITS
 | |
| #define SETBITS (PCI_CMD_MEM_ENABLE)
 | |
| static void
 | |
| pciMemAccessEnable(void* arg)
 | |
| {
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciMemAccessEnable: 0x%05lx\n", *(PCITAG *)arg);
 | |
| #endif
 | |
|     pArg->ctrl |= SETBITS | PCI_CMD_MASTER_ENABLE;
 | |
|     pciWriteLong(pArg->tag, PCI_CMD_STAT_REG, pArg->ctrl);
 | |
| }
 | |
| 
 | |
| static void
 | |
| pciMemAccessDisable(void* arg)
 | |
| {
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciMemAccessDisable: 0x%05lx\n", *(PCITAG *)arg);
 | |
| #endif
 | |
|     pArg->ctrl &= ~SETBITS;
 | |
|     pciWriteLong(pArg->tag, PCI_CMD_STAT_REG, pArg->ctrl);
 | |
| }
 | |
| #undef SETBITS
 | |
| #undef pArg
 | |
| 
 | |
| 
 | |
| /* move to OS layer */
 | |
| #define MASKBITS (PCI_PCI_BRIDGE_VGA_EN | PCI_PCI_BRIDGE_MASTER_ABORT_EN)
 | |
| static void
 | |
| pciBusAccessEnable(BusAccPtr ptr)
 | |
| {
 | |
|     PCITAG tag = ptr->busdep.pci.acc;
 | |
|     CARD16 ctrl;
 | |
| 
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciBusAccessEnable: bus=%d\n", ptr->busdep.pci.bus);
 | |
| #endif
 | |
|     ctrl = pciReadWord(tag, PCI_PCI_BRIDGE_CONTROL_REG);
 | |
|     if ((ctrl & MASKBITS) != PCI_PCI_BRIDGE_VGA_EN) {
 | |
| 	ctrl = (ctrl | PCI_PCI_BRIDGE_VGA_EN) &
 | |
| 	    ~(PCI_PCI_BRIDGE_MASTER_ABORT_EN | PCI_PCI_BRIDGE_SECONDARY_RESET);
 | |
| 	pciWriteWord(tag, PCI_PCI_BRIDGE_CONTROL_REG, ctrl);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* move to OS layer */
 | |
| static void
 | |
| pciBusAccessDisable(BusAccPtr ptr)
 | |
| {
 | |
|     PCITAG tag = ptr->busdep.pci.acc;
 | |
|     CARD16 ctrl;
 | |
| 
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciBusAccessDisable: bus=%d\n", ptr->busdep.pci.bus);
 | |
| #endif
 | |
|     ctrl = pciReadWord(tag, PCI_PCI_BRIDGE_CONTROL_REG);
 | |
|     if (ctrl & MASKBITS) {
 | |
| 	ctrl &= ~(MASKBITS | PCI_PCI_BRIDGE_SECONDARY_RESET);
 | |
| 	pciWriteWord(tag, PCI_PCI_BRIDGE_CONTROL_REG, ctrl);
 | |
|     }
 | |
| }
 | |
| #undef MASKBITS
 | |
| 
 | |
| /* move to OS layer */
 | |
| static void
 | |
| pciDrvBusAccessEnable(BusAccPtr ptr)
 | |
| {
 | |
|     int bus = ptr->busdep.pci.bus;
 | |
| 
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciDrvBusAccessEnable: bus=%d\n", bus);
 | |
| #endif
 | |
|     (*pciBusInfo[bus]->funcs->pciControlBridge)(bus,
 | |
| 						PCI_PCI_BRIDGE_VGA_EN,
 | |
| 						PCI_PCI_BRIDGE_VGA_EN);
 | |
| }
 | |
| 
 | |
| /* move to OS layer */
 | |
| static void
 | |
| pciDrvBusAccessDisable(BusAccPtr ptr)
 | |
| {
 | |
|     int bus = ptr->busdep.pci.bus;
 | |
| 
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciDrvBusAccessDisable: bus=%d\n", bus);
 | |
| #endif
 | |
|     (*pciBusInfo[bus]->funcs->pciControlBridge)(bus,
 | |
| 						PCI_PCI_BRIDGE_VGA_EN, 0);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| pciSetBusAccess(BusAccPtr ptr)
 | |
| {
 | |
| #ifdef DEBUG
 | |
|     ErrorF("pciSetBusAccess: route VGA to bus %d\n", ptr->busdep.pci.bus);
 | |
| #endif
 | |
| 
 | |
|     if (!ptr->primary && !ptr->current)
 | |
| 	return;
 | |
|     
 | |
|     if (ptr->current && ptr->current->disable_f)
 | |
| 	(*ptr->current->disable_f)(ptr->current);
 | |
|     ptr->current = NULL;
 | |
|     
 | |
|     /* walk down */
 | |
|     while (ptr->primary) {	/* No enable for root bus */
 | |
| 	if (ptr != ptr->primary->current) {
 | |
| 	    if (ptr->primary->current && ptr->primary->current->disable_f)
 | |
| 		(*ptr->primary->current->disable_f)(ptr->primary->current);
 | |
| 	    if (ptr->enable_f)
 | |
| 		(*ptr->enable_f)(ptr);
 | |
| 	    ptr->primary->current = ptr;
 | |
| 	}
 | |
| 	ptr = ptr->primary;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* move to OS layer */
 | |
| static void
 | |
| savePciState(PCITAG tag, pciSavePtr ptr)
 | |
| {
 | |
|     int i;
 | |
|      
 | |
|     ptr->command = pciReadLong(tag, PCI_CMD_STAT_REG);
 | |
|     for (i=0; i < 6; i++) 
 | |
|         ptr->base[i] = pciReadLong(tag, PCI_CMD_BASE_REG + i*4);
 | |
|     ptr->biosBase = pciReadLong(tag, PCI_CMD_BIOS_REG);
 | |
| }
 | |
| 
 | |
| /* move to OS layer */
 | |
| static void
 | |
| restorePciState(PCITAG tag, pciSavePtr ptr)
 | |
| {
 | |
|     int i;
 | |
|     
 | |
|     /* disable card before setting anything */
 | |
|     pciSetBitsLong(tag, PCI_CMD_STAT_REG,
 | |
| 		   PCI_CMD_MEM_ENABLE | PCI_CMD_IO_ENABLE , 0);
 | |
|     pciWriteLong(tag,PCI_CMD_BIOS_REG, ptr->biosBase);
 | |
|     for (i=0; i<6; i++)
 | |
|         pciWriteLong(tag, PCI_CMD_BASE_REG + i*4, ptr->base[i]);        
 | |
|     pciWriteLong(tag, PCI_CMD_STAT_REG, ptr->command);
 | |
| }
 | |
| 
 | |
| /* move to OS layer */
 | |
| static void
 | |
| savePciBusState(BusAccPtr ptr)
 | |
| {
 | |
|     PCITAG tag = ptr->busdep.pci.acc;
 | |
| 
 | |
|     ptr->busdep.pci.save.control =
 | |
| 	pciReadWord(tag, PCI_PCI_BRIDGE_CONTROL_REG) &
 | |
| 	~PCI_PCI_BRIDGE_SECONDARY_RESET;
 | |
|     /* Allow master aborts to complete normally on non-root buses */
 | |
|     if (ptr->busdep.pci.save.control & PCI_PCI_BRIDGE_MASTER_ABORT_EN)
 | |
| 	pciWriteWord(tag, PCI_PCI_BRIDGE_CONTROL_REG,
 | |
| 	    ptr->busdep.pci.save.control & ~PCI_PCI_BRIDGE_MASTER_ABORT_EN);
 | |
| }
 | |
| 
 | |
| /* move to OS layer */
 | |
| #define MASKBITS (PCI_PCI_BRIDGE_VGA_EN | PCI_PCI_BRIDGE_MASTER_ABORT_EN)
 | |
| static void
 | |
| restorePciBusState(BusAccPtr ptr)
 | |
| {
 | |
|     PCITAG tag = ptr->busdep.pci.acc;
 | |
|     CARD16 ctrl;
 | |
| 
 | |
|     /* Only restore the bits we've changed (and don't cause resets) */
 | |
|     ctrl = pciReadWord(tag, PCI_PCI_BRIDGE_CONTROL_REG);
 | |
|     if ((ctrl ^ ptr->busdep.pci.save.control) & MASKBITS) {
 | |
| 	ctrl &= ~(MASKBITS | PCI_PCI_BRIDGE_SECONDARY_RESET);
 | |
| 	ctrl |= ptr->busdep.pci.save.control & MASKBITS;
 | |
| 	pciWriteWord(tag, PCI_PCI_BRIDGE_CONTROL_REG, ctrl);
 | |
|     }
 | |
| }
 | |
| #undef MASKBITS
 | |
| 
 | |
| /* move to OS layer */
 | |
| static void
 | |
| savePciDrvBusState(BusAccPtr ptr)
 | |
| {
 | |
|     int bus = ptr->busdep.pci.bus;
 | |
| 
 | |
|     ptr->busdep.pci.save.control =
 | |
| 	(*pciBusInfo[bus]->funcs->pciControlBridge)(bus, 0, 0);
 | |
|     /* Allow master aborts to complete normally on this bus */
 | |
|     (*pciBusInfo[bus]->funcs->pciControlBridge)(bus,
 | |
| 						PCI_PCI_BRIDGE_MASTER_ABORT_EN,
 | |
| 						0);
 | |
| }
 | |
| 
 | |
| /* move to OS layer */
 | |
| static void
 | |
| restorePciDrvBusState(BusAccPtr ptr)
 | |
| {
 | |
|     int bus = ptr->busdep.pci.bus;
 | |
| 
 | |
|     (*pciBusInfo[bus]->funcs->pciControlBridge)(bus, (CARD16)(-1),
 | |
| 					        ptr->busdep.pci.save.control);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| disablePciBios(PCITAG tag)
 | |
| {
 | |
|     pciSetBitsLong(tag, PCI_CMD_BIOS_REG, PCI_CMD_BIOS_ENABLE, 0);
 | |
| }
 | |
| 
 | |
| /* ????? */
 | |
| static void
 | |
| correctPciSize(memType base, memType oldsize, memType newsize,
 | |
| 	       unsigned long type)
 | |
| {
 | |
|     pciConfigPtr pcrp, *pcrpp;
 | |
|     pciVideoPtr pvp, *pvpp;
 | |
|     CARD32 *basep;
 | |
|     int i;
 | |
|     int old_bits = 0, new_bits = 0;
 | |
| 
 | |
|     if (oldsize + 1) while (oldsize & 1) {
 | |
| 	old_bits ++;
 | |
| 	oldsize >>= 1;
 | |
|     }
 | |
|     if (newsize + 1) while (newsize & 1) {
 | |
| 	new_bits ++;
 | |
| 	newsize >>= 1;
 | |
|     }
 | |
|     
 | |
|     for (pcrpp = xf86PciInfo, pcrp = *pcrpp; pcrp; pcrp = *++(pcrpp)) {
 | |
| 	
 | |
| 	/* Only process devices with type 0 headers */
 | |
| 	if ((pcrp->pci_header_type & 0x7f) != 0)
 | |
| 	    continue;
 | |
| 
 | |
| 	basep = &pcrp->pci_base0;
 | |
| 	for (i = 0; i < 6; i++) {
 | |
| 	    if (basep[i] && (pcrp->basesize[i] == old_bits)) {
 | |
| 		if ((((type & ResPhysMask) == ResIo) &&
 | |
| 		     PCI_MAP_IS_IO(basep[i]) &&
 | |
| 		     B2I(pcrp->tag,PCIGETIO(basep[i]) == base)) ||
 | |
| 		    (((type & ResPhysMask) == ResMem) &&
 | |
| 		     PCI_MAP_IS_MEM(basep[i]) &&
 | |
| 		     (((!PCI_MAP_IS64BITMEM(basep[i])) &&
 | |
| 		       (B2M(pcrp->tag,PCIGETMEMORY(basep[i])) == base))
 | |
| #if defined(LONG64) || defined(WORD64)
 | |
| 		      ||
 | |
| 		      (B2M(pcrp->tag,PCIGETMEMORY64(basep[i])) == base)
 | |
| #else
 | |
| 		      ||
 | |
| 		      (!basep[i+1]
 | |
| 		       && (B2M(pcrp->tag,PCIGETMEMORY(basep[i])) == base))
 | |
| #endif 
 | |
| 		     ))) {
 | |
| 		    pcrp->basesize[i] = new_bits;
 | |
| 		    break;	/* to next device */
 | |
| 		}
 | |
| 	    }
 | |
| 	    if (PCI_MAP_IS64BITMEM(basep[i])) i++;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (xf86PciVideoInfo) {
 | |
| 	for (pvpp = xf86PciVideoInfo, pvp = *pvpp; pvp; pvp = *(++pvpp)) {
 | |
| 
 | |
| 	    for (i = 0; i < 6; i++) {
 | |
| 		if (pvp->size[i] == old_bits) {
 | |
| 		    if ((((type & ResPhysMask) == ResIo) && pvp->ioBase[i]
 | |
| 			 && (B2I(TAG(pvp),pvp->ioBase[i]) == base)) || 
 | |
| 			(((type & ResPhysMask) == ResMem) && pvp->memBase[i] 
 | |
| 			  && (B2M(TAG(pvp),pvp->memBase[i]) == base))) {
 | |
| 			pvp->size[i] = new_bits;
 | |
| 			break;	/* to next device */
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* ????? */
 | |
| static void
 | |
| removeOverlapsWithBridges(int busIndex, resPtr target)
 | |
| {
 | |
|     PciBusPtr pbp;
 | |
|     resPtr tmp,bridgeRes = NULL;
 | |
|     resRange range;
 | |
| 
 | |
|     if (!target)
 | |
| 	return;
 | |
|     
 | |
|     if (!ResCanOverlap(&target->val))
 | |
| 	return;
 | |
| 
 | |
|     range = target->val;
 | |
|     
 | |
|     for (pbp=xf86PciBus; pbp; pbp = pbp->next) {
 | |
| 	if (pbp->primary == busIndex) {
 | |
| 	    tmp = xf86DupResList(pbp->preferred_io);
 | |
| 	    bridgeRes = xf86JoinResLists(tmp,bridgeRes);
 | |
| 	    tmp = xf86DupResList(pbp->preferred_mem);
 | |
| 	    bridgeRes = xf86JoinResLists(tmp,bridgeRes);
 | |
| 	    tmp = xf86DupResList(pbp->preferred_pmem);
 | |
| 	    bridgeRes = xf86JoinResLists(tmp,bridgeRes);
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|     RemoveOverlaps(target, bridgeRes, TRUE, TRUE);
 | |
|     if (range.rEnd > target->block_end) {
 | |
| 	correctPciSize(range.rBegin, range.rEnd - range.rBegin,
 | |
| 		       target->block_end - target->block_begin,
 | |
| 		       target->res_type);
 | |
| 	xf86MsgVerb(X_INFO, 3,
 | |
| 	    "PCI %s resource overlap reduced 0x%08lx from 0x%08lx to 0x%08lx\n",
 | |
| 	    ((target->res_type & ResPhysMask) == ResMem) ?  "Memory" : "I/O",
 | |
| 	    range.rBegin, range.rEnd, target->block_end);
 | |
|     }
 | |
|     xf86FreeResList(bridgeRes);
 | |
| }
 | |
|     
 | |
| /* ????? */
 | |
| static void
 | |
| xf86GetPciRes(resPtr *activeRes, resPtr *inactiveRes)
 | |
| {
 | |
|     pciConfigPtr pcrp, *pcrpp;
 | |
|     pciVideoPtr pvp, *pvpp;
 | |
|     CARD32 *basep;
 | |
|     int i;
 | |
|     resPtr pRes, tmp;
 | |
|     resRange range;
 | |
|     long resMisc;
 | |
| 
 | |
|     if (activeRes)
 | |
| 	*activeRes = NULL;
 | |
|     if (inactiveRes)
 | |
| 	*inactiveRes = NULL;
 | |
| 
 | |
|     if (!activeRes || !inactiveRes || !xf86PciInfo)
 | |
| 	return;
 | |
| 
 | |
|     if (xf86PciVideoInfo)
 | |
| 	for (pvpp = xf86PciVideoInfo, pvp = *pvpp; pvp; pvp = *(++pvpp)) {
 | |
| 	    resPtr *res;
 | |
| 
 | |
| 	    if (PCINONSYSTEMCLASSES(pvp->class, pvp->subclass)) 
 | |
| 		resMisc = ResBios;
 | |
| 	    else 
 | |
| 		resMisc = 0;
 | |
| 	    
 | |
| 	    if (((pciConfigPtr)pvp->thisCard)->pci_command
 | |
| 		& (PCI_CMD_IO_ENABLE | PCI_CMD_MEM_ENABLE))
 | |
| 		res = activeRes;
 | |
| 	    else
 | |
| 		res = inactiveRes;
 | |
| 	    
 | |
| 	    if (!pvp->validSize)
 | |
| 		resMisc |= ResEstimated;
 | |
| 	    
 | |
| 	    for (i = 0; i < 6; i++) {
 | |
| 		if (pvp->ioBase[i] &&
 | |
| 		    (pvp->ioBase[i] < (memType)(-1 << pvp->size[i]))) {
 | |
| 		    PV_I_RANGE(range,pvp,i,ResExcIoBlock | resMisc);
 | |
| 		    tmp = xf86AddResToList(NULL, &range, -1);
 | |
| 		    removeOverlapsWithBridges(pvp->bus,tmp);
 | |
| 		    *res = xf86JoinResLists(tmp,*res);
 | |
| 		} else if (pvp->memBase[i] &&
 | |
| 		    (pvp->memBase[i] < (memType)(-1 << pvp->size[i]))) {
 | |
| 		    PV_M_RANGE(range, pvp,i, ResExcMemBlock | resMisc);
 | |
| 		    tmp = xf86AddResToList(NULL, &range, -1);
 | |
| 		    removeOverlapsWithBridges(pvp->bus,tmp);
 | |
| 		    *res = xf86JoinResLists(tmp,*res);
 | |
| 		}
 | |
| 	    }
 | |
| 	    /* FIXME!!!: Don't use BIOS resources for overlap
 | |
| 	     * checking but reserve them!
 | |
| 	     */
 | |
| 	    if (pvp->biosBase &&
 | |
| 		(pvp->biosBase < (memType)(-1 << pvp->biosSize))) {
 | |
| 		PV_B_RANGE(range, pvp, ResExcMemBlock | resMisc);
 | |
| 		tmp = xf86AddResToList(NULL, &range, -1);
 | |
| 		removeOverlapsWithBridges(pvp->bus,tmp);
 | |
| 		*res = xf86JoinResLists(tmp,*res);
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|     for (pcrpp = xf86PciInfo, pcrp = *pcrpp; pcrp; pcrp = *++(pcrpp)) {
 | |
| 	resPtr *res;
 | |
| 	const CARD8 baseclass = pcrp->pci_base_class;
 | |
| 	const CARD8 subclass = pcrp->pci_sub_class;
 | |
| 
 | |
| 	
 | |
| 	if (PCIINFOCLASSES(baseclass, subclass))
 | |
| 	    continue;
 | |
| 	
 | |
| 	/* Only process devices with type 0 headers */
 | |
| 	if ((pcrp->pci_header_type & 0x7f) != 0)
 | |
| 	    continue;
 | |
| 
 | |
| 	if (!pcrp->minBasesize)
 | |
| 	    resMisc = ResEstimated;
 | |
| 	else
 | |
| 	    resMisc = 0;
 | |
| 
 | |
| 	/*
 | |
| 	 * Allow resources allocated to host bridges to overlap.  Perhaps, this
 | |
| 	 * needs to be specific to AGP-capable chipsets.  AGP "memory"
 | |
| 	 * sometimes gets allocated within the range routed to the AGP bus.
 | |
| 	 */
 | |
| 	if ((baseclass == PCI_CLASS_BRIDGE) &&
 | |
| 	    (subclass == PCI_SUBCLASS_BRIDGE_HOST))
 | |
| 	    resMisc |= ResOverlap;
 | |
| 	
 | |
| 	basep = &pcrp->pci_base0;
 | |
| 	for (i = 0; i < 6; i++) {
 | |
| 	    if (basep[i]) {
 | |
| 	        if (PCI_MAP_IS_IO(basep[i])) {
 | |
| 		    if (pcrp->pci_command & PCI_CMD_IO_ENABLE)
 | |
| 			res = activeRes;
 | |
| 		    else
 | |
| 			res = inactiveRes;
 | |
| 		    P_I_RANGE(range, pcrp->tag, PCIGETIO(basep[i]),
 | |
| 			      pcrp->basesize[i], ResExcIoBlock | resMisc)
 | |
| 		} else if (!PCI_MAP_IS64BITMEM(basep[i])) {
 | |
| 		    if (pcrp->pci_command & PCI_CMD_MEM_ENABLE)
 | |
| 			res = activeRes;
 | |
| 		    else
 | |
| 			res = inactiveRes;
 | |
| 		    P_M_RANGE(range, pcrp->tag, PCIGETMEMORY(basep[i]),
 | |
| 			      pcrp->basesize[i], ResExcMemBlock | resMisc)
 | |
| 		} else {
 | |
| 		    i++;
 | |
| #if defined(LONG64) || defined(WORD64)
 | |
| 		    P_M_RANGE(range,pcrp->tag,PCIGETMEMORY64(basep[i - 1]),
 | |
| 			      pcrp->basesize[i - 1], ResExcMemBlock | resMisc)
 | |
| #else
 | |
| 		    if (basep[i])
 | |
| 		      continue;
 | |
| 		    P_M_RANGE(range, pcrp->tag, PCIGETMEMORY(basep[i - 1]),
 | |
| 			      pcrp->basesize[i - 1], ResExcMemBlock | resMisc)
 | |
| #endif
 | |
| 		    if (pcrp->pci_command & PCI_CMD_MEM_ENABLE)
 | |
| 			res = activeRes;
 | |
| 		    else
 | |
| 			res = inactiveRes;
 | |
| 		}
 | |
| 		if (range.rBegin) { /* catch cases where PCI base is unset */
 | |
| 		    tmp = xf86AddResToList(NULL, &range, -1);
 | |
| 		    removeOverlapsWithBridges(pcrp->busnum,tmp);
 | |
| 		    *res = xf86JoinResLists(tmp,*res);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|         /* Ignore disabled non-video ROMs */
 | |
| 	if ((pcrp->pci_command & PCI_CMD_MEM_ENABLE) &&
 | |
| 	    (pcrp->pci_baserom & PCI_MAP_ROM_DECODE_ENABLE)) {
 | |
| 	    P_M_RANGE(range,pcrp->tag,PCIGETROM(pcrp->pci_baserom),
 | |
| 		  pcrp->basesize[6], ResExcMemBlock | resMisc);
 | |
| 	    if (range.rBegin) {
 | |
| 		tmp = xf86AddResToList(NULL, &range, -1);
 | |
| 		removeOverlapsWithBridges(pcrp->busnum, tmp);
 | |
| 		*activeRes = xf86JoinResLists(tmp, *activeRes);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (*activeRes) {
 | |
| 	xf86MsgVerb(X_INFO, 3, "Active PCI resource ranges:\n");
 | |
| 	xf86PrintResList(3, *activeRes);
 | |
|     }
 | |
|     if (*inactiveRes) {
 | |
| 	xf86MsgVerb(X_INFO, 3, "Inactive PCI resource ranges:\n");
 | |
| 	xf86PrintResList(3, *inactiveRes);
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Adjust ranges based on the assumption that there are no real
 | |
|      * overlaps in the PCI base allocations.  This assumption should be
 | |
|      * reasonable in most cases.  It may be possible to refine the
 | |
|      * approximated PCI base sizes by considering bus mapping information
 | |
|      * from PCI-PCI bridges.
 | |
|      */
 | |
| 
 | |
|     if (*activeRes) {
 | |
| 	/* Check for overlaps */
 | |
| 	for (pRes = *activeRes; pRes; pRes = pRes->next) {
 | |
| 	    if (ResCanOverlap(&pRes->val)) {
 | |
| 		range = pRes->val;
 | |
| 
 | |
| 		RemoveOverlaps(pRes, *activeRes, TRUE, TRUE);
 | |
| 		RemoveOverlaps(pRes, *inactiveRes, TRUE, 
 | |
| 		    (xf86Info.estimateSizesAggressively > 0));
 | |
| 		
 | |
| 		if (range.rEnd > pRes->block_end) {
 | |
| 		    correctPciSize(range.rBegin, range.rEnd - range.rBegin,
 | |
| 				   pRes->block_end - pRes->block_begin,
 | |
| 				   pRes->res_type);
 | |
| 		    xf86MsgVerb(X_INFO, 3,
 | |
| 				"PCI %s resource overlap reduced 0x%08lx"
 | |
| 				" from 0x%08lx to 0x%08lx\n",
 | |
| 				((pRes->res_type & ResPhysMask) == ResMem) ?
 | |
| 				 "Memory" : "I/O",
 | |
| 				range.rBegin, range.rEnd, pRes->block_end);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 	xf86MsgVerb(X_INFO, 3,
 | |
| 	    "Active PCI resource ranges after removing overlaps:\n");
 | |
| 	xf86PrintResList(3, *activeRes);
 | |
|     }
 | |
| 
 | |
|     if (*inactiveRes) {
 | |
| 	/* Check for overlaps */
 | |
| 	for (pRes = *inactiveRes; pRes; pRes = pRes->next) {
 | |
| 	    if (ResCanOverlap(&pRes->val)) {
 | |
| 		range = pRes->val;
 | |
| 
 | |
| 		RemoveOverlaps(pRes, *activeRes, TRUE,
 | |
| 		    (xf86Info.estimateSizesAggressively > 1));
 | |
| 		RemoveOverlaps(pRes, *inactiveRes, TRUE,
 | |
| 		    (xf86Info.estimateSizesAggressively > 1));
 | |
| 		
 | |
| 		if (range.rEnd > pRes->block_end) {
 | |
| 		    correctPciSize(range.rBegin, range.rEnd - range.rBegin,
 | |
| 				   pRes->block_end - pRes->block_begin,
 | |
| 				   pRes->res_type);
 | |
| 		    xf86MsgVerb(X_INFO, 3,
 | |
| 				"PCI %s resource overlap reduced 0x%08lx"
 | |
| 				" from 0x%08lx to 0x%08lx\n",
 | |
| 				((pRes->res_type & ResPhysMask) == ResMem) ?
 | |
| 				 "Memory" : "I/O",
 | |
| 				range.rBegin, range.rEnd, pRes->block_end);
 | |
| 		}
 | |
| 		
 | |
| 	    }
 | |
| 	}
 | |
| 	xf86MsgVerb(X_INFO, 3,
 | |
| 	    "Inactive PCI resource ranges after removing overlaps:\n");
 | |
| 	xf86PrintResList(3, *inactiveRes);
 | |
|     }
 | |
| }
 | |
| 
 | |
| resPtr
 | |
| ResourceBrokerInitPci(resPtr *osRes)
 | |
| {
 | |
|     resPtr activeRes, inactiveRes;
 | |
|     resPtr tmp;
 | |
|     
 | |
|     /* Get bus-specific system resources (PCI) */
 | |
|     xf86GetPciRes(&activeRes, &inactiveRes);
 | |
| 
 | |
|     /*
 | |
|      * Adjust OS-reported resource ranges based on the assumption that there
 | |
|      * are no overlaps with the PCI base allocations.  This should be a good
 | |
|      * assumption because writes to PCI address space won't be routed directly
 | |
|      * to host memory.
 | |
|      */
 | |
| 
 | |
|     for (tmp = *osRes; tmp; tmp = tmp->next) 
 | |
| 	RemoveOverlaps(tmp, activeRes, FALSE, TRUE);
 | |
| 
 | |
|     xf86MsgVerb(X_INFO, 3, "OS-reported resource ranges after removing"
 | |
| 		" overlaps with PCI:\n");
 | |
|     xf86PrintResList(3, *osRes);
 | |
| 
 | |
|     pciAvoidRes = xf86AddRangesToList(pciAvoidRes,PciAvoid,-1);
 | |
|     for (tmp = pciAvoidRes; tmp; tmp = tmp->next) 
 | |
| 	RemoveOverlaps(tmp, activeRes, FALSE, TRUE);
 | |
|     tmp = xf86DupResList(*osRes);
 | |
|     pciAvoidRes = xf86JoinResLists(pciAvoidRes,tmp);
 | |
|     
 | |
|     return (xf86JoinResLists(activeRes,inactiveRes));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * PCI Resource modification
 | |
|  */
 | |
| static Bool
 | |
| fixPciResource(int prt, memType alignment, pciVideoPtr pvp, unsigned long type)
 | |
| {
 | |
|     int  res_n;
 | |
|     memType *p_base;
 | |
|     int *p_size;
 | |
|     unsigned char p_type;
 | |
|     resPtr AccTmp = NULL;
 | |
|     resPtr orgAcc = NULL;
 | |
|     resPtr *pAcc = &AccTmp;
 | |
|     resPtr avoid = NULL;
 | |
|     resRange range;
 | |
|     resPtr resSize = NULL;
 | |
|     resPtr w_tmp, w = NULL, w_2nd = NULL;
 | |
|     PCITAG tag;
 | |
|     PciBusPtr pbp = xf86PciBus;
 | |
|     pciConfigPtr pcp;
 | |
|     resPtr tmp;
 | |
|     
 | |
|     if (!pvp) return FALSE;
 | |
|     tag = pciTag(pvp->bus,pvp->device,pvp->func);
 | |
|     pcp = pvp->thisCard;
 | |
| 
 | |
|     type &= ResAccMask;
 | |
|     if (!type) type = ResShared;
 | |
|     if (prt < 6) {
 | |
| 	if (pvp->memBase[prt]) {
 | |
| 	    type |= ResMem;
 | |
| 	    res_n = prt;
 | |
| 	    p_base = &(pvp->memBase[res_n]);
 | |
| 	    p_size = &(pvp->size[res_n]);
 | |
| 	    p_type = pvp->type[res_n];
 | |
| 	    if (!PCI_MAP_IS64BITMEM(pvp->type[res_n])) {
 | |
| 	      PCI_M_RANGE(range,tag,0,0xffffffff,ResExcMemBlock);
 | |
| 	      resSize = xf86AddResToList(resSize,&range,-1);
 | |
| 	    }
 | |
| 	} else if (pvp->ioBase[prt]){
 | |
| 	    type |= ResIo;
 | |
| 	    res_n = prt;
 | |
| 	    p_base = &(pvp->ioBase[res_n]);
 | |
| 	    p_size = &(pvp->size[res_n]);
 | |
| 	    p_type = pvp->type[res_n];
 | |
| 	    PCI_I_RANGE(range, tag, 0, 0xffffffff, ResExcIoBlock);
 | |
| 	    resSize = xf86AddResToList(resSize, &range, -1);
 | |
| 	} else return FALSE;
 | |
|     } else if (prt == 6) {
 | |
| 	type |= ResMem;
 | |
| 	res_n = 0xff;	/* special flag for bios rom */
 | |
| 	p_base = &(pvp->biosBase);
 | |
| 	p_size = &(pvp->biosSize);
 | |
| 	/* XXX This should also include the PCI_MAP_MEMORY_TYPE_MASK part */
 | |
| 	p_type = 0;
 | |
| 	PCI_M_RANGE(range,tag,0,0xffffffff,ResExcMemBlock);
 | |
| 	resSize = xf86AddResToList(resSize,&range,-1);
 | |
|     } else return FALSE;
 | |
| 
 | |
|     if (! *p_base) return FALSE;
 | |
|     
 | |
|     type |= (range.type & ResDomain) | ResBlock;
 | |
|     
 | |
|     /* setup avoid: PciAvoid is bus range: convert later */
 | |
|     avoid = xf86DupResList(pciAvoidRes);
 | |
| 
 | |
|     while (pbp) {
 | |
| 	if (pbp->secondary == pvp->bus) {
 | |
| 	    if ((type & ResPhysMask) == ResMem) {
 | |
| 		if (((p_type & PCI_MAP_MEMORY_CACHABLE)
 | |
| #if 0 /*EE*/
 | |
| 		     || (res_n == 0xff)/* bios should also be prefetchable */
 | |
| #endif
 | |
| 		     )) {
 | |
| 		    if (pbp->preferred_pmem)
 | |
| 			w = xf86FindIntersectOfLists(pbp->preferred_pmem,
 | |
| 						     ResRange);
 | |
| 		    else if (pbp->pmem)
 | |
| 			w = xf86FindIntersectOfLists(pbp->pmem,ResRange);
 | |
| 		    
 | |
| 		    if (pbp->preferred_mem) 
 | |
| 			w_2nd = xf86FindIntersectOfLists(pbp->preferred_mem,
 | |
| 							 ResRange);
 | |
| 		    else if (pbp->mem) 
 | |
| 			w_2nd = xf86FindIntersectOfLists(pbp->mem,
 | |
| 							 ResRange);
 | |
| 		} else {
 | |
| 		    if (pbp->preferred_mem)
 | |
| 			w = xf86FindIntersectOfLists(pbp->preferred_mem,
 | |
| 						     ResRange);
 | |
| 		    else if (pbp->mem)
 | |
| 			w = xf86FindIntersectOfLists(pbp->mem,ResRange);
 | |
| 		}
 | |
| 	    } else {
 | |
| 		if (pbp->preferred_io) 
 | |
| 		    w = xf86FindIntersectOfLists(pbp->preferred_io,ResRange);
 | |
| 		if (pbp->io) 
 | |
| 		    w = xf86FindIntersectOfLists(pbp->io,ResRange);
 | |
| 	    }
 | |
| 	} else if (pbp->primary == pvp->bus) {
 | |
| 	    if ((type & ResPhysMask) == ResMem) {
 | |
| 		tmp = xf86DupResList(pbp->preferred_pmem);
 | |
| 		avoid = xf86JoinResLists(avoid, tmp);
 | |
| 		tmp = xf86DupResList(pbp->preferred_mem);
 | |
| 		avoid = xf86JoinResLists(avoid, tmp);
 | |
| 	    } else {
 | |
| 		tmp = xf86DupResList(pbp->preferred_io);
 | |
| 		avoid = xf86JoinResLists(avoid, tmp);
 | |
| 	    }
 | |
| 	}	
 | |
| 	pbp = pbp->next;
 | |
|     }
 | |
|     
 | |
|     /* convert bus based entries in avoid list to host base */
 | |
|     pciConvertListToHost(pvp->bus,pvp->device,pvp->func, avoid);
 | |
|     
 | |
|     if (!w)
 | |
| 	w = xf86DupResList(ResRange);
 | |
|     xf86MsgVerb(X_INFO, 3, "window:\n");
 | |
|     xf86PrintResList(3, w);
 | |
|     xf86MsgVerb(X_INFO, 3, "resSize:\n");
 | |
|     xf86PrintResList(3, resSize);
 | |
|     
 | |
|     if (resSize) {
 | |
| 	w_tmp = w;
 | |
| 	w = xf86FindIntersectOfLists(w,resSize);
 | |
| 	xf86FreeResList(w_tmp);
 | |
| 	if (w_2nd) {
 | |
| 	    w_tmp = w_2nd;
 | |
| 	    w_2nd = xf86FindIntersectOfLists(w_2nd,resSize);
 | |
| 	    xf86FreeResList(w_tmp);
 | |
| 	}
 | |
| 	xf86FreeResList(resSize);
 | |
|     }
 | |
|     xf86MsgVerb(X_INFO, 3, "window fixed:\n");
 | |
|     xf86PrintResList(3, w);
 | |
| 
 | |
|     if (!alignment)
 | |
| 	alignment = (1 << (*p_size)) - 1;
 | |
|     
 | |
|     /* Access list holds bios resources -- remove this one */
 | |
| #ifdef NOTYET
 | |
|     AccTmp = xf86DupResList(Acc);
 | |
|     while ((*pAcc)) {
 | |
| 	if ((((*pAcc)->res_type & (type & ~ResAccMask))
 | |
| 	     == (type & ~ResAccMask))
 | |
| 	    && ((*pAcc)->block_begin == (B2H(tag,(*p_base),type)))
 | |
| 	    && ((*pAcc)->block_end == (B2H(tag,
 | |
| 					   (*p_base)+SIZE(*p_size),type)))) {
 | |
| 	    resPtr acc_tmp = (*pAcc)->next;
 | |
| 	    xfree((*pAcc));
 | |
| 	    (*pAcc) = acc_tmp;
 | |
| 	    break;
 | |
| 	} else
 | |
| 	    pAcc = &((*pAcc)->next);
 | |
|     }
 | |
|     /* check if we really need to fix anything */
 | |
|     P_X_RANGE(range,tag,(*p_base),(*p_base) + SIZE((*p_size)),type);
 | |
|     if (!ChkConflict(&range,avoid,SETUP)
 | |
| 	&& !ChkConflict(&range,AccTmp,SETUP)
 | |
| 	&& ((B2H(tag,(*p_base),type) & PCI_SIZE(type,tag,alignment)
 | |
| 	     == range->block_begin)
 | |
| 	&& ((xf86IsSubsetOf(range,w)
 | |
| 	    || (w_2nd && xf86IsSubsetOf(range,w_2n))))) {
 | |
| #ifdef DEBUG
 | |
| 	    ErrorF("nothing to fix\n");
 | |
| #endif
 | |
| 	xf86FreeResList(AccTmp);
 | |
| 	xf86FreeResList(w);
 | |
| 	xf86FreeResList(w_2nd);
 | |
| 	xf86FreeResList(avoid);
 | |
| 	return TRUE;
 | |
|     }
 | |
| #ifdef DEBUG
 | |
| 	ErrorF("removing old resource\n");
 | |
| #endif
 | |
|     orgAcc = Acc;
 | |
|     Acc = AccTmp;
 | |
| #else
 | |
|     orgAcc = xf86DupResList(Acc);
 | |
|     pAcc = &Acc;
 | |
|     while (*pAcc) {
 | |
| 	if ((((*pAcc)->res_type & (ResTypeMask|ResExtMask)) ==
 | |
| 	     (type & ~ResAccMask))
 | |
| 	    && ((*pAcc)->block_begin == B2H(tag,(*p_base),type))
 | |
| 	    && ((*pAcc)->block_end == B2H(tag,(*p_base) + SIZE(*p_size),
 | |
| 					  type))) {
 | |
| #ifdef DEBUG
 | |
| 	    ErrorF("removing old resource\n");
 | |
| #endif
 | |
| 	    tmp = *pAcc;
 | |
| 	    *pAcc = (*pAcc)->next;
 | |
| 	    tmp->next = NULL;
 | |
| 	    xf86FreeResList(tmp);
 | |
| 	    break;
 | |
| 	} else
 | |
| 	    pAcc = &((*pAcc)->next);
 | |
|     }
 | |
| #endif
 | |
|     
 | |
| #ifdef DEBUG
 | |
|     ErrorF("base: 0x%lx alignment: 0x%lx host alignment: 0x%lx size[bit]: 0x%x\n",
 | |
| 	   (*p_base),alignment,PCI_SIZE(type,tag,alignment),(*p_size));
 | |
|     xf86MsgVerb(X_INFO, 3, "window:\n");
 | |
|     xf86PrintResList(3, w);
 | |
|     if (w_2nd)
 | |
| 	xf86MsgVerb(X_INFO, 3, "2nd window:\n");
 | |
|     xf86PrintResList(3, w_2nd);
 | |
|     xf86ErrorFVerb(3,"avoid:\n");
 | |
|     xf86PrintResList(3,avoid);
 | |
| #endif
 | |
|     w_tmp = w;
 | |
|     while (w) {
 | |
| 	if ((type & ResTypeMask) == (w->res_type & ResTypeMask)) {
 | |
| #ifdef DEBUG
 | |
| 	    ErrorF("block_begin: 0x%lx block_end: 0x%lx\n",w->block_begin,
 | |
| 		   w->block_end);
 | |
| #endif
 | |
| 	    range = xf86GetBlock(type,PCI_SIZE(type,tag,alignment + 1),
 | |
| 				 w->block_begin, w->block_end,
 | |
| 				 PCI_SIZE(type,tag,alignment),avoid);
 | |
| 	    if (range.type != ResEnd)
 | |
| 		break;
 | |
| 	}
 | |
| 	w = w->next;
 | |
|     }
 | |
|     xf86FreeResList(w_tmp);
 | |
|     /* if unsuccessful and memory prefetchable try non-prefetchable */
 | |
|     if (range.type == ResEnd && w_2nd) {
 | |
| 	w_tmp = w_2nd;
 | |
| 	while (w_2nd) {
 | |
| 	    if ((type & ResTypeMask) == (w_2nd->res_type & ResTypeMask)) {
 | |
| #ifdef DEBUG
 | |
| 	    ErrorF("block_begin: 0x%lx block_end: 0x%lx\n",w_2nd->block_begin,
 | |
| 		   w_2nd->block_end);
 | |
| #endif
 | |
| 	    range = xf86GetBlock(type,PCI_SIZE(type,tag,alignment + 1),
 | |
| 				 w_2nd->block_begin, w_2nd->block_end,
 | |
| 				 PCI_SIZE(type,tag,alignment),avoid);
 | |
| 		if (range.type != ResEnd)
 | |
| 		    break;
 | |
| 	    }
 | |
| 	w_2nd = w_2nd->next;
 | |
| 	}
 | |
| 	xf86FreeResList(w_tmp);
 | |
|     }
 | |
|     xf86FreeResList(avoid);
 | |
| 
 | |
|     if (range.type == ResEnd) {
 | |
| 	xf86MsgVerb(X_ERROR,3,"Cannot find a replacement memory range\n");
 | |
| 	xf86FreeResList(Acc);
 | |
| 	Acc = orgAcc;
 | |
| 	return FALSE;
 | |
|     }
 | |
|     xf86FreeResList(orgAcc);
 | |
| #ifdef DEBUG
 | |
|     ErrorF("begin: 0x%lx, end: 0x%lx\n",range.a,range.b);
 | |
| #endif
 | |
|     
 | |
|     (*p_size) = 0;
 | |
|     while (alignment >> (*p_size))
 | |
| 	(*p_size)++;
 | |
|     (*p_base) = H2B(tag,range.rBegin,type);
 | |
| #ifdef DEBUG
 | |
|     ErrorF("New PCI res %i base: 0x%lx, size: 0x%lx, type %s\n",
 | |
| 	   res_n,(*p_base),(1 << (*p_size)),
 | |
| 	   ((type & ResPhysMask) == ResMem) ? "Mem" : "Io");
 | |
| #endif
 | |
|     if (res_n != 0xff) {
 | |
| 	if ((type & ResPhysMask) == ResMem)
 | |
| 	    pvp->memBase[prt] = range.rBegin;
 | |
| 	else
 | |
| 	    pvp->ioBase[prt] = range.rBegin;
 | |
| 	((CARD32 *)(&(pcp->pci_base0)))[res_n] =
 | |
| 	    (CARD32)(*p_base) | (CARD32)(p_type);
 | |
| 	pciWriteLong(tag, PCI_CMD_BASE_REG + res_n * sizeof(CARD32),
 | |
| 		     ((CARD32 *)(&(pcp->pci_base0)))[res_n]);
 | |
| 	if (PCI_MAP_IS64BITMEM(p_type)) {
 | |
| #if defined(LONG64) || defined(WORD64)
 | |
| 	    ((CARD32 *)(&(pcp->pci_base0)))[res_n + 1] =
 | |
| 		(CARD32)(*p_base >> 32);
 | |
| 	    pciWriteLong(tag, PCI_CMD_BASE_REG + (res_n + 1) * sizeof(CARD32),
 | |
| 	    		 ((CARD32 *)(&(pcp->pci_base0)))[res_n + 1]);
 | |
| #else
 | |
| 	    ((CARD32 *)(&(pcp->pci_base0)))[res_n + 1] = 0;
 | |
| 	    pciWriteLong(tag, PCI_CMD_BASE_REG + (res_n + 1) * sizeof(CARD32),
 | |
| 			 0);
 | |
| #endif
 | |
| 	}
 | |
|     } else {
 | |
| 	pvp->biosBase = range.rBegin;
 | |
| 	pcp->pci_baserom = (pciReadLong(tag,PCI_CMD_BIOS_REG) & 0x01) |
 | |
| 	    (CARD32)(*p_base);
 | |
| 	pciWriteLong(tag, PCI_CMD_BIOS_REG, pcp->pci_baserom);
 | |
|     }
 | |
|     /* @@@ fake BIOS allocated resource */
 | |
|     range.type |= ResBios;
 | |
|     Acc = xf86AddResToList(Acc, &range,-1);
 | |
|     
 | |
|     return TRUE;
 | |
|     
 | |
| }
 | |
| 
 | |
| _X_EXPORT Bool
 | |
| xf86FixPciResource(int entityIndex, int prt, memType alignment,
 | |
| 		   unsigned long type)
 | |
| {
 | |
|     pciVideoPtr pvp = xf86GetPciInfoForEntity(entityIndex);
 | |
|     return fixPciResource(prt, alignment, pvp, type);
 | |
| }
 | |
| 
 | |
| _X_EXPORT resPtr
 | |
| xf86ReallocatePciResources(int entityIndex, resPtr pRes)
 | |
| {
 | |
|     pciVideoPtr pvp = xf86GetPciInfoForEntity(entityIndex);
 | |
|     resPtr pBad = NULL,pResTmp;
 | |
|     unsigned int prt = 0;
 | |
|     int i;
 | |
|     
 | |
|     if (!pvp) return pRes;
 | |
| 
 | |
|     while (pRes) {
 | |
| 	switch (pRes->res_type & ResPhysMask) {
 | |
| 	case ResMem:
 | |
| 	    if (pRes->block_begin == B2M(TAG(pvp),pvp->biosBase) &&
 | |
| 		pRes->block_end == B2M(TAG(pvp),pvp->biosBase
 | |
| 				       + SIZE(pvp->biosSize)))
 | |
| 		prt = 6;
 | |
| 	    else for (i = 0 ; i < 6; i++) 
 | |
| 		if ((pRes->block_begin == B2M(TAG(pvp),pvp->memBase[i]))
 | |
| 		    && (pRes->block_end == B2M(TAG(pvp),pvp->memBase[i]
 | |
| 					      + SIZE(pvp->size[i])))) {
 | |
| 		    prt = i;
 | |
| 		    break;
 | |
| 		}
 | |
| 	    break;
 | |
| 	case ResIo:
 | |
| 	    for (i = 0 ; i < 6; i++) 
 | |
| 		if (pRes->block_begin == B2I(TAG(pvp),pvp->ioBase[i])
 | |
| 		    && pRes->block_end == B2I(TAG(pvp),pvp->ioBase[i]
 | |
| 		    + SIZE(pvp->size[i]))) {
 | |
| 		    prt = i;
 | |
| 		    break;
 | |
| 		}
 | |
| 	    break;
 | |
| 	}
 | |
| 
 | |
| 	if (!prt) return pRes;
 | |
| 
 | |
| 	pResTmp = pRes->next;
 | |
| 	if (! fixPciResource(prt, 0, pvp, pRes->res_type)) {
 | |
| 	    pRes->next = pBad;
 | |
| 	    pBad = pRes;
 | |
| 	} else
 | |
| 	    xfree(pRes);
 | |
| 	
 | |
| 	pRes = pResTmp;
 | |
|     }
 | |
|     return pBad;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * BIOS releated
 | |
|  */
 | |
| static resPtr
 | |
| getOwnResources(pciVideoPtr pvp, resPtr mem)
 | |
| {
 | |
|     resRange range;
 | |
|     int i;
 | |
|     /* Make sure we don't conflict with our own mem resources */
 | |
|     for (i = 0; i < 6; i++) {
 | |
| 	if (!pvp->memBase[i])
 | |
| 	    continue;
 | |
| 	P_M_RANGE(range,TAG(pvp),pvp->memBase[i],pvp->size[i],
 | |
| 		  ResExcMemBlock);
 | |
| 	mem = xf86AddResToList(mem,&range,-1);
 | |
|     }
 | |
|     return mem;
 | |
| }
 | |
| 
 | |
| static void
 | |
| getPciRangesForMapping(pciVideoPtr pvp,  resPtr *map, resPtr *avoid)
 | |
| {
 | |
|     PciBusPtr pbp;
 | |
|     resPtr tmp;
 | |
|     
 | |
|     *avoid = xf86DupResList(pciAvoidRes);
 | |
| 
 | |
|     pbp = xf86PciBus;
 | |
|     while (pbp) {
 | |
| 	if (pbp->secondary == pvp->bus) {
 | |
| 	    if (pbp->preferred_pmem)
 | |
| 		tmp = xf86DupResList(pbp->preferred_pmem);
 | |
| 	    else
 | |
| 		tmp = xf86DupResList(pbp->pmem);
 | |
| 	    *map = xf86JoinResLists(*map,tmp);
 | |
| 	    if (pbp->preferred_mem)
 | |
| 		tmp = xf86DupResList(pbp->preferred_mem);
 | |
| 	    else
 | |
| 		tmp = xf86DupResList(pbp->mem);
 | |
| 	    *map = xf86JoinResLists(*map,tmp);
 | |
| 	    tmp = *map;
 | |
| 	    while (tmp) {
 | |
| 		tmp->block_end = min(tmp->block_end,PCI_MEM32_LENGTH_MAX);
 | |
| 		tmp = tmp->next;
 | |
| 	    }
 | |
| 	} else if ((pbp->primary == pvp->bus) &&
 | |
| 		   (pbp->secondary >= 0) &&
 | |
| 		   (pbp->primary != pbp->secondary)) {
 | |
| 	    tmp = xf86DupResList(pbp->preferred_pmem);
 | |
| 	    *avoid = xf86JoinResLists(*avoid, tmp);
 | |
| 	    tmp = xf86DupResList(pbp->pmem);
 | |
| 	    *avoid = xf86JoinResLists(*avoid, tmp);
 | |
| 	    tmp = xf86DupResList(pbp->preferred_mem);
 | |
| 	    *avoid = xf86JoinResLists(*avoid, tmp);
 | |
| 	    tmp = xf86DupResList(pbp->mem);
 | |
| 	    *avoid = xf86JoinResLists(*avoid, tmp);
 | |
| 	}
 | |
| 	pbp = pbp->next;
 | |
|     }	
 | |
|     pciConvertListToHost(pvp->bus,pvp->device,pvp->func, *avoid);
 | |
|     pciConvertListToHost(pvp->bus,pvp->device,pvp->func, *map);
 | |
| }
 | |
| 
 | |
| static memType
 | |
| findPciRange(PCITAG tag, resPtr m, resPtr avoid, CARD32 size)
 | |
| {
 | |
|     resRange range;
 | |
|     CARD32 alignment = (1 << size) - 1;
 | |
|     
 | |
|     while (m) {
 | |
| 	range = xf86GetBlock(RANGE_TYPE(ResExcMemBlock, xf86GetPciDomain(tag)),
 | |
| 			     PCI_SIZE(ResMem, tag, 1 << size),
 | |
| 			     m->block_begin, m->block_end,
 | |
| 			     PCI_SIZE(ResMem, tag, alignment), 
 | |
| 			     avoid);
 | |
| 	if (range.type != ResEnd) {
 | |
| 	    return  M2B(tag, range.rBase);
 | |
| 	}
 | |
| 	m = m->next;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| pciVideoPtr
 | |
| getPciVideoPtr(tag)
 | |
| {
 | |
|     int n = 0;
 | |
| 
 | |
|     pciVideoPtr pvp = NULL;
 | |
|     if (!xf86PciVideoInfo) return 0;
 | |
|     
 | |
|     while ((pvp = xf86PciVideoInfo[n++])) {
 | |
| 	if (pciTag(pvp->bus,pvp->device,pvp->func) == tag)
 | |
| 	    return pvp;
 | |
|     }
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| memType
 | |
| getValidBIOSBase(PCITAG tag, int num)
 | |
| {
 | |
|     pciVideoPtr pvp = NULL;
 | |
|     memType ret;
 | |
|     CARD32 biosSize;
 | |
|     resPtr mem = NULL;
 | |
|     resPtr avoid = NULL, m = NULL;
 | |
|     resRange range;
 | |
|     
 | |
|     pvp = getPciVideoPtr(tag);
 | |
|     
 | |
|     if (!pvp) return 0;
 | |
| 
 | |
|     biosSize = pvp->biosSize;
 | |
| 
 | |
|     if (biosSize > 24)
 | |
| 	biosSize = 24;
 | |
| 
 | |
|     switch ((romBaseSource)num) {
 | |
|     case ROM_BASE_PRESET:
 | |
| 	return 0; /* This should not happen */
 | |
|     case ROM_BASE_BIOS:
 | |
| 	/* In some cases the BIOS base register contains the size mask */
 | |
| 	if ((memType)(-1 << biosSize) == PCIGETROM(pvp->biosBase))
 | |
| 	    return 0;
 | |
| 	mem = getOwnResources(pvp,mem);
 | |
| 	P_M_RANGE(range, tag, pvp->biosBase,biosSize,ResExcMemBlock);
 | |
| 	ret = pvp->biosBase;
 | |
| 	break;
 | |
|     case ROM_BASE_MEM0:
 | |
|     case ROM_BASE_MEM1:
 | |
|     case ROM_BASE_MEM2:
 | |
|     case ROM_BASE_MEM3:
 | |
|     case ROM_BASE_MEM4:
 | |
|     case ROM_BASE_MEM5:
 | |
| 	if (!pvp->memBase[num] || (pvp->size[num] < biosSize))
 | |
| 	    return 0;
 | |
| 	P_M_RANGE(range, tag ,pvp->memBase[num],biosSize,
 | |
| 		  ResExcMemBlock);
 | |
| 	ret = pvp->memBase[num];
 | |
| 	break;
 | |
|     case ROM_BASE_FIND:
 | |
| 	ret = 0;
 | |
| 	break;
 | |
|     default:
 | |
| 	return 0; /* This should not happen */
 | |
|     }
 | |
| 
 | |
|     /* Now find the ranges for validation */
 | |
|     getPciRangesForMapping(pvp,&m,&avoid);
 | |
|     
 | |
|     if (!ret) {
 | |
| 	/* Return a possible window */
 | |
| 	ret = findPciRange(tag,m,avoid,biosSize);
 | |
|     } else {
 | |
| #if !defined(__ia64__) /* on ia64, trust the kernel, don't look for overlaps */
 | |
| 	if (mem)
 | |
| 	    pciConvertListToHost(pvp->bus,pvp->device,pvp->func, mem);
 | |
| 	if (!xf86IsSubsetOf(range, m) || 
 | |
| 	    ChkConflict(&range, avoid, SETUP) 
 | |
| 	    || (mem && ChkConflict(&range, mem, SETUP))) 
 | |
| 	    ret = 0;
 | |
| #endif 
 | |
|     }
 | |
| 
 | |
|     xf86FreeResList(avoid);
 | |
|     xf86FreeResList(m);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| memType
 | |
| getEmptyPciRange(PCITAG tag, int base_reg)
 | |
| {
 | |
|     resPtr avoid = NULL, m = NULL;
 | |
|     memType ret;
 | |
| 
 | |
|     pciVideoPtr pvp = getPciVideoPtr(tag);
 | |
|     if (!pvp) return 0;
 | |
|     getPciRangesForMapping(pvp,&m,&avoid);
 | |
|     ret = findPciRange(tag,m,avoid,pvp->size[base_reg]);
 | |
|     xf86FreeResList(avoid);
 | |
|     xf86FreeResList(m);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xf86Bus.c interface
 | |
|  */
 | |
| 
 | |
| void
 | |
| xf86PciProbe(void)
 | |
| {
 | |
|     /*
 | |
|      * Initialise the pcidata entry points.
 | |
|      */
 | |
|     xf86SetupPciIds = (ScanPciSetupProcPtr)LoaderSymbol("ScanPciSetupPciIds");
 | |
|     xf86ClosePciIds = (ScanPciCloseProcPtr)LoaderSymbol("ScanPciClosePciIds");
 | |
|     xf86FindPciNamesByDevice =
 | |
| 	(ScanPciFindByDeviceProcPtr)LoaderSymbol("ScanPciFindPciNamesByDevice");
 | |
|     xf86FindPciNamesBySubsys =
 | |
| 	(ScanPciFindBySubsysProcPtr)LoaderSymbol("ScanPciFindPciNamesBySubsys");
 | |
| 
 | |
|     if (!xf86SetupPciIds())
 | |
| 	FatalError("xf86SetupPciIds() failed\n");
 | |
| 
 | |
|     FindPCIVideoInfo();
 | |
| }
 | |
| 
 | |
| static void alignBridgeRanges(PciBusPtr PciBusBase, PciBusPtr primary);
 | |
| 
 | |
| static void
 | |
| printBridgeInfo(PciBusPtr PciBus) 
 | |
| {
 | |
|     char primary[8], secondary[8], subordinate[8], brbus[8];
 | |
| 
 | |
|     xf86FormatPciBusNumber(PciBus->primary, primary);
 | |
|     xf86FormatPciBusNumber(PciBus->secondary, secondary);
 | |
|     xf86FormatPciBusNumber(PciBus->subordinate, subordinate);
 | |
|     xf86FormatPciBusNumber(PciBus->brbus, brbus);
 | |
| 
 | |
|     xf86MsgVerb(X_INFO, 3, "Bus %s: bridge is at (%s:%d:%d), (%s,%s,%s),"
 | |
| 		" BCTRL: 0x%04x (VGA_EN is %s)\n",
 | |
| 		secondary, brbus, PciBus->brdev, PciBus->brfunc,
 | |
| 		primary, secondary, subordinate, PciBus->brcontrol,
 | |
| 		(PciBus->brcontrol & PCI_PCI_BRIDGE_VGA_EN) ?
 | |
| 		 "set" : "cleared");
 | |
|     if (PciBus->preferred_io) {
 | |
| 	xf86MsgVerb(X_INFO, 3,
 | |
| 		    "Bus %s I/O range:\n", secondary);
 | |
| 	xf86PrintResList(3, PciBus->preferred_io);
 | |
|     }
 | |
|     if (PciBus->preferred_mem) {
 | |
| 	xf86MsgVerb(X_INFO, 3,
 | |
| 		    "Bus %s non-prefetchable memory range:\n", secondary);
 | |
| 	xf86PrintResList(3, PciBus->preferred_mem);
 | |
|     }
 | |
|     if (PciBus->preferred_pmem) {
 | |
| 	xf86MsgVerb(X_INFO, 3,
 | |
| 		    "Bus %s prefetchable memory range:\n", secondary);
 | |
| 	xf86PrintResList(3, PciBus->preferred_pmem);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static PciBusPtr
 | |
| xf86GetPciBridgeInfo(void)
 | |
| {
 | |
|     const pciConfigPtr *pcrpp;
 | |
|     pciConfigPtr pcrp;
 | |
|     pciBusInfo_t *pBusInfo;
 | |
|     resRange range;
 | |
|     PciBusPtr PciBus, PciBusBase = NULL;
 | |
|     PciBusPtr *pnPciBus = &PciBusBase;
 | |
|     int MaxBus = 0;
 | |
|     int i, domain;
 | |
|     int primary, secondary, subordinate;
 | |
|     memType base, limit;
 | |
| 
 | |
|     resPtr pciBusAccWindows = xf86PciBusAccWindowsFromOS();
 | |
| 
 | |
|     if (xf86PciInfo == NULL)
 | |
| 	return NULL;
 | |
| 
 | |
|     /* Add each bridge */
 | |
|     for (pcrpp = xf86PciInfo, pcrp = *pcrpp; pcrp; pcrp = *(++pcrpp)) {
 | |
| 	if (pcrp->busnum > MaxBus)
 | |
| 	    MaxBus = pcrp->busnum;
 | |
| 	if ( pcrp->pci_base_class == PCI_CLASS_BRIDGE ) {
 | |
| 	    const int sub_class = pcrp->pci_sub_class;
 | |
| 
 | |
| 	    domain = xf86GetPciDomain(pcrp->tag);
 | |
| 
 | |
| 	    switch (sub_class) {
 | |
| 	    case PCI_SUBCLASS_BRIDGE_PCI:
 | |
| 		/* something fishy about the header? If so: just ignore! */
 | |
| 		if ((pcrp->pci_header_type & 0x7f) != 0x01) {
 | |
| 		    xf86MsgVerb(X_WARNING, 3, "PCI-PCI bridge at %x:%x:%x has"
 | |
| 				" unexpected header:  0x%x",
 | |
| 				pcrp->busnum, pcrp->devnum,
 | |
| 				pcrp->funcnum, pcrp->pci_header_type);
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
| 		domain = pcrp->busnum & 0x0000FF00;
 | |
| 		primary = pcrp->busnum;
 | |
| 		secondary = domain | pcrp->pci_secondary_bus_number;
 | |
| 		subordinate = domain | pcrp->pci_subordinate_bus_number;
 | |
| 
 | |
| 		/* Is this the correct bridge? If not, ignore it */
 | |
| 		pBusInfo = pcrp->businfo;
 | |
| 		if (pBusInfo && (pcrp != pBusInfo->bridge)) {
 | |
| 		    xf86MsgVerb(X_WARNING, 3, "PCI bridge mismatch for bus %x:"
 | |
| 				" %x:%x:%x and %x:%x:%x\n", secondary,
 | |
| 				pcrp->busnum, pcrp->devnum, pcrp->funcnum,
 | |
| 				pBusInfo->bridge->busnum,
 | |
| 				pBusInfo->bridge->devnum,
 | |
| 				pBusInfo->bridge->funcnum);
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
| 		if (pBusInfo && pBusInfo->funcs->pciGetBridgeBuses)
 | |
| 		    (*pBusInfo->funcs->pciGetBridgeBuses)(secondary,
 | |
| 							   &primary,
 | |
| 							   &secondary,
 | |
| 							   &subordinate);
 | |
| 
 | |
| 		if (!pcrp->fakeDevice && (primary >= secondary)) {
 | |
| 		    xf86MsgVerb(X_WARNING, 3, "Misconfigured PCI bridge"
 | |
| 				" %x:%x:%x (%x,%x)\n",
 | |
| 				pcrp->busnum, pcrp->devnum, pcrp->funcnum,
 | |
| 				primary, secondary);
 | |
| 		    break;
 | |
| 		}
 | |
| 		
 | |
| 		*pnPciBus = PciBus = xnfcalloc(1, sizeof(PciBusRec));
 | |
| 		pnPciBus = &PciBus->next;
 | |
| 
 | |
| 		PciBus->primary = primary;
 | |
| 		PciBus->secondary = secondary;
 | |
| 		PciBus->subordinate = subordinate;
 | |
| 
 | |
| 		PciBus->brbus = pcrp->busnum;
 | |
| 		PciBus->brdev = pcrp->devnum;
 | |
| 		PciBus->brfunc = pcrp->funcnum;
 | |
| 
 | |
| 		PciBus->subclass = sub_class;
 | |
| 
 | |
| 		/* The Intel bridges don't report as transparent
 | |
| 		   but guess what they are - from Linux kernel - airlied */
 | |
| 		if ((pcrp->pci_vendor == PCI_VENDOR_INTEL) && 
 | |
| 		   ((pcrp->pci_device & 0xff00) == 0x2400)) {
 | |
| 			xf86MsgVerb(X_INFO, 3, "Intel Bridge workaround enabled\n");
 | |
| 			PciBus->interface = PCI_IF_BRIDGE_PCI_SUBTRACTIVE;
 | |
| 		} else {
 | |
| 			PciBus->interface = pcrp->pci_prog_if;
 | |
| 		}
 | |
| 
 | |
| 		if (pBusInfo && pBusInfo->funcs->pciControlBridge)
 | |
| 		    PciBus->brcontrol =
 | |
| 			(*pBusInfo->funcs->pciControlBridge)(secondary, 0, 0);
 | |
| 		else
 | |
| 		    PciBus->brcontrol = pcrp->pci_bridge_control;
 | |
| 
 | |
| 		if (pBusInfo && pBusInfo->funcs->pciGetBridgeResources) {
 | |
| 		    (*pBusInfo->funcs->pciGetBridgeResources)(secondary,
 | |
| 			(pointer *)&PciBus->preferred_io,
 | |
| 			(pointer *)&PciBus->preferred_mem,
 | |
| 			(pointer *)&PciBus->preferred_pmem);
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
| 		if ((pcrp->pci_command & PCI_CMD_IO_ENABLE) &&
 | |
| 		    (pcrp->pci_upper_io_base || pcrp->pci_io_base ||
 | |
| 		     pcrp->pci_upper_io_limit || pcrp->pci_io_limit)) {
 | |
| 		    base = (pcrp->pci_upper_io_base << 16) |
 | |
| 			((pcrp->pci_io_base & 0xf0u) << 8);
 | |
| 		    limit = (pcrp->pci_upper_io_limit << 16) |
 | |
| 			((pcrp->pci_io_limit & 0xf0u) << 8) | 0x0fff;
 | |
| 		    /*
 | |
| 		     * Deal with bridge ISA mode (256 wide ranges spaced 1K
 | |
| 		     * apart, but only in the first 64K).
 | |
| 		     */
 | |
| 		    if (pcrp->pci_bridge_control & PCI_PCI_BRIDGE_ISA_EN) {
 | |
| 			while ((base <= (CARD16)(-1)) && (base <= limit)) {
 | |
| 			    PCI_I_RANGE(range, pcrp->tag,
 | |
| 				base, base + (CARD8)(-1),
 | |
| 				ResIo | ResBlock | ResExclusive);
 | |
| 			    PciBus->preferred_io =
 | |
| 				xf86AddResToList(PciBus->preferred_io,
 | |
| 						 &range, -1);
 | |
| 			    base += 0x0400;
 | |
| 			}
 | |
| 		    }
 | |
| 		    if (base <= limit) {
 | |
| 			PCI_I_RANGE(range, pcrp->tag, base, limit,
 | |
| 			    ResIo | ResBlock | ResExclusive);
 | |
| 			PciBus->preferred_io =
 | |
| 			    xf86AddResToList(PciBus->preferred_io, &range, -1);
 | |
| 		    }
 | |
| 		}
 | |
| 		if (pcrp->pci_command & PCI_CMD_MEM_ENABLE) {
 | |
| 		  /*
 | |
| 		   * The P2P spec requires these next two, but some bridges
 | |
| 		   * don't comply.  Err on the side of caution, making the not
 | |
| 		   * so bold assumption that no bridge would ever re-route the
 | |
| 		   * bottom megabyte.
 | |
| 		   */
 | |
| 		  if (pcrp->pci_mem_base || pcrp->pci_mem_limit) {
 | |
|                     base = pcrp->pci_mem_base & 0xfff0u;
 | |
|                     limit = pcrp->pci_mem_limit & 0xfff0u;
 | |
| 		    if (base <= limit) {
 | |
| 			PCI_M_RANGE(range, pcrp->tag,
 | |
| 				    base << 16, (limit << 16) | 0x0fffff,
 | |
| 				    ResMem | ResBlock | ResExclusive);
 | |
| 			PciBus->preferred_mem =
 | |
| 			    xf86AddResToList(PciBus->preferred_mem, &range, -1);
 | |
| 		    }
 | |
| 		  }
 | |
| 
 | |
| 		  if (pcrp->pci_prefetch_mem_base ||
 | |
| 		      pcrp->pci_prefetch_mem_limit ||
 | |
| 		      pcrp->pci_prefetch_upper_mem_base ||
 | |
| 		      pcrp->pci_prefetch_upper_mem_limit) {
 | |
|                     base = pcrp->pci_prefetch_mem_base & 0xfff0u;
 | |
|                     limit = pcrp->pci_prefetch_mem_limit & 0xfff0u;
 | |
| #if defined(LONG64) || defined(WORD64)
 | |
| 		    base |= (memType)pcrp->pci_prefetch_upper_mem_base << 16;
 | |
| 		    limit |= (memType)pcrp->pci_prefetch_upper_mem_limit << 16;
 | |
| #endif
 | |
| 		    if (base <= limit) {
 | |
| 			PCI_M_RANGE(range, pcrp->tag,
 | |
| 				    base << 16, (limit << 16) | 0xfffff,
 | |
| 				    ResMem | ResBlock | ResExclusive);
 | |
| 			PciBus->preferred_pmem =
 | |
| 			    xf86AddResToList(PciBus->preferred_pmem,
 | |
| 					     &range, -1);
 | |
| 		    }
 | |
| 		  }
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	    case PCI_SUBCLASS_BRIDGE_CARDBUS:
 | |
| 		/* something fishy about the header? If so: just ignore! */
 | |
| 		if ((pcrp->pci_header_type & 0x7f) != 0x02) {
 | |
| 		    xf86MsgVerb(X_WARNING, 3, "PCI-CardBus bridge at %x:%x:%x"
 | |
| 				" has unexpected header:  0x%x",
 | |
| 				pcrp->busnum, pcrp->devnum,
 | |
| 				pcrp->funcnum, pcrp->pci_header_type);
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
| 		domain = pcrp->busnum & 0x0000FF00;
 | |
| 		primary = pcrp->busnum;
 | |
| 		secondary = domain | pcrp->pci_cb_cardbus_bus_number;
 | |
| 		subordinate = domain | pcrp->pci_subordinate_bus_number;
 | |
| 
 | |
| 		/* Is this the correct bridge?  If not, ignore it */
 | |
| 		pBusInfo = pcrp->businfo;
 | |
| 		if (pBusInfo && (pcrp != pBusInfo->bridge)) {
 | |
| 		    xf86MsgVerb(X_WARNING, 3, "CardBus bridge mismatch for bus"
 | |
| 				" %x: %x:%x:%x and %x:%x:%x\n", secondary,
 | |
| 				pcrp->busnum, pcrp->devnum, pcrp->funcnum,
 | |
| 				pBusInfo->bridge->busnum,
 | |
| 				pBusInfo->bridge->devnum,
 | |
| 				pBusInfo->bridge->funcnum);
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
| 		if (pBusInfo && pBusInfo->funcs->pciGetBridgeBuses)
 | |
| 		    (*pBusInfo->funcs->pciGetBridgeBuses)(secondary,
 | |
| 							   &primary,
 | |
| 							   &secondary,
 | |
| 							   &subordinate);
 | |
| 
 | |
| 		if (primary >= secondary) {
 | |
| 		    if (pcrp->pci_cb_cardbus_bus_number != 0)
 | |
| 		        xf86MsgVerb(X_WARNING, 3, "Misconfigured CardBus"
 | |
| 				    " bridge %x:%x:%x (%x,%x)\n",
 | |
| 				    pcrp->busnum, pcrp->devnum, pcrp->funcnum,
 | |
| 				    primary, secondary);
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
| 		*pnPciBus = PciBus = xnfcalloc(1, sizeof(PciBusRec));
 | |
| 		pnPciBus = &PciBus->next;
 | |
| 
 | |
| 		PciBus->primary = primary;
 | |
| 		PciBus->secondary = secondary;
 | |
| 		PciBus->subordinate = subordinate;
 | |
| 
 | |
| 		PciBus->brbus = pcrp->busnum;
 | |
| 		PciBus->brdev = pcrp->devnum;
 | |
| 		PciBus->brfunc = pcrp->funcnum;
 | |
| 
 | |
| 		PciBus->subclass = sub_class;
 | |
| 		PciBus->interface = pcrp->pci_prog_if;
 | |
| 
 | |
| 		if (pBusInfo && pBusInfo->funcs->pciControlBridge)
 | |
| 		    PciBus->brcontrol =
 | |
| 			(*pBusInfo->funcs->pciControlBridge)(secondary, 0, 0);
 | |
| 		else
 | |
| 		    PciBus->brcontrol = pcrp->pci_bridge_control;
 | |
| 
 | |
| 		if (pBusInfo && pBusInfo->funcs->pciGetBridgeResources) {
 | |
| 		    (*pBusInfo->funcs->pciGetBridgeResources)(secondary,
 | |
| 			(pointer *)&PciBus->preferred_io,
 | |
| 			(pointer *)&PciBus->preferred_mem,
 | |
| 			(pointer *)&PciBus->preferred_pmem);
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
| 		if (pcrp->pci_command & PCI_CMD_IO_ENABLE) {
 | |
| 		    if (pcrp->pci_cb_iobase0) {
 | |
| 			base = PCI_CB_IOBASE(pcrp->pci_cb_iobase0);
 | |
| 			limit = PCI_CB_IOLIMIT(pcrp->pci_cb_iolimit0);
 | |
| 
 | |
| 			/*
 | |
| 			 * Deal with bridge ISA mode (256-wide ranges spaced 1K
 | |
| 			 * apart (start to start), but only in the first 64K).
 | |
| 			 */
 | |
| 			if (pcrp->pci_bridge_control & PCI_PCI_BRIDGE_ISA_EN) {
 | |
| 			    while ((base <= (CARD16)(-1)) &&
 | |
| 				   (base <= limit)) {
 | |
| 				PCI_I_RANGE(range, pcrp->tag,
 | |
| 					    base, base + (CARD8)(-1),
 | |
| 					    ResIo | ResBlock | ResExclusive);
 | |
| 				PciBus->preferred_io =
 | |
| 				    xf86AddResToList(PciBus->preferred_io,
 | |
| 						     &range, -1);
 | |
| 				base += 0x0400;
 | |
| 			    }
 | |
| 			}
 | |
| 
 | |
| 			if (base <= limit) {
 | |
| 			    PCI_I_RANGE(range, pcrp->tag, base, limit,
 | |
| 					ResIo | ResBlock | ResExclusive);
 | |
| 			    PciBus->preferred_io =
 | |
| 				xf86AddResToList(PciBus->preferred_io,
 | |
| 						 &range, -1);
 | |
| 			}
 | |
| 		    }
 | |
| 
 | |
| 		    if (pcrp->pci_cb_iobase1) {
 | |
| 			base = PCI_CB_IOBASE(pcrp->pci_cb_iobase1);
 | |
| 			limit = PCI_CB_IOLIMIT(pcrp->pci_cb_iolimit1);
 | |
| 
 | |
| 			/*
 | |
| 			 * Deal with bridge ISA mode (256-wide ranges spaced 1K
 | |
| 			 * apart (start to start), but only in the first 64K).
 | |
| 			 */
 | |
| 			if (pcrp->pci_bridge_control & PCI_PCI_BRIDGE_ISA_EN) {
 | |
| 			    while ((base <= (CARD16)(-1)) &&
 | |
| 				   (base <= limit)) {
 | |
| 				PCI_I_RANGE(range, pcrp->tag,
 | |
| 					    base, base + (CARD8)(-1),
 | |
| 					    ResIo | ResBlock | ResExclusive);
 | |
| 				PciBus->preferred_io =
 | |
| 				    xf86AddResToList(PciBus->preferred_io,
 | |
| 						     &range, -1);
 | |
| 				base += 0x0400;
 | |
| 			    }
 | |
| 			}
 | |
| 
 | |
| 			if (base <= limit) {
 | |
| 			    PCI_I_RANGE(range, pcrp->tag, base, limit,
 | |
| 					ResIo | ResBlock | ResExclusive);
 | |
| 			    PciBus->preferred_io =
 | |
| 				xf86AddResToList(PciBus->preferred_io,
 | |
| 						 &range, -1);
 | |
| 			}
 | |
| 		    }
 | |
| 		}
 | |
| 
 | |
| 		if (pcrp->pci_command & PCI_CMD_MEM_ENABLE) {
 | |
| 		    if ((pcrp->pci_cb_membase0) &&
 | |
| 			(pcrp->pci_cb_membase0 <= pcrp->pci_cb_memlimit0)) {
 | |
| 			PCI_M_RANGE(range, pcrp->tag,
 | |
| 				    pcrp->pci_cb_membase0 & ~0x0fff,
 | |
| 				    pcrp->pci_cb_memlimit0 | 0x0fff,
 | |
| 				    ResMem | ResBlock | ResExclusive);
 | |
| 			if (pcrp->pci_bridge_control &
 | |
| 			    PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)
 | |
| 			    PciBus->preferred_pmem =
 | |
| 				xf86AddResToList(PciBus->preferred_pmem,
 | |
| 						 &range, -1);
 | |
| 			else
 | |
| 			    PciBus->preferred_mem =
 | |
| 				xf86AddResToList(PciBus->preferred_mem,
 | |
| 						 &range, -1);
 | |
| 		    }
 | |
| 		    if ((pcrp->pci_cb_membase1) &&
 | |
| 			(pcrp->pci_cb_membase1 <= pcrp->pci_cb_memlimit1)) {
 | |
| 			PCI_M_RANGE(range, pcrp->tag,
 | |
| 				    pcrp->pci_cb_membase1 & ~0x0fff,
 | |
| 				    pcrp->pci_cb_memlimit1 | 0x0fff,
 | |
| 				    ResMem | ResBlock | ResExclusive);
 | |
| 			if (pcrp->pci_bridge_control &
 | |
| 			    PCI_CB_BRIDGE_CTL_PREFETCH_MEM1)
 | |
| 			    PciBus->preferred_pmem =
 | |
| 				xf86AddResToList(PciBus->preferred_pmem,
 | |
| 						 &range, -1);
 | |
| 			else
 | |
| 			    PciBus->preferred_mem =
 | |
| 				xf86AddResToList(PciBus->preferred_mem,
 | |
| 						 &range, -1);
 | |
| 		    }
 | |
| 		}
 | |
| 
 | |
| 		break;
 | |
| 
 | |
| 	    case PCI_SUBCLASS_BRIDGE_ISA:
 | |
| 	    case PCI_SUBCLASS_BRIDGE_EISA:
 | |
| 	    case PCI_SUBCLASS_BRIDGE_MC:
 | |
| 		*pnPciBus = PciBus = xnfcalloc(1, sizeof(PciBusRec));
 | |
| 		pnPciBus = &PciBus->next;
 | |
| 		PciBus->primary = pcrp->busnum;
 | |
| 		PciBus->secondary = PciBus->subordinate = -1;
 | |
| 		PciBus->brbus = pcrp->busnum;
 | |
| 		PciBus->brdev = pcrp->devnum;
 | |
| 		PciBus->brfunc = pcrp->funcnum;
 | |
| 		PciBus->subclass = sub_class;
 | |
| 		PciBus->brcontrol = PCI_PCI_BRIDGE_VGA_EN;
 | |
| 		break;
 | |
| 
 | |
| 	    case PCI_SUBCLASS_BRIDGE_HOST:
 | |
| 		/* Is this the correct bridge?  If not, ignore bus info */
 | |
| 		pBusInfo = pcrp->businfo;
 | |
| 
 | |
| 		if (!pBusInfo || pBusInfo == HOST_NO_BUS)
 | |
| 		    break;
 | |
| 
 | |
| 		secondary = 0;
 | |
| 		/* Find "secondary" bus segment */
 | |
| 		while (pBusInfo != pciBusInfo[secondary])
 | |
| 			secondary++;
 | |
| 		if (pcrp != pBusInfo->bridge) {
 | |
| 		    xf86MsgVerb(X_WARNING, 3, "Host bridge mismatch for"
 | |
| 				" bus %x: %x:%x:%x and %x:%x:%x\n",
 | |
| 				pBusInfo->primary_bus,
 | |
| 				pcrp->busnum, pcrp->devnum, pcrp->funcnum,
 | |
| 				pBusInfo->bridge->busnum,
 | |
| 				pBusInfo->bridge->devnum,
 | |
| 				pBusInfo->bridge->funcnum);
 | |
| 		    pBusInfo = NULL;
 | |
| 		}
 | |
| 
 | |
| 		*pnPciBus = PciBus = xnfcalloc(1, sizeof(PciBusRec));
 | |
| 		pnPciBus = &PciBus->next;
 | |
| 
 | |
| 
 | |
| 		PciBus->primary = PciBus->secondary = secondary;
 | |
| 		PciBus->subordinate = pciNumBuses - 1;
 | |
| 
 | |
| 		if (pBusInfo->funcs->pciGetBridgeBuses)
 | |
| 		    (*pBusInfo->funcs->pciGetBridgeBuses)
 | |
| 		        (secondary,
 | |
| 			   &PciBus->primary,
 | |
| 			   &PciBus->secondary,
 | |
| 			   &PciBus->subordinate);
 | |
| 
 | |
| 		PciBus->brbus = pcrp->busnum;
 | |
| 		PciBus->brdev = pcrp->devnum;
 | |
| 		PciBus->brfunc = pcrp->funcnum;
 | |
| 
 | |
| 		PciBus->subclass = sub_class;
 | |
| 
 | |
| 		if (pBusInfo && pBusInfo->funcs->pciControlBridge)
 | |
| 		    PciBus->brcontrol =
 | |
| 			(*pBusInfo->funcs->pciControlBridge)(secondary, 0, 0);
 | |
| 		else
 | |
| 		    PciBus->brcontrol = PCI_PCI_BRIDGE_VGA_EN;
 | |
| 
 | |
| 		if (pBusInfo && pBusInfo->funcs->pciGetBridgeResources) {
 | |
| 		    (*pBusInfo->funcs->pciGetBridgeResources)
 | |
| 			(secondary,
 | |
| 			 (pointer *)&PciBus->preferred_io,
 | |
| 			 (pointer *)&PciBus->preferred_mem,
 | |
| 			 (pointer *)&PciBus->preferred_pmem);
 | |
| 		    break;
 | |
| 		}
 | |
| 
 | |
| 		PciBus->preferred_io =
 | |
| 		    xf86ExtractTypeFromList(pciBusAccWindows,
 | |
| 					    RANGE_TYPE(ResIo, domain));
 | |
| 		PciBus->preferred_mem =
 | |
| 		    xf86ExtractTypeFromList(pciBusAccWindows,
 | |
| 					    RANGE_TYPE(ResMem, domain));
 | |
| 		PciBus->preferred_pmem =
 | |
| 		    xf86ExtractTypeFromList(pciBusAccWindows,
 | |
| 					    RANGE_TYPE(ResMem, domain));
 | |
| 		break;
 | |
| 
 | |
| 	    default:
 | |
| 		break;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     for (i = 0; i <= MaxBus; i++) { /* find PCI buses not attached to bridge */
 | |
| 	if (!pciBusInfo[i])
 | |
| 	    continue;
 | |
| 	for (PciBus = PciBusBase; PciBus; PciBus = PciBus->next)
 | |
| 	    if (PciBus->secondary == i) break;
 | |
| 	if (!PciBus) {  /* We assume it's behind a HOST-PCI bridge */
 | |
| 	    /*
 | |
| 	     * Find the 'smallest' free HOST-PCI bridge, where 'small' is in
 | |
| 	     * the order of pciTag().
 | |
| 	     */
 | |
| 	    PCITAG minTag = 0xFFFFFFFF, tag;
 | |
| 	    PciBusPtr PciBusFound = NULL;
 | |
| 	    for (PciBus = PciBusBase; PciBus; PciBus = PciBus->next)
 | |
| 		if ((PciBus->subclass == PCI_SUBCLASS_BRIDGE_HOST) &&
 | |
| 		    (PciBus->secondary == -1) &&
 | |
| 		    ((tag = pciTag(PciBus->brbus,PciBus->brdev,PciBus->brfunc))
 | |
| 		     < minTag) )  {
 | |
| 		    minTag = tag;
 | |
| 		    PciBusFound = PciBus;
 | |
| 		}
 | |
| 	    if (PciBusFound)
 | |
| 		PciBusFound->secondary = i;
 | |
| 	    else {  /* if nothing found it may not be visible: create new */
 | |
| 		/* Find a device on this bus */
 | |
| 		domain = 0;
 | |
| 		for (pcrpp = xf86PciInfo;  (pcrp = *pcrpp);  pcrpp++) {
 | |
| 		    if (pcrp->busnum == i) {
 | |
| 			domain = xf86GetPciDomain(pcrp->tag);
 | |
| 			break;
 | |
| 		    }
 | |
| 		}
 | |
| 		*pnPciBus = PciBus = xnfcalloc(1, sizeof(PciBusRec));
 | |
| 		pnPciBus = &PciBus->next;
 | |
| 		PciBus->primary = PciBus->secondary = i;
 | |
| 		PciBus->subclass = PCI_SUBCLASS_BRIDGE_HOST;
 | |
| 		PciBus->brcontrol = PCI_PCI_BRIDGE_VGA_EN;
 | |
| 		PciBus->preferred_io =
 | |
| 		    xf86ExtractTypeFromList(pciBusAccWindows,
 | |
| 					    RANGE_TYPE(ResIo, domain));
 | |
| 		PciBus->preferred_mem =
 | |
| 		    xf86ExtractTypeFromList(pciBusAccWindows,
 | |
| 					    RANGE_TYPE(ResMem, domain));
 | |
| 		PciBus->preferred_pmem =
 | |
| 		    xf86ExtractTypeFromList(pciBusAccWindows,
 | |
| 					    RANGE_TYPE(ResMem, domain));
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     for (PciBus = PciBusBase; PciBus; PciBus = PciBus->next) {
 | |
| 	if (PciBus->primary == PciBus->secondary) {
 | |
| 	    alignBridgeRanges(PciBusBase, PciBus);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     for (PciBus = PciBusBase; PciBus; PciBus = PciBus->next) {
 | |
| 	switch (PciBus->subclass) {
 | |
| 	    case PCI_SUBCLASS_BRIDGE_PCI:
 | |
| 		if (PciBus->interface == PCI_IF_BRIDGE_PCI_SUBTRACTIVE)
 | |
| 		    xf86MsgVerb(X_INFO, 3, "Subtractive PCI-to-PCI bridge:\n");
 | |
| 		else
 | |
| 		    xf86MsgVerb(X_INFO, 3, "PCI-to-PCI bridge:\n");
 | |
| 		break;
 | |
| 	    case PCI_SUBCLASS_BRIDGE_CARDBUS:
 | |
| 		xf86MsgVerb(X_INFO, 3, "PCI-to-CardBus bridge:\n");
 | |
| 		break;
 | |
| 	    case PCI_SUBCLASS_BRIDGE_HOST:
 | |
| 		xf86MsgVerb(X_INFO, 3, "Host-to-PCI bridge:\n");
 | |
| 		break;
 | |
| 	    case PCI_SUBCLASS_BRIDGE_ISA:
 | |
| 		xf86MsgVerb(X_INFO, 3, "PCI-to-ISA bridge:\n");
 | |
| 		break;
 | |
| 	    case PCI_SUBCLASS_BRIDGE_EISA:
 | |
| 		xf86MsgVerb(X_INFO, 3, "PCI-to-EISA bridge:\n");
 | |
| 		break;
 | |
| 	    case PCI_SUBCLASS_BRIDGE_MC:
 | |
| 		xf86MsgVerb(X_INFO, 3, "PCI-to-MCA bridge:\n");
 | |
| 		break;
 | |
| 	    default:
 | |
| 		break;
 | |
| 	}
 | |
| 	printBridgeInfo(PciBus);
 | |
|     }
 | |
|     xf86FreeResList(pciBusAccWindows);
 | |
|     return PciBusBase;
 | |
| }
 | |
| 
 | |
| static void
 | |
| alignBridgeRanges(PciBusPtr PciBusBase, PciBusPtr primary)
 | |
| {
 | |
|     PciBusPtr PciBus;
 | |
| 
 | |
|     for (PciBus = PciBusBase; PciBus; PciBus = PciBus->next) {
 | |
| 	if ((PciBus != primary) && (PciBus->primary != -1)
 | |
| 	    && (PciBus->primary == primary->secondary)) {
 | |
| 	    resPtr tmp;
 | |
| 	    tmp = xf86FindIntersectOfLists(primary->preferred_io,
 | |
| 					   PciBus->preferred_io);
 | |
| 	    xf86FreeResList(PciBus->preferred_io);
 | |
| 	    PciBus->preferred_io = tmp;
 | |
| 	    tmp = xf86FindIntersectOfLists(primary->preferred_pmem,
 | |
| 					   PciBus->preferred_pmem);
 | |
| 	    xf86FreeResList(PciBus->preferred_pmem);
 | |
| 	    PciBus->preferred_pmem = tmp;
 | |
| 	    tmp = xf86FindIntersectOfLists(primary->preferred_mem,
 | |
| 					   PciBus->preferred_mem);
 | |
| 	    xf86FreeResList(PciBus->preferred_mem);
 | |
| 	    PciBus->preferred_mem = tmp;
 | |
| 
 | |
| 	    /* Deal with subtractive decoding */
 | |
| 	    switch (PciBus->subclass) {
 | |
| 	    case PCI_SUBCLASS_BRIDGE_PCI:
 | |
| 		if (PciBus->interface != PCI_IF_BRIDGE_PCI_SUBTRACTIVE)
 | |
| 		    break;
 | |
| 		/* Fall through */
 | |
| #if 0	/* Not yet */
 | |
| 	    case PCI_SUBCLASS_BRIDGE_ISA:
 | |
| 	    case PCI_SUBCLASS_BRIDGE_EISA:
 | |
| 	    case PCI_SUBCLASS_BRIDGE_MC:
 | |
| #endif
 | |
| 		if (!(PciBus->io = primary->io))
 | |
| 		    PciBus->io = primary->preferred_io;
 | |
| 		if (!(PciBus->mem = primary->mem))
 | |
| 		    PciBus->mem = primary->preferred_mem;
 | |
| 		if (!(PciBus->pmem = primary->pmem))
 | |
| 		    PciBus->pmem = primary->preferred_pmem;
 | |
| 	    default:
 | |
| 		break;
 | |
| 	    }
 | |
| 
 | |
| 	    alignBridgeRanges(PciBusBase, PciBus);
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ValidatePci(void)
 | |
| {
 | |
|     pciVideoPtr pvp, pvp1;
 | |
|     PciBusPtr pbp;
 | |
|     pciConfigPtr pcrp, *pcrpp;
 | |
|     CARD32 *basep;
 | |
|     resPtr Sys;
 | |
|     resRange range;
 | |
|     int n = 0, m, i;
 | |
| 
 | |
|     if (!xf86PciVideoInfo) return;
 | |
| 
 | |
|     /*
 | |
|      * Mark all pciInfoRecs that need to be validated. These are
 | |
|      * the ones which have been assigned to a screen.
 | |
|      */
 | |
|     Sys = xf86DupResList(osRes);
 | |
|     /* Only validate graphics devices in use */
 | |
|     for (i=0; i<xf86NumScreens; i++) {
 | |
| 	for (m = 0; m < xf86Screens[i]->numEntities; m++)
 | |
| 	    if ((pvp = xf86GetPciInfoForEntity(xf86Screens[i]->entityList[m])))
 | |
| 		pvp->validate = TRUE;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Collect all background PCI resources we need to validate against.
 | |
|      * These are all resources which don't belong to PCINONSYSTEMCLASSES
 | |
|      * and which have not been assigned to an entity.
 | |
|      */
 | |
|     /* First get the PCIINFOCLASSES */
 | |
|     m = 0;
 | |
|     while ((pvp = xf86PciVideoInfo[m++])) {
 | |
| 	/* is it a PCINONSYSTEMCLASS? */
 | |
| 	if (PCINONSYSTEMCLASSES(pvp->class, pvp->subclass))
 | |
| 	    continue;
 | |
| 	/* has it an Entity assigned to it? */
 | |
| 	for (i=0; i<xf86NumEntities; i++) {
 | |
| 	    EntityPtr p = xf86Entities[i];
 | |
| 	    if (p->busType != BUS_PCI)
 | |
| 		continue;
 | |
| 	    if (p->pciBusId.bus == pvp->bus
 | |
| 		&& p->pciBusId.device == pvp->device
 | |
| 		&& p->pciBusId.func == pvp->func)
 | |
| 		break;
 | |
| 	}
 | |
| 	if (i != xf86NumEntities) /* found an Entity for this one */
 | |
| 	    continue;
 | |
| 	
 | |
| 	for (i = 0; i<6; i++) {
 | |
| 	    if (pvp->ioBase[i]) {
 | |
| 		PV_I_RANGE(range,pvp,i,ResExcIoBlock);
 | |
| 		Sys = xf86AddResToList(Sys,&range,-1);
 | |
| 	    } else if (pvp->memBase[i]) {
 | |
| 		PV_M_RANGE(range,pvp,i,ResExcMemBlock);
 | |
| 		Sys = xf86AddResToList(Sys,&range,-1);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     for (pcrpp = xf86PciInfo, pcrp = *pcrpp; pcrp; pcrp = *++(pcrpp)) {
 | |
| 
 | |
| 	/* These were handled above */
 | |
| 	if (PCIINFOCLASSES(pcrp->pci_base_class, pcrp->pci_sub_class))
 | |
| 	    continue;
 | |
| 	
 | |
| 	if ((pcrp->pci_header_type & 0x7f) ||
 | |
| 	    !(pcrp->pci_command & (PCI_CMD_IO_ENABLE | PCI_CMD_MEM_ENABLE)))
 | |
| 	    continue;
 | |
| 
 | |
| 	basep = &pcrp->pci_base0;
 | |
| 	for (i = 0; i < 6; i++) {
 | |
| 	    if (basep[i]) {
 | |
| 		if (PCI_MAP_IS_IO(basep[i]))  {
 | |
| 		    if (!(pcrp->pci_command & PCI_CMD_IO_ENABLE))
 | |
| 			continue;
 | |
| 		    P_I_RANGE(range, pcrp->tag, PCIGETIO(basep[i]),
 | |
| 			      pcrp->basesize[i], ResExcIoBlock)
 | |
| 		} else if (!PCI_MAP_IS64BITMEM(basep[i])) {
 | |
| 		    if (!(pcrp->pci_command & PCI_CMD_MEM_ENABLE))
 | |
| 			continue;
 | |
| 		    P_M_RANGE(range, pcrp->tag, PCIGETMEMORY(basep[i]),
 | |
| 			      pcrp->basesize[i], ResExcMemBlock)
 | |
| 		} else {
 | |
| 		    i++;
 | |
| 		    if (!(pcrp->pci_command & PCI_CMD_MEM_ENABLE))
 | |
| 			continue;
 | |
| #if defined(LONG64) || defined(WORD64)
 | |
| 		    P_M_RANGE(range, pcrp->tag, PCIGETMEMORY64(basep[i-1]),
 | |
| 			      pcrp->basesize[i-1], ResExcMemBlock)
 | |
| #else
 | |
| 		    if (basep[i])
 | |
| 		        continue;
 | |
| 		    P_M_RANGE(range, pcrp->tag, PCIGETMEMORY(basep[i-1]),
 | |
| 			      pcrp->basesize[i-1], ResExcMemBlock)
 | |
| #endif
 | |
| 		} 
 | |
| 		Sys = xf86AddResToList(Sys, &range, -1);
 | |
| 	    }
 | |
| 	}
 | |
| 	if ((pcrp->pci_baserom) &&
 | |
| 	    (pcrp->pci_command & PCI_CMD_MEM_ENABLE) &&
 | |
| 	    (pcrp->pci_baserom & PCI_MAP_ROM_DECODE_ENABLE)) {
 | |
| 	    P_M_RANGE(range,pcrp->tag,PCIGETROM(pcrp->pci_baserom),
 | |
| 		      pcrp->basesize[6],ResExcMemBlock);
 | |
| 	    Sys = xf86AddResToList(Sys, &range, -1);
 | |
| 	}
 | |
|     }
 | |
| #ifdef DEBUG
 | |
|     xf86MsgVerb(X_INFO, 3,"Sys:\n");
 | |
|     xf86PrintResList(3,Sys);
 | |
| #endif
 | |
| 
 | |
|     /*
 | |
|      * The order the video devices are listed in is
 | |
|      * just right: the lower buses come first.
 | |
|      * This way we attempt to fix a conflict of
 | |
|      * a lower bus device with a higher bus device
 | |
|      * where we have more room to find different
 | |
|      * resources.
 | |
|      */
 | |
|     while ((pvp = xf86PciVideoInfo[n++])) {
 | |
| 	resPtr res_mp = NULL, res_m_io = NULL;
 | |
| 	resPtr NonSys;
 | |
| 	resPtr tmp, avoid = NULL;
 | |
| 
 | |
| 	if (!pvp->validate) continue;
 | |
| 	NonSys = xf86DupResList(Sys);
 | |
| 	m = n;
 | |
| 	while ((pvp1 = xf86PciVideoInfo[m++])) {
 | |
| 	    if (!pvp1->validate) continue;
 | |
| 	    for (i = 0; i<6; i++) {
 | |
| 		if (pvp1->ioBase[i]) {
 | |
| 		    PV_I_RANGE(range,pvp1,i,ResExcIoBlock);
 | |
| 		    NonSys = xf86AddResToList(NonSys,&range,-1);
 | |
| 		} else if (pvp1->memBase[i]) {
 | |
| 		    PV_M_RANGE(range,pvp1,i,ResExcMemBlock);
 | |
| 		    NonSys = xf86AddResToList(NonSys,&range,-1);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| #ifdef DEBUG
 | |
| 	xf86MsgVerb(X_INFO, 3,"NonSys:\n");
 | |
| 	xf86PrintResList(3,NonSys);
 | |
| #endif
 | |
| 	pbp = xf86PciBus;
 | |
| 	while (pbp) {
 | |
| 	    if (pbp->secondary == pvp->bus) {
 | |
| 		if (pbp->preferred_pmem) {
 | |
| 		    /* keep prefetchable separate */
 | |
| 		    res_mp =
 | |
| 			xf86FindIntersectOfLists(pbp->preferred_pmem, ResRange);
 | |
| 		}
 | |
| 		if (pbp->pmem) {
 | |
| 		    res_mp = xf86FindIntersectOfLists(pbp->pmem, ResRange);
 | |
| 		}
 | |
| 		if (pbp->preferred_mem) {
 | |
| 		    res_m_io =
 | |
| 			xf86FindIntersectOfLists(pbp->preferred_mem, ResRange);
 | |
| 		}
 | |
| 		if (pbp->mem) {
 | |
| 		    res_m_io = xf86FindIntersectOfLists(pbp->mem, ResRange);
 | |
| 		}
 | |
| 		if (pbp->preferred_io) {
 | |
| 		    res_m_io = xf86JoinResLists(res_m_io,
 | |
| 			xf86FindIntersectOfLists(pbp->preferred_io, ResRange));
 | |
| 		}
 | |
| 		if (pbp->io) {
 | |
| 		    res_m_io = xf86JoinResLists(res_m_io,
 | |
| 			xf86FindIntersectOfLists(pbp->preferred_io, ResRange));
 | |
| 		}
 | |
| 	    } else if ((pbp->primary == pvp->bus) &&
 | |
| 		       (pbp->secondary >= 0) &&
 | |
| 		       (pbp->primary != pbp->secondary)) {
 | |
| 		tmp = xf86DupResList(pbp->preferred_pmem);
 | |
| 		avoid = xf86JoinResLists(avoid, tmp);
 | |
| 		tmp = xf86DupResList(pbp->preferred_mem);
 | |
| 		avoid = xf86JoinResLists(avoid, tmp);
 | |
| 		tmp = xf86DupResList(pbp->preferred_io);
 | |
| 		avoid = xf86JoinResLists(avoid, tmp);
 | |
| 	    }
 | |
| 	    pbp = pbp->next;
 | |
| 	}
 | |
| 	if (res_m_io == NULL)
 | |
| 	   res_m_io = xf86DupResList(ResRange);
 | |
| 
 | |
| 	pciConvertListToHost(pvp->bus,pvp->device,pvp->func, avoid);
 | |
| 
 | |
| #ifdef DEBUG
 | |
| 	xf86MsgVerb(X_INFO, 3,"avoid:\n");
 | |
| 	xf86PrintResList(3,avoid);
 | |
| 	xf86MsgVerb(X_INFO, 3,"prefetchable Memory:\n");
 | |
| 	xf86PrintResList(3,res_mp);
 | |
| 	xf86MsgVerb(X_INFO, 3,"MEM/IO:\n");
 | |
| 	xf86PrintResList(3,res_m_io);
 | |
| #endif
 | |
| 	for (i = 0; i < 6; i++) {
 | |
| 	    int j;
 | |
| 	    resPtr own = NULL;
 | |
| 	    for (j = i+1; j < 6; j++) {
 | |
| 		if (pvp->ioBase[j]) {
 | |
| 		    PV_I_RANGE(range,pvp,j,ResExcIoBlock);
 | |
| 		    own = xf86AddResToList(own,&range,-1);
 | |
| 		} else if (pvp->memBase[j]) {
 | |
| 		    PV_M_RANGE(range,pvp,j,ResExcMemBlock);
 | |
| 		    own = xf86AddResToList(own,&range,-1);
 | |
| 		}
 | |
| 	    }
 | |
| #ifdef DEBUG
 | |
| 	    xf86MsgVerb(X_INFO, 3, "own:\n");
 | |
| 	    xf86PrintResList(3, own);
 | |
| #endif
 | |
| 	    if (pvp->ioBase[i]) {
 | |
| 		PV_I_RANGE(range,pvp,i,ResExcIoBlock);
 | |
| 		if (xf86IsSubsetOf(range,res_m_io)
 | |
| 		    && ! ChkConflict(&range,own,SETUP)
 | |
| 		    && ! ChkConflict(&range,avoid,SETUP)
 | |
| 		    && ! ChkConflict(&range,NonSys,SETUP)) {
 | |
| 		    xf86FreeResList(own);
 | |
| 		    continue;
 | |
| 		}
 | |
| 		xf86MsgVerb(X_WARNING, 0,
 | |
| 			"****INVALID IO ALLOCATION**** b: 0x%lx e: 0x%lx "
 | |
| 			"correcting\a\n", range.rBegin,range.rEnd);
 | |
| #ifdef DEBUG
 | |
| 		sleep(2);
 | |
| #endif
 | |
| 		fixPciResource(i, 0, pvp, range.type);
 | |
| 	    } else if (pvp->memBase[i]) {
 | |
| 		PV_M_RANGE(range,pvp,i,ResExcMemBlock);
 | |
| 		if (pvp->type[i] & PCI_MAP_MEMORY_CACHABLE) {
 | |
| 		    if (xf86IsSubsetOf(range,res_mp)
 | |
| 			&& ! ChkConflict(&range,own,SETUP)
 | |
| 			&& ! ChkConflict(&range,avoid,SETUP)
 | |
| 			&& ! ChkConflict(&range,NonSys,SETUP)) {
 | |
| 		        xf86FreeResList(own);
 | |
| 			continue;
 | |
| 		    }
 | |
| 		}
 | |
| 		if (xf86IsSubsetOf(range,res_m_io)
 | |
| 		    && ! ChkConflict(&range,own,SETUP)
 | |
| 		    && ! ChkConflict(&range,avoid,SETUP)
 | |
| 		    && ! ChkConflict(&range,NonSys,SETUP)) {
 | |
| 		    xf86FreeResList(own);
 | |
| 		    continue;
 | |
| 		}
 | |
| 		xf86MsgVerb(X_WARNING, 0,
 | |
| 			"****INVALID MEM ALLOCATION**** b: 0x%lx e: 0x%lx "
 | |
| 			"correcting\a\n", range.rBegin,range.rEnd);
 | |
| 		if (ChkConflict(&range,own,SETUP)) {
 | |
| 		    xf86MsgVerb(X_INFO,3,"own\n");
 | |
| 		    xf86PrintResList(3,own);
 | |
| 		}
 | |
| 		if (ChkConflict(&range,avoid,SETUP)) {
 | |
| 		    xf86MsgVerb(X_INFO,3,"avoid\n");
 | |
| 		    xf86PrintResList(3,avoid);
 | |
| 		}
 | |
| 		if (ChkConflict(&range,NonSys,SETUP)) {
 | |
| 		    xf86MsgVerb(X_INFO,3,"NonSys\n");
 | |
| 		    xf86PrintResList(3,NonSys);
 | |
| 		}
 | |
| 
 | |
| #ifdef DEBUG
 | |
| 		sleep(2);
 | |
| #endif
 | |
| 		fixPciResource(i, 0, pvp, range.type);
 | |
| 	    }
 | |
| 	    xf86FreeResList(own);
 | |
| 	}
 | |
| 	xf86FreeResList(avoid);
 | |
| 	xf86FreeResList(NonSys);
 | |
| 	xf86FreeResList(res_mp);
 | |
| 	xf86FreeResList(res_m_io);
 | |
|     }
 | |
|     xf86FreeResList(Sys);
 | |
| }
 | |
|     
 | |
| resList
 | |
| GetImplicitPciResources(int entityIndex)
 | |
| {
 | |
|     pciVideoPtr pvp;
 | |
|     int i;
 | |
|     resList list = NULL;
 | |
|     int num = 0;
 | |
|     
 | |
|     if (! (pvp = xf86GetPciInfoForEntity(entityIndex))) return NULL;
 | |
| 
 | |
|     for (i = 0; i < 6; i++) {
 | |
| 	if (pvp->ioBase[i]) {
 | |
| 	    list = xnfrealloc(list,sizeof(resRange) * (++num));
 | |
| 	    PV_I_RANGE(list[num - 1],pvp,i,ResShrIoBlock | ResBios); 
 | |
| 	} else if (pvp->memBase[i]) {
 | |
| 	    list = xnfrealloc(list,sizeof(resRange) * (++num));
 | |
| 	    PV_M_RANGE(list[num - 1],pvp,i,ResShrMemBlock | ResBios);
 | |
| 	}
 | |
|     }
 | |
| #if 0
 | |
|     if (pvp->biosBase) {
 | |
| 	list = xnfrealloc(list,sizeof(resRange) * (++num));
 | |
| 	PV_B_RANGE(list[num - 1],pvp,ResShrMemBlock | ResBios);
 | |
|     }
 | |
| #endif
 | |
|     list = xnfrealloc(list,sizeof(resRange) * (++num));
 | |
|     list[num - 1].type = ResEnd;
 | |
|     
 | |
|     return list;
 | |
| }
 | |
| 
 | |
| void
 | |
| initPciState(void)
 | |
| {
 | |
|     int i = 0;
 | |
|     int j = 0;
 | |
|     pciVideoPtr pvp; 
 | |
|     pciAccPtr pcaccp;
 | |
| 
 | |
|     if (xf86PciAccInfo != NULL)
 | |
| 	return;
 | |
|   
 | |
|     if (xf86PciVideoInfo == NULL)
 | |
| 	return;
 | |
| 
 | |
|     while ((pvp = xf86PciVideoInfo[i]) != NULL) {
 | |
|   	i++;
 | |
|   	    j++;
 | |
|   	    xf86PciAccInfo = xnfrealloc(xf86PciAccInfo,
 | |
|   					sizeof(pciAccPtr) * (j + 1));
 | |
|   	    xf86PciAccInfo[j] = NULL;
 | |
|   	    pcaccp = xf86PciAccInfo[j - 1] = xnfalloc(sizeof(pciAccRec));
 | |
| 	    pcaccp->busnum = pvp->bus; 
 | |
|  	    pcaccp->devnum = pvp->device; 
 | |
|  	    pcaccp->funcnum = pvp->func;
 | |
|  	    pcaccp->arg.tag = pciTag(pvp->bus, pvp->device, pvp->func);
 | |
|   	    pcaccp->ioAccess.AccessDisable = pciIoAccessDisable;
 | |
|   	    pcaccp->ioAccess.AccessEnable = pciIoAccessEnable;
 | |
|   	    pcaccp->ioAccess.arg = &pcaccp->arg;
 | |
| 	    pcaccp->io_memAccess.AccessDisable = pciIo_MemAccessDisable;
 | |
| 	    pcaccp->io_memAccess.AccessEnable = pciIo_MemAccessEnable;
 | |
| 	    pcaccp->io_memAccess.arg = &pcaccp->arg;
 | |
| 	    pcaccp->memAccess.AccessDisable = pciMemAccessDisable;
 | |
| 	    pcaccp->memAccess.AccessEnable = pciMemAccessEnable;
 | |
| 	    pcaccp->memAccess.arg = &pcaccp->arg;
 | |
|  	    if (PCISHAREDIOCLASSES(pvp->class, pvp->subclass))
 | |
|  		pcaccp->ctrl = TRUE;
 | |
|  	    else
 | |
|  		pcaccp->ctrl = FALSE;
 | |
|  	    savePciState(pcaccp->arg.tag, &pcaccp->save);
 | |
| 	    pcaccp->arg.ctrl = pcaccp->save.command;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * initPciBusState() - fill out the BusAccRec for a PCI bus.
 | |
|  * Theory: each bus is associated with one bridge connecting it
 | |
|  * to its parent bus. The address of a bridge is therefore stored
 | |
|  * in the BusAccRec of the bus it connects to. Each bus can
 | |
|  * have several bridges connecting secondary buses to it. Only one
 | |
|  * of these bridges can be open. Therefore the status of a bridge
 | |
|  * associated with a bus is stored in the BusAccRec of the parent
 | |
|  * the bridge connects to. The first member of the structure is
 | |
|  * a pointer to a function that open access to this bus. This function
 | |
|  * receives a pointer to the structure itself as argument. This
 | |
|  * design should be common to BusAccRecs of any type of buses we
 | |
|  * support. The remeinder of the structure is bus type specific.
 | |
|  * In this case it contains a pointer to the structure of the
 | |
|  * parent bus. Thus enabling access to a specific bus is simple:
 | |
|  * 1. Close any bridge going to secondary buses.
 | |
|  * 2. Climb down the ladder and enable any bridge on buses
 | |
|  *    on the path from the CPU to this bus.
 | |
|  */
 | |
|  
 | |
| void
 | |
| initPciBusState(void)
 | |
| {
 | |
|     BusAccPtr pbap, pbap_tmp;
 | |
|     PciBusPtr pbp = xf86PciBus;
 | |
|     pciBusInfo_t *pBusInfo;
 | |
| 
 | |
|     while (pbp) {
 | |
| 	pbap = xnfcalloc(1,sizeof(BusAccRec));
 | |
| 	pbap->busdep.pci.bus = pbp->secondary;
 | |
| 	pbap->busdep.pci.primary_bus = pbp->primary;
 | |
| 	pbap->busdep_type = BUS_PCI;
 | |
| 	pbap->busdep.pci.acc = PCITAG_SPECIAL;
 | |
| 
 | |
| 	if ((pbp->secondary >= 0) && (pbp->secondary < pciNumBuses) &&
 | |
| 	    (pBusInfo = pciBusInfo[pbp->secondary]) &&
 | |
| 	    pBusInfo->funcs->pciControlBridge) {
 | |
| 	    pbap->type = BUS_PCI;
 | |
| 	    pbap->save_f = savePciDrvBusState;
 | |
| 	    pbap->restore_f = restorePciDrvBusState;
 | |
| 	    pbap->set_f = pciSetBusAccess;
 | |
| 	    pbap->enable_f = pciDrvBusAccessEnable;
 | |
| 	    pbap->disable_f = pciDrvBusAccessDisable;
 | |
| 	    savePciDrvBusState(pbap);
 | |
| 	} else switch (pbp->subclass) {
 | |
| 	case PCI_SUBCLASS_BRIDGE_HOST:
 | |
| 	    pbap->type = BUS_PCI;
 | |
| 	    pbap->set_f = pciSetBusAccess;
 | |
| 	    break;
 | |
| 	case PCI_SUBCLASS_BRIDGE_PCI:
 | |
| 	case PCI_SUBCLASS_BRIDGE_CARDBUS:
 | |
| 	    pbap->type = BUS_PCI;
 | |
| 	    pbap->save_f = savePciBusState;
 | |
| 	    pbap->restore_f = restorePciBusState;
 | |
| 	    pbap->set_f = pciSetBusAccess;
 | |
| 	    pbap->enable_f = pciBusAccessEnable;
 | |
| 	    pbap->disable_f = pciBusAccessDisable;
 | |
| 	    pbap->busdep.pci.acc = pciTag(pbp->brbus,pbp->brdev,pbp->brfunc);
 | |
| 	    savePciBusState(pbap);
 | |
| 	    break;
 | |
| 	case PCI_SUBCLASS_BRIDGE_ISA:
 | |
| 	case PCI_SUBCLASS_BRIDGE_EISA:
 | |
| 	case PCI_SUBCLASS_BRIDGE_MC:
 | |
| 	    pbap->type = BUS_ISA;
 | |
| 	    pbap->set_f = pciSetBusAccess;
 | |
| 	    break;
 | |
| 	}
 | |
| 	pbap->next = xf86BusAccInfo;
 | |
| 	xf86BusAccInfo = pbap;
 | |
| 	pbp = pbp->next;
 | |
|     }
 | |
| 
 | |
|     pbap = xf86BusAccInfo;
 | |
| 
 | |
|     while (pbap) {
 | |
| 	pbap->primary = NULL;
 | |
| 	if (pbap->busdep_type == BUS_PCI
 | |
| 	    && pbap->busdep.pci.primary_bus > -1) {
 | |
| 	    pbap_tmp = xf86BusAccInfo;
 | |
| 	    while (pbap_tmp) {
 | |
| 		if (pbap_tmp->busdep_type == BUS_PCI &&
 | |
| 		    pbap_tmp->busdep.pci.bus == pbap->busdep.pci.primary_bus) {
 | |
| 		    /* Don't create loops */
 | |
| 		    if (pbap == pbap_tmp)
 | |
| 			break;
 | |
| 		    pbap->primary = pbap_tmp;
 | |
| 		    break;
 | |
| 		}
 | |
| 		pbap_tmp = pbap_tmp->next;
 | |
| 	    }
 | |
| 	}
 | |
| 	pbap = pbap->next;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void 
 | |
| PciStateEnter(void)
 | |
| {
 | |
|     pciAccPtr paccp;
 | |
|     int i = 0;
 | |
|     
 | |
|     if (xf86PciAccInfo == NULL) 
 | |
| 	return;
 | |
| 
 | |
|     while ((paccp = xf86PciAccInfo[i]) != NULL) {
 | |
| 	i++;
 | |
|  	if (!paccp->ctrl)
 | |
|  	    continue;
 | |
| 	savePciState(paccp->arg.tag, &paccp->save);
 | |
| 	restorePciState(paccp->arg.tag, &paccp->restore);
 | |
| 	paccp->arg.ctrl = paccp->restore.command;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| PciBusStateEnter(void)
 | |
| {
 | |
|     BusAccPtr pbap = xf86BusAccInfo;
 | |
| 
 | |
|     while (pbap) {
 | |
| 	if (pbap->save_f)
 | |
| 	    pbap->save_f(pbap);
 | |
| 	pbap = pbap->next;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void 
 | |
| PciStateLeave(void)
 | |
| {
 | |
|     pciAccPtr paccp;
 | |
|     int i = 0;
 | |
| 
 | |
|     if (xf86PciAccInfo == NULL) 
 | |
| 	return;
 | |
| 
 | |
|     while ((paccp = xf86PciAccInfo[i]) != NULL) {
 | |
| 	i++;
 | |
| 	if (!paccp->ctrl)
 | |
| 	    continue;
 | |
| 	savePciState(paccp->arg.tag, &paccp->restore);
 | |
| 	restorePciState(paccp->arg.tag, &paccp->save);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| PciBusStateLeave(void)
 | |
| {
 | |
|     BusAccPtr pbap = xf86BusAccInfo;
 | |
| 
 | |
|     while (pbap) {
 | |
| 	if (pbap->restore_f)
 | |
| 	    pbap->restore_f(pbap);
 | |
| 	pbap = pbap->next;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void 
 | |
| DisablePciAccess(void)
 | |
| {
 | |
|     int i = 0;
 | |
|     pciAccPtr paccp;
 | |
|     if (xf86PciAccInfo == NULL)
 | |
| 	return;
 | |
| 
 | |
|     while ((paccp = xf86PciAccInfo[i]) != NULL) {
 | |
| 	i++;
 | |
| 	if (!paccp->ctrl) /* disable devices that are under control initially*/
 | |
| 	    continue;
 | |
| 	pciIo_MemAccessDisable(paccp->io_memAccess.arg);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| DisablePciBusAccess(void)
 | |
| {
 | |
|     BusAccPtr pbap = xf86BusAccInfo;
 | |
| 
 | |
|     while (pbap) {
 | |
| 	if (pbap->disable_f)
 | |
| 	    pbap->disable_f(pbap);
 | |
| 	if (pbap->primary)
 | |
| 	    pbap->primary->current = NULL;
 | |
| 	pbap = pbap->next;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Public functions
 | |
|  */
 | |
| 
 | |
| _X_EXPORT Bool
 | |
| xf86IsPciDevPresent(int bus, int dev, int func)
 | |
| {
 | |
|     int i = 0;
 | |
|     pciConfigPtr pcp;
 | |
|     
 | |
|     while ((pcp = xf86PciInfo[i]) != NULL) {
 | |
| 	if ((pcp->busnum == bus)
 | |
| 	    && (pcp->devnum == dev)
 | |
| 	    && (pcp->funcnum == func))
 | |
| 	    return TRUE;
 | |
| 	i++;
 | |
|     }
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * If the slot requested is already in use, return -1.
 | |
|  * Otherwise, claim the slot for the screen requesting it.
 | |
|  */
 | |
| 
 | |
| _X_EXPORT int
 | |
| xf86ClaimPciSlot(int bus, int device, int func, DriverPtr drvp,
 | |
| 		 int chipset, GDevPtr dev, Bool active)
 | |
| {
 | |
|     EntityPtr p = NULL;
 | |
|     pciAccPtr *ppaccp = xf86PciAccInfo;
 | |
|     BusAccPtr pbap = xf86BusAccInfo;
 | |
|     
 | |
|     int num;
 | |
|     
 | |
|     if (xf86CheckPciSlot(bus, device, func)) {
 | |
| 	num = xf86AllocateEntity();
 | |
| 	p = xf86Entities[num];
 | |
| 	p->driver = drvp;
 | |
| 	p->chipset = chipset;
 | |
| 	p->busType = BUS_PCI;
 | |
| 	p->pciBusId.bus = bus;
 | |
| 	p->pciBusId.device = device;
 | |
| 	p->pciBusId.func = func;
 | |
| 	p->active = active;
 | |
| 	p->inUse = FALSE;
 | |
| 	if (dev)
 | |
|             xf86AddDevToEntity(num, dev);
 | |
| 	/* Here we initialize the access structure */
 | |
| 	p->access = xnfcalloc(1,sizeof(EntityAccessRec));
 | |
| 	while (ppaccp && *ppaccp) {
 | |
| 	    if ((*ppaccp)->busnum == bus
 | |
| 		&& (*ppaccp)->devnum == device
 | |
| 		&& (*ppaccp)->funcnum == func) {
 | |
| 		p->access->fallback = &(*ppaccp)->io_memAccess;
 | |
| 		p->access->pAccess = &(*ppaccp)->io_memAccess;
 | |
|  		(*ppaccp)->ctrl = TRUE; /* mark control if not already */
 | |
| 		break;
 | |
| 	    }
 | |
| 	    ppaccp++;
 | |
| 	}
 | |
| 	if (!ppaccp || !*ppaccp) {
 | |
| 	    p->access->fallback = &AccessNULL;
 | |
| 	    p->access->pAccess = &AccessNULL;
 | |
| 	}
 | |
| 	
 | |
| 	p->busAcc = NULL;
 | |
| 	while (pbap) {
 | |
| 	    if (pbap->type == BUS_PCI && pbap->busdep.pci.bus == bus)
 | |
| 		p->busAcc = pbap;
 | |
| 	    pbap = pbap->next;
 | |
| 	}
 | |
| 	fixPciSizeInfo(num);
 | |
| 
 | |
| 	/* in case bios is enabled disable it */
 | |
| 	disablePciBios(pciTag(bus,device,func));
 | |
| 	pciSlotClaimed = TRUE;
 | |
| 
 | |
| 	if (active) {
 | |
| 	    /* Map in this domain's I/O space */
 | |
| 	   p->domainIO = xf86MapDomainIO(-1, VIDMEM_MMIO,
 | |
| 					 pciTag(bus, device, func), 0, 1);
 | |
| 	}
 | |
| 	
 | |
|  	return num;
 | |
|     } else
 | |
|  	return -1;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Get xf86PciVideoInfo for a driver.
 | |
|  */
 | |
| _X_EXPORT pciVideoPtr *
 | |
| xf86GetPciVideoInfo(void)
 | |
| {
 | |
|     return xf86PciVideoInfo;
 | |
| }
 | |
| 
 | |
| /* --- Used by ATI driver, but also more generally useful */
 | |
| 
 | |
| /*
 | |
|  * Get the full xf86scanpci data.
 | |
|  */
 | |
| _X_EXPORT pciConfigPtr *
 | |
| xf86GetPciConfigInfo(void)
 | |
| {
 | |
|     return xf86PciInfo;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Enable a device and route VGA to it.  This is intended for a driver's
 | |
|  * Probe(), before creating EntityRec's.  Only one device can be thus enabled
 | |
|  * at any one time, and should be disabled when the driver is done with it.
 | |
|  *
 | |
|  * The following special calls are also available:
 | |
|  *
 | |
|  * pvp == NULL && rt == NONE    disable previously enabled device
 | |
|  * pvp != NULL && rt == NONE    ensure device is disabled
 | |
|  * pvp == NULL && rt != NONE    disable >all< subsequent calls to this function
 | |
|  *                              (done from xf86PostProbe())
 | |
|  * The last combination has been removed! To do this cleanly we have
 | |
|  * to implement stages and need to test at each stage dependent function
 | |
|  * if it is allowed to execute.
 | |
|  *
 | |
|  * The device represented by pvp may not have been previously claimed.
 | |
|  */
 | |
| _X_EXPORT void
 | |
| xf86SetPciVideo(pciVideoPtr pvp, resType rt)
 | |
| {
 | |
|     static BusAccPtr pbap = NULL;
 | |
|     static xf86AccessPtr pAcc = NULL;
 | |
|     static Bool DoneProbes = FALSE;
 | |
|     pciAccPtr pcaccp;
 | |
|     int i;
 | |
| 
 | |
|     if (DoneProbes)
 | |
| 	return;
 | |
| 
 | |
|     /* Disable previous access */
 | |
|     if (pAcc) {
 | |
| 	if (pAcc->AccessDisable)
 | |
| 	    (*pAcc->AccessDisable)(pAcc->arg);
 | |
| 	pAcc = NULL;
 | |
|     }
 | |
|     if (pbap) {
 | |
| 	while (pbap->primary) {
 | |
| 	    if (pbap->disable_f)
 | |
| 		(*pbap->disable_f)(pbap);
 | |
| 	    pbap->primary->current = NULL;
 | |
| 	    pbap = pbap->primary;
 | |
| 	}
 | |
| 	pbap = NULL;
 | |
|     }
 | |
| 
 | |
|     /* Check for xf86PostProbe's magic combo */
 | |
|     if (!pvp) {
 | |
| 	if (rt != NONE)
 | |
| 	    DoneProbes = TRUE;
 | |
| 	return;
 | |
|     }
 | |
| 
 | |
|     /* Validate device */
 | |
|     if (!xf86PciVideoInfo || !xf86PciAccInfo || !xf86BusAccInfo)
 | |
| 	return;
 | |
| 
 | |
|     for (i = 0; pvp != xf86PciVideoInfo[i]; i++)
 | |
| 	if (!xf86PciVideoInfo[i])
 | |
| 	    return;
 | |
| 
 | |
|     /* Ignore request for claimed adapters */
 | |
|     if (!xf86CheckPciSlot(pvp->bus, pvp->device, pvp->func))
 | |
| 	return;
 | |
| 
 | |
|     /* Find pciAccRec structure */
 | |
|     for (i = 0; ; i++) {
 | |
| 	if (!(pcaccp = xf86PciAccInfo[i]))
 | |
| 	    return;
 | |
| 	if ((pvp->bus == pcaccp->busnum) &&
 | |
| 	    (pvp->device == pcaccp->devnum) &&
 | |
| 	    (pvp->func == pcaccp->funcnum))
 | |
| 	    break;
 | |
|     }
 | |
| 
 | |
|     if (rt == NONE) {
 | |
| 	/* This is a call to ensure the adapter is disabled */
 | |
| 	if (pcaccp->io_memAccess.AccessDisable)
 | |
| 	    (*pcaccp->io_memAccess.AccessDisable)(pcaccp->io_memAccess.arg);
 | |
| 	return;
 | |
|     }
 | |
| 
 | |
|     /* Find BusAccRec structure */
 | |
|     for (pbap = xf86BusAccInfo; ; pbap = pbap->next) {
 | |
| 	if (!pbap)
 | |
| 	    return;
 | |
| 	if (pvp->bus == pbap->busdep.pci.bus)
 | |
| 	    break;
 | |
|     }
 | |
| 
 | |
|     /* Route VGA */
 | |
|     if (pbap->set_f)
 | |
| 	(*pbap->set_f)(pbap);
 | |
| 
 | |
|     /* Enable device */
 | |
|     switch (rt) {
 | |
|     case IO:
 | |
| 	pAcc = &pcaccp->ioAccess;
 | |
| 	break;
 | |
|     case MEM_IO:
 | |
| 	pAcc = &pcaccp->io_memAccess;
 | |
| 	break;
 | |
|     case MEM:
 | |
| 	pAcc = &pcaccp->memAccess;
 | |
| 	break;
 | |
|     default:	/* no compiler noise */
 | |
| 	break;
 | |
|     }
 | |
| 
 | |
|     if (pAcc && pAcc->AccessEnable)
 | |
| 	(*pAcc->AccessEnable)(pAcc->arg);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Parse a BUS ID string, and return the PCI bus parameters if it was
 | |
|  * in the correct format for a PCI bus id.
 | |
|  */
 | |
| 
 | |
| _X_EXPORT Bool
 | |
| xf86ParsePciBusString(const char *busID, int *bus, int *device, int *func)
 | |
| {
 | |
|     /*
 | |
|      * The format is assumed to be "bus[@domain]:device[:func]", where domain,
 | |
|      * bus, device and func are decimal integers.  domain and func may be
 | |
|      * omitted and assumed to be zero, although doing this isn't encouraged.
 | |
|      */
 | |
| 
 | |
|     char *p, *s, *d;
 | |
|     const char *id;
 | |
|     int i;
 | |
| 
 | |
|     if (StringToBusType(busID, &id) != BUS_PCI)
 | |
| 	return FALSE;
 | |
| 
 | |
|     s = xstrdup(id);
 | |
|     p = strtok(s, ":");
 | |
|     if (p == NULL || *p == 0) {
 | |
| 	xfree(s);
 | |
| 	return FALSE;
 | |
|     }
 | |
|     d = strpbrk(p, "@");
 | |
|     if (d != NULL) {
 | |
| 	*(d++) = 0;
 | |
| 	for (i = 0; d[i] != 0; i++) {
 | |
| 	    if (!isdigit(d[i])) {
 | |
| 		xfree(s);
 | |
| 		return FALSE;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     for (i = 0; p[i] != 0; i++) {
 | |
| 	if (!isdigit(p[i])) {
 | |
| 	    xfree(s);
 | |
| 	    return FALSE;
 | |
| 	}
 | |
|     }
 | |
|     *bus = atoi(p);
 | |
|     if (d != NULL && *d != 0)
 | |
| 	*bus += atoi(d) << 8;
 | |
|     p = strtok(NULL, ":");
 | |
|     if (p == NULL || *p == 0) {
 | |
| 	xfree(s);
 | |
| 	return FALSE;
 | |
|     }
 | |
|     for (i = 0; p[i] != 0; i++) {
 | |
| 	if (!isdigit(p[i])) {
 | |
| 	    xfree(s);
 | |
| 	    return FALSE;
 | |
| 	}
 | |
|     }
 | |
|     *device = atoi(p);
 | |
|     *func = 0;
 | |
|     p = strtok(NULL, ":");
 | |
|     if (p == NULL || *p == 0) {
 | |
| 	xfree(s);
 | |
| 	return TRUE;
 | |
|     }
 | |
|     for (i = 0; p[i] != 0; i++) {
 | |
| 	if (!isdigit(p[i])) {
 | |
| 	    xfree(s);
 | |
| 	    return FALSE;
 | |
| 	}
 | |
|     }
 | |
|     *func = atoi(p);
 | |
|     xfree(s);
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Compare a BUS ID string with a PCI bus id.  Return TRUE if they match.
 | |
|  */
 | |
| 
 | |
| _X_EXPORT Bool
 | |
| xf86ComparePciBusString(const char *busID, int bus, int device, int func)
 | |
| {
 | |
|     int ibus, idevice, ifunc;
 | |
| 
 | |
|     if (xf86ParsePciBusString(busID, &ibus, &idevice, &ifunc)) {
 | |
| 	return bus == ibus && device == idevice && func == ifunc;
 | |
|     } else {
 | |
| 	return FALSE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xf86IsPrimaryPci() -- return TRUE if primary device
 | |
|  * is PCI and bus, dev and func numbers match.
 | |
|  */
 | |
|  
 | |
| _X_EXPORT Bool
 | |
| xf86IsPrimaryPci(pciVideoPtr pPci)
 | |
| {
 | |
|     if (primaryBus.type != BUS_PCI) return FALSE;
 | |
|     return (pPci->bus == primaryBus.id.pci.bus &&
 | |
| 	    pPci->device == primaryBus.id.pci.device &&
 | |
| 	    pPci->func == primaryBus.id.pci.func);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity.
 | |
|  */
 | |
| _X_EXPORT pciVideoPtr
 | |
| xf86GetPciInfoForEntity(int entityIndex)
 | |
| {
 | |
|     pciVideoPtr *ppPci;
 | |
|     EntityPtr p;
 | |
|     
 | |
|     if (entityIndex >= xf86NumEntities)
 | |
| 	return NULL;
 | |
| 
 | |
|     p = xf86Entities[entityIndex];
 | |
|     if (p->busType != BUS_PCI)
 | |
| 	return NULL;
 | |
|     
 | |
|     for (ppPci = xf86PciVideoInfo; *ppPci != NULL; ppPci++) {
 | |
| 	if (p->pciBusId.bus == (*ppPci)->bus &&
 | |
| 	    p->pciBusId.device == (*ppPci)->device &&
 | |
| 	    p->pciBusId.func == (*ppPci)->func) 
 | |
| 	    return (*ppPci);
 | |
|     }
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| _X_EXPORT int
 | |
| xf86GetPciEntity(int bus, int dev, int func)
 | |
| {
 | |
|     int i;
 | |
|     
 | |
|     for (i = 0; i < xf86NumEntities; i++) {
 | |
| 	EntityPtr p = xf86Entities[i];
 | |
| 	if (p->busType != BUS_PCI) continue;
 | |
| 	
 | |
| 	if (p->pciBusId.bus == bus &&
 | |
| 	    p->pciBusId.device == dev &&
 | |
| 	    p->pciBusId.func == func) 
 | |
| 	    return i;
 | |
|     }
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xf86CheckPciMemBase() checks that the memory base value matches one of the
 | |
|  * PCI base address register values for the given PCI device.
 | |
|  */
 | |
| _X_EXPORT Bool
 | |
| xf86CheckPciMemBase(pciVideoPtr pPci, memType base)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < 6; i++)
 | |
| 	if (base == pPci->memBase[i])
 | |
| 	    return TRUE;
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Check if the slot requested is free.  If it is already in use, return FALSE.
 | |
|  */
 | |
| 
 | |
| _X_EXPORT Bool
 | |
| xf86CheckPciSlot(int bus, int device, int func)
 | |
| {
 | |
|     int i;
 | |
|     EntityPtr p;
 | |
| 
 | |
|     for (i = 0; i < xf86NumEntities; i++) {
 | |
| 	p = xf86Entities[i];
 | |
| 	/* Check if this PCI slot is taken */
 | |
| 	if (p->busType == BUS_PCI && p->pciBusId.bus == bus &&
 | |
| 	    p->pciBusId.device == device && p->pciBusId.func == func)
 | |
| 	    return FALSE;
 | |
|     }
 | |
|     
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * xf86FindPciVendorDevice() xf86FindPciClass(): These functions
 | |
|  * are meant to be used by the pci bios emulation. Some bioses
 | |
|  * need to see if there are _other_ chips of the same type around
 | |
|  * so by setting pvp_exclude one pci device can be explicitely
 | |
|  * _excluded if required.
 | |
|  */
 | |
| _X_EXPORT pciVideoPtr
 | |
| xf86FindPciDeviceVendor(CARD16 vendorID, CARD16 deviceID,
 | |
| 			char n, pciVideoPtr pvp_exclude)
 | |
| {
 | |
|     pciVideoPtr pvp, *ppvp;
 | |
|     n++;
 | |
| 
 | |
|     for (ppvp = xf86PciVideoInfo, pvp =*ppvp; pvp ; pvp = *(++ppvp)) {
 | |
| 	if (pvp == pvp_exclude) continue;
 | |
| 	if ((pvp->vendor == vendorID) && (pvp->chipType == deviceID)) {
 | |
| 	    if (!(--n)) break;
 | |
| 	}
 | |
|     }
 | |
|     return pvp;
 | |
| }
 | |
| 
 | |
| _X_EXPORT pciVideoPtr
 | |
| xf86FindPciClass(CARD8 intf, CARD8 subClass, CARD16 class,
 | |
| 		 char n, pciVideoPtr pvp_exclude)
 | |
| {
 | |
|     pciVideoPtr pvp, *ppvp;
 | |
|     n++;
 | |
|     
 | |
|     for (ppvp = xf86PciVideoInfo, pvp =*ppvp; pvp ; pvp = *(++ppvp)) {
 | |
| 	if (pvp == pvp_exclude) continue;
 | |
| 	if ((pvp->interface == intf) && (pvp->subclass == subClass)
 | |
| 	    && (pvp->class == class)) {
 | |
| 	    if (!(--n)) break;
 | |
| 	}
 | |
|     }
 | |
|     return pvp;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * This attempts to detect a multi-device card and sets up a list
 | |
|  * of pci tags of the devices of this card. On some of these
 | |
|  * cards the BIOS is not visible from all chipsets. We therefore
 | |
|  * need to use the BIOS from a chipset where it is visible.
 | |
|  * We do the following heuristics:
 | |
|  * If we detect only identical pci devices on a bus we assume it's
 | |
|  * a multi-device card. This assumption isn't true always, however.
 | |
|  * One might just use identical cards on a bus. We therefore don't
 | |
|  * detect this situation when we set up the PCI video info. Instead
 | |
|  * we wait until an attempt to read the BIOS fails.
 | |
|  */
 | |
| int
 | |
| pciTestMultiDeviceCard(int bus, int dev, int func, PCITAG** pTag)
 | |
| {
 | |
|   pciConfigPtr *ppcrp = xf86PciInfo;
 | |
|   pciConfigPtr pcrp = NULL;
 | |
|   int i,j;
 | |
|   Bool multicard = FALSE;
 | |
|   Bool multifunc = FALSE;
 | |
|   char str[256];
 | |
|   char *str1;
 | |
|   
 | |
|   str1 = str;
 | |
|   if (!pTag) 
 | |
|     return 0;
 | |
| 
 | |
|   *pTag = NULL;
 | |
|  
 | |
|   for (i=0; i < 8; i++) {
 | |
|     j = 0;
 | |
| 
 | |
|     while (ppcrp[j]) {
 | |
|       if (ppcrp[j]->busnum == bus && ppcrp[j]->funcnum == i) {
 | |
| 	pcrp = ppcrp[j];
 | |
| 	break;
 | |
|       }
 | |
|       j++;
 | |
|     }
 | |
| 
 | |
|     if (!pcrp) return 0;
 | |
| 
 | |
|     /* 
 | |
|      * we check all functions here: since multifunc devices need
 | |
|      * to implement func 0 we catch all devices on the bus when
 | |
|      * i = 0
 | |
|      */
 | |
|     if (pcrp->pci_header_type &0x80) 
 | |
| 	multifunc = TRUE;
 | |
|     
 | |
|     j = 0;
 | |
|     
 | |
|     while (ppcrp[j]) {
 | |
|       if (ppcrp[j]->busnum == bus && ppcrp[j]->funcnum == i
 | |
| 	  && ppcrp[j]->devnum != pcrp->devnum) {
 | |
| 	/* don't test subsys ID here. It might be set by POST 
 | |
| 	   - however some cards might not have been POSTed */
 | |
| 	if (ppcrp[j]->pci_device_vendor != pcrp->pci_device_vendor 
 | |
| 	    || ppcrp[j]->pci_header_type != pcrp->pci_header_type ) 
 | |
| 	  return 0;
 | |
| 	else
 | |
| 	  multicard = TRUE;
 | |
|       }
 | |
|       j++;
 | |
|     }
 | |
|     if (!multifunc)
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   if (!multicard) 
 | |
|     return 0;
 | |
| 
 | |
|   j = 0;
 | |
|   i = 0;
 | |
|   while (ppcrp[i]) {
 | |
|     if (ppcrp[i]->busnum == bus && ppcrp[i]->funcnum == func) {
 | |
|       str1 += sprintf(str1,"[%x:%x:%x]",ppcrp[i]->busnum,
 | |
| 		      ppcrp[i]->devnum,ppcrp[i]->funcnum);
 | |
|       *pTag = xnfrealloc(*pTag,sizeof(PCITAG) * (j + 1));
 | |
|       (*pTag)[j++] = pciTag(ppcrp[i]->busnum,
 | |
| 			      ppcrp[i]->devnum,ppcrp[i]->funcnum);
 | |
|     }
 | |
|     i++;
 | |
|   }
 | |
|   xf86MsgVerb(X_INFO,3,"Multi Device Card detected: %s\n",str);
 | |
|   return j;
 | |
| }
 | |
| 
 | |
| static void
 | |
| pciTagConvertRange2Host(PCITAG tag, resRange *pRange)
 | |
| {
 | |
|     if (!(pRange->type & ResBus))
 | |
| 	return;
 | |
| 
 | |
|     switch(pRange->type & ResPhysMask) {
 | |
|     case ResMem:
 | |
| 	switch(pRange->type & ResExtMask) {
 | |
| 	case ResBlock:
 | |
| 	    pRange->rBegin = pciBusAddrToHostAddr(tag,PCI_MEM, pRange->rBegin);
 | |
| 	    pRange->rEnd = pciBusAddrToHostAddr(tag,PCI_MEM, pRange->rEnd);
 | |
| 	    break;
 | |
| 	case ResSparse:
 | |
| 	    pRange->rBase = pciBusAddrToHostAddr(tag,PCI_MEM_SPARSE_BASE,
 | |
| 						  pRange->rBegin);
 | |
| 	    pRange->rMask = pciBusAddrToHostAddr(tag,PCI_MEM_SPARSE_MASK,
 | |
| 						pRange->rEnd);
 | |
| 	    break;
 | |
| 	}
 | |
| 	break;
 | |
|     case ResIo:
 | |
| 	switch(pRange->type & ResExtMask) {
 | |
| 	case ResBlock:
 | |
| 	    pRange->rBegin = pciBusAddrToHostAddr(tag,PCI_IO, pRange->rBegin);
 | |
| 	    pRange->rEnd = pciBusAddrToHostAddr(tag,PCI_IO, pRange->rEnd);
 | |
| 	    break;
 | |
| 	case ResSparse:
 | |
| 	    pRange->rBase = pciBusAddrToHostAddr(tag,PCI_IO_SPARSE_BASE
 | |
| 						  , pRange->rBegin);
 | |
| 	    pRange->rMask = pciBusAddrToHostAddr(tag,PCI_IO_SPARSE_MASK
 | |
| 						, pRange->rEnd);
 | |
| 	    break;
 | |
| 	}
 | |
| 	break;
 | |
|     }
 | |
| 
 | |
|     /* Set domain number */
 | |
|     pRange->type &= ~(ResDomain | ResBus);
 | |
|     pRange->type |= xf86GetPciDomain(tag) << 24;
 | |
| }
 | |
| 
 | |
| static void
 | |
| pciConvertListToHost(int bus, int dev, int func, resPtr list)
 | |
| {
 | |
|     PCITAG tag = pciTag(bus,dev,func);
 | |
|     while (list) {
 | |
| 	pciTagConvertRange2Host(tag, &list->val);
 | |
| 	list = list->next;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| updateAccessInfoStatusControlInfo(PCITAG tag, CARD32 ctrl)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     if (!xf86PciAccInfo)
 | |
| 	return;
 | |
|     
 | |
|     for (i = 0; xf86PciAccInfo[i] != NULL; i++) {
 | |
| 	if (xf86PciAccInfo[i]->arg.tag == tag)
 | |
| 	    xf86PciAccInfo[i]->arg.ctrl = ctrl;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| pciConvertRange2Host(int entityIndex, resRange *pRange)
 | |
| {
 | |
|     PCITAG tag;
 | |
|     pciVideoPtr pvp;
 | |
| 
 | |
|     pvp = xf86GetPciInfoForEntity(entityIndex);
 | |
|     if (!pvp) return;
 | |
|     tag = TAG(pvp);
 | |
|     pciTagConvertRange2Host(tag, pRange);
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef INCLUDE_DEPRECATED
 | |
| _X_EXPORT void
 | |
| xf86EnablePciBusMaster(pciVideoPtr pPci, Bool enable)
 | |
| {
 | |
|     CARD32 temp;
 | |
|     PCITAG tag;
 | |
| 
 | |
|     if (!pPci) return;
 | |
| 
 | |
|     tag = pciTag(pPci->bus, pPci->device, pPci->func);
 | |
|     temp = pciReadLong(tag, PCI_CMD_STAT_REG);
 | |
|     if (enable) {
 | |
| 	updateAccessInfoStatusControlInfo(tag, temp | PCI_CMD_MASTER_ENABLE);
 | |
| 	pciWriteLong(tag, PCI_CMD_STAT_REG, temp | PCI_CMD_MASTER_ENABLE);
 | |
|     } else {
 | |
| 	updateAccessInfoStatusControlInfo(tag, temp & ~PCI_CMD_MASTER_ENABLE);
 | |
| 	pciWriteLong(tag, PCI_CMD_STAT_REG, temp & ~PCI_CMD_MASTER_ENABLE);
 | |
|     }
 | |
| }
 | |
| #endif /* INCLUDE_DEPRECATED */
 |