pci_cfgreg.c revision 10887
1/************************************************************************** 2** 3** $Id: pcibus.c,v 1.13 1995/09/15 21:43:45 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#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41 42#include <machine/cpu.h> /* bootverbose */ 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 int 87pcibus_check (void); 88 89static void 90pcibus_setup (void); 91 92static pcici_t 93pcibus_tag (u_char bus, u_char device, u_char func); 94 95static pcici_t 96pcibus_ftag (pcici_t tag, u_char func); 97 98static u_long 99pcibus_read (pcici_t tag, u_long reg); 100 101static void 102pcibus_write (pcici_t tag, u_long reg, u_long data); 103 104static int 105pcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp); 106 107static int 108pcibus_ihandler_detach (int irq, void(*handler)()); 109 110static int 111pcibus_imask_include (int irq, unsigned* maskptr); 112 113static int 114pcibus_imask_exclude (int irq, unsigned* maskptr); 115 116struct pcibus i386pci = { 117 "pci", 118 pcibus_setup, 119 pcibus_tag, 120 pcibus_ftag, 121 pcibus_read, 122 pcibus_write, 123 ICU_LEN, 124 pcibus_ihandler_attach, 125 pcibus_ihandler_detach, 126 pcibus_imask_include, 127 pcibus_imask_exclude, 128}; 129 130/* 131** Announce structure to generic driver 132*/ 133 134DATA_SET (pcibus_set, i386pci); 135 136/*-------------------------------------------------------------------- 137** 138** Determine configuration mode 139** 140**-------------------------------------------------------------------- 141*/ 142 143 144#define CONF1_ADDR_PORT 0x0cf8 145#define CONF1_DATA_PORT 0x0cfc 146 147#define CONF1_ENABLE 0x80000000ul 148#define CONF1_ENABLE_CHK1 0xF0000001ul 149#define CONF1_ENABLE_MSK1 0x80000001ul 150#define CONF1_ENABLE_RES1 0x80000000ul 151#define CONF1_ENABLE_CHK2 0xfffffffful 152#define CONF1_ENABLE_RES2 0x80fffffcul 153 154#define CONF2_ENABLE_PORT 0x0cf8 155#define CONF2_FORWARD_PORT 0x0cfa 156 157#define CONF2_ENABLE_CHK 0x0e 158#define CONF2_ENABLE_RES 0x0e 159 160 161static int 162pcibus_check (void) 163{ 164 u_char device; 165 166 for (device = 0; device < pci_maxdevice; device++) { 167 if (pcibus_read (pcibus_tag (0,device,0), 0) != 0xfffffffful) 168 return 1; 169 } 170 return 0; 171} 172 173static void 174pcibus_setup (void) 175{ 176 u_long result, oldval; 177 178 /*--------------------------------------- 179 ** Configuration mode 1 ? 180 **--------------------------------------- 181 */ 182 183 oldval = inl (CONF1_ADDR_PORT); 184 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 185 outb (CONF1_ADDR_PORT +3, 0); 186 result = inl (CONF1_ADDR_PORT); 187 outl (CONF1_ADDR_PORT, oldval); 188 189 if ((result & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 190 pci_mechanism = 1; 191 pci_maxdevice = 32; 192 if (pcibus_check()) 193 return; 194 }; 195 196 /*--------------------------------------- 197 ** Configuration mode 2 ? 198 **--------------------------------------- 199 */ 200 201 outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 202 outb (CONF2_FORWARD_PORT, 0); 203 result = inb (CONF2_ENABLE_PORT); 204 205 outb (CONF2_ENABLE_PORT, 0); 206 outb (CONF2_FORWARD_PORT, 0); 207 if ((result == CONF2_ENABLE_RES) 208 && !inb (CONF2_ENABLE_PORT) 209 && !inb (CONF2_FORWARD_PORT)) { 210 pci_mechanism = 2; 211 pci_maxdevice = 16; 212 if (pcibus_check()) 213 return; 214 }; 215 216 217 /*----------------------------------------------------- 218 ** Well, is it Configuration mode 1, after all ? 219 **----------------------------------------------------- 220 */ 221 222 oldval = inl (CONF1_ADDR_PORT); 223 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK2); 224 outl (CONF1_DATA_PORT, 0); 225 result = inl (CONF1_ADDR_PORT); 226 outl (CONF1_ADDR_PORT, oldval); 227 228 if (result == CONF1_ENABLE_RES2) { 229 pci_mechanism = 1; 230 pci_maxdevice = 32; 231 if (pcibus_check()) 232 return; 233 } 234 235 /*--------------------------------------- 236 ** No PCI bus host bridge found 237 **--------------------------------------- 238 */ 239 240 if (bootverbose && (result != 0xfffffffful)) 241 printf ("pcibus_setup: " 242 "wrote 0x%08x, read back 0x%08x, expected 0x%08x\n", 243 CONF1_ENABLE_CHK2, result, CONF1_ENABLE_RES2); 244 245 pci_mechanism = 0; 246 pci_maxdevice = 0; 247} 248 249/*-------------------------------------------------------------------- 250** 251** Build a pcitag from bus, device and function number 252** 253**-------------------------------------------------------------------- 254*/ 255 256static pcici_t 257pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) 258{ 259 pcici_t tag; 260 261 tag.cfg1 = 0; 262 if (func >= 8) return tag; 263 264 switch (pci_mechanism) { 265 266 case 1: 267 if (device < 32) { 268 tag.cfg1 = CONF1_ENABLE 269 | (((u_long) bus ) << 16ul) 270 | (((u_long) device) << 11ul) 271 | (((u_long) func ) << 8ul); 272 } 273 break; 274 case 2: 275 if (device < 16) { 276 tag.cfg2.port = 0xc000 | (device << 8ul); 277 tag.cfg2.enable = 0xf0 | (func << 1ul); 278 tag.cfg2.forward = bus; 279 } 280 break; 281 }; 282 return tag; 283} 284 285static pcici_t 286pcibus_ftag (pcici_t tag, u_char func) 287{ 288 switch (pci_mechanism) { 289 290 case 1: 291 tag.cfg1 &= ~0x700ul; 292 tag.cfg1 |= (((u_long) func) << 8ul); 293 break; 294 case 2: 295 tag.cfg2.enable = 0xf0 | (func << 1ul); 296 break; 297 }; 298 return tag; 299} 300 301/*-------------------------------------------------------------------- 302** 303** Read register from configuration space. 304** 305**-------------------------------------------------------------------- 306*/ 307 308static u_long 309pcibus_read (pcici_t tag, u_long reg) 310{ 311 u_long addr, data = 0; 312 313 if (!tag.cfg1) return (0xfffffffful); 314 315 switch (pci_mechanism) { 316 317 case 1: 318 addr = tag.cfg1 | (reg & 0xfc); 319#ifdef PCI_DEBUG 320 printf ("pci_conf_read(1): addr=%x ", addr); 321#endif 322 outl (CONF1_ADDR_PORT, addr); 323 data = inl (CONF1_DATA_PORT); 324 outl (CONF1_ADDR_PORT, 0 ); 325 break; 326 327 case 2: 328 addr = tag.cfg2.port | (reg & 0xfc); 329#ifdef PCI_DEBUG 330 printf ("pci_conf_read(2): addr=%x ", addr); 331#endif 332 outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); 333 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 334 335 data = inl ((u_short) addr); 336 337 outb (CONF2_ENABLE_PORT, 0); 338 outb (CONF2_FORWARD_PORT, 0); 339 break; 340 }; 341 342#ifdef PCI_DEBUG 343 printf ("data=%x\n", data); 344#endif 345 346 return (data); 347} 348 349/*-------------------------------------------------------------------- 350** 351** Write register into configuration space. 352** 353**-------------------------------------------------------------------- 354*/ 355 356static void 357pcibus_write (pcici_t tag, u_long reg, u_long data) 358{ 359 u_long addr; 360 361 if (!tag.cfg1) return; 362 363 switch (pci_mechanism) { 364 365 case 1: 366 addr = tag.cfg1 | (reg & 0xfc); 367#ifdef PCI_DEBUG 368 printf ("pci_conf_write(1): addr=%x data=%x\n", 369 addr, data); 370#endif 371 outl (CONF1_ADDR_PORT, addr); 372 outl (CONF1_DATA_PORT, data); 373 outl (CONF1_ADDR_PORT, 0 ); 374 break; 375 376 case 2: 377 addr = tag.cfg2.port | (reg & 0xfc); 378#ifdef PCI_DEBUG 379 printf ("pci_conf_write(2): addr=%x data=%x\n", 380 addr, data); 381#endif 382 outb (CONF2_ENABLE_PORT, tag.cfg2.enable); 383 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 384 385 outl ((u_short) addr, data); 386 387 outb (CONF2_ENABLE_PORT, 0); 388 outb (CONF2_FORWARD_PORT, 0); 389 break; 390 }; 391} 392 393/*----------------------------------------------------------------------- 394** 395** Register an interupt handler for a pci device. 396** 397**----------------------------------------------------------------------- 398*/ 399 400static int 401pcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr) 402{ 403 int result; 404 result = register_intr( 405 irq, /* isa irq */ 406 0, /* deviced?? */ 407 0, /* flags? */ 408 (inthand2_t*) func, /* handler */ 409 maskptr, /* mask pointer */ 410 arg); /* handler arg */ 411 412 if (result) { 413 printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); 414 return (result); 415 }; 416 update_intr_masks(); 417 418 INTREN ((1ul<<irq)); 419 return (0); 420} 421 422static int 423pcibus_ihandler_detach (int irq, void(*func)()) 424{ 425 int result; 426 427 INTRDIS ((1ul<<irq)); 428 429 result = unregister_intr (irq, (inthand2_t*) func); 430 431 if (result) 432 printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); 433 434 update_intr_masks(); 435 436 return (result); 437} 438 439static int 440pcibus_imask_include (int irq, unsigned* maskptr) 441{ 442 unsigned mask; 443 444 if (!maskptr) return (0); 445 446 mask = 1ul << irq; 447 448 if (*maskptr & mask) 449 return (-1); 450 451 INTRMASK (*maskptr, mask); 452 update_intr_masks(); 453 454 return (0); 455} 456 457static int 458pcibus_imask_exclude (int irq, unsigned* maskptr) 459{ 460 unsigned mask; 461 462 if (!maskptr) return (0); 463 464 mask = 1ul << irq; 465 466 if (! (*maskptr & mask)) 467 return (-1); 468 469 *maskptr &= ~mask; 470 update_intr_masks(); 471 472 return (0); 473} 474