pci_pir.c revision 47307
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 * 2647307Speter * $Id: pcibus.c,v 1.41 1997/12/20 09:04:25 se Exp $ 2726159Sse * 2826159Sse */ 296104Sse 3047307Speter#include <sys/param.h> 316734Sbde#include <sys/systm.h> 3247307Speter#include <sys/bus.h> 3347307Speter#include <sys/kernel.h> 346734Sbde 356104Sse#include <pci/pcivar.h> 3626159Sse#include <i386/isa/pcibus.h> 376104Sse 3826159Sse#ifdef PCI_COMPAT 3926159Sse/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ 4026159Sse#define cfgmech pci_mechanism 4126159Sseint cfgmech; 4226159Sse#else 4326159Ssestatic int cfgmech; 4426159Sse#endif /* PCI_COMPAT */ 4526159Ssestatic int devmax; 466104Sse 4726159Sse/* enable configuration space accesses and return data port address */ 4826159Sse 4910887Ssestatic int 5026159Ssepci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 5126159Sse{ 5226159Sse int dataport = 0; 5310887Sse 5426159Sse if (bus <= PCI_BUSMAX 5526159Sse && slot < devmax 5626159Sse && func <= PCI_FUNCMAX 5726159Sse && reg <= PCI_REGMAX 5826159Sse && bytes != 3 5926159Sse && (unsigned) bytes <= 4 6026159Sse && (reg & (bytes -1)) == 0) { 6126159Sse switch (cfgmech) { 6226159Sse case 1: 6326174Sse outl(CONF1_ADDR_PORT, (1 << 31) 6426174Sse | (bus << 16) | (slot << 11) 6526174Sse | (func << 8) | (reg & ~0x03)); 6626174Sse dataport = CONF1_DATA_PORT + (reg & 0x03); 6726159Sse break; 6826159Sse case 2: 6926159Sse outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 7026159Sse outb(CONF2_FORWARD_PORT, bus); 7126159Sse dataport = 0xc000 | (slot << 8) | reg; 7226159Sse break; 7326159Sse } 7426159Sse } 7526159Sse return (dataport); 7626159Sse} 776104Sse 7826159Sse/* disable configuration space accesses */ 796104Sse 806104Ssestatic void 8126159Ssepci_cfgdisable(void) 8226159Sse{ 8326159Sse switch (cfgmech) { 8426159Sse case 1: 8526159Sse outl(CONF1_ADDR_PORT, 0); 8626159Sse break; 8726159Sse case 2: 8826159Sse outb(CONF2_ENABLE_PORT, 0); 8926159Sse outb(CONF2_FORWARD_PORT, 0); 9026159Sse break; 9126159Sse } 9226159Sse} 936104Sse 9426159Sse/* read configuration space register */ 956104Sse 9626159Sseint 9726159Ssepci_cfgread(pcicfgregs *cfg, int reg, int bytes) 9826159Sse{ 9926159Sse int data = -1; 10026159Sse int port; 1017234Sse 10226159Sse port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 1037234Sse 10426159Sse if (port != 0) { 10526159Sse switch (bytes) { 10626159Sse case 1: 10726159Sse data = inb(port); 10826159Sse break; 10926159Sse case 2: 11026159Sse data = inw(port); 11126159Sse break; 11226159Sse case 4: 11326159Sse data = inl(port); 11426159Sse break; 11526159Sse } 11626159Sse pci_cfgdisable(); 11726159Sse } 11826159Sse return (data); 11926159Sse} 1207234Sse 12126159Sse/* write configuration space register */ 1226104Sse 12326159Ssevoid 12426159Ssepci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 12526159Sse{ 12626159Sse int port; 1276104Sse 12826159Sse port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 12926159Sse if (port != 0) { 13026159Sse switch (bytes) { 13126159Sse case 1: 13226159Sse outb(port, data); 13326159Sse break; 13426159Sse case 2: 13526159Sse outw(port, data); 13626159Sse break; 13726159Sse case 4: 13826159Sse outl(port, data); 13926159Sse break; 14026159Sse } 14126159Sse pci_cfgdisable(); 14226159Sse } 14326159Sse} 1446104Sse 14526159Sse/* check whether the configuration mechanism has been correct identified */ 1466104Sse 14710887Ssestatic int 14826159Ssepci_cfgcheck(int maxdev) 14910887Sse{ 15010887Sse u_char device; 15110735Sse 15226159Sse if (bootverbose) 15326159Sse printf("pci_cfgcheck:\tdevice "); 15410960Sse 15526159Sse for (device = 0; device < maxdev; device++) { 15626159Sse unsigned id, class, header; 15711378Sse if (bootverbose) 15826159Sse printf("%d ", device); 15926159Sse 16026159Sse id = inl(pci_cfgenable(0, device, 0, 0, 4)); 16126159Sse if (id == 0 || id == -1) 16223415Sse continue; 16323415Sse 16426159Sse class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 16523415Sse if (bootverbose) 16626159Sse printf("[class=%06x] ", class); 16731893Sse if (class == 0 || (class & 0xf870ff) != 0) 16823415Sse continue; 16923415Sse 17026159Sse header = inb(pci_cfgenable(0, device, 0, 14, 1)); 17123415Sse if (bootverbose) 17226159Sse printf("[hdr=%02x] ", header); 17326159Sse if ((header & 0x7e) != 0) 17423415Sse continue; 17523415Sse 17626159Sse if (bootverbose) 17726159Sse printf("is there (id=%08x)\n", id); 17826159Sse 17926159Sse pci_cfgdisable(); 18026159Sse return (1); 18110887Sse } 18211378Sse if (bootverbose) 18326159Sse printf("-- nothing found\n"); 18426159Sse 18526159Sse pci_cfgdisable(); 18626159Sse return (0); 18710887Sse} 18810887Sse 18947307Speterstatic int 19026159Ssepci_cfgopen(void) 1916104Sse{ 19211524Sse unsigned long mode1res,oldval1; 19311524Sse unsigned char mode2res,oldval2; 1946104Sse 19526159Sse oldval1 = inl(CONF1_ADDR_PORT); 19610960Sse 19710960Sse if (bootverbose) { 19826159Sse printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 19926159Sse oldval1); 20010960Sse } 20110960Sse 20211544Sse if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 20310960Sse 20426159Sse cfgmech = 1; 20526159Sse devmax = 32; 20610960Sse 20726159Sse outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 20826159Sse outb(CONF1_ADDR_PORT +3, 0); 20926159Sse mode1res = inl(CONF1_ADDR_PORT); 21026159Sse outl(CONF1_ADDR_PORT, oldval1); 21110960Sse 21211524Sse if (bootverbose) 21326159Sse printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 21426159Sse mode1res, CONF1_ENABLE_CHK); 2156104Sse 21611524Sse if (mode1res) { 21726159Sse if (pci_cfgcheck(32)) 21826159Sse return (cfgmech); 21926159Sse } 22010960Sse 22126159Sse outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 22211524Sse mode1res = inl(CONF1_ADDR_PORT); 22326159Sse outl(CONF1_ADDR_PORT, oldval1); 2246104Sse 22511524Sse if (bootverbose) 22626159Sse printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 22726159Sse mode1res, CONF1_ENABLE_CHK1); 2289360Sse 22911524Sse if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 23026159Sse if (pci_cfgcheck(32)) 23126159Sse return (cfgmech); 23226159Sse } 23311524Sse } 23410807Sse 23526159Sse oldval2 = inb(CONF2_ENABLE_PORT); 23610887Sse 23711524Sse if (bootverbose) { 23826159Sse printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 23926159Sse oldval2); 24011524Sse } 24110887Sse 24211524Sse if ((oldval2 & 0xf0) == 0) { 24310887Sse 24426159Sse cfgmech = 2; 24526159Sse devmax = 16; 24626159Sse 24726159Sse outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 24811524Sse mode2res = inb(CONF2_ENABLE_PORT); 24926159Sse outb(CONF2_ENABLE_PORT, oldval2); 25011524Sse 25111524Sse if (bootverbose) 25226159Sse printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 25326159Sse mode2res, CONF2_ENABLE_CHK); 25411524Sse 25511524Sse if (mode2res == CONF2_ENABLE_RES) { 25626159Sse if (bootverbose) 25726159Sse printf("pci_open(2a):\tnow trying mechanism 2\n"); 25811524Sse 25926159Sse if (pci_cfgcheck(16)) 26026159Sse return (cfgmech); 26111524Sse } 26211524Sse } 26311524Sse 26426159Sse cfgmech = 0; 26526159Sse devmax = 0; 26626159Sse return (cfgmech); 2676104Sse} 26847307Speter 26947307Speterstatic devclass_t pcib_devclass; 27047307Speter 27147307Speterstatic int 27247307Speternexus_pcib_probe(device_t dev) 27347307Speter{ 27447307Speter if (pci_cfgopen() != 0) { 27547307Speter device_set_desc(dev, "PCI host bus adapter"); 27647307Speter 27747307Speter device_add_child(dev, "pci", 0, 0); 27847307Speter return 0; 27947307Speter } 28047307Speter return ENXIO; 28147307Speter} 28247307Speter 28347307Speterstatic device_method_t nexus_pcib_methods[] = { 28447307Speter /* Device interface */ 28547307Speter DEVMETHOD(device_probe, nexus_pcib_probe), 28647307Speter DEVMETHOD(device_attach, bus_generic_attach), 28747307Speter DEVMETHOD(device_shutdown, bus_generic_shutdown), 28847307Speter DEVMETHOD(device_suspend, bus_generic_suspend), 28947307Speter DEVMETHOD(device_resume, bus_generic_resume), 29047307Speter 29147307Speter /* Bus interface */ 29247307Speter DEVMETHOD(bus_print_child, bus_generic_print_child), 29347307Speter DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 29447307Speter DEVMETHOD(bus_release_resource, bus_generic_release_resource), 29547307Speter DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 29647307Speter DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 29747307Speter DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 29847307Speter DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 29947307Speter 30047307Speter { 0, 0 } 30147307Speter}; 30247307Speter 30347307Speterstatic driver_t nexus_pcib_driver = { 30447307Speter "pcib", 30547307Speter nexus_pcib_methods, 30647307Speter 1, 30747307Speter}; 30847307Speter 30947307SpeterDRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0); 310