pci_cfgreg.c revision 7234
1/************************************************************************** 2** 3** $Id: pcibus.c,v 1.4 1995/02/26 05:14:51 bde 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 52extern int printf(); 53 54#ifdef DENTARO 55 56#define SFAKE (32) 57 58static void 59dec21050 (u_int*reg) { 60 reg[0] = 0x00011011; 61 reg[1]&= 0x000001e7; 62 reg[2] = 0x06040001; 63 reg[3]&= 0x0000f8ff; 64 reg[3]|= 0x000100ff; 65 reg[4] = 0x00000000; 66 reg[5] = 0x00000000; 67 reg[6]&= 0xf8ffffff; 68 reg[7]&= 0x0000f0f0; /* io-limit */ 69 reg[8]&= 0xfff0fff0; /* mem-limit, non prefatchable */ 70 reg[9]&= 0xfff0fff0; /* mem-limit, prefetchable memory */ 71 reg[10] = 0x00000000; 72 reg[11] = 0x00000000; 73 reg[12] = 0x00000000; 74 reg[13] = 0x00000000; 75 reg[14] = 0x00000000; 76 reg[15]&= 0x00ef0000; 77} 78 79static void 80dec21140 (u_int*reg) { 81 reg[0] = 0x00091011u; 82 reg[4]&= 0xfffffffdu; 83 reg[4]|= 0x00000001u; 84 reg[5]&= 0xffffff00u; 85} 86 87struct fake { 88 u_int tag; 89 void (*proc)(u_int*); 90}; 91 92struct fake faketable [] = { 93{ 0xc70000f1, dec21050 }, 94{ 0xc00001f1, dec21140 }, 95{ 0xc40001f1, dec21140 }, 96{ 0xc80001f1, dec21140 }, 97{ 0xcc0001f1, dec21140 }, 98}; 99 100#define NFAKE (sizeof faketable / sizeof (struct fake)) 101 102static u_int fakedata[NFAKE * SFAKE]; 103 104u_int* findfake (pcici_t tag) 105{ 106 u_int *p; 107 int i; 108 for (i=0; i<NFAKE; i++) 109 if (faketable[i].tag == tag.tag) 110 break; 111 112 if (i>=NFAKE) 113 return (0); 114 p = &fakedata[i*SFAKE]; 115 (*faketable[i].proc)(p); 116 return (p); 117} 118#endif /*DENTARO*/ 119 120/*----------------------------------------------------------------- 121** 122** The following functions are provided by the pci bios. 123** They are used only by the pci configuration. 124** 125** pcibus_setup(): 126** Probes for a pci system. 127** Sets pci_maxdevice and pci_mechanism. 128** 129** pcibus_tag(): 130** Creates a handle for pci configuration space access. 131** This handle is given to the read/write functions. 132** 133** pcibus_ftag(): 134** Creates a modified handle. 135** 136** pcibus_read(): 137** Read a long word from the pci configuration space. 138** Requires a tag (from pcitag) and the register 139** number (should be a long word alligned one). 140** 141** pcibus_write(): 142** Writes a long word to the pci configuration space. 143** Requires a tag (from pcitag), the register number 144** (should be a long word alligned one), and a value. 145** 146** pcibus_regirq(): 147** Register an interupt handler for a pci device. 148** Requires a tag (from pcitag), the register number 149** (should be a long word alligned one), and a value. 150** 151**----------------------------------------------------------------- 152*/ 153 154static void 155pcibus_setup (void); 156 157static pcici_t 158pcibus_tag (u_char bus, u_char device, u_char func); 159 160static pcici_t 161pcibus_ftag (pcici_t tag, u_char func); 162 163static u_long 164pcibus_read (pcici_t tag, u_long reg); 165 166static void 167pcibus_write (pcici_t tag, u_long reg, u_long data); 168 169static int 170pcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp); 171 172static int 173pcibus_ihandler_detach (int irq, void(*handler)()); 174 175static int 176pcibus_imask_include (int irq, unsigned* maskptr); 177 178static int 179pcibus_imask_exclude (int irq, unsigned* maskptr); 180 181struct pcibus i386pci = { 182 "pci", 183 pcibus_setup, 184 pcibus_tag, 185 pcibus_ftag, 186 pcibus_read, 187 pcibus_write, 188 ICU_LEN, 189 pcibus_ihandler_attach, 190 pcibus_ihandler_detach, 191 pcibus_imask_include, 192 pcibus_imask_exclude, 193}; 194 195/* 196** Announce structure to generic driver 197*/ 198 199DATA_SET (pcibus_set, i386pci); 200 201/*-------------------------------------------------------------------- 202** 203** Determine configuration mode 204** 205**-------------------------------------------------------------------- 206*/ 207 208 209#define CONF1_ENABLE 0x80000000ul 210#define CONF1_ADDR_PORT 0x0cf8 211#define CONF1_DATA_PORT 0x0cfc 212 213 214#define CONF2_ENABLE_PORT 0x0cf8 215#define CONF2_FORWARD_PORT 0x0cfa 216 217 218static void 219pcibus_setup (void) 220{ 221 u_long result, oldval; 222 223 /*--------------------------------------- 224 ** Configuration mode 2 ? 225 **--------------------------------------- 226 */ 227 228 outb (CONF2_ENABLE_PORT, 0); 229 outb (CONF2_FORWARD_PORT, 0); 230 if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) { 231 pci_mechanism = 2; 232 pci_maxdevice = 16; 233 }; 234 235 /*--------------------------------------- 236 ** Configuration mode 1 ? 237 **--------------------------------------- 238 */ 239 240 oldval = inl (CONF1_ADDR_PORT); 241 outl (CONF1_ADDR_PORT, CONF1_ENABLE); 242 result = inl (CONF1_ADDR_PORT); 243 outl (CONF1_ADDR_PORT, oldval); 244 245 if (result == CONF1_ENABLE) { 246 pci_mechanism = 1; 247 pci_maxdevice = 32; 248 }; 249 250 /*--------------------------------------- 251 ** No PCI bus available. 252 **--------------------------------------- 253 */ 254} 255 256/*-------------------------------------------------------------------- 257** 258** Build a pcitag from bus, device and function number 259** 260**-------------------------------------------------------------------- 261*/ 262 263static pcici_t 264pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) 265{ 266 pcici_t tag; 267 268 tag.cfg1 = 0; 269 if (device >= 32) return tag; 270 if (func >= 8) return tag; 271 272 switch (pci_mechanism) { 273 274 case 1: 275 tag.cfg1 = CONF1_ENABLE 276 | (((u_long) bus ) << 16ul) 277 | (((u_long) device) << 11ul) 278 | (((u_long) func ) << 8ul); 279 break; 280 case 2: 281 if (device >= 16) break; 282 tag.cfg2.port = 0xc000 | (device << 8ul); 283 tag.cfg2.enable = 0xf1 | (func << 1ul); 284 tag.cfg2.forward = bus; 285 break; 286 }; 287 return tag; 288} 289 290static pcici_t 291pcibus_ftag (pcici_t tag, u_char func) 292{ 293 switch (pci_mechanism) { 294 295 case 1: 296 tag.cfg1 &= ~0x700ul; 297 tag.cfg1 |= (((u_long) func) << 8ul); 298 break; 299 case 2: 300 tag.cfg2.enable = 0xf1 | (func << 1ul); 301 break; 302 }; 303 return tag; 304} 305 306/*-------------------------------------------------------------------- 307** 308** Read register from configuration space. 309** 310**-------------------------------------------------------------------- 311*/ 312 313static u_long 314pcibus_read (pcici_t tag, u_long reg) 315{ 316 u_long addr, data = 0; 317 318#ifdef DENTARO 319 u_int*p = findfake(tag); 320 if (p) { 321#if 0 322 printf ("fake conf_read (tag=%x reg=%d val=%08x).\n", 323 tag.tag, (unsigned) reg, (unsigned) p[reg/4]); 324#endif 325 return (p[reg/4]); 326 } 327#endif 328 329 if (!tag.cfg1) return (0xfffffffful); 330 331 switch (pci_mechanism) { 332 333 case 1: 334 addr = tag.cfg1 | (reg & 0xfc); 335#ifdef PCI_DEBUG 336 printf ("pci_conf_read(1): addr=%x ", addr); 337#endif 338 outl (CONF1_ADDR_PORT, addr); 339 data = inl (CONF1_DATA_PORT); 340 outl (CONF1_ADDR_PORT, 0 ); 341 break; 342 343 case 2: 344 addr = tag.cfg2.port | (reg & 0xfc); 345#ifdef PCI_DEBUG 346 printf ("pci_conf_read(2): addr=%x ", addr); 347#endif 348 outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); 349 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 350 351 data = inl ((u_short) addr); 352 353 outb (CONF2_ENABLE_PORT, 0); 354 outb (CONF2_FORWARD_PORT, 0); 355 break; 356 }; 357 358#ifdef PCI_DEBUG 359 printf ("data=%x\n", data); 360#endif 361 362 return (data); 363} 364 365/*-------------------------------------------------------------------- 366** 367** Write register into configuration space. 368** 369**-------------------------------------------------------------------- 370*/ 371 372static void 373pcibus_write (pcici_t tag, u_long reg, u_long data) 374{ 375 u_long addr; 376 377#ifdef DENTARO 378 u_int*p = findfake(tag); 379 if (p) { 380#if 0 381 printf ("fake conf_write (tag=%x reg=%d val=%08x).\n", 382 tag.tag, (unsigned) reg, (unsigned) data); 383#endif 384 p[reg/4]=data; 385 return; 386 } 387#endif 388 389 if (!tag.cfg1) return; 390 391 switch (pci_mechanism) { 392 393 case 1: 394 addr = tag.cfg1 | (reg & 0xfc); 395#ifdef PCI_DEBUG 396 printf ("pci_conf_write(1): addr=%x data=%x\n", 397 addr, data); 398#endif 399 outl (CONF1_ADDR_PORT, addr); 400 outl (CONF1_DATA_PORT, data); 401 outl (CONF1_ADDR_PORT, 0 ); 402 break; 403 404 case 2: 405 addr = tag.cfg2.port | (reg & 0xfc); 406#ifdef PCI_DEBUG 407 printf ("pci_conf_write(2): addr=%x data=%x\n", 408 addr, data); 409#endif 410 outb (CONF2_ENABLE_PORT, tag.cfg2.enable); 411 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 412 413 outl ((u_short) addr, data); 414 415 outb (CONF2_ENABLE_PORT, 0); 416 outb (CONF2_FORWARD_PORT, 0); 417 break; 418 }; 419} 420 421/*----------------------------------------------------------------------- 422** 423** Register an interupt handler for a pci device. 424** 425**----------------------------------------------------------------------- 426*/ 427 428static int 429pcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr) 430{ 431 int result; 432 result = register_intr( 433 irq, /* isa irq */ 434 0, /* deviced?? */ 435 0, /* flags? */ 436 (inthand2_t*) func, /* handler */ 437 maskptr, /* mask pointer */ 438 arg); /* handler arg */ 439 440 if (result) { 441 printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); 442 return (result); 443 }; 444 update_intr_masks(); 445 446 INTREN ((1ul<<irq)); 447 return (0); 448} 449 450static int 451pcibus_ihandler_detach (int irq, void(*func)()) 452{ 453 int result; 454 455 INTRDIS ((1ul<<irq)); 456 457 result = unregister_intr (irq, (inthand2_t*) func); 458 459 if (result) 460 printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); 461 462 update_intr_masks(); 463 464 return (result); 465} 466 467static int 468pcibus_imask_include (int irq, unsigned* maskptr) 469{ 470 unsigned mask; 471 472 if (!maskptr) return (0); 473 474 mask = 1ul << irq; 475 476 if (*maskptr & mask) 477 return (-1); 478 479 INTRMASK (*maskptr, mask); 480 update_intr_masks(); 481 482 return (0); 483} 484 485static int 486pcibus_imask_exclude (int irq, unsigned* maskptr) 487{ 488 unsigned mask; 489 490 if (!maskptr) return (0); 491 492 mask = 1ul << irq; 493 494 if (! (*maskptr & mask)) 495 return (-1); 496 497 *maskptr &= ~mask; 498 update_intr_masks(); 499 500 return (0); 501} 502