pci_cfgreg.c revision 11378
143939Sabial/************************************************************************** 246493Sabial** 343939Sabial** $Id: pcibus.c,v 1.15 1995/09/22 19:10:54 se Exp $ 443939Sabial** 543939Sabial** pci bus subroutines for i386 architecture. 643939Sabial** 746493Sabial** FreeBSD 846493Sabial** 943939Sabial**------------------------------------------------------------------------- 1043939Sabial** 1143939Sabial** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. 1243939Sabial** 1343939Sabial** Redistribution and use in source and binary forms, with or without 1443939Sabial** modification, are permitted provided that the following conditions 1543939Sabial** are met: 1643939Sabial** 1. Redistributions of source code must retain the above copyright 1743939Sabial** notice, this list of conditions and the following disclaimer. 1843939Sabial** 2. Redistributions in binary form must reproduce the above copyright 1943939Sabial** notice, this list of conditions and the following disclaimer in the 2043939Sabial** documentation and/or other materials provided with the distribution. 2143939Sabial** 3. The name of the author may not be used to endorse or promote products 2243939Sabial** derived from this software without specific prior written permission. 2343939Sabial** 2443939Sabial** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2543939Sabial** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2643939Sabial** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2743939Sabial** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2843939Sabial** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2943939Sabial** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3050479Speter** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3138589Sabial** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3238589Sabial** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3338589Sabial** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3438589Sabial** 3538589Sabial*************************************************************************** 3638589Sabial*/ 3746493Sabial 3838589Sabial#include <sys/param.h> 3938589Sabial#include <sys/systm.h> 4046493Sabial#include <sys/kernel.h> 4146493Sabial 4238589Sabial#include <machine/cpu.h> /* bootverbose */ 4346493Sabial 4446493Sabial#include <i386/isa/icu.h> 4546493Sabial#include <i386/isa/isa.h> 4638589Sabial#include <i386/isa/isa_device.h> 4746493Sabial 4846493Sabial#include <pci/pcivar.h> 4938589Sabial#include <pci/pcireg.h> 5046493Sabial#include <pci/pcibus.h> 5146493Sabial 5246493Sabial/*----------------------------------------------------------------- 5338589Sabial** 5446493Sabial** The following functions are provided by the pci bios. 55113126Sdwmalone** They are used only by the pci configuration. 5646493Sabial** 5746493Sabial** pcibus_setup(): 58113126Sdwmalone** Probes for a pci system. 59113126Sdwmalone** Sets pci_maxdevice and pci_mechanism. 60113126Sdwmalone** 61113126Sdwmalone** pcibus_tag(): 62113126Sdwmalone** Creates a handle for pci configuration space access. 63113126Sdwmalone** This handle is given to the read/write functions. 64113126Sdwmalone** 6546493Sabial** pcibus_ftag(): 6638589Sabial** Creates a modified handle. 6746493Sabial** 6838589Sabial** pcibus_read(): 6946493Sabial** Read a long word from the pci configuration space. 7046493Sabial** Requires a tag (from pcitag) and the register 7146493Sabial** number (should be a long word alligned one). 7246493Sabial** 7346493Sabial** pcibus_write(): 7446493Sabial** Writes a long word to the pci configuration space. 75113126Sdwmalone** Requires a tag (from pcitag), the register number 7646493Sabial** (should be a long word alligned one), and a value. 7746493Sabial** 7846493Sabial** pcibus_regirq(): 7946493Sabial** Register an interupt handler for a pci device. 8046493Sabial** Requires a tag (from pcitag), the register number 81113126Sdwmalone** (should be a long word alligned one), and a value. 8246493Sabial** 8346493Sabial**----------------------------------------------------------------- 8446493Sabial*/ 8546493Sabial 8646493Sabialstatic int 8746493Sabialpcibus_check (void); 8846493Sabial 8946493Sabialstatic void 9038589Sabialpcibus_setup (void); 9138589Sabial 9238589Sabialstatic pcici_t 9338589Sabialpcibus_tag (u_char bus, u_char device, u_char func); 9438589Sabial 9538589Sabialstatic pcici_t 9638589Sabialpcibus_ftag (pcici_t tag, u_char func); 9738589Sabial 9838589Sabialstatic u_long 9938589Sabialpcibus_read (pcici_t tag, u_long reg); 10038589Sabial 10138589Sabialstatic void 10238589Sabialpcibus_write (pcici_t tag, u_long reg, u_long data); 10338589Sabial 10438589Sabialstatic int 10538589Sabialpcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp); 10638589Sabial 10738589Sabialstatic int 10894130Sasmodaipcibus_ihandler_detach (int irq, void(*handler)()); 10938589Sabial 11038589Sabialstatic int 11146493Sabialpcibus_imask_include (int irq, unsigned* maskptr); 11246493Sabial 11346493Sabialstatic int 11494134Sasmodaipcibus_imask_exclude (int irq, unsigned* maskptr); 11546493Sabial 11638589Sabialstruct pcibus i386pci = { 117113126Sdwmalone "pci", 11838589Sabial pcibus_setup, 11938589Sabial pcibus_tag, 12038589Sabial pcibus_ftag, 12138589Sabial pcibus_read, 12238589Sabial pcibus_write, 12338589Sabial ICU_LEN, 12438589Sabial pcibus_ihandler_attach, 12538589Sabial pcibus_ihandler_detach, 12638589Sabial pcibus_imask_include, 12738589Sabial pcibus_imask_exclude, 12846493Sabial}; 12946493Sabial 13046493Sabial/* 13194134Sasmodai** Announce structure to generic driver 13294134Sasmodai*/ 13338589Sabial 13438589SabialDATA_SET (pcibus_set, i386pci); 13538589Sabial 13638589Sabial/*-------------------------------------------------------------------- 13738589Sabial** 13838589Sabial** Determine configuration mode 13938589Sabial** 140113126Sdwmalone**-------------------------------------------------------------------- 14138589Sabial*/ 14238589Sabial 14346493Sabial 14446493Sabial#define CONF1_ADDR_PORT 0x0cf8 14546493Sabial#define CONF1_DATA_PORT 0x0cfc 14694134Sasmodai 147113126Sdwmalone#define CONF1_ENABLE 0x80000000ul 14846493Sabial#define CONF1_ENABLE_CHK 0x80000000ul 14946493Sabial#define CONF1_ENABLE_CHK1 0xFF000001ul 15046493Sabial#define CONF1_ENABLE_MSK1 0x80000000ul 15146493Sabial#define CONF1_ENABLE_RES1 0x80000000ul 15238589Sabial 15338589Sabial#define CONF2_ENABLE_PORT 0x0cf8 15446493Sabial#define CONF2_FORWARD_PORT 0x0cfa 15546493Sabial 15646493Sabial#define CONF2_ENABLE_CHK 0x0e 15746493Sabial#define CONF2_ENABLE_RES 0x0e 15894134Sasmodai 15946493Sabialstatic int 16038589Sabialpcibus_check (void) 16146493Sabial{ 16246493Sabial u_char device; 16346493Sabial 16446493Sabial if (bootverbose) printf ("pcibus_check:\tdevice "); 16546493Sabial 16638589Sabial for (device = 0; device < pci_maxdevice; device++) { 16746493Sabial unsigned long id; 16846493Sabial if (bootverbose) 16946493Sabial printf ("%d ", device); 17046493Sabial id = pcibus_read (pcibus_tag (0,device,0), 0); 17146493Sabial if (id != 0xfffffffful) { 17246493Sabial if (bootverbose) printf ("is there (id=%08lx)\n", id); 17346493Sabial return 1; 17446493Sabial } 17546493Sabial } 17646493Sabial if (bootverbose) 17746493Sabial printf ("-- nothing found\n"); 17846493Sabial return 0; 17946493Sabial} 18038589Sabial 18146493Sabialstatic void 18246493Sabialpcibus_setup (void) 18346493Sabial{ 18446493Sabial unsigned long mode1res,oldval; 18546493Sabial unsigned char mode2res; 18646493Sabial 18746493Sabial oldval = inl (CONF1_ADDR_PORT); 18846493Sabial outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 18946493Sabial outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 19046493Sabial mode1res = inl(CONF1_ADDR_PORT); 19146493Sabial mode2res = inb(CONF2_ENABLE_PORT); 19246493Sabial outb (CONF2_ENABLE_PORT, 0); 19346493Sabial outl (CONF1_ADDR_PORT, oldval); 19446493Sabial 19546493Sabial if (bootverbose) { 19638589Sabial printf ("pcibus_setup(1):\tmode1res=0x%08lx (0x%08lx), " 19738589Sabial "mode2res=0x%02x (0x%02x)\n", 19846493Sabial mode1res,CONF1_ENABLE_CHK, 19946493Sabial (int)mode2res,CONF2_ENABLE_CHK); 20046493Sabial } 20146493Sabial 20294134Sasmodai /*--------------------------------------- 20394135Sasmodai ** No PCI, if neither mode1res nor mode2res could be read back 20438589Sabial **--------------------------------------- 20594132Sasmodai */ 20646493Sabial 20746493Sabial if ((mode1res != CONF1_ENABLE_CHK) && (mode2res != CONF2_ENABLE_CHK)) { 208113126Sdwmalone return; 20946493Sabial } 21038589Sabial 21146493Sabial /*--------------------------------------- 21238589Sabial ** Assume configuration mechanism 1 for now ... 21338589Sabial **--------------------------------------- 21438589Sabial */ 215113126Sdwmalone 216113126Sdwmalone pci_mechanism = 1; 21738589Sabial pci_maxdevice = 32; 21846493Sabial 21938589Sabial outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 22046493Sabial outb (CONF1_ADDR_PORT +3, 0); 22138589Sabial mode1res = inl (CONF1_ADDR_PORT); 22246493Sabial outl (CONF1_ADDR_PORT, oldval); 22346493Sabial 22446493Sabial if (bootverbose) 22546493Sabial printf ("pcibus_setup(2):\tmode1res=0x%08lx (0x%08lx)\n", 22646493Sabial mode1res, CONF1_ENABLE_CHK); 22746493Sabial 22838589Sabial if (mode1res) { 22946493Sabial if (pcibus_check()) 23046493Sabial return; 23138589Sabial }; 23246493Sabial 23346493Sabial outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 23446493Sabial outl (CONF1_DATA_PORT, 0); 23546493Sabial mode1res = inl(CONF1_ADDR_PORT); 23646493Sabial outl (CONF1_ADDR_PORT, oldval); 23738589Sabial 23838589Sabial if (bootverbose) 23938589Sabial printf ("pcibus_setup(3):\tmode1res=0x%08lx (0x%08lx)\n", 24038589Sabial mode1res, CONF1_ENABLE_CHK1); 24138589Sabial 242113126Sdwmalone if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 24338589Sabial if (pcibus_check()) 24438589Sabial return; 24538589Sabial }; 24646493Sabial 24746493Sabial /*--------------------------------------- 24846493Sabial ** Try configuration mechanism 2 ... 24938589Sabial **--------------------------------------- 25038589Sabial */ 25138589Sabial 252113126Sdwmalone if (bootverbose) 25338589Sabial printf ("pcibus_setup(4):\tnow trying mechanism 2\n"); 25438589Sabial 25538589Sabial pci_mechanism = 2; 25638589Sabial pci_maxdevice = 16; 25738589Sabial 25846493Sabial if (pcibus_check()) 259112205Sdwmalone return; 260112205Sdwmalone 26138589Sabial /*--------------------------------------- 26238589Sabial ** No PCI bus host bridge found 26338589Sabial **--------------------------------------- 26438589Sabial */ 265113126Sdwmalone 26646493Sabial pci_mechanism = 0; 26746493Sabial pci_maxdevice = 0; 26846493Sabial} 26946493Sabial 27079452Sbrian/*-------------------------------------------------------------------- 27138589Sabial** 27238589Sabial** Build a pcitag from bus, device and function number 273112205Sdwmalone** 27438589Sabial**-------------------------------------------------------------------- 27538589Sabial*/ 27638589Sabial 27746493Sabialstatic pcici_t 27846493Sabialpcibus_tag (unsigned char bus, unsigned char device, unsigned char func) 27946493Sabial{ 28038589Sabial pcici_t tag; 28146493Sabial 28246493Sabial tag.cfg1 = 0; 28346493Sabial if (func >= 8) return tag; 28438589Sabial 28538589Sabial switch (pci_mechanism) { 28646493Sabial 28746493Sabial case 1: 28846493Sabial if (device < 32) { 28946493Sabial tag.cfg1 = CONF1_ENABLE 29046493Sabial | (((u_long) bus ) << 16ul) 29146493Sabial | (((u_long) device) << 11ul) 29246493Sabial | (((u_long) func ) << 8ul); 29346493Sabial } 29438589Sabial break; 29538589Sabial case 2: 29646493Sabial if (device < 16) { 29746493Sabial tag.cfg2.port = 0xc000 | (device << 8ul); 29846493Sabial tag.cfg2.enable = 0xf0 | (func << 1ul); 29938589Sabial tag.cfg2.forward = bus; 30046493Sabial } 30146493Sabial break; 30246493Sabial }; 30346493Sabial return tag; 30446493Sabial} 305113126Sdwmalone 30638589Sabialstatic pcici_t 30746493Sabialpcibus_ftag (pcici_t tag, u_char func) 30846493Sabial{ 30946493Sabial switch (pci_mechanism) { 31046493Sabial 31146493Sabial case 1: 312113126Sdwmalone tag.cfg1 &= ~0x700ul; 31346493Sabial tag.cfg1 |= (((u_long) func) << 8ul); 31438589Sabial break; 31546493Sabial case 2: 31646493Sabial tag.cfg2.enable = 0xf0 | (func << 1ul); 31746493Sabial break; 31846493Sabial }; 31946493Sabial return tag; 32038589Sabial} 32194133Sasmodai 322113129Sdwmalone/*-------------------------------------------------------------------- 32338589Sabial** 32446493Sabial** Read register from configuration space. 32546493Sabial** 32646493Sabial**-------------------------------------------------------------------- 32746493Sabial*/ 32846493Sabial 32946493Sabialstatic u_long 33046493Sabialpcibus_read (pcici_t tag, u_long reg) 33146493Sabial{ 33246493Sabial u_long addr, data = 0; 33346493Sabial 33446493Sabial if (!tag.cfg1) return (0xfffffffful); 33546493Sabial 33646493Sabial switch (pci_mechanism) { 33746493Sabial 33846493Sabial case 1: 33946493Sabial addr = tag.cfg1 | (reg & 0xfc); 34046493Sabial#ifdef PCI_DEBUG 34146493Sabial printf ("pci_conf_read(1): addr=%x ", addr); 34238589Sabial#endif 34346493Sabial outl (CONF1_ADDR_PORT, addr); 34438589Sabial data = inl (CONF1_DATA_PORT); 345113126Sdwmalone outl (CONF1_ADDR_PORT, 0 ); 34646493Sabial break; 34738589Sabial 34838589Sabial case 2: 349113126Sdwmalone addr = tag.cfg2.port | (reg & 0xfc); 350113126Sdwmalone#ifdef PCI_DEBUG 35146493Sabial printf ("pci_conf_read(2): addr=%x ", addr); 35238589Sabial#endif 35338589Sabial outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); 35438589Sabial outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 35538589Sabial 35646493Sabial data = inl ((u_short) addr); 35746493Sabial 35846493Sabial outb (CONF2_ENABLE_PORT, 0); 35946493Sabial outb (CONF2_FORWARD_PORT, 0); 36046493Sabial break; 36194134Sasmodai }; 36246493Sabial 36338589Sabial#ifdef PCI_DEBUG 36494132Sasmodai printf ("data=%x\n", data); 36546493Sabial#endif 36646493Sabial 36746493Sabial return (data); 36846493Sabial} 36938589Sabial 37038589Sabial/*-------------------------------------------------------------------- 37138589Sabial** 37238589Sabial** Write register into configuration space. 37346493Sabial** 37446493Sabial**-------------------------------------------------------------------- 37546493Sabial*/ 37646493Sabial 37746493Sabialstatic void 37846493Sabialpcibus_write (pcici_t tag, u_long reg, u_long data) 37946493Sabial{ 38038589Sabial u_long addr; 38146493Sabial 38246493Sabial if (!tag.cfg1) return; 38346493Sabial 38446493Sabial switch (pci_mechanism) { 38546493Sabial 38646493Sabial case 1: 38746493Sabial addr = tag.cfg1 | (reg & 0xfc); 38846493Sabial#ifdef PCI_DEBUG 38946493Sabial printf ("pci_conf_write(1): addr=%x data=%x\n", 390113126Sdwmalone addr, data); 39146493Sabial#endif 39246493Sabial outl (CONF1_ADDR_PORT, addr); 39346493Sabial outl (CONF1_DATA_PORT, data); 39446493Sabial outl (CONF1_ADDR_PORT, 0 ); 39546493Sabial break; 39646493Sabial 39746493Sabial case 2: 39846493Sabial addr = tag.cfg2.port | (reg & 0xfc); 39946493Sabial#ifdef PCI_DEBUG 40046493Sabial printf ("pci_conf_write(2): addr=%x data=%x\n", 40146493Sabial addr, data); 40246493Sabial#endif 40346493Sabial outb (CONF2_ENABLE_PORT, tag.cfg2.enable); 40446493Sabial outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 40546493Sabial 40646493Sabial outl ((u_short) addr, data); 40746493Sabial 40846493Sabial outb (CONF2_ENABLE_PORT, 0); 40946493Sabial outb (CONF2_FORWARD_PORT, 0); 41046493Sabial break; 41146493Sabial }; 41246493Sabial} 41346493Sabial 41446493Sabial/*----------------------------------------------------------------------- 41546493Sabial** 41646493Sabial** Register an interupt handler for a pci device. 41746493Sabial** 41846493Sabial**----------------------------------------------------------------------- 41946493Sabial*/ 42046493Sabial 421113126Sdwmalonestatic int 42246493Sabialpcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr) 42346493Sabial{ 42446493Sabial int result; 42546493Sabial result = register_intr( 42646493Sabial irq, /* isa irq */ 42746493Sabial 0, /* deviced?? */ 42846493Sabial 0, /* flags? */ 42946493Sabial (inthand2_t*) func, /* handler */ 43046493Sabial maskptr, /* mask pointer */ 43146493Sabial arg); /* handler arg */ 43246493Sabial 43346493Sabial if (result) { 43446493Sabial printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); 43546493Sabial return (result); 43638589Sabial }; 43738589Sabial update_intr_masks(); 43846493Sabial 43946493Sabial INTREN ((1ul<<irq)); 44046493Sabial return (0); 441113126Sdwmalone} 44246493Sabial 44346493Sabialstatic int 44438589Sabialpcibus_ihandler_detach (int irq, void(*func)()) 44546493Sabial{ 44646493Sabial int result; 447113126Sdwmalone 44846493Sabial INTRDIS ((1ul<<irq)); 44946493Sabial 45046493Sabial result = unregister_intr (irq, (inthand2_t*) func); 45146493Sabial 45246493Sabial if (result) 45346493Sabial printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); 45438589Sabial 455113126Sdwmalone update_intr_masks(); 45646493Sabial 45746493Sabial return (result); 45846493Sabial} 45946493Sabial 46046493Sabialstatic int 46146493Sabialpcibus_imask_include (int irq, unsigned* maskptr) 46238589Sabial{ 46346493Sabial unsigned mask; 46446493Sabial 46546493Sabial if (!maskptr) return (0); 46646493Sabial 46746493Sabial mask = 1ul << irq; 46846493Sabial 46946493Sabial if (*maskptr & mask) 47046493Sabial return (-1); 47146493Sabial 47246493Sabial INTRMASK (*maskptr, mask); 47346493Sabial update_intr_masks(); 47446493Sabial 47538589Sabial return (0); 47638589Sabial} 47738589Sabial 478113126Sdwmalonestatic int 479113126Sdwmalonepcibus_imask_exclude (int irq, unsigned* maskptr) 48038589Sabial{ 48138589Sabial unsigned mask; 482112205Sdwmalone 48338589Sabial if (!maskptr) return (0); 48438589Sabial 48538589Sabial mask = 1ul << irq; 48643939Sabial 48743939Sabial if (! (*maskptr & mask)) 48843939Sabial return (-1); 48938589Sabial 49038589Sabial *maskptr &= ~mask; 491 update_intr_masks(); 492 493 return (0); 494} 495