pci_pir.c revision 26159
126159Sse/* 226159Sse * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 326159Sse * All rights reserved. 426159Sse * 526159Sse * Redistribution and use in source and binary forms, with or without 626159Sse * modification, are permitted provided that the following conditions 726159Sse * are met: 826159Sse * 1. Redistributions of source code must retain the above copyright 926159Sse * notice unmodified, this list of conditions, and the following 1026159Sse * disclaimer. 1126159Sse * 2. Redistributions in binary form must reproduce the above copyright 1226159Sse * notice, this list of conditions and the following disclaimer in the 1326159Sse * documentation and/or other materials provided with the distribution. 1426159Sse * 1526159Sse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1626159Sse * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1726159Sse * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1826159Sse * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1926159Sse * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2026159Sse * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2126159Sse * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2226159Sse * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2326159Sse * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2426159Sse * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2526159Sse * 2626159Sse * $Id$ 2726159Sse * 2826159Sse */ 296104Sse 3026159Sse#include <sys/types.h> 316734Sbde#include <sys/systm.h> 326734Sbde 3326159Sse#include <pci/pcireg.h> 346104Sse#include <pci/pcivar.h> 3526159Sse#include <i386/isa/pcibus.h> 366104Sse 3726159Sse#ifdef PCI_COMPAT 3826159Sse/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ 3926159Sse#define cfgmech pci_mechanism 4026159Sseint cfgmech; 4126159Sse#else 4226159Ssestatic int cfgmech; 4326159Sse#endif /* PCI_COMPAT */ 4426159Ssestatic int devmax; 456104Sse 4626159Sse/* enable configuration space accesses and return data port address */ 4726159Sse 4810887Ssestatic int 4926159Ssepci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 5026159Sse{ 5126159Sse int dataport = 0; 5210887Sse 5326159Sse if (bus <= PCI_BUSMAX 5426159Sse && slot < devmax 5526159Sse && func <= PCI_FUNCMAX 5626159Sse && reg <= PCI_REGMAX 5726159Sse && bytes != 3 5826159Sse && (unsigned) bytes <= 4 5926159Sse && (reg & (bytes -1)) == 0) { 6026159Sse switch (cfgmech) { 6126159Sse case 1: 6226159Sse outl(CONF1_ADDR_PORT, 6326159Sse (bus << 16) | (slot << 11) | (func << 8) | reg); 6426159Sse dataport = CONF1_DATA_PORT; 6526159Sse break; 6626159Sse case 2: 6726159Sse outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 6826159Sse outb(CONF2_FORWARD_PORT, bus); 6926159Sse dataport = 0xc000 | (slot << 8) | reg; 7026159Sse break; 7126159Sse } 7226159Sse } 7326159Sse return (dataport); 7426159Sse} 756104Sse 7626159Sse/* disable configuration space accesses */ 776104Sse 786104Ssestatic void 7926159Ssepci_cfgdisable(void) 8026159Sse{ 8126159Sse switch (cfgmech) { 8226159Sse case 1: 8326159Sse outl(CONF1_ADDR_PORT, 0); 8426159Sse break; 8526159Sse case 2: 8626159Sse outb(CONF2_ENABLE_PORT, 0); 8726159Sse outb(CONF2_FORWARD_PORT, 0); 8826159Sse break; 8926159Sse } 9026159Sse} 916104Sse 9226159Sse/* read configuration space register */ 936104Sse 9426159Sseint 9526159Ssepci_cfgread(pcicfgregs *cfg, int reg, int bytes) 9626159Sse{ 9726159Sse int data = -1; 9826159Sse int port; 997234Sse 10026159Sse port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 1017234Sse 10226159Sse if (port != 0) { 10326159Sse switch (bytes) { 10426159Sse case 1: 10526159Sse data = inb(port); 10626159Sse break; 10726159Sse case 2: 10826159Sse data = inw(port); 10926159Sse break; 11026159Sse case 4: 11126159Sse data = inl(port); 11226159Sse break; 11326159Sse } 11426159Sse pci_cfgdisable(); 11526159Sse } 11626159Sse return (data); 11726159Sse} 1187234Sse 11926159Sse/* write configuration space register */ 1206104Sse 12126159Ssevoid 12226159Ssepci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 12326159Sse{ 12426159Sse int port; 1256104Sse 12626159Sse port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 12726159Sse if (port != 0) { 12826159Sse switch (bytes) { 12926159Sse case 1: 13026159Sse outb(port, data); 13126159Sse break; 13226159Sse case 2: 13326159Sse outw(port, data); 13426159Sse break; 13526159Sse case 4: 13626159Sse outl(port, data); 13726159Sse break; 13826159Sse } 13926159Sse pci_cfgdisable(); 14026159Sse } 14126159Sse} 1426104Sse 14326159Sse/* check whether the configuration mechanism has been correct identified */ 1446104Sse 14510887Ssestatic int 14626159Ssepci_cfgcheck(int maxdev) 14710887Sse{ 14810887Sse u_char device; 14910735Sse 15026159Sse if (bootverbose) 15126159Sse printf("pci_cfgcheck:\tdevice "); 15210960Sse 15326159Sse for (device = 0; device < maxdev; device++) { 15426159Sse unsigned id, class, header; 15511378Sse if (bootverbose) 15626159Sse printf("%d ", device); 15726159Sse 15826159Sse id = inl(pci_cfgenable(0, device, 0, 0, 4)); 15926159Sse if (id == 0 || id == -1) 16023415Sse continue; 16123415Sse 16226159Sse class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 16323415Sse if (bootverbose) 16426159Sse printf("[class=%06x] ", class); 16526159Sse if (class == 0 || (class & 0xf8f0ff) != 0) 16623415Sse continue; 16723415Sse 16826159Sse header = inb(pci_cfgenable(0, device, 0, 14, 1)); 16923415Sse if (bootverbose) 17026159Sse printf("[hdr=%02x] ", header); 17126159Sse if ((header & 0x7e) != 0) 17223415Sse continue; 17323415Sse 17426159Sse if (bootverbose) 17526159Sse printf("is there (id=%08x)\n", id); 17626159Sse 17726159Sse pci_cfgdisable(); 17826159Sse return (1); 17910887Sse } 18011378Sse if (bootverbose) 18126159Sse printf("-- nothing found\n"); 18226159Sse 18326159Sse pci_cfgdisable(); 18426159Sse return (0); 18510887Sse} 18610887Sse 18726159Sseint 18826159Ssepci_cfgopen(void) 1896104Sse{ 19011524Sse unsigned long mode1res,oldval1; 19111524Sse unsigned char mode2res,oldval2; 1926104Sse 19326159Sse oldval1 = inl(CONF1_ADDR_PORT); 19410960Sse 19510960Sse if (bootverbose) { 19626159Sse printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 19726159Sse oldval1); 19810960Sse } 19910960Sse 20011544Sse if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 20110960Sse 20226159Sse cfgmech = 1; 20326159Sse devmax = 32; 20410960Sse 20526159Sse outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 20626159Sse outb(CONF1_ADDR_PORT +3, 0); 20726159Sse mode1res = inl(CONF1_ADDR_PORT); 20826159Sse outl(CONF1_ADDR_PORT, oldval1); 20910960Sse 21011524Sse if (bootverbose) 21126159Sse printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 21226159Sse mode1res, CONF1_ENABLE_CHK); 2136104Sse 21411524Sse if (mode1res) { 21526159Sse if (pci_cfgcheck(32)) 21626159Sse return (cfgmech); 21726159Sse } 21810960Sse 21926159Sse outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 22011524Sse mode1res = inl(CONF1_ADDR_PORT); 22126159Sse outl(CONF1_ADDR_PORT, oldval1); 2226104Sse 22311524Sse if (bootverbose) 22426159Sse printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 22526159Sse mode1res, CONF1_ENABLE_CHK1); 2269360Sse 22711524Sse if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 22826159Sse if (pci_cfgcheck(32)) 22926159Sse return (cfgmech); 23026159Sse } 23111524Sse } 23210807Sse 23326159Sse oldval2 = inb(CONF2_ENABLE_PORT); 23410887Sse 23511524Sse if (bootverbose) { 23626159Sse printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 23726159Sse oldval2); 23811524Sse } 23910887Sse 24011524Sse if ((oldval2 & 0xf0) == 0) { 24110887Sse 24226159Sse cfgmech = 2; 24326159Sse devmax = 16; 24426159Sse 24526159Sse outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 24611524Sse mode2res = inb(CONF2_ENABLE_PORT); 24726159Sse outb(CONF2_ENABLE_PORT, oldval2); 24811524Sse 24911524Sse if (bootverbose) 25026159Sse printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 25126159Sse mode2res, CONF2_ENABLE_CHK); 25211524Sse 25311524Sse if (mode2res == CONF2_ENABLE_RES) { 25426159Sse if (bootverbose) 25526159Sse printf("pci_open(2a):\tnow trying mechanism 2\n"); 25611524Sse 25726159Sse if (pci_cfgcheck(16)) 25826159Sse return (cfgmech); 25911524Sse } 26011524Sse } 26111524Sse 26226159Sse cfgmech = 0; 26326159Sse devmax = 0; 26426159Sse return (cfgmech); 2656104Sse} 266