From f4092abdf94af6a99aff944d6264bc1284e8bdd4 Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Mon, 10 Oct 2011 17:43:39 +0200 Subject: Imported nx-X11-3.1.0-1.tar.gz Summary: Imported nx-X11-3.1.0-1.tar.gz Keywords: Imported nx-X11-3.1.0-1.tar.gz into Git repository --- .../Xserver/hw/xfree86/os-support/bus/zx1PCI.c | 1133 ++++++++++++++++++++ 1 file changed, 1133 insertions(+) create mode 100644 nx-X11/programs/Xserver/hw/xfree86/os-support/bus/zx1PCI.c (limited to 'nx-X11/programs/Xserver/hw/xfree86/os-support/bus/zx1PCI.c') diff --git a/nx-X11/programs/Xserver/hw/xfree86/os-support/bus/zx1PCI.c b/nx-X11/programs/Xserver/hw/xfree86/os-support/bus/zx1PCI.c new file mode 100644 index 000000000..3d219c86f --- /dev/null +++ b/nx-X11/programs/Xserver/hw/xfree86/os-support/bus/zx1PCI.c @@ -0,0 +1,1133 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/bus/zx1PCI.c,v 1.8 2004/01/16 15:39:38 tsi Exp $ */ +/* + * Copyright (C) 2002-2003 The XFree86 Project, Inc. All Rights Reserved. + * + * 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 + * XFREE86 PROJECT 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 XFree86 Project 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 + * XFree86 Project. + */ + +/* + * This file contains the glue necessary for support of HP's ZX1 chipset. + * Keep in mind that this chipset is used in both Itanium2 and PA-RISC + * architectures. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include "zx1PCI.h" +#include "xf86.h" +#include "xf86_OSlib.h" +#include "Pci.h" + +#define MIO_BASE 0xFED00000UL /* mio register base */ +#define MIO_SIZE 0x00002000UL /* 8k, minimum */ + +/* ZX1 mio register definitions */ +#define MIO_FUNCTION0 0x0000U + +#define MODULE_INFO 0x0100U +#define STATUS_CONTROL 0x0108U +#define DILLON_PRESENT 0x02UL + +#define LMMIO_DIR_BASE0 0x0300U +#define LMMIO_DIR_MASK0 0x0308U +#define LMMIO_DIR_ROUTE0 0x0310U +#define LMMIO_DIR_BASE1 0x0318U +#define LMMIO_DIR_MASK1 0x0320U +#define LMMIO_DIR_ROUTE1 0x0328U +#define LMMIO_DIR_BASE2 0x0330U +#define LMMIO_DIR_MASK2 0x0338U +#define LMMIO_DIR_ROUTE2 0x0340U +#define LMMIO_DIR_BASE3 0x0348U +#define LMMIO_DIR_MASK3 0x0350U +#define LMMIO_DIR_ROUTE3 0x0358U +#define LMMIO_DIST_BASE 0x0360U +#define LMMIO_DIST_MASK 0x0368U +#define LMMIO_DIST_ROUTE 0x0370U +#define GMMIO_DIST_BASE 0x0378U +#define PORT_DISABLE 0x02UL +#define MAP_TO_LMMIO 0x04UL +#define GMMIO_DIST_MASK 0x0380U +#define GMMIO_DIST_ROUTE 0x0388U +#define IOS_DIST_BASE 0x0390U +#define IOS_DIST_MASK 0x0398U +#define IOS_DIST_ROUTE 0x03A0U +#define ROPE_CONFIG_BASE 0x03A8U +#define VGA_ROUTE 0x03B0U +#define VGA_ENABLE 0x8000000000000000UL +#define VGA_LIGHT 0x4000000000000000UL + +#define IOS_DIR_BASE 0x03C0U +#define IOS_DIR_MASK 0x03C8U +#define IOS_DIR_ROUTE 0x03D0U +#define IOS_BASE 0x03D8U + +#define MIO_FUNCTION1 0x1000U + +#define ROPE_CONFIG 0x1040U +#define ROPE_D0 0x0100UL +#define ROPE_D2 0x0200UL +#define ROPE_D4 0x0400UL +#define ROPE_D6 0x0800UL +#define ROPE_Q0 0x1000UL +#define ROPE_Q4 0x2000UL + +#define LBA_PORT0_CNTRL 0x1200U +#define LBA_PORT1_CNTRL 0x1208U +#define LBA_PORT2_CNTRL 0x1210U +#define LBA_PORT3_CNTRL 0x1218U +#define LBA_PORT4_CNTRL 0x1220U +#define LBA_PORT5_CNTRL 0x1228U +#define LBA_PORT6_CNTRL 0x1230U +#define LBA_PORT7_CNTRL 0x1238U +#define LBA_RESET_FUNCTION 0x0000000001UL +#define LBA_CLEAR_ERROR 0x0000000010UL +#define LBA_HARD_FAIL 0x0000000040UL +#define LBA_RESET_COMPLETE 0x0100000000UL + +#define ROPE_PAGE_CONTROL 0x1418U + +/* + * Total ioa configuration space size is actually 128k, but we only need the + * first 64k. + */ +#define IOA_SIZE 0x00010000UL + +/* ZX1 ioa register definitions */ +#define IOA_CONFIG_ADDR 0x0040U +#define IOA_CONFIG_DATA 0x0048U + +#define IOA_SECONDARY_BUS 0x0058U +#define IOA_SUBORDINATE_BUS 0x0059U + +#define IOA_CONTROL 0x0108U +#define IOA_RESET_FUNCTION 0x0000000001UL +#define IOA_FORWARD_VGA 0x0000000008UL +#define IOA_CLEAR_ERROR 0x0000000010UL +#define IOA_HARD_FAIL 0x0000000040UL +#define IOA_RESET_COMPLETE 0x0100000000UL + +#define IOA_LMMIO_BASE 0x0200U +#define IOA_LMMIO_MASK 0x0208U +#define IOA_GMMIO_BASE 0x0210U +#define IOA_GMMIO_MASK 0x0218U +#define IOA_WLMMIO_BASE 0x0220U +#define IOA_WLMMIO_MASK 0x0228U +#define IOA_WGMMIO_BASE 0x0230U +#define IOA_WGMMIO_MASK 0x0238U +#define IOA_IOS_BASE 0x0240U +#define IOA_IOS_MASK 0x0248U +#define IOA_ELMMIO_BASE 0x0250U +#define IOA_ELMMIO_MASK 0x0258U +#define IOA_EIOS_BASE 0x0260U +#define IOA_EIOS_MASK 0x0268U +#define IOA_GLOBAL_MASK 0x0270U +#define IOA_SLAVE_CONTROL 0x0278U +#define IOA_VGA_PEER_ENABLE 0x2000UL +#define IOA_MSI_BASE 0x0280U +#define IOA_MSI_MASK 0x0288U + +#define IOA_DMA_BASE 0x02B0U +#define IOA_DMA_MASK 0x02B8U + +#define IOA_ERROR_CONFIG 0x0680U +#define IOA_ERROR_PIOWRITE 0x0001UL +#define IOA_ERROR_PIOREAD 0x0002UL +#define IOA_ERROR_DMAWRITE 0x0004UL +#define IOA_ERROR_DMAREAD 0x0008UL +#define IOA_ERROR_CONFIG_MASTER 0x0010UL +#define IOA_ERROR_SMART 0x0020UL +#define IOA_ERROR_FATAL_SERR 0x0040UL +#define IOA_ERROR_ASSERT_SERR 0x0080UL +/* ? 0x0100UL */ +#define IOA_ERROR_LOOPBACK 0x0200UL +#define IOA_ERROR_CONFIG_TARGET 0x0400UL +#define IOA_ERROR_IO_MASTER 0x0800UL +#define IOA_ERROR_IO_TARGET 0x1000UL +#define IOA_ERROR_MEM_MASTER 0x2000UL +#define IOA_ERROR_MEM_TARGET 0x4000UL +#define IOA_ERROR_HF_IO_FATAL 0x8000UL + +#define RANGE_ENABLE 0x01UL /* In various base registers */ + +#define IO_MASK ((1UL << 16) - 1UL) +#define LMMIO_MASK ((1UL << 32) - 1UL) +#ifdef __ia64__ +#define GMMIO_MASK ((1UL << 44) - 1UL) +#else /* PA-RISC */ +#define GMMIO_MASK ((1UL << 40) - 1UL) +#endif + +#define PDH_START 0xFF000000UL +#define PDH_LAST 0xFFFFFFFFUL + +static CARD8 *pZX1mio = NULL, + *pZX1ioa = NULL; + +/* Per-rope data */ +static INT8 zx1_ropemap[8]; +static CARD32 zx1_pciids[8]; +static CARD64 zx1_lbacntl[8]; +static int zx1_busno[8], zx1_subno[8]; + +/* Array of Booleans for non-empty buses */ +static INT8 zx1_busnmpt[MAX_PCI_BUSES]; + +static pciBusFuncs_t zx1BusFuncs; +static int zx1_fakebus = -1; +static Bool zx1_hasvga = FALSE; + +static pointer pZX1IoRes[8], pZX1MemRes[8]; /* Rope resources */ + +/* Non-PCI configuration space access macros */ +#define MIO_BYTE(offset) \ + (*(volatile CARD8 *)(pointer)(pZX1mio + (offset))) +#define MIO_WORD(offset) \ + (*(volatile CARD16 *)(pointer)(pZX1mio + (offset))) +#define MIO_LONG(offset) \ + (*(volatile CARD32 *)(pointer)(pZX1mio + (offset))) +#define MIO_QUAD(offset) \ + (*(volatile CARD64 *)(pointer)(pZX1mio + (offset))) +#define IOA_BYTE(ioa, offset) \ + (*(volatile CARD8 *)(pointer)(pZX1ioa + ((offset) + ((ioa) << 13)))) +#define IOA_WORD(ioa, offset) \ + (*(volatile CARD16 *)(pointer)(pZX1ioa + ((offset) + ((ioa) << 13)))) +#define IOA_LONG(ioa, offset) \ + (*(volatile CARD32 *)(pointer)(pZX1ioa + ((offset) + ((ioa) << 13)))) +#define IOA_QUAD(ioa, offset) \ + (*(volatile CARD64 *)(pointer)(pZX1ioa + ((offset) + ((ioa) << 13)))) + +/* Range definitions */ +#define MAX_RANGE 16 +static CARD64 bot[MAX_RANGE], top[MAX_RANGE], msk[MAX_RANGE], siz[MAX_RANGE]; +static INT8 *pDecode[MAX_RANGE]; +static int nRange = 0; + +/* Track a resource range and assign a granularity to it */ +static void +SetRange(CARD64 base, CARD64 last, CARD8 width) +{ + int i; + + bot[nRange] = base; + top[nRange] = last; + msk[nRange] = (CARD64)(-1L); + if (base) + msk[nRange] &= (base ^ (base - 1UL)) >> 1; + if (last + 1UL) + msk[nRange] &= (last ^ (last + 1UL)) >> 1; + if (width < 64) + msk[nRange] &= (1UL << width) - 1UL; + + /* Look for overlapping ranges */ + for (i = 0; i < nRange; i++) { + if ((bot[i] > top[i]) || + (top[nRange] < bot[i]) || + (top[i] < bot[nRange])) + continue; + + /* Merge in overlapping range */ + if (bot[nRange] > bot[i]) + bot[nRange] = bot[i]; + if (top[nRange] < top[i]) + top[nRange] = top[i]; + + /* Assign finer granularity */ + msk[nRange] &= msk[i]; + bot[i] = 1UL; + top[i] = 0; + } + + nRange++; +} + +/* Lookup granularity associated with the range containing 'base' */ +static int +GetRange(CARD64 base) +{ + int i; + + for (i = 0; i < nRange; i++) { + if ((bot[i] > top[i]) || + (base < bot[i]) || + (base > top[i])) + continue; + + if (pDecode[i]) + break; + + /* Allocate decoding array */ + msk[i]++; + siz[i] = ((top[i] - bot[i] + 1UL) / msk[i]) + 1UL; + pDecode[i] = xnfalloc(siz[i]); + (void)memset(pDecode[i], -1, siz[i]); + break; + } + + return i; +} + +/* + * Verify that 'bus' is a rope's secondary bus and return the pciConfigPtr of + * the associated fake PCI-to-PCI bridge. + */ +static pciConfigPtr +VerifyZX1Bus(int bus) +{ + pciConfigPtr pPCI; + + if ((bus < 0) || (bus >= pciNumBuses) || + !pciBusInfo[bus] || !(pPCI = pciBusInfo[bus]->bridge) || + (pPCI->busnum != zx1_fakebus) || (pPCI->funcnum != 0) || + (pPCI->devnum < 0x10) || (pPCI->devnum > 0x17)) + return NULL; + + return pPCI; +} + +/* + * This function is called to emulate the various settings in a P2P or CardBus + * bridge's control register on a ZX1-based system. + */ +static CARD16 +ControlZX1Bridge(int bus, CARD16 mask, CARD16 value) +{ + pciConfigPtr pPCI; + CARD64 tmp1, tmp2, tmp3, ropenum; + CARD16 current = 0; + + if ((pPCI = VerifyZX1Bus(bus))) { + ropenum = pPCI->devnum & 0x07; + + /* + * Start with VGA enablement. This preserves the "VGA-lite" bit + * in mio's VGA_ROUTE register, and the VPE bit in each ioa's + * SLAVE_CONTROL register. + */ + tmp1 = MIO_QUAD(VGA_ROUTE); + tmp2 = IOA_QUAD(ropenum, IOA_CONTROL) & + ~(IOA_RESET_FUNCTION | IOA_CLEAR_ERROR); + if ((tmp1 & VGA_ENABLE) && ((tmp1 & 0x07UL) == ropenum)) { + current |= PCI_PCI_BRIDGE_VGA_EN; + if ((mask & PCI_PCI_BRIDGE_VGA_EN) && + !(value & PCI_PCI_BRIDGE_VGA_EN)) { + MIO_QUAD(VGA_ROUTE) = tmp1 & ~VGA_ENABLE; + tmp2 &= ~IOA_FORWARD_VGA; + IOA_QUAD(ropenum, IOA_CONTROL) = tmp2; + } + } else if (mask & value & PCI_PCI_BRIDGE_VGA_EN) { + if (!zx1_hasvga) { + xf86MsgVerb(X_WARNING, 3, + "HP ZX1: Attempt to enable VGA routing to bus %d" + " through rope %ld disallowed\n", bus, ropenum); + value &= ~PCI_PCI_BRIDGE_VGA_EN; + } else { + if (tmp1 & VGA_ENABLE) { + /* + * VGA is routed somewhere else. Disable it. + */ + MIO_QUAD(VGA_ROUTE) = 0UL; + tmp3 = IOA_QUAD(tmp1 & 0x07UL, IOA_CONTROL); + if (tmp3 & IOA_FORWARD_VGA) + IOA_QUAD(tmp1 & 0x07UL, IOA_CONTROL) = tmp3 & + ~(IOA_RESET_FUNCTION | IOA_FORWARD_VGA | + IOA_CLEAR_ERROR); + } + if (!(tmp2 & IOA_FORWARD_VGA)) { + tmp2 |= IOA_FORWARD_VGA; + IOA_QUAD(ropenum, IOA_CONTROL) = tmp2; + } + tmp1 = (tmp1 & ~0x07UL) | ropenum | VGA_ENABLE; + MIO_QUAD(VGA_ROUTE) = tmp1; + } + } + + /* Move on to master abort failure enablement */ + tmp1 = MIO_QUAD((ropenum << 3) + LBA_PORT0_CNTRL) & + ~(LBA_RESET_FUNCTION | LBA_CLEAR_ERROR); + if ((tmp1 & LBA_HARD_FAIL) || (tmp2 & IOA_HARD_FAIL)) { + current |= PCI_PCI_BRIDGE_MASTER_ABORT_EN; + if ((mask & PCI_PCI_BRIDGE_MASTER_ABORT_EN) && + !(value & PCI_PCI_BRIDGE_MASTER_ABORT_EN)) { + if (tmp1 & LBA_HARD_FAIL) + MIO_QUAD((ropenum << 3) + LBA_PORT0_CNTRL) = + tmp1 & ~LBA_HARD_FAIL; + if (tmp2 & IOA_HARD_FAIL) { + tmp2 &= ~IOA_HARD_FAIL; + IOA_QUAD(ropenum, IOA_CONTROL) = tmp2; + } + } + } else { + if (mask & value & PCI_PCI_BRIDGE_MASTER_ABORT_EN) { + if (!(tmp1 & LBA_HARD_FAIL)) + MIO_QUAD((ropenum << 3) + LBA_PORT0_CNTRL) = + tmp1 | LBA_HARD_FAIL; + if (!(tmp2 & IOA_HARD_FAIL)) { + tmp2 |= IOA_HARD_FAIL; + IOA_QUAD(ropenum, IOA_CONTROL) = tmp2; + } + } + } + + /* Put emulation of any other P2P bridge control here */ + } + + return (current & ~mask) | (value & mask); +} + +/* Retrieves a list of the resources routed to a rope's secondary bus */ +static void +GetZX1BridgeResources(int bus, + pointer *ppIoRes, + pointer *ppMemRes, + pointer *ppPmemRes) +{ + pciConfigPtr pPCI = VerifyZX1Bus(bus); + + if (ppIoRes) { + xf86FreeResList(*ppIoRes); + *ppIoRes = + pPCI ? xf86DupResList(pZX1IoRes[pPCI->devnum & 0x07]) : NULL; + } + + if (ppMemRes) { + xf86FreeResList(*ppMemRes); + *ppMemRes = + pPCI ? xf86DupResList(pZX1MemRes[pPCI->devnum & 0x07]) : NULL; + } + + if (ppPmemRes) { + xf86FreeResList(*ppPmemRes); + *ppPmemRes = NULL; + } +} + +/* The fake bus */ +static CARD32 +zx1FakeReadLong(PCITAG tag, int offset) +{ + FatalError("zx1FakeReadLong(0x%lX, 0x%X) called\n", + (unsigned long)tag, offset); +} + +static void +zx1FakeWriteLong(PCITAG tag, int offset, CARD32 val) +{ + FatalError("zx1FakeWriteLong(0x%lX, 0x%X, 0x%08X) called\n", + (unsigned long)tag, offset, val); +} + +static void +zx1FakeSetBits(PCITAG tag, int offset, CARD32 mask, CARD32 bits) +{ + CARD32 val; + + val = zx1FakeReadLong(tag, offset); + val &= ~mask; + val |= bits; + zx1FakeWriteLong(tag, offset, val); +} + +static pciBusFuncs_t zx1FakeBusFuncs = { + zx1FakeReadLong, + zx1FakeWriteLong, + zx1FakeSetBits +}; + +static pciBusInfo_t zx1FakeBus = { + 0, /* configMech -- copied from bus 0 */ + 0, /* numDevices -- copied from bus 0 */ + FALSE, /* secondary */ + 0, /* primary_bus -- dynamically set */ +#ifdef PowerMAX_OS + 0, /* ppc_io_base -- ignored */ + 0, /* ppc_io_size -- ignored */ +#endif + &zx1FakeBusFuncs, /* funcs */ + NULL, /* pciBusPriv -- none */ + NULL, /* bridge -- dynamically set */ +}; + +void +xf86PreScanZX1(void) +{ + resRange range; + unsigned long mapSize = xf86getpagesize(); + unsigned long tmp, base, ioaaddr; + unsigned long flagsd, based, lastd, maskd, routed; + unsigned long flags0, base0, last0, mask0, route0; + unsigned long flags1, base1, last1, mask1, route1; + unsigned long flags2, base2, last2, mask2, route2; + unsigned long flags3, base3, last3, mask3, route3; + unsigned long flagsg, baseg, lastg, maskg, routeg; + unsigned long flagsl, basel, lastl; + int i, rope; + + /* Map mio registers (minimum 8k) */ + if (mapSize < MIO_SIZE) + mapSize = MIO_SIZE; + + if (!(pZX1mio = xf86MapVidMem(-1, VIDMEM_MMIO, MIO_BASE, mapSize))) + return; + + /* Look for ZX1's SBA and IOC */ + if (((MIO_LONG(MIO_FUNCTION0 + PCI_ID_REG) != + DEVID(VENDOR_HP, CHIP_ZX1_SBA)) || + (MIO_LONG(MIO_FUNCTION1 + PCI_ID_REG) != + DEVID(VENDOR_HP, CHIP_ZX1_IOC))) && + ((MIO_LONG(MIO_FUNCTION0 + PCI_ID_REG) != + DEVID(VENDOR_HP, CHIP_ZX2_SBA)) || + (MIO_LONG(MIO_FUNCTION1 + PCI_ID_REG) != + DEVID(VENDOR_HP, CHIP_ZX2_IOC)))) { + xf86UnMapVidMem(-1, pZX1mio, mapSize); + pZX1mio = NULL; + return; + } + + /* Map rope configuration space */ + ioaaddr = MIO_QUAD(ROPE_CONFIG_BASE); + if (!(ioaaddr & RANGE_ENABLE) || /* No ropes */ + ((ioaaddr = ioaaddr & ~RANGE_ENABLE) & 0x01FFFFUL) || /* Not aligned */ + !(pZX1ioa = xf86MapVidMem(-1, VIDMEM_MMIO, ioaaddr, IOA_SIZE))) { + xf86UnMapVidMem(-1, pZX1mio, mapSize); + pZX1mio = NULL; + return; + } + + for (i = 0; i < 8; i++) { + zx1_ropemap[i] = i; + zx1_lbacntl[i] = 0; + xf86FreeResList(pZX1IoRes[i]); + xf86FreeResList(pZX1MemRes[i]); + pZX1IoRes[i] = pZX1MemRes[i] = NULL; + } + + /* + * Determine which of 8 possible ropes exist in the system. This is done + * by looking at their "coupling" to generate a list of candidates, + * whittling this list down by factoring in ROPE_PAGE_CONTROL register + * contents, then poking each candidate's configuration space to determine + * its existence. + */ + tmp = MIO_QUAD(ROPE_CONFIG); + if (tmp & ROPE_D0) + zx1_ropemap[1] = 0; + if (tmp & ROPE_D2) + zx1_ropemap[3] = 2; + if (tmp & ROPE_D4) + zx1_ropemap[5] = 4; + if (tmp & ROPE_D6) + zx1_ropemap[7] = 6; + if (tmp & ROPE_Q0) + zx1_ropemap[1] = zx1_ropemap[2] = zx1_ropemap[3] = 0; + if (tmp & ROPE_Q4) + zx1_ropemap[5] = zx1_ropemap[6] = zx1_ropemap[7] = 4; + + /* + * zx2 should allow better probing support via hard-fails, so no need to + * use the ROPE_PAGE_CONTROL register. Also, zx2 always has ropes 3 & 7 + * active regardless of bundling. + */ + if (MIO_LONG(MIO_FUNCTION0 + PCI_ID_REG) != + DEVID(VENDOR_HP, CHIP_ZX2_SBA)) { + + tmp = MIO_QUAD(ROPE_PAGE_CONTROL); + for (i = 0; i < 8; i++, tmp >>= 8) + if (!(CARD8)tmp) + zx1_ropemap[i] = -1; + } else { + zx1_ropemap[3] = 3; + zx1_ropemap[7] = 7; + } + + for (i = 0; i < 8; ) { + if (zx1_ropemap[i] == i) { + + /* Prevent hard-fails */ + zx1_lbacntl[i] = MIO_QUAD((i << 3) + LBA_PORT0_CNTRL) & + ~(LBA_RESET_FUNCTION | LBA_CLEAR_ERROR); + if (zx1_lbacntl[i] & LBA_HARD_FAIL) + MIO_QUAD((i << 3) + LBA_PORT0_CNTRL) = + zx1_lbacntl[i] & ~LBA_HARD_FAIL; + + /* Poke for an ioa */ + zx1_pciids[i] = IOA_LONG(i, PCI_ID_REG); + switch (zx1_pciids[i]) { + case DEVID(VENDOR_HP, CHIP_ELROY): + case DEVID(VENDOR_HP, CHIP_ZX1_LBA): /* Mercury */ + case DEVID(VENDOR_HP, CHIP_ZX1_AGP8): /* QuickSilver */ + case DEVID(VENDOR_HP, CHIP_ZX2_LBA): + /* Expected vendor/device IDs */ + zx1_busno[i] = + (unsigned int)IOA_BYTE(i, IOA_SECONDARY_BUS); + zx1_subno[i] = + (unsigned int)IOA_BYTE(i, IOA_SUBORDINATE_BUS); + break; + + default: + if ((CARD16)(zx1_pciids[i] + 1U) > (CARD16)1U) + xf86MsgVerb(X_NOTICE, 0, + "HP ZX1: Unexpected vendor/device id 0x%08X" + " on rope %d\n", zx1_pciids[i], i); + /* Nobody home, or not the "right" kind of rope guest */ + + /* + * Restore hard-fail setting. For "active" ropes, this is done + * later. + */ + if (zx1_lbacntl[i] & LBA_HARD_FAIL) { + MIO_QUAD((i << 3) + LBA_PORT0_CNTRL) = zx1_lbacntl[i]; + zx1_lbacntl[i] = 0; + } + + /* Ignore this rope and its couplings */ + do { + zx1_ropemap[i++] = -1; + } while ((i < 8) && (zx1_ropemap[i] < i)); + continue; /* Avoid over-incrementing 'i' */ + } + } + i++; + } + + /* Determine if VGA is currently routed */ + tmp = MIO_QUAD(VGA_ROUTE); + if (tmp & VGA_ENABLE) + zx1_hasvga = TRUE; + + /* + * Decode mio resource "coarse" routing (i.e. ignoring VGA). Due to the + * rather unusual flexibility of this chipset, this is done in a number of + * stages. For each of I/O and memory, first decode the relevant registers + * to generate ranges with an associated granularity. Overlapping ranges + * are merged into a larger range with the finer granularity. Each + * original range is then more thoroughly decoded using the granularity + * associated with the merged range that contains it. The result is then + * converted into resource lists for the common layer. + * + * Note that this doesn't care whether or not read-only bits are actually + * set as documented, nor that mask bits are contiguous. This does, + * however, factor in upper limits on I/O, LMMIO anf GMMIO addresses, and + * thus assumes high-order address bits are ignored rather than decoded. + * For example, an I/O address of 0x76543210 will be treated as 0x3210 + * rather than considered out-of-range. In part, this handling is a + * consequence of the fact that high-order mask bits are zeroes instead of + * ones. + */ + + flagsd = 0; based = 0; lastd = 0; maskd = 0; routed = 0; + flags0 = 0; base0 = 0; last0 = 0; mask0 = 0; route0 = 0; + flags1 = 0; base1 = 0; last1 = 0; mask1 = 0; route1 = 0; + flags2 = 0; base2 = 0; last2 = 0; mask2 = 0; route2 = 0; + flags3 = 0; base3 = 0; last3 = 0; mask3 = 0; route3 = 0; + flagsg = 0; baseg = 0; lastg = 0; maskg = 0; routeg = 0; + flagsl = 0; basel = 0; lastl = 0; + + if ((tmp = MIO_QUAD(IOS_DIST_BASE)) & RANGE_ENABLE) { + flagsd = RANGE_ENABLE; + maskd = MIO_QUAD(IOS_DIST_MASK); + based = tmp & maskd & (~RANGE_ENABLE & IO_MASK); + lastd = based | (~maskd & IO_MASK); + routed = MIO_QUAD(IOS_DIST_ROUTE) >> 58; + SetRange(based, lastd, routed); + } + + if ((tmp = MIO_QUAD(IOS_DIR_BASE)) & RANGE_ENABLE) { + flags0 = RANGE_ENABLE; + mask0 = MIO_QUAD(IOS_DIR_MASK); + base0 = tmp & mask0 & (~RANGE_ENABLE & IO_MASK); + last0 = base0 | (~mask0 & IO_MASK); + route0 = MIO_QUAD(IOS_DIR_ROUTE) & 0x07U; + SetRange(base0, last0, 64); + } + + if (flagsd) { + i = GetRange(based); + for (tmp = based; tmp <= lastd; tmp += msk[i]) { + if ((tmp & maskd) == based) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = zx1_ropemap[(tmp >> routed) & 0x07U]; + } + } + + flagsd = 0; + } + + if (flags0) { + i = GetRange(base0); + for (tmp = base0; tmp <= last0; tmp += msk[i]) { + if ((tmp & mask0) == base0) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = zx1_ropemap[route0]; + } + } + + flags0 = 0; + } + + for (i = 0; i < nRange; i++) { + if (!pDecode[i]) + continue; + + rope = pDecode[i][0]; + for (base = tmp = 0; ++tmp < siz[i]; ) { + if (rope == pDecode[i][tmp]) + continue; + + if (rope >= 0) { + RANGE(range, (base * msk[i]) + bot[i], + (tmp * msk[i]) + bot[i] - 1UL, + RANGE_TYPE(ResExcIoBlock, 0)); + pZX1IoRes[rope] = + xf86AddResToList(pZX1IoRes[rope], &range, -1); + } + + base = tmp; + rope = pDecode[i][base]; + } + + xfree(pDecode[i]); + pDecode[i] = NULL; + } + + nRange = 0; + + /* + * Move on to CPU memory access decoding. For now, don't tell the common + * layer about CPU memory ranges that are either relocated to 0 or + * translated into PCI I/O. + */ + + SetRange(MIO_BASE, MIO_BASE + MIO_SIZE - 1UL, 64); /* mio */ + SetRange(ioaaddr, ioaaddr + ((IOA_SIZE << 1) - 1UL), 64); /* ioa */ + SetRange(PDH_START, PDH_LAST, 64); /* PDH */ + + SetRange(MIO_BASE, LMMIO_MASK, 64); /* Completeness */ + + if ((tmp = MIO_QUAD(LMMIO_DIST_BASE)) & RANGE_ENABLE) { + flagsd = RANGE_ENABLE; + maskd = MIO_QUAD(LMMIO_DIST_MASK); + based = tmp & maskd & (~RANGE_ENABLE & LMMIO_MASK); + lastd = based | (~maskd & LMMIO_MASK); + routed = MIO_QUAD(LMMIO_DIST_ROUTE) >> 58; + SetRange(based, lastd, routed); + } + + if ((tmp = MIO_QUAD(LMMIO_DIR_BASE0)) & RANGE_ENABLE) { + flags0 = RANGE_ENABLE; + mask0 = MIO_QUAD(LMMIO_DIR_MASK0); + base0 = tmp & mask0 & (~RANGE_ENABLE & LMMIO_MASK); + last0 = base0 | (~mask0 & LMMIO_MASK); + route0 = MIO_QUAD(LMMIO_DIR_ROUTE0) & 0x07U; + SetRange(base0, last0, 64); + } + + if ((tmp = MIO_QUAD(LMMIO_DIR_BASE1)) & RANGE_ENABLE) { + flags1 = RANGE_ENABLE; + mask1 = MIO_QUAD(LMMIO_DIR_MASK1); + base1 = tmp & mask1 & (~RANGE_ENABLE & LMMIO_MASK); + last1 = base1 | (~mask1 & LMMIO_MASK); + route1 = MIO_QUAD(LMMIO_DIR_ROUTE1) & 0x07U; + SetRange(base1, last1, 64); + } + + if ((tmp = MIO_QUAD(LMMIO_DIR_BASE2)) & RANGE_ENABLE) { + flags2 = RANGE_ENABLE; + mask2 = MIO_QUAD(LMMIO_DIR_MASK2); + base2 = tmp & mask2 & (~RANGE_ENABLE & LMMIO_MASK); + last2 = base2 | (~mask2 & LMMIO_MASK); + route2 = MIO_QUAD(LMMIO_DIR_ROUTE2) & 0x07U; + SetRange(base2, last2, 64); + } + + if ((tmp = MIO_QUAD(LMMIO_DIR_BASE3)) & RANGE_ENABLE) { + flags3 = RANGE_ENABLE; + mask3 = MIO_QUAD(LMMIO_DIR_MASK3); + base3 = tmp & mask3 & (~RANGE_ENABLE & LMMIO_MASK); + last3 = base3 | (~mask3 & LMMIO_MASK); + route3 = MIO_QUAD(LMMIO_DIR_ROUTE3) & 0x07U; + SetRange(base3, last3, 64); + } + + if ((tmp = MIO_QUAD(GMMIO_DIST_BASE)) & RANGE_ENABLE) { + flagsg = tmp & (RANGE_ENABLE | PORT_DISABLE | MAP_TO_LMMIO); + maskg = MIO_QUAD(GMMIO_DIST_MASK); + baseg = tmp & maskg & + (~(RANGE_ENABLE | PORT_DISABLE | MAP_TO_LMMIO) & GMMIO_MASK); + lastg = baseg | (~maskg & GMMIO_MASK); + tmp = routeg = MIO_QUAD(GMMIO_DIST_ROUTE) >> 58; + if (!(flagsg & (PORT_DISABLE & MAP_TO_LMMIO)) && (tmp > 26)) + tmp = 26; + SetRange(baseg, lastg, tmp); + } + + if ((tmp = MIO_QUAD(IOS_BASE)) & RANGE_ENABLE) { + flagsl = RANGE_ENABLE; + basel = tmp & (~RANGE_ENABLE & GMMIO_MASK); + lastl = basel | 0x001FFFFFUL; + SetRange(basel, lastl, 64); + } + + if (flagsd) { + i = GetRange(based); + for (tmp = based; tmp <= lastd; tmp += msk[i]) { + if ((tmp & maskd) == based) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = zx1_ropemap[(tmp >> routed) & 0x07U]; + } + } + + flagsd = 0; + } + + /* LMMIO distributed range does not address anything beyond 0xFED00000 */ + i = GetRange(MIO_BASE); + for (tmp = MIO_BASE; tmp <= LMMIO_MASK; tmp += msk[i]) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = -1; + } + + /* Dillon space can sometimes be redirected to rope 0 */ + tmp = MIO_QUAD(STATUS_CONTROL); + if (!(tmp & DILLON_PRESENT)) { + i = GetRange(PDH_START); + for (tmp = PDH_START; tmp <= PDH_LAST; tmp += msk[i]) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = zx1_ropemap[0]; + } + } + + if (flagsg) { + unsigned long mask = (0x07UL << routeg) | maskg; + + i = GetRange(baseg); + for (tmp = baseg; tmp <= lastg; tmp += msk[i]) { + if ((tmp & maskg) == baseg) { + base = (tmp - bot[i]) / msk[i]; + + if ((flagsg & MAP_TO_LMMIO) || + (!(flagsg & PORT_DISABLE) && + (tmp <= ((tmp & mask) | 0x03FFFFFFUL)))) { + pDecode[i][base] = -1; + } else { + pDecode[i][base] = zx1_ropemap[(tmp >> routeg) & 0x07U]; + } + } + } + + flagsg = 0; + } + + if (flagsl) { + i = GetRange(basel); + for (tmp = basel; tmp <= lastl; tmp += msk[i]) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = -1; + } + + flagsl = 0; + } + + /* For now, assume directed LMMIO ranges don't overlap with each other */ + if (flags0) { + i = GetRange(base0); + for (tmp = base0; tmp <= last0; tmp += msk[i]) { + if ((tmp & mask0) == base0) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = zx1_ropemap[route0]; + } + } + + flags0 = 0; + } + + if (flags1) { + i = GetRange(base1); + for (tmp = base1; tmp <= last1; tmp += msk[i]) { + if ((tmp & mask1) == base1) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = zx1_ropemap[route1]; + } + } + + flags1 = 0; + } + + if (flags2) { + i = GetRange(base2); + for (tmp = base2; tmp <= last2; tmp += msk[i]) { + if ((tmp & mask2) == base2) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = zx1_ropemap[route2]; + } + } + + flags2 = 0; + } + + if (flags3) { + i = GetRange(base3); + for (tmp = base3; tmp <= last3; tmp += msk[i]) { + if ((tmp & mask3) == base3) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = zx1_ropemap[route3]; + } + } + + flags3 = 0; + } + + /* Claim iao config area */ + i = GetRange(ioaaddr); + for (tmp = ioaaddr; tmp < ioaaddr + (IOA_SIZE << 1); tmp += msk[i]) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = -1; + } + + /* Claim mio config area */ + i = GetRange(MIO_BASE); + for (tmp = MIO_BASE; tmp < (MIO_BASE + MIO_SIZE); tmp += msk[i]) { + base = (tmp - bot[i]) / msk[i]; + pDecode[i][base] = -1; + } + + for (i = 0; i < nRange; i++) { + if (!pDecode[i]) + continue; + + rope = pDecode[i][0]; + for (base = tmp = 0; ++tmp < siz[i]; ) { + if (rope == pDecode[i][tmp]) + continue; + + if (rope >= 0) { + RANGE(range, (base * msk[i]) + bot[i], + (tmp * msk[i]) + bot[i] - 1UL, + RANGE_TYPE(ResExcMemBlock, 0)); + pZX1MemRes[rope] = + xf86AddResToList(pZX1MemRes[rope], &range, -1); + } + + base = tmp; + rope = pDecode[i][base]; + } + + xfree(pDecode[i]); + pDecode[i] = NULL; + } + + nRange = 0; + + return; +} + +/* This is called to finalise the results of a PCI bus scan */ +void +xf86PostScanZX1(void) +{ + pciConfigPtr pPCI, *ppPCI, *ppPCI2; + pciBusInfo_t *pBusInfo; + int i, idx; + + if (!pZX1mio) + return; + + (void)memset(zx1_busnmpt, FALSE, sizeof(zx1_busnmpt)); + pBusInfo = pciBusInfo[0]; + + /* + * Certain 2.4 & 2.5 Linux kernels add fake PCI devices. Remove them to + * prevent any possible interference with our PCI validation. + * + * Also, if VGA isn't routed on server entry, determine if VGA routing + * needs to be enabled while the server is running. + */ + idx = 0; + ppPCI = ppPCI2 = xf86scanpci(0); /* Recursion is only apparent */ + while ((pPCI = *ppPCI2++)) { + switch (pPCI->pci_device_vendor) { + case DEVID(VENDOR_HP, CHIP_ELROY): + case DEVID(VENDOR_HP, CHIP_ZX1_SBA): /* Pluto function 0 */ + case DEVID(VENDOR_HP, CHIP_ZX1_IOC): /* Pluto function 1 */ + case DEVID(VENDOR_HP, CHIP_ZX1_LBA): /* Mercury */ + case DEVID(VENDOR_HP, CHIP_ZX1_AGP8): /* QuickSilver */ + case DEVID(VENDOR_HP, CHIP_ZX2_SBA): + case DEVID(VENDOR_HP, CHIP_ZX2_IOC): + case DEVID(VENDOR_HP, CHIP_ZX2_LBA): + xfree(pPCI); /* Remove it */ + continue; + + default: + *ppPCI++ = pPCI; + idx++; + + zx1_busnmpt[pPCI->busnum] = TRUE; + + if (zx1_hasvga) + continue; + + switch (pPCI->pci_base_class) { + case PCI_CLASS_PREHISTORIC: + if (pPCI->pci_sub_class == PCI_SUBCLASS_PREHISTORIC_VGA) + break; + continue; + + case PCI_CLASS_DISPLAY: + if (pPCI->pci_sub_class == PCI_SUBCLASS_DISPLAY_VGA) + break; + continue; + + default: + continue; + } + + zx1_hasvga = TRUE; + continue; + } + } + + /* + * Restore hard-fail settings and figure out the actual secondary and + * subordinate bus numbers. + */ + for (i = 0; i < 8; i++) { + if (zx1_ropemap[i] != i) + continue; + + if (zx1_lbacntl[i] & LBA_HARD_FAIL) + MIO_QUAD((i << 3) + LBA_PORT0_CNTRL) = zx1_lbacntl[i]; + + while ((zx1_busno[i] < zx1_subno[i]) && !pciBusInfo[zx1_subno[i]]) + zx1_subno[i]--; + + if (zx1_fakebus <= zx1_subno[i]) + zx1_fakebus = zx1_subno[i] + 1; + + while (!zx1_busnmpt[zx1_busno[i]]) { + if (zx1_busno[i]) /* Info for bus zero is in static storage */ + xfree(pciBusInfo[zx1_busno[i]]); + pciBusInfo[zx1_busno[i]++] = NULL; + if (zx1_busno[i] > zx1_subno[i]) + break; + } + } + + if (zx1_fakebus >= pciNumBuses) { + if (zx1_fakebus >= pciMaxBusNum) + FatalError("HP ZX1: No room for fake PCI bus\n"); + pciNumBuses = zx1_fakebus + 1; + } + + /* Set up our extra bus functions */ + zx1BusFuncs = *(pBusInfo->funcs); + zx1BusFuncs.pciControlBridge = ControlZX1Bridge; + zx1BusFuncs.pciGetBridgeResources = GetZX1BridgeResources; + + /* Set up our own fake bus to act as the root segment */ + zx1FakeBus.configMech = pBusInfo->configMech; + zx1FakeBus.numDevices = pBusInfo->numDevices; + zx1FakeBus.primary_bus = zx1_fakebus; + pciBusInfo[zx1_fakebus] = &zx1FakeBus; + + /* Add the fake bus' host bridge */ + if (++idx >= MAX_PCI_DEVICES) + FatalError("HP ZX1: No room for fake Host-to-PCI bridge\n"); + *ppPCI++ = zx1FakeBus.bridge = pPCI = xnfcalloc(1, sizeof(pciDevice)); + pPCI->tag = PCI_MAKE_TAG(zx1_fakebus, 0, 0); + pPCI->busnum = zx1_fakebus; + /* pPCI->devnum = pPCI->funcnum = 0; */ + pPCI->pci_device_vendor = DEVID(VENDOR_HP, CHIP_ZX1_SBA); + pPCI->pci_base_class = PCI_CLASS_BRIDGE; + /* pPCI->pci_sub_class = PCI_SUBCLASS_BRIDGE_HOST; */ + pPCI->fakeDevice = TRUE; + +#ifdef OLD_FORMAT + xf86MsgVerb(X_INFO, 2, "PCI: BusID 0x%.2x,0x%02x,0x%1x " + "ID 0x%04x,0x%04x Rev 0x%02x Class 0x%02x,0x%02x\n", + pPCI->busnum, pPCI->devnum, pPCI->funcnum, + pPCI->pci_vendor, pPCI->pci_device, pPCI->pci_rev_id, + pPCI->pci_base_class, pPCI->pci_sub_class); +#else + xf86MsgVerb(X_INFO, 2, "PCI: %.2x:%02x:%1x: chip %04x,%04x" + " card %04x,%04x rev %02x class %02x,%02x,%02x hdr %02x\n", + pPCI->busnum, pPCI->devnum, pPCI->funcnum, + pPCI->pci_vendor, pPCI->pci_device, + pPCI->pci_subsys_vendor, pPCI->pci_subsys_card, + pPCI->pci_rev_id, pPCI->pci_base_class, + pPCI->pci_sub_class, pPCI->pci_prog_if, + pPCI->pci_header_type); +#endif + + /* Add a fake PCI-to-PCI bridge to represent each active rope */ + for (i = 0; i < 8; i++) { + if ((zx1_ropemap[i] != i) || (zx1_busno[i] > zx1_subno[i]) || + !(pBusInfo = pciBusInfo[zx1_busno[i]])) + continue; + + if (++idx >= MAX_PCI_DEVICES) + FatalError("HP ZX1: No room for fake PCI-to-PCI bridge\n"); + *ppPCI++ = pPCI = xnfcalloc(1, sizeof(pciDevice)); + pPCI->busnum = zx1_fakebus; + pPCI->devnum = i | 0x10; + /* pPCI->funcnum = 0; */ + pPCI->tag = PCI_MAKE_TAG(zx1_fakebus, pPCI->devnum, 0); + pPCI->pci_device_vendor = zx1_pciids[i]; + pPCI->pci_base_class = PCI_CLASS_BRIDGE; + pPCI->pci_sub_class = PCI_SUBCLASS_BRIDGE_PCI; + pPCI->pci_header_type = 1; + pPCI->pci_primary_bus_number = zx1_fakebus; + pPCI->pci_secondary_bus_number = zx1_busno[i]; + pPCI->pci_subordinate_bus_number = zx1_subno[i]; + pPCI->fakeDevice = TRUE; + + pBusInfo->bridge = pPCI; + pBusInfo->secondary = TRUE; + pBusInfo->primary_bus = zx1_fakebus; + + /* Plug in chipset routines */ + pBusInfo->funcs = &zx1BusFuncs; + + /* Set bridge control register for scanpci utility */ + pPCI->pci_bridge_control = ControlZX1Bridge(zx1_busno[i], 0, 0); + +#ifdef OLD_FORMAT + xf86MsgVerb(X_INFO, 2, "PCI: BusID 0x%.2x,0x%02x,0x%1x " + "ID 0x%04x,0x%04x Rev 0x%02x Class 0x%02x,0x%02x\n", + pPCI->busnum, pPCI->devnum, pPCI->funcnum, + pPCI->pci_vendor, pPCI->pci_device, pPCI->pci_rev_id, + pPCI->pci_base_class, pPCI->pci_sub_class); +#else + xf86MsgVerb(X_INFO, 2, "PCI: %.2x:%02x:%1x: chip %04x,%04x" + " card %04x,%04x rev %02x class %02x,%02x,%02x hdr %02x\n", + pPCI->busnum, pPCI->devnum, pPCI->funcnum, + pPCI->pci_vendor, pPCI->pci_device, + pPCI->pci_subsys_vendor, pPCI->pci_subsys_card, + pPCI->pci_rev_id, pPCI->pci_base_class, + pPCI->pci_sub_class, pPCI->pci_prog_if, + pPCI->pci_header_type); +#endif + } + + *ppPCI = NULL; /* Terminate array */ +} -- cgit v1.2.3