pci_pir.c revision 26173
143412Snewton/* 243412Snewton * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 343412Snewton * All rights reserved. 443412Snewton * 543412Snewton * Redistribution and use in source and binary forms, with or without 643412Snewton * modification, are permitted provided that the following conditions 743412Snewton * are met: 843412Snewton * 1. Redistributions of source code must retain the above copyright 943412Snewton * notice unmodified, this list of conditions, and the following 1043412Snewton * disclaimer. 1143412Snewton * 2. Redistributions in binary form must reproduce the above copyright 1243412Snewton * notice, this list of conditions and the following disclaimer in the 1343412Snewton * documentation and/or other materials provided with the distribution. 1443412Snewton * 1543412Snewton * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1643412Snewton * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1743412Snewton * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1843412Snewton * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1943412Snewton * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2043412Snewton * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2143412Snewton * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2243412Snewton * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2343412Snewton * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2443412Snewton * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2543412Snewton * 2643412Snewton * $Id: pcibus.c,v 1.37 1997/05/26 21:11:05 se Exp $ 2749267Snewton * 2850477Speter */ 2943412Snewton 3043412Snewton#include <sys/types.h> 3143412Snewton#include <sys/systm.h> 3243412Snewton 3343412Snewton#include <pci/pcireg.h> 3443412Snewton#include <pci/pcivar.h> 3543412Snewton#include <i386/isa/pcibus.h> 3643412Snewton 3743412Snewton#ifdef PCI_COMPAT 3843412Snewton/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ 3943412Snewton#define cfgmech pci_mechanism 4043412Snewtonint cfgmech; 4143412Snewton#else 4243499Snewtonstatic int cfgmech; 4343412Snewton#endif /* PCI_COMPAT */ 4443412Snewtonstatic int devmax; 4543412Snewton 4643412Snewton/* enable configuration space accesses and return data port address */ 4743412Snewton 4843412Snewtonstatic int 4943412Snewtonpci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 5043412Snewton{ 5143412Snewton int dataport = 0; 5243412Snewton 5343412Snewton if (bus <= PCI_BUSMAX 5443412Snewton && slot < devmax 5543412Snewton && func <= PCI_FUNCMAX 5643412Snewton && reg <= PCI_REGMAX 5743412Snewton && bytes != 3 5843412Snewton && (unsigned) bytes <= 4 5943412Snewton && (reg & (bytes -1)) == 0) { 6043412Snewton switch (cfgmech) { 6143412Snewton case 1: 6243412Snewton outl(CONF1_ADDR_PORT, (1 << 31) | 6343412Snewton (bus << 16) | (slot << 11) | (func << 8) | reg); 6443412Snewton dataport = CONF1_DATA_PORT; 6565302Sobrien break; 6665302Sobrien case 2: 6765302Sobrien outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 6865302Sobrien outb(CONF2_FORWARD_PORT, bus); 6965302Sobrien dataport = 0xc000 | (slot << 8) | reg; 7065302Sobrien break; 7165302Sobrien } 7265302Sobrien } 7365302Sobrien return (dataport); 7465302Sobrien} 7565302Sobrien 7665302Sobrien/* disable configuration space accesses */ 7765302Sobrien 7843412Snewtonstatic void 7943412Snewtonpci_cfgdisable(void) 8043412Snewton{ 8143412Snewton switch (cfgmech) { 8243412Snewton case 1: 8371452Sjhb outl(CONF1_ADDR_PORT, 0); 8471452Sjhb break; 8571452Sjhb case 2: 8643412Snewton outb(CONF2_ENABLE_PORT, 0); 8743412Snewton outb(CONF2_FORWARD_PORT, 0); 8843412Snewton break; 8943412Snewton } 9043412Snewton} 9143412Snewton 9243412Snewton/* read configuration space register */ 9343412Snewton 9443412Snewtonint 9543412Snewtonpci_cfgread(pcicfgregs *cfg, int reg, int bytes) 9643412Snewton{ 9743412Snewton int data = -1; 9843412Snewton int port; 9943412Snewton 10043412Snewton port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 10143412Snewton 10243412Snewton if (port != 0) { 10343412Snewton switch (bytes) { 10443412Snewton case 1: 10543412Snewton data = inb(port); 10643412Snewton break; 10743412Snewton case 2: 10843412Snewton data = inw(port); 10943412Snewton break; 11043412Snewton case 4: 11143412Snewton data = inl(port); 11243412Snewton break; 11343412Snewton } 11443412Snewton pci_cfgdisable(); 11543412Snewton } 11643412Snewton return (data); 11743412Snewton} 11843412Snewton 11943412Snewton/* write configuration space register */ 12043412Snewton 12143412Snewtonvoid 12243412Snewtonpci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 12343412Snewton{ 12443412Snewton int port; 12543412Snewton 12643412Snewton port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 12743412Snewton if (port != 0) { 12843412Snewton switch (bytes) { 12943412Snewton case 1: 13043412Snewton outb(port, data); 13143412Snewton break; 13243412Snewton case 2: 13343412Snewton outw(port, data); 13443412Snewton break; 13543412Snewton case 4: 13643412Snewton outl(port, data); 13743412Snewton break; 13843412Snewton } 13943412Snewton pci_cfgdisable(); 14043412Snewton } 14143412Snewton} 14243412Snewton 14343412Snewton/* check whether the configuration mechanism has been correct identified */ 14443412Snewton 14543412Snewtonstatic int 14643412Snewtonpci_cfgcheck(int maxdev) 14743412Snewton{ 14843412Snewton u_char device; 14943412Snewton 15043412Snewton if (bootverbose) 15143412Snewton printf("pci_cfgcheck:\tdevice "); 15243412Snewton 15351793Smarcel for (device = 0; device < maxdev; device++) { 15443412Snewton unsigned id, class, header; 15543412Snewton if (bootverbose) 15643412Snewton printf("%d ", device); 15751793Smarcel 15843412Snewton id = inl(pci_cfgenable(0, device, 0, 0, 4)); 15943412Snewton if (id == 0 || id == -1) 16043412Snewton continue; 16143412Snewton 16243412Snewton class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 16343412Snewton if (bootverbose) 16443412Snewton printf("[class=%06x] ", class); 16543412Snewton if (class == 0 || (class & 0xf8f0ff) != 0) 16643412Snewton continue; 16743412Snewton 16843412Snewton header = inb(pci_cfgenable(0, device, 0, 14, 1)); 16943412Snewton if (bootverbose) 17043412Snewton printf("[hdr=%02x] ", header); 17143412Snewton if ((header & 0x7e) != 0) 17243412Snewton continue; 17343412Snewton 17443412Snewton if (bootverbose) 17543412Snewton printf("is there (id=%08x)\n", id); 17643412Snewton 17743412Snewton pci_cfgdisable(); 17843412Snewton return (1); 17943412Snewton } 18043412Snewton if (bootverbose) 18143412Snewton printf("-- nothing found\n"); 18243412Snewton 18343412Snewton pci_cfgdisable(); 18443412Snewton return (0); 18543412Snewton} 18643412Snewton 18743412Snewtonint 18843412Snewtonpci_cfgopen(void) 18943412Snewton{ 19043412Snewton unsigned long mode1res,oldval1; 19143412Snewton unsigned char mode2res,oldval2; 19243412Snewton 19343412Snewton oldval1 = inl(CONF1_ADDR_PORT); 19443412Snewton 19543412Snewton if (bootverbose) { 19643412Snewton printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 19743412Snewton oldval1); 19843412Snewton } 19943412Snewton 20043412Snewton if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 20143412Snewton 20243412Snewton cfgmech = 1; 20343412Snewton devmax = 32; 20443412Snewton 20543412Snewton outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 20643412Snewton outb(CONF1_ADDR_PORT +3, 0); 20743412Snewton mode1res = inl(CONF1_ADDR_PORT); 20843412Snewton outl(CONF1_ADDR_PORT, oldval1); 20943412Snewton 21043412Snewton if (bootverbose) 21143412Snewton printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 21243412Snewton mode1res, CONF1_ENABLE_CHK); 21343412Snewton 21443412Snewton if (mode1res) { 21543412Snewton if (pci_cfgcheck(32)) 21643412Snewton return (cfgmech); 21743412Snewton } 21843412Snewton 21943412Snewton outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 22043412Snewton mode1res = inl(CONF1_ADDR_PORT); 22143412Snewton outl(CONF1_ADDR_PORT, oldval1); 22243412Snewton 22343412Snewton if (bootverbose) 22443412Snewton printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 22543412Snewton mode1res, CONF1_ENABLE_CHK1); 22643412Snewton 22743412Snewton if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 22843412Snewton if (pci_cfgcheck(32)) 22943412Snewton return (cfgmech); 23054494Snewton } 23143412Snewton } 23254494Snewton 23354494Snewton oldval2 = inb(CONF2_ENABLE_PORT); 23454494Snewton 23543412Snewton if (bootverbose) { 23643412Snewton printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 23743412Snewton oldval2); 23843412Snewton } 23943412Snewton 24043412Snewton if ((oldval2 & 0xf0) == 0) { 24154494Snewton 24243412Snewton cfgmech = 2; 24354494Snewton devmax = 16; 24454494Snewton 24554494Snewton outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 24654494Snewton mode2res = inb(CONF2_ENABLE_PORT); 24743412Snewton outb(CONF2_ENABLE_PORT, oldval2); 24843412Snewton 24943412Snewton if (bootverbose) 25054494Snewton printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 25171452Sjhb mode2res, CONF2_ENABLE_CHK); 25254494Snewton 25354494Snewton if (mode2res == CONF2_ENABLE_RES) { 25454494Snewton if (bootverbose) 25554494Snewton printf("pci_open(2a):\tnow trying mechanism 2\n"); 25654494Snewton 25743412Snewton if (pci_cfgcheck(16)) 25854494Snewton return (cfgmech); 25954494Snewton } 26054494Snewton } 26143412Snewton 26254494Snewton cfgmech = 0; 26343412Snewton devmax = 0; 26443412Snewton return (cfgmech); 26543412Snewton} 26643412Snewton