pci_cfgreg.c revision 9379
1/************************************************************************** 2** 3** $Id: pcibus.c,v 1.9 1995/06/28 15:54:57 se Exp $ 4** 5** pci bus subroutines for i386 architecture. 6** 7** FreeBSD 8** 9**------------------------------------------------------------------------- 10** 11** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. 12** 13** Redistribution and use in source and binary forms, with or without 14** modification, are permitted provided that the following conditions 15** are met: 16** 1. Redistributions of source code must retain the above copyright 17** notice, this list of conditions and the following disclaimer. 18** 2. Redistributions in binary form must reproduce the above copyright 19** notice, this list of conditions and the following disclaimer in the 20** documentation and/or other materials provided with the distribution. 21** 3. The name of the author may not be used to endorse or promote products 22** derived from this software without specific prior written permission. 23** 24** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34** 35*************************************************************************** 36*/ 37 38#define __PCIBUS_C___ "pl4 95/03/21" 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43 44#include <i386/isa/icu.h> 45#include <i386/isa/isa.h> 46#include <i386/isa/isa_device.h> 47 48#include <pci/pcivar.h> 49#include <pci/pcireg.h> 50#include <pci/pcibus.h> 51 52/*----------------------------------------------------------------- 53** 54** The following functions are provided by the pci bios. 55** They are used only by the pci configuration. 56** 57** pcibus_setup(): 58** Probes for a pci system. 59** Sets pci_maxdevice and pci_mechanism. 60** 61** pcibus_tag(): 62** Creates a handle for pci configuration space access. 63** This handle is given to the read/write functions. 64** 65** pcibus_ftag(): 66** Creates a modified handle. 67** 68** pcibus_read(): 69** Read a long word from the pci configuration space. 70** Requires a tag (from pcitag) and the register 71** number (should be a long word alligned one). 72** 73** pcibus_write(): 74** Writes a long word to the pci configuration space. 75** Requires a tag (from pcitag), the register number 76** (should be a long word alligned one), and a value. 77** 78** pcibus_regirq(): 79** Register an interupt handler for a pci device. 80** Requires a tag (from pcitag), the register number 81** (should be a long word alligned one), and a value. 82** 83**----------------------------------------------------------------- 84*/ 85 86static void 87pcibus_setup (void); 88 89static pcici_t 90pcibus_tag (u_char bus, u_char device, u_char func); 91 92static pcici_t 93pcibus_ftag (pcici_t tag, u_char func); 94 95static u_long 96pcibus_read (pcici_t tag, u_long reg); 97 98static void 99pcibus_write (pcici_t tag, u_long reg, u_long data); 100 101static int 102pcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp); 103 104static int 105pcibus_ihandler_detach (int irq, void(*handler)()); 106 107static int 108pcibus_imask_include (int irq, unsigned* maskptr); 109 110static int 111pcibus_imask_exclude (int irq, unsigned* maskptr); 112 113struct pcibus i386pci = { 114 "pci", 115 pcibus_setup, 116 pcibus_tag, 117 pcibus_ftag, 118 pcibus_read, 119 pcibus_write, 120 ICU_LEN, 121 pcibus_ihandler_attach, 122 pcibus_ihandler_detach, 123 pcibus_imask_include, 124 pcibus_imask_exclude, 125}; 126 127/* 128** Announce structure to generic driver 129*/ 130 131DATA_SET (pcibus_set, i386pci); 132 133/*-------------------------------------------------------------------- 134** 135** Determine configuration mode 136** 137**-------------------------------------------------------------------- 138*/ 139 140 141#define CONF1_ENABLE 0x80000000ul 142#define CONF1_ENABLE_CHK 0xF0000000ul 143#define CONF1_ADDR_PORT 0x0cf8 144#define CONF1_DATA_PORT 0x0cfc 145 146 147#define CONF2_ENABLE_PORT 0x0cf8 148#define CONF2_FORWARD_PORT 0x0cfa 149 150 151static void 152pcibus_setup (void) 153{ 154 u_long result, oldval; 155 156 /*--------------------------------------- 157 ** Configuration mode 1 ? 158 **--------------------------------------- 159 */ 160 161 oldval = inl (CONF1_ADDR_PORT); 162 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 163 outb (CONF1_ADDR_PORT +3, 0); 164 result = inl (CONF1_ADDR_PORT); 165 outl (CONF1_ADDR_PORT, oldval); 166 167 if (result & CONF1_ENABLE) { 168 pci_mechanism = 1; 169 pci_maxdevice = 32; 170 return; 171 }; 172 173 /*--------------------------------------- 174 ** Configuration mode 2 ? 175 **--------------------------------------- 176 */ 177 178 outb (CONF2_ENABLE_PORT, 0); 179 outb (CONF2_FORWARD_PORT, 0); 180 if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) { 181 pci_mechanism = 2; 182 pci_maxdevice = 16; 183 return; 184 }; 185 186 /*--------------------------------------- 187 ** No PCI bus available. 188 **--------------------------------------- 189 */ 190} 191 192/*-------------------------------------------------------------------- 193** 194** Build a pcitag from bus, device and function number 195** 196**-------------------------------------------------------------------- 197*/ 198 199static pcici_t 200pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) 201{ 202 pcici_t tag; 203 204 tag.cfg1 = 0; 205 if (device >= 32) return tag; 206 if (func >= 8) return tag; 207 208 switch (pci_mechanism) { 209 210 case 1: 211 tag.cfg1 = CONF1_ENABLE 212 | (((u_long) bus ) << 16ul) 213 | (((u_long) device) << 11ul) 214 | (((u_long) func ) << 8ul); 215 break; 216 case 2: 217 if (device >= 16) break; 218 tag.cfg2.port = 0xc000 | (device << 8ul); 219 tag.cfg2.enable = 0xf1 | (func << 1ul); 220 tag.cfg2.forward = bus; 221 break; 222 }; 223 return tag; 224} 225 226static pcici_t 227pcibus_ftag (pcici_t tag, u_char func) 228{ 229 switch (pci_mechanism) { 230 231 case 1: 232 tag.cfg1 &= ~0x700ul; 233 tag.cfg1 |= (((u_long) func) << 8ul); 234 break; 235 case 2: 236 tag.cfg2.enable = 0xf1 | (func << 1ul); 237 break; 238 }; 239 return tag; 240} 241 242/*-------------------------------------------------------------------- 243** 244** Read register from configuration space. 245** 246**-------------------------------------------------------------------- 247*/ 248 249static u_long 250pcibus_read (pcici_t tag, u_long reg) 251{ 252 u_long addr, data = 0; 253 254 if (!tag.cfg1) return (0xfffffffful); 255 256 switch (pci_mechanism) { 257 258 case 1: 259 addr = tag.cfg1 | (reg & 0xfc); 260#ifdef PCI_DEBUG 261 printf ("pci_conf_read(1): addr=%x ", addr); 262#endif 263 outl (CONF1_ADDR_PORT, addr); 264 data = inl (CONF1_DATA_PORT); 265 outl (CONF1_ADDR_PORT, 0 ); 266 break; 267 268 case 2: 269 addr = tag.cfg2.port | (reg & 0xfc); 270#ifdef PCI_DEBUG 271 printf ("pci_conf_read(2): addr=%x ", addr); 272#endif 273 outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); 274 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 275 276 data = inl ((u_short) addr); 277 278 outb (CONF2_ENABLE_PORT, 0); 279 outb (CONF2_FORWARD_PORT, 0); 280 break; 281 }; 282 283#ifdef PCI_DEBUG 284 printf ("data=%x\n", data); 285#endif 286 287 return (data); 288} 289 290/*-------------------------------------------------------------------- 291** 292** Write register into configuration space. 293** 294**-------------------------------------------------------------------- 295*/ 296 297static void 298pcibus_write (pcici_t tag, u_long reg, u_long data) 299{ 300 u_long addr; 301 302 if (!tag.cfg1) return; 303 304 switch (pci_mechanism) { 305 306 case 1: 307 addr = tag.cfg1 | (reg & 0xfc); 308#ifdef PCI_DEBUG 309 printf ("pci_conf_write(1): addr=%x data=%x\n", 310 addr, data); 311#endif 312 outl (CONF1_ADDR_PORT, addr); 313 outl (CONF1_DATA_PORT, data); 314 outl (CONF1_ADDR_PORT, 0 ); 315 break; 316 317 case 2: 318 addr = tag.cfg2.port | (reg & 0xfc); 319#ifdef PCI_DEBUG 320 printf ("pci_conf_write(2): addr=%x data=%x\n", 321 addr, data); 322#endif 323 outb (CONF2_ENABLE_PORT, tag.cfg2.enable); 324 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 325 326 outl ((u_short) addr, data); 327 328 outb (CONF2_ENABLE_PORT, 0); 329 outb (CONF2_FORWARD_PORT, 0); 330 break; 331 }; 332} 333 334/*----------------------------------------------------------------------- 335** 336** Register an interupt handler for a pci device. 337** 338**----------------------------------------------------------------------- 339*/ 340 341static int 342pcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr) 343{ 344 int result; 345 result = register_intr( 346 irq, /* isa irq */ 347 0, /* deviced?? */ 348 0, /* flags? */ 349 (inthand2_t*) func, /* handler */ 350 maskptr, /* mask pointer */ 351 arg); /* handler arg */ 352 353 if (result) { 354 printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); 355 return (result); 356 }; 357 update_intr_masks(); 358 359 INTREN ((1ul<<irq)); 360 return (0); 361} 362 363static int 364pcibus_ihandler_detach (int irq, void(*func)()) 365{ 366 int result; 367 368 INTRDIS ((1ul<<irq)); 369 370 result = unregister_intr (irq, (inthand2_t*) func); 371 372 if (result) 373 printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); 374 375 update_intr_masks(); 376 377 return (result); 378} 379 380static int 381pcibus_imask_include (int irq, unsigned* maskptr) 382{ 383 unsigned mask; 384 385 if (!maskptr) return (0); 386 387 mask = 1ul << irq; 388 389 if (*maskptr & mask) 390 return (-1); 391 392 INTRMASK (*maskptr, mask); 393 update_intr_masks(); 394 395 return (0); 396} 397 398static int 399pcibus_imask_exclude (int irq, unsigned* maskptr) 400{ 401 unsigned mask; 402 403 if (!maskptr) return (0); 404 405 mask = 1ul << irq; 406 407 if (! (*maskptr & mask)) 408 return (-1); 409 410 *maskptr &= ~mask; 411 update_intr_masks(); 412 413 return (0); 414} 415