pci_cfgreg.c revision 9360
167754Smsmith/************************************************************************** 267754Smsmith** 367754Smsmith** $Id: pcibus.c,v 1.8 1995/03/22 21:35:39 se Exp $ 467754Smsmith** 567754Smsmith** pci bus subroutines for i386 architecture. 667754Smsmith** 767754Smsmith** FreeBSD 867754Smsmith** 967754Smsmith**------------------------------------------------------------------------- 1067754Smsmith** 1167754Smsmith** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. 1267754Smsmith** 1367754Smsmith** Redistribution and use in source and binary forms, with or without 1467754Smsmith** modification, are permitted provided that the following conditions 1567754Smsmith** are met: 1667754Smsmith** 1. Redistributions of source code must retain the above copyright 1767754Smsmith** notice, this list of conditions and the following disclaimer. 1867754Smsmith** 2. Redistributions in binary form must reproduce the above copyright 1967754Smsmith** notice, this list of conditions and the following disclaimer in the 2067754Smsmith** documentation and/or other materials provided with the distribution. 2167754Smsmith** 3. The name of the author may not be used to endorse or promote products 2267754Smsmith** derived from this software without specific prior written permission. 2367754Smsmith** 2467754Smsmith** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2567754Smsmith** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2667754Smsmith** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2767754Smsmith** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2867754Smsmith** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2967754Smsmith** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3067754Smsmith** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3167754Smsmith** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3267754Smsmith** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3367754Smsmith** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3467754Smsmith** 3567754Smsmith*************************************************************************** 3667754Smsmith*/ 3767754Smsmith 3867754Smsmith#define __PCIBUS_C___ "pl4 95/03/21" 3967754Smsmith 4067754Smsmith#include <sys/param.h> 4167754Smsmith#include <sys/systm.h> 4267754Smsmith#include <sys/kernel.h> 4367754Smsmith 4467754Smsmith#include <i386/isa/icu.h> 4567754Smsmith#include <i386/isa/isa.h> 4667754Smsmith#include <i386/isa/isa_device.h> 4767754Smsmith 4867754Smsmith#include <pci/pcivar.h> 4967754Smsmith#include <pci/pcireg.h> 5067754Smsmith#include <pci/pcibus.h> 5167754Smsmith 5267754Smsmith/*----------------------------------------------------------------- 5367754Smsmith** 5467754Smsmith** The following functions are provided by the pci bios. 5567754Smsmith** They are used only by the pci configuration. 5667754Smsmith** 5767754Smsmith** pcibus_setup(): 5867754Smsmith** Probes for a pci system. 5967754Smsmith** Sets pci_maxdevice and pci_mechanism. 6067754Smsmith** 6167754Smsmith** pcibus_tag(): 6267754Smsmith** Creates a handle for pci configuration space access. 6367754Smsmith** This handle is given to the read/write functions. 6467754Smsmith** 6567754Smsmith** pcibus_ftag(): 6667754Smsmith** Creates a modified handle. 6767754Smsmith** 6867754Smsmith** pcibus_read(): 6967754Smsmith** Read a long word from the pci configuration space. 7067754Smsmith** Requires a tag (from pcitag) and the register 7167754Smsmith** number (should be a long word alligned one). 7267754Smsmith** 7367754Smsmith** pcibus_write(): 7467754Smsmith** Writes a long word to the pci configuration space. 7567754Smsmith** Requires a tag (from pcitag), the register number 7667754Smsmith** (should be a long word alligned one), and a value. 7767754Smsmith** 7867754Smsmith** pcibus_regirq(): 7967754Smsmith** Register an interupt handler for a pci device. 8067754Smsmith** Requires a tag (from pcitag), the register number 8167754Smsmith** (should be a long word alligned one), and a value. 8267754Smsmith** 8367754Smsmith**----------------------------------------------------------------- 8467754Smsmith*/ 8567754Smsmith 8667754Smsmithstatic void 8767754Smsmithpcibus_setup (void); 8867754Smsmith 8967754Smsmithstatic pcici_t 9067754Smsmithpcibus_tag (u_char bus, u_char device, u_char func); 9167754Smsmith 9267754Smsmithstatic pcici_t 9367754Smsmithpcibus_ftag (pcici_t tag, u_char func); 9467754Smsmith 9567754Smsmithstatic u_long 9667754Smsmithpcibus_read (pcici_t tag, u_long reg); 9767754Smsmith 9867754Smsmithstatic void 9967754Smsmithpcibus_write (pcici_t tag, u_long reg, u_long data); 10067754Smsmith 10167754Smsmithstatic int 10267754Smsmithpcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp); 10367754Smsmith 10467754Smsmithstatic int 10567754Smsmithpcibus_ihandler_detach (int irq, void(*handler)()); 10667754Smsmith 10767754Smsmithstatic int 10867754Smsmithpcibus_imask_include (int irq, unsigned* maskptr); 10967754Smsmith 11067754Smsmithstatic int 11167754Smsmithpcibus_imask_exclude (int irq, unsigned* maskptr); 11267754Smsmith 11367754Smsmithstruct pcibus i386pci = { 11467754Smsmith "pci", 11567754Smsmith pcibus_setup, 11667754Smsmith pcibus_tag, 11767754Smsmith pcibus_ftag, 11867754Smsmith pcibus_read, 11967754Smsmith pcibus_write, 12067754Smsmith ICU_LEN, 12167754Smsmith pcibus_ihandler_attach, 12267754Smsmith pcibus_ihandler_detach, 12367754Smsmith pcibus_imask_include, 12467754Smsmith pcibus_imask_exclude, 12567754Smsmith}; 12667754Smsmith 12767754Smsmith/* 12867754Smsmith** Announce structure to generic driver 12967754Smsmith*/ 13067754Smsmith 13167754SmsmithDATA_SET (pcibus_set, i386pci); 13267754Smsmith 13367754Smsmith/*-------------------------------------------------------------------- 13467754Smsmith** 13567754Smsmith** Determine configuration mode 13667754Smsmith** 13767754Smsmith**-------------------------------------------------------------------- 13867754Smsmith*/ 13967754Smsmith 14067754Smsmith 14167754Smsmith#define CONF1_ENABLE 0x80000000ul 14267754Smsmith#define CONF1_ENABLE_CHK 0xF0000000ul 14367754Smsmith#define CONF1_ADDR_PORT 0x0cf8 14467754Smsmith#define CONF1_DATA_PORT 0x0cfc 14567754Smsmith 14667754Smsmith 14767754Smsmith#define CONF2_ENABLE_PORT 0x0cf8 14867754Smsmith#define CONF2_FORWARD_PORT 0x0cfa 14967754Smsmith 15067754Smsmith 15167754Smsmithstatic void 15267754Smsmithpcibus_setup (void) 15367754Smsmith{ 15467754Smsmith u_long result, oldval; 15567754Smsmith 15667754Smsmith /*--------------------------------------- 15767754Smsmith ** Configuration mode 1 ? 15867754Smsmith **--------------------------------------- 15967754Smsmith */ 16067754Smsmith 16167754Smsmith oldval = inl (CONF1_ADDR_PORT); 16267754Smsmith outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 16367754Smsmith outb (CONF1_ADDR_PORT +3, 0); 16467754Smsmith result = inl (CONF1_ADDR_PORT); 16567754Smsmith outl (CONF1_ADDR_PORT, oldval); 16667754Smsmith 16767754Smsmith if (result == CONF1_ENABLE) { 16867754Smsmith pci_mechanism = 1; 16967754Smsmith pci_maxdevice = 32; 17067754Smsmith return; 17167754Smsmith }; 17267754Smsmith 17367754Smsmith /*--------------------------------------- 17467754Smsmith ** Configuration mode 2 ? 17567754Smsmith **--------------------------------------- 17667754Smsmith */ 17767754Smsmith 17867754Smsmith outb (CONF2_ENABLE_PORT, 0); 17967754Smsmith outb (CONF2_FORWARD_PORT, 0); 18067754Smsmith if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) { 18167754Smsmith pci_mechanism = 2; 18267754Smsmith pci_maxdevice = 16; 18367754Smsmith return; 18467754Smsmith }; 18567754Smsmith 18667754Smsmith /*--------------------------------------- 18767754Smsmith ** No PCI bus available. 18867754Smsmith **--------------------------------------- 18967754Smsmith */ 19067754Smsmith} 19167754Smsmith 19267754Smsmith/*-------------------------------------------------------------------- 19367754Smsmith** 19467754Smsmith** Build a pcitag from bus, device and function number 19567754Smsmith** 19667754Smsmith**-------------------------------------------------------------------- 19767754Smsmith*/ 19867754Smsmith 19967754Smsmithstatic pcici_t 20067754Smsmithpcibus_tag (unsigned char bus, unsigned char device, unsigned char func) 20167754Smsmith{ 20267754Smsmith pcici_t tag; 20367754Smsmith 20467754Smsmith tag.cfg1 = 0; 20567754Smsmith if (device >= 32) return tag; 20667754Smsmith if (func >= 8) return tag; 20767754Smsmith 20867754Smsmith switch (pci_mechanism) { 20967754Smsmith 21067754Smsmith case 1: 21167754Smsmith tag.cfg1 = CONF1_ENABLE 21267754Smsmith | (((u_long) bus ) << 16ul) 21367754Smsmith | (((u_long) device) << 11ul) 21467754Smsmith | (((u_long) func ) << 8ul); 21567754Smsmith break; 21667754Smsmith case 2: 21767754Smsmith if (device >= 16) break; 21867754Smsmith tag.cfg2.port = 0xc000 | (device << 8ul); 21967754Smsmith tag.cfg2.enable = 0xf1 | (func << 1ul); 22067754Smsmith tag.cfg2.forward = bus; 22167754Smsmith break; 22267754Smsmith }; 22367754Smsmith return tag; 22467754Smsmith} 22567754Smsmith 22667754Smsmithstatic pcici_t 22767754Smsmithpcibus_ftag (pcici_t tag, u_char func) 22867754Smsmith{ 22967754Smsmith switch (pci_mechanism) { 23067754Smsmith 23167754Smsmith case 1: 23267754Smsmith tag.cfg1 &= ~0x700ul; 23367754Smsmith tag.cfg1 |= (((u_long) func) << 8ul); 23467754Smsmith break; 23567754Smsmith case 2: 23667754Smsmith tag.cfg2.enable = 0xf1 | (func << 1ul); 23767754Smsmith break; 23867754Smsmith }; 23967754Smsmith return tag; 24067754Smsmith} 24167754Smsmith 24267754Smsmith/*-------------------------------------------------------------------- 24367754Smsmith** 24467754Smsmith** Read register from configuration space. 24567754Smsmith** 24667754Smsmith**-------------------------------------------------------------------- 24767754Smsmith*/ 24867754Smsmith 24967754Smsmithstatic u_long 25067754Smsmithpcibus_read (pcici_t tag, u_long reg) 25167754Smsmith{ 25267754Smsmith u_long addr, data = 0; 25367754Smsmith 25467754Smsmith if (!tag.cfg1) return (0xfffffffful); 25567754Smsmith 25667754Smsmith switch (pci_mechanism) { 25767754Smsmith 25867754Smsmith case 1: 25967754Smsmith addr = tag.cfg1 | (reg & 0xfc); 26067754Smsmith#ifdef PCI_DEBUG 26167754Smsmith printf ("pci_conf_read(1): addr=%x ", addr); 26267754Smsmith#endif 26367754Smsmith outl (CONF1_ADDR_PORT, addr); 26467754Smsmith data = inl (CONF1_DATA_PORT); 26567754Smsmith outl (CONF1_ADDR_PORT, 0 ); 26667754Smsmith break; 26767754Smsmith 26867754Smsmith case 2: 26967754Smsmith addr = tag.cfg2.port | (reg & 0xfc); 27067754Smsmith#ifdef PCI_DEBUG 27167754Smsmith printf ("pci_conf_read(2): addr=%x ", addr); 27267754Smsmith#endif 27367754Smsmith outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); 27467754Smsmith outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 27567754Smsmith 27667754Smsmith data = inl ((u_short) addr); 27767754Smsmith 27867754Smsmith outb (CONF2_ENABLE_PORT, 0); 27967754Smsmith outb (CONF2_FORWARD_PORT, 0); 28067754Smsmith break; 28167754Smsmith }; 28267754Smsmith 28367754Smsmith#ifdef PCI_DEBUG 28467754Smsmith printf ("data=%x\n", data); 28567754Smsmith#endif 28667754Smsmith 28767754Smsmith return (data); 28867754Smsmith} 28967754Smsmith 29067754Smsmith/*-------------------------------------------------------------------- 29167754Smsmith** 29267754Smsmith** Write register into configuration space. 29367754Smsmith** 29467754Smsmith**-------------------------------------------------------------------- 29567754Smsmith*/ 29667754Smsmith 29767754Smsmithstatic void 29867754Smsmithpcibus_write (pcici_t tag, u_long reg, u_long data) 29967754Smsmith{ 30067754Smsmith u_long addr; 30167754Smsmith 30267754Smsmith if (!tag.cfg1) return; 30367754Smsmith 30467754Smsmith switch (pci_mechanism) { 30567754Smsmith 30667754Smsmith case 1: 30767754Smsmith addr = tag.cfg1 | (reg & 0xfc); 30867754Smsmith#ifdef PCI_DEBUG 30967754Smsmith printf ("pci_conf_write(1): addr=%x data=%x\n", 31067754Smsmith addr, data); 31167754Smsmith#endif 31267754Smsmith outl (CONF1_ADDR_PORT, addr); 31367754Smsmith outl (CONF1_DATA_PORT, data); 31467754Smsmith outl (CONF1_ADDR_PORT, 0 ); 31567754Smsmith break; 31667754Smsmith 31767754Smsmith case 2: 31867754Smsmith addr = tag.cfg2.port | (reg & 0xfc); 31967754Smsmith#ifdef PCI_DEBUG 32067754Smsmith printf ("pci_conf_write(2): addr=%x data=%x\n", 32167754Smsmith addr, data); 32267754Smsmith#endif 32367754Smsmith outb (CONF2_ENABLE_PORT, tag.cfg2.enable); 32467754Smsmith outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 32567754Smsmith 32667754Smsmith outl ((u_short) addr, data); 32767754Smsmith 32867754Smsmith outb (CONF2_ENABLE_PORT, 0); 32967754Smsmith outb (CONF2_FORWARD_PORT, 0); 33067754Smsmith break; 33167754Smsmith }; 33267754Smsmith} 33367754Smsmith 33467754Smsmith/*----------------------------------------------------------------------- 33567754Smsmith** 33667754Smsmith** Register an interupt handler for a pci device. 33767754Smsmith** 33867754Smsmith**----------------------------------------------------------------------- 33967754Smsmith*/ 34067754Smsmith 34167754Smsmithstatic int 34267754Smsmithpcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr) 34367754Smsmith{ 34467754Smsmith int result; 34567754Smsmith result = register_intr( 34667754Smsmith irq, /* isa irq */ 34767754Smsmith 0, /* deviced?? */ 34867754Smsmith 0, /* flags? */ 34967754Smsmith (inthand2_t*) func, /* handler */ 35067754Smsmith maskptr, /* mask pointer */ 35167754Smsmith arg); /* handler arg */ 35267754Smsmith 35367754Smsmith if (result) { 35467754Smsmith printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); 35567754Smsmith return (result); 35667754Smsmith }; 35767754Smsmith update_intr_masks(); 35867754Smsmith 35967754Smsmith INTREN ((1ul<<irq)); 36067754Smsmith return (0); 36167754Smsmith} 36267754Smsmith 36367754Smsmithstatic int 36467754Smsmithpcibus_ihandler_detach (int irq, void(*func)()) 36567754Smsmith{ 36667754Smsmith int result; 36767754Smsmith 36867754Smsmith INTRDIS ((1ul<<irq)); 36967754Smsmith 37067754Smsmith result = unregister_intr (irq, (inthand2_t*) func); 37167754Smsmith 37267754Smsmith if (result) 37367754Smsmith printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); 37467754Smsmith 37567754Smsmith update_intr_masks(); 37667754Smsmith 37767754Smsmith return (result); 37867754Smsmith} 37967754Smsmith 38067754Smsmithstatic int 38167754Smsmithpcibus_imask_include (int irq, unsigned* maskptr) 38267754Smsmith{ 38367754Smsmith unsigned mask; 38467754Smsmith 38567754Smsmith if (!maskptr) return (0); 38667754Smsmith 38767754Smsmith mask = 1ul << irq; 38867754Smsmith 38967754Smsmith if (*maskptr & mask) 39067754Smsmith return (-1); 39167754Smsmith 39267754Smsmith INTRMASK (*maskptr, mask); 39367754Smsmith update_intr_masks(); 39467754Smsmith 39567754Smsmith return (0); 39667754Smsmith} 39767754Smsmith 39867754Smsmithstatic int 39967754Smsmithpcibus_imask_exclude (int irq, unsigned* maskptr) 40067754Smsmith{ 40167754Smsmith unsigned mask; 40267754Smsmith 40367754Smsmith if (!maskptr) return (0); 40467754Smsmith 40567754Smsmith mask = 1ul << irq; 40667754Smsmith 40767754Smsmith if (! (*maskptr & mask)) 40867754Smsmith return (-1); 40967754Smsmith 41067754Smsmith *maskptr &= ~mask; 41167754Smsmith update_intr_masks(); 41267754Smsmith 41367754Smsmith return (0); 41467754Smsmith} 41567754Smsmith