pci_pir.c revision 10807
1/************************************************************************** 2** 3** $Id: pcibus.c,v 1.12 1995/09/14 20:27:31 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 <machine/cpu.h> /* bootverbose */ 45 46#include <i386/isa/icu.h> 47#include <i386/isa/isa.h> 48#include <i386/isa/isa_device.h> 49 50#include <pci/pcivar.h> 51#include <pci/pcireg.h> 52#include <pci/pcibus.h> 53 54/*----------------------------------------------------------------- 55** 56** The following functions are provided by the pci bios. 57** They are used only by the pci configuration. 58** 59** pcibus_setup(): 60** Probes for a pci system. 61** Sets pci_maxdevice and pci_mechanism. 62** 63** pcibus_tag(): 64** Creates a handle for pci configuration space access. 65** This handle is given to the read/write functions. 66** 67** pcibus_ftag(): 68** Creates a modified handle. 69** 70** pcibus_read(): 71** Read a long word from the pci configuration space. 72** Requires a tag (from pcitag) and the register 73** number (should be a long word alligned one). 74** 75** pcibus_write(): 76** Writes a long word to the pci configuration space. 77** Requires a tag (from pcitag), the register number 78** (should be a long word alligned one), and a value. 79** 80** pcibus_regirq(): 81** Register an interupt handler for a pci device. 82** Requires a tag (from pcitag), the register number 83** (should be a long word alligned one), and a value. 84** 85**----------------------------------------------------------------- 86*/ 87 88static void 89pcibus_setup (void); 90 91static pcici_t 92pcibus_tag (u_char bus, u_char device, u_char func); 93 94static pcici_t 95pcibus_ftag (pcici_t tag, u_char func); 96 97static u_long 98pcibus_read (pcici_t tag, u_long reg); 99 100static void 101pcibus_write (pcici_t tag, u_long reg, u_long data); 102 103static int 104pcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp); 105 106static int 107pcibus_ihandler_detach (int irq, void(*handler)()); 108 109static int 110pcibus_imask_include (int irq, unsigned* maskptr); 111 112static int 113pcibus_imask_exclude (int irq, unsigned* maskptr); 114 115struct pcibus i386pci = { 116 "pci", 117 pcibus_setup, 118 pcibus_tag, 119 pcibus_ftag, 120 pcibus_read, 121 pcibus_write, 122 ICU_LEN, 123 pcibus_ihandler_attach, 124 pcibus_ihandler_detach, 125 pcibus_imask_include, 126 pcibus_imask_exclude, 127}; 128 129/* 130** Announce structure to generic driver 131*/ 132 133DATA_SET (pcibus_set, i386pci); 134 135/*-------------------------------------------------------------------- 136** 137** Determine configuration mode 138** 139**-------------------------------------------------------------------- 140*/ 141 142 143#define CONF1_ADDR_PORT 0x0cf8 144#define CONF1_DATA_PORT 0x0cfc 145 146#define CONF1_ENABLE 0x80000000ul 147 148#define CONF1_ENABLE_CHK 0x80000001ul 149#define CONF1_ENABLE_MSK 0x80000001ul 150#define CONF1_ENABLE_RES 0x80000000ul 151 152 153#define CONF2_ENABLE_PORT 0x0cf8 154#define CONF2_FORWARD_PORT 0x0cfa 155 156#define CONF2_ENABLE_CHK 0x0e 157#define CONF2_ENABLE_RES 0x0e 158 159 160 161static void 162pcibus_setup (void) 163{ 164 u_long result, oldval; 165 166 /*--------------------------------------- 167 ** Configuration mode 1 ? 168 **--------------------------------------- 169 */ 170 171 oldval = inl (CONF1_ADDR_PORT); 172 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 173 outl (CONF1_DATA_PORT, 0); 174 result = inl (CONF1_ADDR_PORT); 175 outl (CONF1_ADDR_PORT, oldval); 176 177 if (bootverbose && (result != 0xfffffffful)) 178 printf ("pcibus_setup: " 179 "wrote 0x%08x, read back 0x%08x, expected 0x%08x\n", 180 CONF1_ENABLE_CHK, result, CONF1_ENABLE_RES); 181 182 if ((result & CONF1_ENABLE_MSK) == CONF1_ENABLE_RES) { 183 pci_mechanism = 1; 184 pci_maxdevice = 32; 185 return; 186 }; 187 188 /*--------------------------------------- 189 ** Configuration mode 2 ? 190 **--------------------------------------- 191 */ 192 193 outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 194 outb (CONF2_FORWARD_PORT, 0); 195 result = inb (CONF2_ENABLE_PORT); 196 197 outb (CONF2_ENABLE_PORT, 0); 198 if ((result == CONF2_ENABLE_RES) 199 && !inb (CONF2_ENABLE_PORT) 200 && !inb (CONF2_FORWARD_PORT)) { 201 pci_mechanism = 2; 202 pci_maxdevice = 16; 203 return; 204 }; 205 206 /*--------------------------------------- 207 ** No PCI bus host bridge found 208 **--------------------------------------- 209 */ 210 211 pci_mechanism = 0; 212 pci_maxdevice = 0; 213} 214 215/*-------------------------------------------------------------------- 216** 217** Build a pcitag from bus, device and function number 218** 219**-------------------------------------------------------------------- 220*/ 221 222static pcici_t 223pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) 224{ 225 pcici_t tag; 226 227 tag.cfg1 = 0; 228 if (func >= 8) return tag; 229 230 switch (pci_mechanism) { 231 232 case 1: 233 if (device < 32) { 234 tag.cfg1 = CONF1_ENABLE 235 | (((u_long) bus ) << 16ul) 236 | (((u_long) device) << 11ul) 237 | (((u_long) func ) << 8ul); 238 } 239 break; 240 case 2: 241 if (device < 16) { 242 tag.cfg2.port = 0xc000 | (device << 8ul); 243 tag.cfg2.enable = 0xf0 | (func << 1ul); 244 tag.cfg2.forward = bus; 245 } 246 break; 247 }; 248 return tag; 249} 250 251static pcici_t 252pcibus_ftag (pcici_t tag, u_char func) 253{ 254 switch (pci_mechanism) { 255 256 case 1: 257 tag.cfg1 &= ~0x700ul; 258 tag.cfg1 |= (((u_long) func) << 8ul); 259 break; 260 case 2: 261 tag.cfg2.enable = 0xf0 | (func << 1ul); 262 break; 263 }; 264 return tag; 265} 266 267/*-------------------------------------------------------------------- 268** 269** Read register from configuration space. 270** 271**-------------------------------------------------------------------- 272*/ 273 274static u_long 275pcibus_read (pcici_t tag, u_long reg) 276{ 277 u_long addr, data = 0; 278 279 if (!tag.cfg1) return (0xfffffffful); 280 281 switch (pci_mechanism) { 282 283 case 1: 284 addr = tag.cfg1 | (reg & 0xfc); 285#ifdef PCI_DEBUG 286 printf ("pci_conf_read(1): addr=%x ", addr); 287#endif 288 outl (CONF1_ADDR_PORT, addr); 289 data = inl (CONF1_DATA_PORT); 290 outl (CONF1_ADDR_PORT, 0 ); 291 break; 292 293 case 2: 294 addr = tag.cfg2.port | (reg & 0xfc); 295#ifdef PCI_DEBUG 296 printf ("pci_conf_read(2): addr=%x ", addr); 297#endif 298 outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); 299 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 300 301 data = inl ((u_short) addr); 302 303 outb (CONF2_ENABLE_PORT, 0); 304 outb (CONF2_FORWARD_PORT, 0); 305 break; 306 }; 307 308#ifdef PCI_DEBUG 309 printf ("data=%x\n", data); 310#endif 311 312 return (data); 313} 314 315/*-------------------------------------------------------------------- 316** 317** Write register into configuration space. 318** 319**-------------------------------------------------------------------- 320*/ 321 322static void 323pcibus_write (pcici_t tag, u_long reg, u_long data) 324{ 325 u_long addr; 326 327 if (!tag.cfg1) return; 328 329 switch (pci_mechanism) { 330 331 case 1: 332 addr = tag.cfg1 | (reg & 0xfc); 333#ifdef PCI_DEBUG 334 printf ("pci_conf_write(1): addr=%x data=%x\n", 335 addr, data); 336#endif 337 outl (CONF1_ADDR_PORT, addr); 338 outl (CONF1_DATA_PORT, data); 339 outl (CONF1_ADDR_PORT, 0 ); 340 break; 341 342 case 2: 343 addr = tag.cfg2.port | (reg & 0xfc); 344#ifdef PCI_DEBUG 345 printf ("pci_conf_write(2): addr=%x data=%x\n", 346 addr, data); 347#endif 348 outb (CONF2_ENABLE_PORT, tag.cfg2.enable); 349 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 350 351 outl ((u_short) addr, data); 352 353 outb (CONF2_ENABLE_PORT, 0); 354 outb (CONF2_FORWARD_PORT, 0); 355 break; 356 }; 357} 358 359/*----------------------------------------------------------------------- 360** 361** Register an interupt handler for a pci device. 362** 363**----------------------------------------------------------------------- 364*/ 365 366static int 367pcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr) 368{ 369 int result; 370 result = register_intr( 371 irq, /* isa irq */ 372 0, /* deviced?? */ 373 0, /* flags? */ 374 (inthand2_t*) func, /* handler */ 375 maskptr, /* mask pointer */ 376 arg); /* handler arg */ 377 378 if (result) { 379 printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); 380 return (result); 381 }; 382 update_intr_masks(); 383 384 INTREN ((1ul<<irq)); 385 return (0); 386} 387 388static int 389pcibus_ihandler_detach (int irq, void(*func)()) 390{ 391 int result; 392 393 INTRDIS ((1ul<<irq)); 394 395 result = unregister_intr (irq, (inthand2_t*) func); 396 397 if (result) 398 printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); 399 400 update_intr_masks(); 401 402 return (result); 403} 404 405static int 406pcibus_imask_include (int irq, unsigned* maskptr) 407{ 408 unsigned mask; 409 410 if (!maskptr) return (0); 411 412 mask = 1ul << irq; 413 414 if (*maskptr & mask) 415 return (-1); 416 417 INTRMASK (*maskptr, mask); 418 update_intr_masks(); 419 420 return (0); 421} 422 423static int 424pcibus_imask_exclude (int irq, unsigned* maskptr) 425{ 426 unsigned mask; 427 428 if (!maskptr) return (0); 429 430 mask = 1ul << irq; 431 432 if (! (*maskptr & mask)) 433 return (-1); 434 435 *maskptr &= ~mask; 436 update_intr_masks(); 437 438 return (0); 439} 440