689 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			689 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/bus/ix86Pci.c,v 1.25 2003/09/24 02:43:34 dawes Exp $ */
 | 
						|
/*
 | 
						|
 * ix86Pci.c - x86 PCI driver
 | 
						|
 *
 | 
						|
 * The XFree86 server PCI access functions have been reimplemented as a
 | 
						|
 * framework that allows each supported platform/OS to have their own
 | 
						|
 * platform/OS specific PCI driver.
 | 
						|
 *
 | 
						|
 * Most of the code of these functions was simply lifted from the
 | 
						|
 * Intel architecture specifric portion of the original Xfree86
 | 
						|
 * PCI code in hw/xfree86/common_hw/xf86_PCI.C...
 | 
						|
 *
 | 
						|
 * Gary Barton
 | 
						|
 * Concurrent Computer Corporation
 | 
						|
 * garyb@gate.net
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Copyright 1998 by Concurrent Computer Corporation
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software
 | 
						|
 * and its documentation for any purpose is hereby granted without fee,
 | 
						|
 * provided that the above copyright notice appear in all copies and that
 | 
						|
 * both that copyright notice and this permission notice appear in
 | 
						|
 * supporting documentation, and that the name of Concurrent Computer
 | 
						|
 * Corporation not be used in advertising or publicity pertaining to
 | 
						|
 * distribution of the software without specific, written prior
 | 
						|
 * permission.  Concurrent Computer Corporation makes no representations
 | 
						|
 * about the suitability of this software for any purpose.  It is
 | 
						|
 * provided "as is" without express or implied warranty.
 | 
						|
 *
 | 
						|
 * CONCURRENT COMPUTER CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD
 | 
						|
 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
						|
 * AND FITNESS, IN NO EVENT SHALL CONCURRENT COMPUTER CORPORATION BE
 | 
						|
 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
 | 
						|
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 | 
						|
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 | 
						|
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 | 
						|
 * SOFTWARE.
 | 
						|
 *
 | 
						|
 * Copyright 1998 by Metro Link Incorporated
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software
 | 
						|
 * and its documentation for any purpose is hereby granted without fee,
 | 
						|
 * provided that the above copyright notice appear in all copies and that
 | 
						|
 * both that copyright notice and this permission notice appear in
 | 
						|
 * supporting documentation, and that the name of Metro Link
 | 
						|
 * Incorporated not be used in advertising or publicity pertaining to
 | 
						|
 * distribution of the software without specific, written prior
 | 
						|
 * permission.  Metro Link Incorporated makes no representations
 | 
						|
 * about the suitability of this software for any purpose.  It is
 | 
						|
 * provided "as is" without express or implied warranty.
 | 
						|
 *
 | 
						|
 * METRO LINK INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD
 | 
						|
 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
						|
 * AND FITNESS, IN NO EVENT SHALL METRO LINK INCORPORATED BE
 | 
						|
 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
 | 
						|
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 | 
						|
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 | 
						|
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 | 
						|
 * SOFTWARE.
 | 
						|
 *
 | 
						|
 * This software is derived from the original XFree86 PCI code
 | 
						|
 * which includes the following copyright notices as well:
 | 
						|
 *
 | 
						|
 * Copyright 1995 by Robin Cutshaw <robin@XFree86.Org>
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
 * documentation for any purpose is hereby granted without fee, provided that
 | 
						|
 * the above copyright notice appear in all copies and that both that
 | 
						|
 * copyright notice and this permission notice appear in supporting
 | 
						|
 * documentation, and that the names of the above listed copyright holder(s)
 | 
						|
 * not be used in advertising or publicity pertaining to distribution of
 | 
						|
 * the software without specific, written prior permission.  The above listed
 | 
						|
 * copyright holder(s) make(s) no representations about the suitability of this
 | 
						|
 * software for any purpose.  It is provided "as is" without express or
 | 
						|
 * implied warranty.
 | 
						|
 *
 | 
						|
 * THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM(S) ALL WARRANTIES WITH REGARD
 | 
						|
 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
						|
 * AND FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE
 | 
						|
 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
 | 
						|
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 | 
						|
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 | 
						|
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 *
 | 
						|
 * This code is also based heavily on the code in FreeBSD-current, which was
 | 
						|
 * written by Wolfgang Stanglmeier, and contains the following copyright:
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 * 3. The name of the author may not be used to endorse or promote products
 | 
						|
 *    derived from this software without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | 
						|
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
						|
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
						|
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
						|
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
						|
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
						|
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 */
 | 
						|
/*
 | 
						|
 * Copyright (c) 1999-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).
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include "compiler.h"
 | 
						|
#include "xf86.h"
 | 
						|
#include "xf86Priv.h"
 | 
						|
#include "Pci.h"
 | 
						|
 | 
						|
#ifdef PC98
 | 
						|
#define outb(port,data) _outb(port,data)
 | 
						|
#define outl(port,data) _outl(port,data)
 | 
						|
#define inb(port) _inb(port)
 | 
						|
#define inl(port) _inl(port)
 | 
						|
#endif
 | 
						|
 | 
						|
#define	PCI_CFGMECH2_ENABLE_REG		0xCF8
 | 
						|
#ifdef PC98
 | 
						|
#define	PCI_CFGMECH2_FORWARD_REG	0xCF9
 | 
						|
#else
 | 
						|
#define	PCI_CFGMECH2_FORWARD_REG	0xCFA
 | 
						|
#endif
 | 
						|
 | 
						|
#define PCI_CFGMECH2_MAXDEV	16
 | 
						|
 | 
						|
#define PCI_ADDR_FROM_TAG_CFG1(tag,reg) (PCI_EN | tag | (reg & 0xfc))
 | 
						|
#define PCI_FORWARD_FROM_TAG(tag)       PCI_BUS_FROM_TAG(tag)
 | 
						|
#define PCI_ENABLE_FROM_TAG(tag)        (0xf0 | (((tag) & 0x00000700) >> 7))
 | 
						|
#define PCI_ADDR_FROM_TAG_CFG2(tag,reg) (0xc000 | (((tag) & 0x0000f800) >> 3) \
 | 
						|
                                        | (reg & 0xfc))
 | 
						|
 | 
						|
/*
 | 
						|
 * Intel x86 platform specific PCI access functions
 | 
						|
 */
 | 
						|
static CARD32 ix86PciReadLongSetup(PCITAG tag, int off);
 | 
						|
static void ix86PciWriteLongSetup(PCITAG, int off, CARD32 val);
 | 
						|
static void ix86PciSetBitsLongSetup(PCITAG, int off, CARD32 mask, CARD32 val);
 | 
						|
static CARD32 ix86PciReadLongCFG1(PCITAG tag, int off);
 | 
						|
static void ix86PciWriteLongCFG1(PCITAG, int off, CARD32 val);
 | 
						|
static void ix86PciSetBitsLongCFG1(PCITAG, int off, CARD32 mask, CARD32 val);
 | 
						|
static CARD32 ix86PciReadLongCFG2(PCITAG tag, int off);
 | 
						|
static void ix86PciWriteLongCFG2(PCITAG, int off, CARD32 val);
 | 
						|
static void ix86PciSetBitsLongCFG2(PCITAG, int off, CARD32 mask, CARD32 val);
 | 
						|
 | 
						|
static pciBusFuncs_t ix86Funcs0 = {
 | 
						|
/* pciReadLong      */	ix86PciReadLongSetup,
 | 
						|
/* pciWriteLong     */	ix86PciWriteLongSetup,
 | 
						|
/* pciSetBitsLong   */	ix86PciSetBitsLongSetup,
 | 
						|
/* pciAddrHostToBus */	pciAddrNOOP,
 | 
						|
/* pciAddrBusToHost */	pciAddrNOOP
 | 
						|
};
 | 
						|
 | 
						|
static pciBusFuncs_t ix86Funcs1 = {
 | 
						|
/* pciReadLong      */	ix86PciReadLongCFG1,
 | 
						|
/* pciWriteLong     */	ix86PciWriteLongCFG1,
 | 
						|
/* pciSetBitsLong   */	ix86PciSetBitsLongCFG1,
 | 
						|
/* pciAddrHostToBus */	pciAddrNOOP,
 | 
						|
/* pciAddrBusToHost */	pciAddrNOOP
 | 
						|
};
 | 
						|
 | 
						|
static pciBusFuncs_t ix86Funcs2 = {
 | 
						|
/* pciReadLong      */	ix86PciReadLongCFG2,
 | 
						|
/* pciWriteLong     */	ix86PciWriteLongCFG2,
 | 
						|
/* pciSetBitsLong   */	ix86PciSetBitsLongCFG2,
 | 
						|
/* pciAddrHostToBus */	pciAddrNOOP,
 | 
						|
/* pciAddrBusToHost */	pciAddrNOOP
 | 
						|
};
 | 
						|
 | 
						|
static pciBusInfo_t ix86Pci0 = {
 | 
						|
/* configMech  */	PCI_CFG_MECH_UNKNOWN,	/* Set by ix86PciInit() */
 | 
						|
/* numDevices  */	0,			/* Set by ix86PciInit() */
 | 
						|
/* secondary   */	FALSE,
 | 
						|
/* primary_bus */	0,
 | 
						|
#ifdef PowerMAX_OS
 | 
						|
/* ppc_io_base */	0,
 | 
						|
/* ppc_io_size */	0,
 | 
						|
#endif
 | 
						|
/* funcs       */	&ix86Funcs0,		/* Set by ix86PciInit() */
 | 
						|
/* pciBusPriv  */	NULL,
 | 
						|
/* bridge      */	NULL
 | 
						|
};
 | 
						|
 | 
						|
static Bool
 | 
						|
ix86PciBusCheck(void)
 | 
						|
{
 | 
						|
    PCITAG tag;
 | 
						|
    CARD32 id, class;
 | 
						|
    CARD8 device;
 | 
						|
 | 
						|
    for (device = 0; device < ix86Pci0.numDevices; device++) {
 | 
						|
	tag = PCI_MAKE_TAG(0, device, 0);
 | 
						|
	id = (*ix86Pci0.funcs->pciReadLong)(tag, PCI_ID_REG);
 | 
						|
 | 
						|
	if ((CARD16)(id + 1U) <= (CARD16)1UL)
 | 
						|
		continue;
 | 
						|
 | 
						|
	/* The rest of this is inspired by the Linux kernel */
 | 
						|
	class = (*ix86Pci0.funcs->pciReadLong)(tag, PCI_CLASS_REG);
 | 
						|
 | 
						|
	/* Ignore revision id and programming interface */
 | 
						|
	switch (class >> 16) {
 | 
						|
	case (PCI_CLASS_PREHISTORIC << 8) | PCI_SUBCLASS_PREHISTORIC_MISC:
 | 
						|
	    /* Check for vendors of known buggy chipsets */
 | 
						|
	    id &= 0x0000ffff;
 | 
						|
	    if ((id == PCI_VENDOR_INTEL) || (id == PCI_VENDOR_COMPAQ))
 | 
						|
		return TRUE;
 | 
						|
	    continue;
 | 
						|
 | 
						|
	case (PCI_CLASS_PREHISTORIC << 8) | PCI_SUBCLASS_PREHISTORIC_VGA:
 | 
						|
	case (PCI_CLASS_DISPLAY << 8) | PCI_SUBCLASS_DISPLAY_VGA:
 | 
						|
	case (PCI_CLASS_BRIDGE << 8) | PCI_SUBCLASS_BRIDGE_HOST:
 | 
						|
	    return TRUE;
 | 
						|
 | 
						|
	default:
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void ix86PciSelectCfgmech(void)
 | 
						|
{
 | 
						|
    static Bool beenhere = FALSE;
 | 
						|
    CARD32 mode1Res1 = 0, mode1Res2 = 0, oldVal1 = 0;
 | 
						|
    CARD8  mode2Res1 = 0, mode2Res2 = 0, oldVal2 = 0;
 | 
						|
    int stages = 0;
 | 
						|
 | 
						|
    if (beenhere)
 | 
						|
	return; /* Been there, done that */
 | 
						|
 | 
						|
    beenhere = TRUE;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Determine if motherboard chipset supports PCI Config Mech 1 or 2
 | 
						|
     * We rely on xf86Info.pciFlags to tell which mechanisms to try....
 | 
						|
     */
 | 
						|
    switch (xf86Info.pciFlags) {
 | 
						|
 | 
						|
    case PCIProbe1: /* { */
 | 
						|
 | 
						|
      xf86MsgVerb(X_INFO, 2, "PCI: Probing config type using method 1\n");
 | 
						|
      oldVal1 = inl(PCI_CFGMECH1_ADDRESS_REG);
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
      if (xf86Verbose > 2) {
 | 
						|
	ErrorF("Checking config type 1:\n"
 | 
						|
		"\tinitial value of MODE1_ADDR_REG is 0x%08x\n", oldVal1);
 | 
						|
	ErrorF("\tChecking that all bits in mask 0x7f000000 are clear\n");
 | 
						|
      }
 | 
						|
#endif
 | 
						|
 | 
						|
      /* Assuming config type 1 to start with */
 | 
						|
      if ((oldVal1 & 0x7f000000) == 0) {
 | 
						|
 | 
						|
	stages |= 0x01;
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
	if (xf86Verbose > 2) {
 | 
						|
	    ErrorF("\tValue indicates possibly config type 1\n");
 | 
						|
	    ErrorF("\tWriting 32-bit value 0x%08x to MODE1_ADDR_REG\n", PCI_EN);
 | 
						|
#if 0
 | 
						|
	    ErrorF("\tWriting 8-bit value 0x00 to MODE1_ADDR_REG + 3\n");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	ix86Pci0.configMech = PCI_CFG_MECH_1;
 | 
						|
	ix86Pci0.numDevices = PCI_CFGMECH1_MAXDEV;
 | 
						|
	ix86Pci0.funcs = &ix86Funcs1;
 | 
						|
 | 
						|
	outl(PCI_CFGMECH1_ADDRESS_REG, PCI_EN);
 | 
						|
 | 
						|
#if 0
 | 
						|
	/*
 | 
						|
	 * This seems to cause some Neptune-based PCI machines to switch
 | 
						|
	 * from config type 1 to config type 2
 | 
						|
	 */
 | 
						|
	outb(PCI_CFGMECH1_ADDRESS_REG + 3, 0);
 | 
						|
#endif
 | 
						|
	mode1Res1 = inl(PCI_CFGMECH1_ADDRESS_REG);
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
	if (xf86Verbose > 2) {
 | 
						|
	    ErrorF("\tValue read back from MODE1_ADDR_REG is 0x%08x\n",
 | 
						|
			mode1Res1);
 | 
						|
	    ErrorF("\tRestoring original contents of MODE1_ADDR_REG\n");
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	outl(PCI_CFGMECH1_ADDRESS_REG, oldVal1);
 | 
						|
 | 
						|
	if (mode1Res1) {
 | 
						|
 | 
						|
	    stages |= 0x02;
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
	    if (xf86Verbose > 2) {
 | 
						|
		ErrorF("\tValue read back is non-zero, and indicates possible"
 | 
						|
			" config type 1\n");
 | 
						|
	    }
 | 
						|
#endif
 | 
						|
 | 
						|
	    if (ix86PciBusCheck()) {
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
		if (xf86Verbose > 2)
 | 
						|
		    ErrorF("\tBus check Confirms this: ");
 | 
						|
#endif
 | 
						|
 | 
						|
		xf86MsgVerb(X_INFO, 2, "PCI: Config type is 1\n");
 | 
						|
		xf86MsgVerb(X_INFO, 3,
 | 
						|
			"PCI: stages = 0x%02x, oldVal1 = 0x%08lx, mode1Res1"
 | 
						|
			" = 0x%08lx\n", stages, (unsigned long)oldVal1,
 | 
						|
			(unsigned long)mode1Res1);
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
	    if (xf86Verbose > 2) {
 | 
						|
		ErrorF("\tBus check fails to confirm this, continuing type 1"
 | 
						|
			" check ...\n");
 | 
						|
	    }
 | 
						|
#endif
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	stages |= 0x04;
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
	if (xf86Verbose > 2) {
 | 
						|
	    ErrorF("\tWriting 0xff000001 to MODE1_ADDR_REG\n");
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	outl(PCI_CFGMECH1_ADDRESS_REG, 0xff000001);
 | 
						|
	mode1Res2 = inl(PCI_CFGMECH1_ADDRESS_REG);
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
	if (xf86Verbose > 2) {
 | 
						|
	    ErrorF("\tValue read back from MODE1_ADDR_REG is 0x%08x\n",
 | 
						|
			mode1Res2);
 | 
						|
	    ErrorF("\tRestoring original contents of MODE1_ADDR_REG\n");
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	outl(PCI_CFGMECH1_ADDRESS_REG, oldVal1);
 | 
						|
 | 
						|
	if ((mode1Res2 & 0x80000001) == 0x80000000) {
 | 
						|
 | 
						|
	    stages |= 0x08;
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
	    if (xf86Verbose > 2) {
 | 
						|
		ErrorF("\tValue read back has only the msb set\n"
 | 
						|
			"\tThis indicates possible config type 1\n");
 | 
						|
	    }
 | 
						|
#endif
 | 
						|
 | 
						|
	    if (ix86PciBusCheck()) {
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
		if (xf86Verbose > 2)
 | 
						|
		    ErrorF("\tBus check Confirms this: ");
 | 
						|
#endif
 | 
						|
 | 
						|
		xf86MsgVerb(X_INFO, 2, "PCI: Config type is 1\n");
 | 
						|
		xf86MsgVerb(X_INFO, 3,
 | 
						|
			"PCI: stages = 0x%02x, oldVal1 = 0x%08lx,\n"
 | 
						|
			"\tmode1Res1 = 0x%08lx, mode1Res2 = 0x%08lx\n",
 | 
						|
			stages, (unsigned long)oldVal1,
 | 
						|
			(unsigned long)mode1Res1, (unsigned long)mode1Res2);
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
	    if (xf86Verbose > 2) {
 | 
						|
		ErrorF("\tBus check fails to confirm this.\n");
 | 
						|
	    }
 | 
						|
#endif
 | 
						|
 | 
						|
	}
 | 
						|
      }
 | 
						|
 | 
						|
      xf86MsgVerb(X_INFO, 3, "PCI: Standard check for type 1 failed.\n");
 | 
						|
      xf86MsgVerb(X_INFO, 3, "PCI: stages = 0x%02x, oldVal1 = 0x%08lx,\n"
 | 
						|
	       "\tmode1Res1 = 0x%08lx, mode1Res2 = 0x%08lx\n",
 | 
						|
	       stages, (unsigned long)oldVal1, (unsigned long)mode1Res1,
 | 
						|
	       (unsigned long)mode1Res2);
 | 
						|
 | 
						|
      /* Try config type 2 */
 | 
						|
      oldVal2 = inb(PCI_CFGMECH2_ENABLE_REG);
 | 
						|
      if ((oldVal2 & 0xf0) == 0) {
 | 
						|
	ix86Pci0.configMech = PCI_CFG_MECH_2;
 | 
						|
	ix86Pci0.numDevices = PCI_CFGMECH2_MAXDEV;
 | 
						|
	ix86Pci0.funcs = &ix86Funcs2;
 | 
						|
 | 
						|
	outb(PCI_CFGMECH2_ENABLE_REG, 0x0e);
 | 
						|
	mode2Res1 = inb(PCI_CFGMECH2_ENABLE_REG);
 | 
						|
	outb(PCI_CFGMECH2_ENABLE_REG, oldVal2);
 | 
						|
 | 
						|
	if (mode2Res1 == 0x0e) {
 | 
						|
	    if (ix86PciBusCheck()) {
 | 
						|
		xf86MsgVerb(X_INFO, 2, "PCI: Config type is 2\n");
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      }
 | 
						|
      break; /* } */
 | 
						|
 | 
						|
    case PCIProbe2: /* { */
 | 
						|
 | 
						|
      /* The scanpci-style detection method */
 | 
						|
 | 
						|
      xf86MsgVerb(X_INFO, 2, "PCI: Probing config type using method 2\n");
 | 
						|
 | 
						|
      outb(PCI_CFGMECH2_ENABLE_REG, 0x00);
 | 
						|
      outb(PCI_CFGMECH2_FORWARD_REG, 0x00);
 | 
						|
      mode2Res1 = inb(PCI_CFGMECH2_ENABLE_REG);
 | 
						|
      mode2Res2 = inb(PCI_CFGMECH2_FORWARD_REG);
 | 
						|
 | 
						|
      if (mode2Res1 == 0 && mode2Res2 == 0) {
 | 
						|
	xf86MsgVerb(X_INFO, 2, "PCI: Config type is 2\n");
 | 
						|
	ix86Pci0.configMech = PCI_CFG_MECH_2;
 | 
						|
	ix86Pci0.numDevices = PCI_CFGMECH2_MAXDEV;
 | 
						|
	ix86Pci0.funcs = &ix86Funcs2;
 | 
						|
	return;
 | 
						|
      }
 | 
						|
 | 
						|
      oldVal1 = inl(PCI_CFGMECH1_ADDRESS_REG);
 | 
						|
      outl(PCI_CFGMECH1_ADDRESS_REG, PCI_EN);
 | 
						|
      mode1Res1 = inl(PCI_CFGMECH1_ADDRESS_REG);
 | 
						|
      outl(PCI_CFGMECH1_ADDRESS_REG, oldVal1);
 | 
						|
      if (mode1Res1 == PCI_EN) {
 | 
						|
	xf86MsgVerb(X_INFO, 2, "PCI: Config type is 1\n");
 | 
						|
	ix86Pci0.configMech = PCI_CFG_MECH_1;
 | 
						|
	ix86Pci0.numDevices = PCI_CFGMECH1_MAXDEV;
 | 
						|
	ix86Pci0.funcs = &ix86Funcs1;
 | 
						|
	return;
 | 
						|
      }
 | 
						|
      break; /* } */
 | 
						|
 | 
						|
    case PCIForceConfig1:
 | 
						|
 | 
						|
      xf86MsgVerb(X_INFO, 2, "PCI: Forcing config type 1\n");
 | 
						|
 | 
						|
      ix86Pci0.configMech = PCI_CFG_MECH_1;
 | 
						|
      ix86Pci0.numDevices = PCI_CFGMECH1_MAXDEV;
 | 
						|
      ix86Pci0.funcs = &ix86Funcs1;
 | 
						|
      return;
 | 
						|
 | 
						|
    case PCIForceConfig2:
 | 
						|
 | 
						|
      xf86MsgVerb(X_INFO, 2, "PCI: Forcing config type 2\n");
 | 
						|
 | 
						|
      ix86Pci0.configMech = PCI_CFG_MECH_2;
 | 
						|
      ix86Pci0.numDevices = PCI_CFGMECH2_MAXDEV;
 | 
						|
      ix86Pci0.funcs = &ix86Funcs2;
 | 
						|
      return;
 | 
						|
 | 
						|
    case PCIOsConfig:
 | 
						|
	return;
 | 
						|
 | 
						|
    case PCIForceNone:
 | 
						|
	break;
 | 
						|
    }
 | 
						|
 | 
						|
    /* No PCI found */
 | 
						|
    ix86Pci0.configMech = PCI_CFG_MECH_UNKNOWN;
 | 
						|
    xf86MsgVerb(X_INFO, 2, "PCI: No PCI bus found or probed for\n");
 | 
						|
}
 | 
						|
 | 
						|
#if 0
 | 
						|
static pciTagRec
 | 
						|
ix86PcibusTag(CARD8 bus, CARD8 cardnum, CARD8 func)
 | 
						|
{
 | 
						|
    pciTagRec tag;
 | 
						|
 | 
						|
    tag.cfg1 = 0;
 | 
						|
 | 
						|
    if (func > 7 || cardnum >= pciBusInfo[bus]->numDevices)
 | 
						|
	return tag;
 | 
						|
 | 
						|
    switch (ix86Pci0.configMech) {
 | 
						|
    case PCI_CFG_MECH_1:
 | 
						|
	    tag.cfg1 = PCI_EN | ((CARD32)bus << 16) |
 | 
						|
		       ((CARD32)cardnum << 11) |
 | 
						|
		       ((CARD32)func << 8);
 | 
						|
	    break;
 | 
						|
 | 
						|
    case PCI_CFG_MECH_2:
 | 
						|
	    tag.cfg2.port    = 0xc000 | ((CARD16)cardnum << 8);
 | 
						|
	    tag.cfg2.enable  = 0xf0 | (func << 1);
 | 
						|
	    tag.cfg2.forward = bus;
 | 
						|
	    break;
 | 
						|
    }
 | 
						|
 | 
						|
    return tag;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static CARD32
 | 
						|
ix86PciReadLongSetup(PCITAG Tag, int reg)
 | 
						|
{
 | 
						|
    ix86PciSelectCfgmech();
 | 
						|
    return (*ix86Pci0.funcs->pciReadLong)(Tag,reg);
 | 
						|
}
 | 
						|
 | 
						|
static CARD32
 | 
						|
ix86PciReadLongCFG1(PCITAG Tag, int reg)
 | 
						|
{
 | 
						|
    CARD32    addr, data = 0;
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
    ErrorF("ix86PciReadLong 0x%lx, %d\n", Tag, reg);
 | 
						|
#endif
 | 
						|
 | 
						|
    addr = PCI_ADDR_FROM_TAG_CFG1(Tag,reg);
 | 
						|
    outl(PCI_CFGMECH1_ADDRESS_REG, addr);
 | 
						|
    data = inl(PCI_CFGMECH1_DATA_REG);
 | 
						|
    outl(PCI_CFGMECH1_ADDRESS_REG, 0);
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
    ErrorF("ix86PciReadLong 0x%lx\n", data);
 | 
						|
#endif
 | 
						|
 | 
						|
    return data;
 | 
						|
}
 | 
						|
 | 
						|
static CARD32
 | 
						|
ix86PciReadLongCFG2(PCITAG Tag, int reg)
 | 
						|
{
 | 
						|
    CARD32    addr, data = 0;
 | 
						|
    CARD8     forward, enable;
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
    ErrorF("ix86PciReadLong 0x%lx, %d\n", Tag, reg);
 | 
						|
#endif
 | 
						|
 | 
						|
    forward  = PCI_FORWARD_FROM_TAG(Tag);
 | 
						|
    enable   = PCI_ENABLE_FROM_TAG(Tag);
 | 
						|
    addr     = PCI_ADDR_FROM_TAG_CFG2(Tag,reg);
 | 
						|
 | 
						|
    outb(PCI_CFGMECH2_ENABLE_REG, enable);
 | 
						|
    outb(PCI_CFGMECH2_FORWARD_REG, forward);
 | 
						|
    data = inl((CARD16)addr);
 | 
						|
    outb(PCI_CFGMECH2_ENABLE_REG, 0);
 | 
						|
    outb(PCI_CFGMECH2_FORWARD_REG, 0);
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
    ErrorF("ix86PciReadLong 0x%lx\n", data);
 | 
						|
#endif
 | 
						|
 | 
						|
    return data;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ix86PciWriteLongSetup(PCITAG Tag, int reg, CARD32 data)
 | 
						|
{
 | 
						|
    ix86PciSelectCfgmech();
 | 
						|
    (*ix86Pci0.funcs->pciWriteLong)(Tag,reg,data);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ix86PciWriteLongCFG1(PCITAG Tag, int reg, CARD32 data)
 | 
						|
{
 | 
						|
    CARD32    addr;
 | 
						|
 | 
						|
    addr = PCI_ADDR_FROM_TAG_CFG1(Tag,reg);
 | 
						|
    outl(PCI_CFGMECH1_ADDRESS_REG, addr);
 | 
						|
    outl(PCI_CFGMECH1_DATA_REG, data);
 | 
						|
    outl(PCI_CFGMECH1_ADDRESS_REG, 0);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ix86PciWriteLongCFG2(PCITAG Tag, int reg, CARD32 data)
 | 
						|
{
 | 
						|
    CARD32    addr;
 | 
						|
    CARD8 forward, enable;
 | 
						|
 | 
						|
    forward  = PCI_FORWARD_FROM_TAG(Tag);
 | 
						|
    enable   = PCI_ENABLE_FROM_TAG(Tag);
 | 
						|
    addr     = PCI_ADDR_FROM_TAG_CFG2(Tag,reg);
 | 
						|
 | 
						|
    outb(PCI_CFGMECH2_ENABLE_REG, enable);
 | 
						|
    outb(PCI_CFGMECH2_FORWARD_REG, forward);
 | 
						|
    outl((CARD16)addr, data);
 | 
						|
    outb(PCI_CFGMECH2_ENABLE_REG, 0);
 | 
						|
    outb(PCI_CFGMECH2_FORWARD_REG, 0);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ix86PciSetBitsLongSetup(PCITAG Tag, int reg, CARD32 mask, CARD32 val)
 | 
						|
{
 | 
						|
    ix86PciSelectCfgmech();
 | 
						|
    (*ix86Pci0.funcs->pciSetBitsLong)(Tag,reg,mask,val);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ix86PciSetBitsLongCFG1(PCITAG Tag, int reg, CARD32 mask, CARD32 val)
 | 
						|
{
 | 
						|
    CARD32    addr, data = 0;
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
    ErrorF("ix86PciSetBitsLong 0x%lx, %d\n", Tag, reg);
 | 
						|
#endif
 | 
						|
 | 
						|
    addr = PCI_ADDR_FROM_TAG_CFG1(Tag,reg);
 | 
						|
    outl(PCI_CFGMECH1_ADDRESS_REG, addr);
 | 
						|
    data = inl(PCI_CFGMECH1_DATA_REG);
 | 
						|
    data = (data & ~mask) | (val & mask);
 | 
						|
    outl(PCI_CFGMECH1_DATA_REG, data);
 | 
						|
    outl(PCI_CFGMECH1_ADDRESS_REG, 0);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ix86PciSetBitsLongCFG2(PCITAG Tag, int reg, CARD32 mask, CARD32 val)
 | 
						|
{
 | 
						|
    CARD32    addr, data = 0;
 | 
						|
    CARD8 enable, forward;
 | 
						|
 | 
						|
#ifdef DEBUGPCI
 | 
						|
    ErrorF("ix86PciSetBitsLong 0x%lx, %d\n", Tag, reg);
 | 
						|
#endif
 | 
						|
 | 
						|
    forward  = PCI_FORWARD_FROM_TAG(Tag);
 | 
						|
    enable   = PCI_ENABLE_FROM_TAG(Tag);
 | 
						|
    addr     = PCI_ADDR_FROM_TAG_CFG2(Tag,reg);
 | 
						|
 | 
						|
    outb(PCI_CFGMECH2_ENABLE_REG, enable);
 | 
						|
    outb(PCI_CFGMECH2_FORWARD_REG, forward);
 | 
						|
    data = inl((CARD16)addr);
 | 
						|
    data = (data & ~mask) | (val & mask);
 | 
						|
    outl((CARD16)addr, data);
 | 
						|
    outb(PCI_CFGMECH2_ENABLE_REG, 0);
 | 
						|
    outb(PCI_CFGMECH2_FORWARD_REG, 0);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ix86PciInit()
 | 
						|
{
 | 
						|
    /* Initialize pciBusInfo[] array and function pointers */
 | 
						|
    pciNumBuses    = 1;
 | 
						|
    pciBusInfo[0]  = &ix86Pci0;
 | 
						|
    pciFindFirstFP = pciGenFindFirst;
 | 
						|
    pciFindNextFP  = pciGenFindNext;
 | 
						|
 | 
						|
    /* Make sure that there is a PCI bus present. */
 | 
						|
    ix86PciSelectCfgmech();
 | 
						|
    if (ix86Pci0.configMech == PCI_CFG_MECH_UNKNOWN) {
 | 
						|
	pciNumBuses    = 0;
 | 
						|
	pciBusInfo[0]  = NULL;
 | 
						|
    }
 | 
						|
}
 |