pci_cfgreg.c revision 26173
15897Sjmz/* 25897Sjmz * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 35897Sjmz * All rights reserved. 45897Sjmz * 55897Sjmz * Redistribution and use in source and binary forms, with or without 65897Sjmz * modification, are permitted provided that the following conditions 75897Sjmz * are met: 85897Sjmz * 1. Redistributions of source code must retain the above copyright 95897Sjmz * notice unmodified, this list of conditions, and the following 105897Sjmz * disclaimer. 115897Sjmz * 2. Redistributions in binary form must reproduce the above copyright 125897Sjmz * notice, this list of conditions and the following disclaimer in the 135897Sjmz * documentation and/or other materials provided with the distribution. 145897Sjmz * 1597748Sschweikh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 165897Sjmz * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 175897Sjmz * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 185897Sjmz * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 195897Sjmz * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 205897Sjmz * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 215897Sjmz * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 225897Sjmz * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 235897Sjmz * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 245897Sjmz * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 255897Sjmz * 265897Sjmz * $Id: pcibus.c,v 1.37 1997/05/26 21:11:05 se Exp $ 275897Sjmz * 285897Sjmz */ 295897Sjmz 30119418Sobrien#include <sys/types.h> 31119418Sobrien#include <sys/systm.h> 32119418Sobrien 337430Sbde#include <pci/pcireg.h> 347430Sbde#include <pci/pcivar.h> 3512675Sjulian#include <i386/isa/pcibus.h> 3634924Sbde 3754156Speter#ifdef PCI_COMPAT 3854156Speter/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ 3954156Speter#define cfgmech pci_mechanism 4054156Speterint cfgmech; 4154156Speter#else 4254156Speterstatic int cfgmech; 4354156Speter#endif /* PCI_COMPAT */ 4454156Speterstatic int devmax; 4587384Simp 466734Sbde/* enable configuration space accesses and return data port address */ 478876Srgrimes 485897Sjmzstatic int 495897Sjmzpci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 505897Sjmz{ 515897Sjmz int dataport = 0; 525897Sjmz 535897Sjmz if (bus <= PCI_BUSMAX 545897Sjmz && slot < devmax 555897Sjmz && func <= PCI_FUNCMAX 565897Sjmz && reg <= PCI_REGMAX 57183397Sed && bytes != 3 585897Sjmz && (unsigned) bytes <= 4 595897Sjmz && (reg & (bytes -1)) == 0) { 605897Sjmz switch (cfgmech) { 615897Sjmz case 1: 6212675Sjulian outl(CONF1_ADDR_PORT, (1 << 31) | 6312675Sjulian (bus << 16) | (slot << 11) | (func << 8) | reg); 6412675Sjulian dataport = CONF1_DATA_PORT; 6512675Sjulian break; 6612675Sjulian case 2: 6747625Sphk outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 68126080Sphk outb(CONF2_FORWARD_PORT, bus); 69126080Sphk dataport = 0xc000 | (slot << 8) | reg; 70111815Sphk break; 71111815Sphk } 72111815Sphk } 73111815Sphk return (dataport); 74111815Sphk} 7547625Sphk 7612675Sjulian/* disable configuration space accesses */ 7789086Simp 785897Sjmzstatic void 7987384Simppci_cfgdisable(void) 8087384Simp{ 815897Sjmz switch (cfgmech) { 825897Sjmz case 1: 8354156Speter outl(CONF1_ADDR_PORT, 0); 8487384Simp break; 8587384Simp case 2: 8687384Simp outb(CONF2_ENABLE_PORT, 0); 8787384Simp outb(CONF2_FORWARD_PORT, 0); 8887384Simp break; 8954156Speter } 905897Sjmz} 9187384Simp 925897Sjmz/* read configuration space register */ 935897Sjmz 945897Sjmzint 9587384Simppci_cfgread(pcicfgregs *cfg, int reg, int bytes) 9687384Simp{ 975897Sjmz int data = -1; 9887384Simp int port; 9987384Simp 1005897Sjmz port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 10187384Simp 102127135Snjl if (port != 0) { 103152249Sjylefort switch (bytes) { 10487384Simp case 1: 10587384Simp data = inb(port); 10687384Simp break; 10787384Simp case 2: 10887384Simp data = inw(port); 109152249Sjylefort break; 110191054Sed case 4: 11187384Simp data = inl(port); 1125897Sjmz break; 1135897Sjmz } 11487384Simp pci_cfgdisable(); 11587384Simp } 11687384Simp return (data); 11787384Simp} 11854156Speter 11987384Simp/* write configuration space register */ 12087384Simp 12187384Simpvoid 12287384Simppci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 12387384Simp{ 12487384Simp int port; 12554156Speter 12654156Speter port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 12754156Speter if (port != 0) { 128130585Sphk switch (bytes) { 1295897Sjmz case 1: 13087384Simp outb(port, data); 131191054Sed break; 1325897Sjmz case 2: 13387384Simp outw(port, data); 13487384Simp break; 13587384Simp case 4: 13687384Simp outl(port, data); 13787384Simp break; 1385897Sjmz } 13954156Speter pci_cfgdisable(); 14054156Speter } 141130585Sphk} 1425897Sjmz 14387384Simp/* check whether the configuration mechanism has been correct identified */ 144191054Sed 1455897Sjmzstatic int 14687384Simppci_cfgcheck(int maxdev) 14787384Simp{ 1485897Sjmz u_char device; 1495897Sjmz 15054156Speter if (bootverbose) 151130585Sphk printf("pci_cfgcheck:\tdevice "); 1525897Sjmz 153191054Sed for (device = 0; device < maxdev; device++) { 15487384Simp unsigned id, class, header; 15587384Simp if (bootverbose) 15687384Simp printf("%d ", device); 15787384Simp 15887384Simp id = inl(pci_cfgenable(0, device, 0, 0, 4)); 15987384Simp if (id == 0 || id == -1) 16097554Salfred continue; 16187384Simp 1628876Srgrimes class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 16387384Simp if (bootverbose) 16454156Speter printf("[class=%06x] ", class); 16587384Simp if (class == 0 || (class & 0xf8f0ff) != 0) 16654156Speter continue; 167152249Sjylefort 168152249Sjylefort header = inb(pci_cfgenable(0, device, 0, 14, 1)); 169152249Sjylefort if (bootverbose) 170152249Sjylefort printf("[hdr=%02x] ", header); 171152249Sjylefort if ((header & 0x7e) != 0) 172152249Sjylefort continue; 17387384Simp 17487384Simp if (bootverbose) 17587384Simp printf("is there (id=%08x)\n", id); 17687384Simp 17787384Simp pci_cfgdisable(); 17887384Simp return (1); 17987384Simp } 18087384Simp if (bootverbose) 18187384Simp printf("-- nothing found\n"); 18287384Simp 18387384Simp pci_cfgdisable(); 18487384Simp return (0); 18587384Simp} 18687384Simp 18787384Simpint 18887384Simppci_cfgopen(void) 18987384Simp{ 19087384Simp unsigned long mode1res,oldval1; 19187384Simp unsigned char mode2res,oldval2; 19287384Simp 19397554Salfred oldval1 = inl(CONF1_ADDR_PORT); 19487384Simp 19554156Speter if (bootverbose) { 19687384Simp printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 19754156Speter oldval1); 19887384Simp } 19987384Simp 20087384Simp if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 20187384Simp 20287384Simp cfgmech = 1; 20387384Simp devmax = 32; 20487384Simp 20587384Simp outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 20687384Simp outb(CONF1_ADDR_PORT +3, 0); 20787384Simp mode1res = inl(CONF1_ADDR_PORT); 20887384Simp outl(CONF1_ADDR_PORT, oldval1); 20987384Simp 21087384Simp if (bootverbose) 21187384Simp printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 2125897Sjmz mode1res, CONF1_ENABLE_CHK); 21312675Sjulian 21454156Speter if (mode1res) { 215130585Sphk if (pci_cfgcheck(32)) 2165897Sjmz return (cfgmech); 217191054Sed } 21887384Simp 21987384Simp outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 2205897Sjmz mode1res = inl(CONF1_ADDR_PORT); 22187384Simp outl(CONF1_ADDR_PORT, oldval1); 22287384Simp 22387384Simp if (bootverbose) 22487384Simp printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 22587384Simp mode1res, CONF1_ENABLE_CHK1); 22687384Simp 22787384Simp if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 22887384Simp if (pci_cfgcheck(32)) 22987384Simp return (cfgmech); 23087384Simp } 23187384Simp } 23287384Simp 23387384Simp oldval2 = inb(CONF2_ENABLE_PORT); 23487384Simp 23587384Simp if (bootverbose) { 23687384Simp printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 23787384Simp oldval2); 23887384Simp } 23987384Simp 24087384Simp if ((oldval2 & 0xf0) == 0) { 24187384Simp 24287384Simp cfgmech = 2; 24387384Simp devmax = 16; 24487384Simp 24587384Simp outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 24687384Simp mode2res = inb(CONF2_ENABLE_PORT); 2475897Sjmz outb(CONF2_ENABLE_PORT, oldval2); 248 249 if (bootverbose) 250 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 251 mode2res, CONF2_ENABLE_CHK); 252 253 if (mode2res == CONF2_ENABLE_RES) { 254 if (bootverbose) 255 printf("pci_open(2a):\tnow trying mechanism 2\n"); 256 257 if (pci_cfgcheck(16)) 258 return (cfgmech); 259 } 260 } 261 262 cfgmech = 0; 263 devmax = 0; 264 return (cfgmech); 265} 266