1 /************************************************************************** 2 ** 3 ** $Id: pcibus.c,v 1.7 1995/03/22 19:51:59 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 86 static void 87 pcibus_setup (void); 88 89 static pcici_t 90 pcibus_tag (u_char bus, u_char device, u_char func); 91 92 static pcici_t 93 pcibus_ftag (pcici_t tag, u_char func); 94 95 static u_long 96 pcibus_read (pcici_t tag, u_long reg); 97 98 static void 99 pcibus_write (pcici_t tag, u_long reg, u_long data); 100 101 static int 102 pcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp); 103 104 static int 105 pcibus_ihandler_detach (int irq, void(*handler)()); 106 107 static int 108 pcibus_imask_include (int irq, unsigned* maskptr); 109 110 static int 111 pcibus_imask_exclude (int irq, unsigned* maskptr); 112 113 struct 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 131 DATA_SET (pcibus_set, i386pci); 132 133 /*-------------------------------------------------------------------- 134 ** 135 ** Determine configuration mode 136 ** 137 **-------------------------------------------------------------------- 138 */ 139 140 141 #define CONF1_ENABLE 0x80000000ul 142 #define CONF1_ADDR_PORT 0x0cf8 143 #define CONF1_DATA_PORT 0x0cfc 144 145 146 #define CONF2_ENABLE_PORT 0x0cf8 147 #define CONF2_FORWARD_PORT 0x0cfa 148 149 150 static void 151 pcibus_setup (void) 152 { 153 u_long result, oldval; 154 155 /*--------------------------------------- 156 ** Configuration mode 2 ? 157 **--------------------------------------- 158 */ 159 160 outb (CONF2_ENABLE_PORT, 0); 161 outb (CONF2_FORWARD_PORT, 0); 162 if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) { 163 pci_mechanism = 2; 164 pci_maxdevice = 16; 165 return; 166 }; 167 168 /*--------------------------------------- 169 ** Configuration mode 1 ? 170 **--------------------------------------- 171 */ 172 173 oldval = inl (CONF1_ADDR_PORT); 174 outl (CONF1_ADDR_PORT, CONF1_ENABLE); 175 result = inl (CONF1_ADDR_PORT); 176 outl (CONF1_ADDR_PORT, oldval); 177 178 if (result == CONF1_ENABLE) { 179 pci_mechanism = 1; 180 pci_maxdevice = 32; 181 return; 182 }; 183 184 /*--------------------------------------- 185 ** No PCI bus available. 186 **--------------------------------------- 187 */ 188 } 189 190 /*-------------------------------------------------------------------- 191 ** 192 ** Build a pcitag from bus, device and function number 193 ** 194 **-------------------------------------------------------------------- 195 */ 196 197 static pcici_t 198 pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) 199 { 200 pcici_t tag; 201 202 tag.cfg1 = 0; 203 if (device >= 32) return tag; 204 if (func >= 8) return tag; 205 206 switch (pci_mechanism) { 207 208 case 1: 209 tag.cfg1 = CONF1_ENABLE 210 | (((u_long) bus ) << 16ul) 211 | (((u_long) device) << 11ul) 212 | (((u_long) func ) << 8ul); 213 break; 214 case 2: 215 if (device >= 16) break; 216 tag.cfg2.port = 0xc000 | (device << 8ul); 217 tag.cfg2.enable = 0xf1 | (func << 1ul); 218 tag.cfg2.forward = bus; 219 break; 220 }; 221 return tag; 222 } 223 224 static pcici_t 225 pcibus_ftag (pcici_t tag, u_char func) 226 { 227 switch (pci_mechanism) { 228 229 case 1: 230 tag.cfg1 &= ~0x700ul; 231 tag.cfg1 |= (((u_long) func) << 8ul); 232 break; 233 case 2: 234 tag.cfg2.enable = 0xf1 | (func << 1ul); 235 break; 236 }; 237 return tag; 238 } 239 240 /*-------------------------------------------------------------------- 241 ** 242 ** Read register from configuration space. 243 ** 244 **-------------------------------------------------------------------- 245 */ 246 247 static u_long 248 pcibus_read (pcici_t tag, u_long reg) 249 { 250 u_long addr, data = 0; 251 252 if (!tag.cfg1) return (0xfffffffful); 253 254 switch (pci_mechanism) { 255 256 case 1: 257 addr = tag.cfg1 | (reg & 0xfc); 258 #ifdef PCI_DEBUG 259 printf ("pci_conf_read(1): addr=%x ", addr); 260 #endif 261 outl (CONF1_ADDR_PORT, addr); 262 data = inl (CONF1_DATA_PORT); 263 outl (CONF1_ADDR_PORT, 0 ); 264 break; 265 266 case 2: 267 addr = tag.cfg2.port | (reg & 0xfc); 268 #ifdef PCI_DEBUG 269 printf ("pci_conf_read(2): addr=%x ", addr); 270 #endif 271 outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); 272 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 273 274 data = inl ((u_short) addr); 275 276 outb (CONF2_ENABLE_PORT, 0); 277 outb (CONF2_FORWARD_PORT, 0); 278 break; 279 }; 280 281 #ifdef PCI_DEBUG 282 printf ("data=%x\n", data); 283 #endif 284 285 return (data); 286 } 287 288 /*-------------------------------------------------------------------- 289 ** 290 ** Write register into configuration space. 291 ** 292 **-------------------------------------------------------------------- 293 */ 294 295 static void 296 pcibus_write (pcici_t tag, u_long reg, u_long data) 297 { 298 u_long addr; 299 300 if (!tag.cfg1) return; 301 302 switch (pci_mechanism) { 303 304 case 1: 305 addr = tag.cfg1 | (reg & 0xfc); 306 #ifdef PCI_DEBUG 307 printf ("pci_conf_write(1): addr=%x data=%x\n", 308 addr, data); 309 #endif 310 outl (CONF1_ADDR_PORT, addr); 311 outl (CONF1_DATA_PORT, data); 312 outl (CONF1_ADDR_PORT, 0 ); 313 break; 314 315 case 2: 316 addr = tag.cfg2.port | (reg & 0xfc); 317 #ifdef PCI_DEBUG 318 printf ("pci_conf_write(2): addr=%x data=%x\n", 319 addr, data); 320 #endif 321 outb (CONF2_ENABLE_PORT, tag.cfg2.enable); 322 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 323 324 outl ((u_short) addr, data); 325 326 outb (CONF2_ENABLE_PORT, 0); 327 outb (CONF2_FORWARD_PORT, 0); 328 break; 329 }; 330 } 331 332 /*----------------------------------------------------------------------- 333 ** 334 ** Register an interupt handler for a pci device. 335 ** 336 **----------------------------------------------------------------------- 337 */ 338 339 static int 340 pcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr) 341 { 342 int result; 343 result = register_intr( 344 irq, /* isa irq */ 345 0, /* deviced?? */ 346 0, /* flags? */ 347 (inthand2_t*) func, /* handler */ 348 maskptr, /* mask pointer */ 349 arg); /* handler arg */ 350 351 if (result) { 352 printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); 353 return (result); 354 }; 355 update_intr_masks(); 356 357 INTREN ((1ul<<irq)); 358 return (0); 359 } 360 361 static int 362 pcibus_ihandler_detach (int irq, void(*func)()) 363 { 364 int result; 365 366 INTRDIS ((1ul<<irq)); 367 368 result = unregister_intr (irq, (inthand2_t*) func); 369 370 if (result) 371 printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); 372 373 update_intr_masks(); 374 375 return (result); 376 } 377 378 static int 379 pcibus_imask_include (int irq, unsigned* maskptr) 380 { 381 unsigned mask; 382 383 if (!maskptr) return (0); 384 385 mask = 1ul << irq; 386 387 if (*maskptr & mask) 388 return (-1); 389 390 INTRMASK (*maskptr, mask); 391 update_intr_masks(); 392 393 return (0); 394 } 395 396 static int 397 pcibus_imask_exclude (int irq, unsigned* maskptr) 398 { 399 unsigned mask; 400 401 if (!maskptr) return (0); 402 403 mask = 1ul << irq; 404 405 if (! (*maskptr & mask)) 406 return (-1); 407 408 *maskptr &= ~mask; 409 update_intr_masks(); 410 411 return (0); 412 } 413