1/************************************************************************** 2**
|
3** $Id: pcibus.c,v 1.15 1995/09/22 19:10:54 se Exp $
|
3** $Id: pcibus.c,v 1.16 1995/10/09 21:56:24 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_CHK 0x80000000ul 149#define CONF1_ENABLE_CHK1 0xFF000001ul
|
150#define CONF1_ENABLE_MSK1 0x80000000ul
|
150#define CONF1_ENABLE_MSK1 0x80000001ul |
151#define CONF1_ENABLE_RES1 0x80000000ul 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 159static int 160pcibus_check (void) 161{ 162 u_char device; 163 164 if (bootverbose) printf ("pcibus_check:\tdevice "); 165 166 for (device = 0; device < pci_maxdevice; device++) { 167 unsigned long id; 168 if (bootverbose) 169 printf ("%d ", device); 170 id = pcibus_read (pcibus_tag (0,device,0), 0); 171 if (id != 0xfffffffful) { 172 if (bootverbose) printf ("is there (id=%08lx)\n", id); 173 return 1; 174 } 175 } 176 if (bootverbose) 177 printf ("-- nothing found\n"); 178 return 0; 179} 180 181static void 182pcibus_setup (void) 183{
|
184 unsigned long mode1res,oldval;
185 unsigned char mode2res;
|
184 unsigned long mode1res,oldval1; 185 unsigned char mode2res,oldval2; |
186
|
187 oldval = inl (CONF1_ADDR_PORT);
188 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
189 outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
190 mode1res = inl(CONF1_ADDR_PORT);
191 mode2res = inb(CONF2_ENABLE_PORT);
192 outb (CONF2_ENABLE_PORT, 0);
193 outl (CONF1_ADDR_PORT, oldval);
|
187 oldval1 = inl (CONF1_ADDR_PORT); |
188 189 if (bootverbose) {
|
196 printf ("pcibus_setup(1):\tmode1res=0x%08lx (0x%08lx), "
197 "mode2res=0x%02x (0x%02x)\n",
198 mode1res,CONF1_ENABLE_CHK,
199 (int)mode2res,CONF2_ENABLE_CHK);
|
190 printf ("pcibus_setup(1):\tmode1 addr port (0x0cf8) is 0x%08lx\n", oldval1); |
191 } 192 193 /*---------------------------------------
|
203 ** No PCI, if neither mode1res nor mode2res could be read back
204 **---------------------------------------
205 */
206
207 if ((mode1res != CONF1_ENABLE_CHK) && (mode2res != CONF2_ENABLE_CHK)) {
208 return;
209 }
210
211 /*---------------------------------------
|
194 ** Assume configuration mechanism 1 for now ... 195 **--------------------------------------- 196 */ 197
|
216 pci_mechanism = 1;
217 pci_maxdevice = 32;
|
198 if ((oldval1 & CONF1_ENABLE) == 0) { |
199
|
219 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
220 outb (CONF1_ADDR_PORT +3, 0);
221 mode1res = inl (CONF1_ADDR_PORT);
222 outl (CONF1_ADDR_PORT, oldval);
|
200 pci_mechanism = 1; 201 pci_maxdevice = 32; |
202
|
224 if (bootverbose)
225 printf ("pcibus_setup(2):\tmode1res=0x%08lx (0x%08lx)\n",
226 mode1res, CONF1_ENABLE_CHK);
|
203 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 204 outb (CONF1_ADDR_PORT +3, 0); 205 mode1res = inl (CONF1_ADDR_PORT); 206 outl (CONF1_ADDR_PORT, oldval1); |
207
|
228 if (mode1res) {
229 if (pcibus_check())
230 return;
231 };
|
208 if (bootverbose) 209 printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n", 210 mode1res, CONF1_ENABLE_CHK); |
211
|
233 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
234 outl (CONF1_DATA_PORT, 0);
235 mode1res = inl(CONF1_ADDR_PORT);
236 outl (CONF1_ADDR_PORT, oldval);
|
212 if (mode1res) { 213 if (pcibus_check()) 214 return; 215 }; |
216
|
238 if (bootverbose)
239 printf ("pcibus_setup(3):\tmode1res=0x%08lx (0x%08lx)\n",
240 mode1res, CONF1_ENABLE_CHK1);
|
217 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 218 mode1res = inl(CONF1_ADDR_PORT); 219 outl (CONF1_ADDR_PORT, oldval1); |
220
|
242 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
243 if (pcibus_check())
244 return;
245 };
|
221 if (bootverbose) 222 printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n", 223 mode1res, CONF1_ENABLE_CHK1); |
224
|
225 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 226 if (pcibus_check()) 227 return; 228 }; 229 } 230 |
231 /*--------------------------------------- 232 ** Try configuration mechanism 2 ... 233 **--------------------------------------- 234 */ 235
|
252 if (bootverbose)
253 printf ("pcibus_setup(4):\tnow trying mechanism 2\n");
|
236 oldval2 = inb (CONF2_ENABLE_PORT); |
237
|
255 pci_mechanism = 2;
256 pci_maxdevice = 16;
|
238 if (bootverbose) { 239 printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2); 240 } |
241
|
258 if (pcibus_check())
259 return;
|
242 if ((oldval2 & 0xf0) == 0) { |
243
|
244 pci_mechanism = 2; 245 pci_maxdevice = 16; 246 247 outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 248 mode2res = inb(CONF2_ENABLE_PORT); 249 outb (CONF2_ENABLE_PORT, oldval2); 250 251 if (bootverbose) 252 printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n", 253 mode2res, CONF2_ENABLE_CHK); 254 255 if (mode2res == CONF2_ENABLE_RES) { 256 if (bootverbose) 257 printf ("pcibus_setup(2a):\tnow trying mechanism 2\n"); 258 259 if (pcibus_check()) 260 return; 261 } 262 } 263 |
264 /*--------------------------------------- 265 ** No PCI bus host bridge found 266 **--------------------------------------- 267 */ 268 269 pci_mechanism = 0; 270 pci_maxdevice = 0; 271} 272 273/*-------------------------------------------------------------------- 274** 275** Build a pcitag from bus, device and function number 276** 277**-------------------------------------------------------------------- 278*/ 279 280static pcici_t 281pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) 282{ 283 pcici_t tag; 284 285 tag.cfg1 = 0; 286 if (func >= 8) return tag; 287 288 switch (pci_mechanism) { 289 290 case 1: 291 if (device < 32) { 292 tag.cfg1 = CONF1_ENABLE 293 | (((u_long) bus ) << 16ul) 294 | (((u_long) device) << 11ul) 295 | (((u_long) func ) << 8ul); 296 } 297 break; 298 case 2: 299 if (device < 16) { 300 tag.cfg2.port = 0xc000 | (device << 8ul); 301 tag.cfg2.enable = 0xf0 | (func << 1ul); 302 tag.cfg2.forward = bus; 303 } 304 break; 305 }; 306 return tag; 307} 308 309static pcici_t 310pcibus_ftag (pcici_t tag, u_char func) 311{ 312 switch (pci_mechanism) { 313 314 case 1: 315 tag.cfg1 &= ~0x700ul; 316 tag.cfg1 |= (((u_long) func) << 8ul); 317 break; 318 case 2: 319 tag.cfg2.enable = 0xf0 | (func << 1ul); 320 break; 321 }; 322 return tag; 323} 324 325/*-------------------------------------------------------------------- 326** 327** Read register from configuration space. 328** 329**-------------------------------------------------------------------- 330*/ 331 332static u_long 333pcibus_read (pcici_t tag, u_long reg) 334{ 335 u_long addr, data = 0; 336 337 if (!tag.cfg1) return (0xfffffffful); 338 339 switch (pci_mechanism) { 340 341 case 1: 342 addr = tag.cfg1 | (reg & 0xfc); 343#ifdef PCI_DEBUG 344 printf ("pci_conf_read(1): addr=%x ", addr); 345#endif 346 outl (CONF1_ADDR_PORT, addr); 347 data = inl (CONF1_DATA_PORT); 348 outl (CONF1_ADDR_PORT, 0 ); 349 break; 350 351 case 2: 352 addr = tag.cfg2.port | (reg & 0xfc); 353#ifdef PCI_DEBUG 354 printf ("pci_conf_read(2): addr=%x ", addr); 355#endif 356 outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); 357 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 358 359 data = inl ((u_short) addr); 360 361 outb (CONF2_ENABLE_PORT, 0); 362 outb (CONF2_FORWARD_PORT, 0); 363 break; 364 }; 365 366#ifdef PCI_DEBUG 367 printf ("data=%x\n", data); 368#endif 369 370 return (data); 371} 372 373/*-------------------------------------------------------------------- 374** 375** Write register into configuration space. 376** 377**-------------------------------------------------------------------- 378*/ 379 380static void 381pcibus_write (pcici_t tag, u_long reg, u_long data) 382{ 383 u_long addr; 384 385 if (!tag.cfg1) return; 386 387 switch (pci_mechanism) { 388 389 case 1: 390 addr = tag.cfg1 | (reg & 0xfc); 391#ifdef PCI_DEBUG 392 printf ("pci_conf_write(1): addr=%x data=%x\n", 393 addr, data); 394#endif 395 outl (CONF1_ADDR_PORT, addr); 396 outl (CONF1_DATA_PORT, data); 397 outl (CONF1_ADDR_PORT, 0 ); 398 break; 399 400 case 2: 401 addr = tag.cfg2.port | (reg & 0xfc); 402#ifdef PCI_DEBUG 403 printf ("pci_conf_write(2): addr=%x data=%x\n", 404 addr, data); 405#endif 406 outb (CONF2_ENABLE_PORT, tag.cfg2.enable); 407 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 408 409 outl ((u_short) addr, data); 410 411 outb (CONF2_ENABLE_PORT, 0); 412 outb (CONF2_FORWARD_PORT, 0); 413 break; 414 }; 415} 416 417/*----------------------------------------------------------------------- 418** 419** Register an interupt handler for a pci device. 420** 421**----------------------------------------------------------------------- 422*/ 423 424static int 425pcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr) 426{ 427 int result; 428 result = register_intr( 429 irq, /* isa irq */ 430 0, /* deviced?? */ 431 0, /* flags? */ 432 (inthand2_t*) func, /* handler */ 433 maskptr, /* mask pointer */ 434 arg); /* handler arg */ 435 436 if (result) { 437 printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); 438 return (result); 439 }; 440 update_intr_masks(); 441 442 INTREN ((1ul<<irq)); 443 return (0); 444} 445 446static int 447pcibus_ihandler_detach (int irq, void(*func)()) 448{ 449 int result; 450 451 INTRDIS ((1ul<<irq)); 452 453 result = unregister_intr (irq, (inthand2_t*) func); 454 455 if (result) 456 printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); 457 458 update_intr_masks(); 459 460 return (result); 461} 462 463static int 464pcibus_imask_include (int irq, unsigned* maskptr) 465{ 466 unsigned mask; 467 468 if (!maskptr) return (0); 469 470 mask = 1ul << irq; 471 472 if (*maskptr & mask) 473 return (-1); 474 475 INTRMASK (*maskptr, mask); 476 update_intr_masks(); 477 478 return (0); 479} 480 481static int 482pcibus_imask_exclude (int irq, unsigned* maskptr) 483{ 484 unsigned mask; 485 486 if (!maskptr) return (0); 487 488 mask = 1ul << irq; 489 490 if (! (*maskptr & mask)) 491 return (-1); 492 493 *maskptr &= ~mask; 494 update_intr_masks(); 495 496 return (0); 497}
|