1 /* $NetBSD: pci_ranges.c,v 1.4 2012/10/27 17:18:14 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by David Young <dyoung@NetBSD.org>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: pci_ranges.c,v 1.4 2012/10/27 17:18:14 chs Exp $"); 35 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/errno.h> 40 #include <sys/bus.h> 41 #include <sys/kmem.h> 42 43 #include <prop/proplib.h> 44 #include <ppath/ppath.h> 45 46 #include <dev/pci/pcivar.h> 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pccbbreg.h> 49 50 #include <machine/autoconf.h> 51 52 typedef enum pci_alloc_regtype { 53 PCI_ALLOC_REGTYPE_NONE = 0 54 , PCI_ALLOC_REGTYPE_BAR = 1 55 , PCI_ALLOC_REGTYPE_WIN = 2 56 , PCI_ALLOC_REGTYPE_CBWIN = 3 57 , PCI_ALLOC_REGTYPE_VGA_EN = 4 58 } pci_alloc_regtype_t; 59 60 typedef enum pci_alloc_space { 61 PCI_ALLOC_SPACE_IO = 0 62 , PCI_ALLOC_SPACE_MEM = 1 63 } pci_alloc_space_t; 64 65 typedef enum pci_alloc_flags { 66 PCI_ALLOC_F_PREFETCHABLE = 0x1 67 } pci_alloc_flags_t; 68 69 typedef struct pci_alloc { 70 TAILQ_ENTRY(pci_alloc) pal_link; 71 pcitag_t pal_tag; 72 uint64_t pal_addr; 73 uint64_t pal_size; 74 pci_alloc_regtype_t pal_type; 75 struct pci_alloc_reg { 76 int r_ofs; 77 pcireg_t r_val; 78 pcireg_t r_mask; 79 } pal_reg[3]; 80 pci_alloc_space_t pal_space; 81 pci_alloc_flags_t pal_flags; 82 } pci_alloc_t; 83 84 typedef struct pci_alloc_reg pci_alloc_reg_t; 85 86 TAILQ_HEAD(pci_alloc_list, pci_alloc); 87 88 typedef struct pci_alloc_list pci_alloc_list_t; 89 90 static pci_alloc_t * 91 pci_alloc_dup(const pci_alloc_t *pal) 92 { 93 pci_alloc_t *npal; 94 95 if ((npal = kmem_alloc(sizeof(*npal), KM_SLEEP)) == NULL) 96 return NULL; 97 98 *npal = *pal; 99 100 return npal; 101 } 102 103 static bool 104 pci_alloc_linkdup(pci_alloc_list_t *pals, const pci_alloc_t *pal) 105 { 106 pci_alloc_t *npal; 107 108 if ((npal = pci_alloc_dup(pal)) == NULL) 109 return false; 110 111 TAILQ_INSERT_TAIL(pals, npal, pal_link); 112 113 return true; 114 } 115 116 struct range_infer_ctx { 117 pci_chipset_tag_t ric_pc; 118 pci_alloc_list_t ric_pals; 119 bus_addr_t ric_mmio_bottom; 120 bus_addr_t ric_mmio_top; 121 bus_addr_t ric_io_bottom; 122 bus_addr_t ric_io_top; 123 }; 124 125 static bool 126 io_range_extend(struct range_infer_ctx *ric, const pci_alloc_t *pal) 127 { 128 if (ric->ric_io_bottom > pal->pal_addr) 129 ric->ric_io_bottom = pal->pal_addr; 130 if (ric->ric_io_top < pal->pal_addr + pal->pal_size) 131 ric->ric_io_top = pal->pal_addr + pal->pal_size; 132 133 return pci_alloc_linkdup(&ric->ric_pals, pal); 134 } 135 136 static bool 137 io_range_extend_by_bar(struct range_infer_ctx *ric, int bus, int dev, int fun, 138 int ofs, pcireg_t curbar, pcireg_t sizebar) 139 { 140 pci_alloc_reg_t *r; 141 pci_alloc_t pal = { 142 .pal_flags = 0 143 , .pal_space = PCI_ALLOC_SPACE_IO 144 , .pal_type = PCI_ALLOC_REGTYPE_BAR 145 , .pal_reg = {{ 146 .r_mask = ~(pcireg_t)0 147 }} 148 }; 149 150 r = &pal.pal_reg[0]; 151 152 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun); 153 r->r_ofs = ofs; 154 r->r_val = curbar; 155 156 pal.pal_addr = PCI_MAPREG_IO_ADDR(curbar); 157 pal.pal_size = PCI_MAPREG_IO_SIZE(sizebar); 158 159 aprint_debug("%s: %d.%d.%d base at %" PRIx64 " size %" PRIx64 "\n", 160 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size); 161 162 return (pal.pal_size == 0) || io_range_extend(ric, &pal); 163 } 164 165 static bool 166 io_range_extend_by_vga_enable(struct range_infer_ctx *ric, 167 int bus, int dev, int fun, pcireg_t csr, pcireg_t bcr) 168 { 169 pci_alloc_reg_t *r; 170 pci_alloc_t tpal = { 171 .pal_flags = 0 172 , .pal_space = PCI_ALLOC_SPACE_IO 173 , .pal_type = PCI_ALLOC_REGTYPE_VGA_EN 174 , .pal_reg = {{ 175 .r_ofs = PCI_COMMAND_STATUS_REG 176 , .r_mask = PCI_COMMAND_IO_ENABLE 177 }, { 178 .r_ofs = PCI_BRIDGE_CONTROL_REG 179 , .r_mask = 180 PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT 181 }} 182 }, pal[2]; 183 184 aprint_debug("%s: %d.%d.%d enter\n", __func__, bus, dev, fun); 185 186 if ((csr & PCI_COMMAND_IO_ENABLE) == 0 || 187 (bcr & (PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT)) == 0) { 188 aprint_debug("%s: %d.%d.%d I/O or VGA disabled\n", 189 __func__, bus, dev, fun); 190 return true; 191 } 192 193 r = &tpal.pal_reg[0]; 194 tpal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun); 195 r[0].r_val = csr; 196 r[1].r_val = bcr; 197 198 pal[0] = pal[1] = tpal; 199 200 pal[0].pal_addr = 0x3b0; 201 pal[0].pal_size = 0x3bb - 0x3b0 + 1; 202 203 pal[1].pal_addr = 0x3c0; 204 pal[1].pal_size = 0x3df - 0x3c0 + 1; 205 206 /* XXX add aliases for pal[0..1] */ 207 208 return io_range_extend(ric, &pal[0]) && io_range_extend(ric, &pal[1]); 209 } 210 211 static bool 212 io_range_extend_by_win(struct range_infer_ctx *ric, 213 int bus, int dev, int fun, int ofs, int ofshigh, 214 pcireg_t io, pcireg_t iohigh) 215 { 216 const int fourkb = 4 * 1024; 217 pcireg_t baser, limitr; 218 pci_alloc_reg_t *r; 219 pci_alloc_t pal = { 220 .pal_flags = 0 221 , .pal_space = PCI_ALLOC_SPACE_IO 222 , .pal_type = PCI_ALLOC_REGTYPE_WIN 223 , .pal_reg = {{ 224 .r_mask = ~(pcireg_t)0 225 }} 226 }; 227 228 r = &pal.pal_reg[0]; 229 230 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun); 231 r[0].r_ofs = ofs; 232 r[0].r_val = io; 233 234 baser = ((io >> PCI_BRIDGE_STATIO_IOBASE_SHIFT) & 235 PCI_BRIDGE_STATIO_IOBASE_MASK) >> 4; 236 limitr = ((io >> PCI_BRIDGE_STATIO_IOLIMIT_SHIFT) & 237 PCI_BRIDGE_STATIO_IOLIMIT_MASK) >> 4; 238 239 if (PCI_BRIDGE_IO_32BITS(io)) { 240 pcireg_t baseh, limith; 241 242 r[1].r_mask = ~(pcireg_t)0; 243 r[1].r_ofs = ofshigh; 244 r[1].r_val = iohigh; 245 246 baseh = (iohigh >> PCI_BRIDGE_IOHIGH_BASE_SHIFT) & PCI_BRIDGE_IOHIGH_BASE_MASK; 247 limith = (iohigh >> PCI_BRIDGE_IOHIGH_LIMIT_SHIFT) & PCI_BRIDGE_IOHIGH_LIMIT_MASK; 248 249 baser |= baseh << 4; 250 limitr |= limith << 4; 251 } 252 253 /* XXX check with the PCI standard */ 254 if (baser > limitr) 255 return true; 256 257 pal.pal_addr = baser * fourkb; 258 pal.pal_size = (limitr - baser + 1) * fourkb; 259 260 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n", 261 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size); 262 263 return io_range_extend(ric, &pal); 264 } 265 266 static bool 267 io_range_extend_by_cbwin(struct range_infer_ctx *ric, 268 int bus, int dev, int fun, int ofs, pcireg_t base0, pcireg_t limit0) 269 { 270 pcireg_t base, limit; 271 pci_alloc_reg_t *r; 272 pci_alloc_t pal = { 273 .pal_flags = 0 274 , .pal_space = PCI_ALLOC_SPACE_IO 275 , .pal_type = PCI_ALLOC_REGTYPE_CBWIN 276 , .pal_reg = {{ 277 .r_mask = ~(pcireg_t)0 278 }, { 279 .r_mask = ~(pcireg_t)0 280 }} 281 }; 282 283 r = &pal.pal_reg[0]; 284 285 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun); 286 r[0].r_ofs = ofs; 287 r[0].r_val = base0; 288 r[1].r_ofs = ofs + 4; 289 r[1].r_val = limit0; 290 291 base = base0 & __BITS(31, 2); 292 limit = limit0 & __BITS(31, 2); 293 294 if (base > limit) 295 return true; 296 297 pal.pal_addr = base; 298 pal.pal_size = limit - base + 4; /* XXX */ 299 300 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n", 301 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size); 302 303 return io_range_extend(ric, &pal); 304 } 305 306 static void 307 io_range_infer(pci_chipset_tag_t pc, pcitag_t tag, void *ctx) 308 { 309 struct range_infer_ctx *ric = ctx; 310 pcireg_t bhlcr, limit, io; 311 int bar, bus, dev, fun, hdrtype, nbar; 312 bool ok = true; 313 314 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); 315 316 hdrtype = PCI_HDRTYPE_TYPE(bhlcr); 317 318 pci_decompose_tag(pc, tag, &bus, &dev, &fun); 319 320 switch (hdrtype) { 321 case PCI_HDRTYPE_PPB: 322 nbar = 2; 323 /* Extract I/O windows */ 324 ok = ok && io_range_extend_by_win(ric, bus, dev, fun, 325 PCI_BRIDGE_STATIO_REG, 326 PCI_BRIDGE_IOHIGH_REG, 327 pci_conf_read(pc, tag, PCI_BRIDGE_STATIO_REG), 328 pci_conf_read(pc, tag, PCI_BRIDGE_IOHIGH_REG)); 329 ok = ok && io_range_extend_by_vga_enable(ric, bus, dev, fun, 330 pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG), 331 pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG)); 332 break; 333 case PCI_HDRTYPE_PCB: 334 /* Extract I/O windows */ 335 io = pci_conf_read(pc, tag, PCI_CB_IOBASE0); 336 limit = pci_conf_read(pc, tag, PCI_CB_IOLIMIT0); 337 ok = ok && io_range_extend_by_cbwin(ric, bus, dev, fun, 338 PCI_CB_IOBASE0, io, limit); 339 io = pci_conf_read(pc, tag, PCI_CB_IOBASE1); 340 limit = pci_conf_read(pc, tag, PCI_CB_IOLIMIT1); 341 ok = ok && io_range_extend_by_cbwin(ric, bus, dev, fun, 342 PCI_CB_IOBASE1, io, limit); 343 nbar = 1; 344 break; 345 case PCI_HDRTYPE_DEVICE: 346 nbar = 6; 347 break; 348 default: 349 aprint_debug("%s: unknown header type %d at %d.%d.%d\n", 350 __func__, hdrtype, bus, dev, fun); 351 return; 352 } 353 354 for (bar = 0; bar < nbar; bar++) { 355 pcireg_t basebar, sizebar; 356 357 basebar = pci_conf_read(pc, tag, PCI_BAR(bar)); 358 pci_conf_write(pc, tag, PCI_BAR(bar), 0xffffffff); 359 sizebar = pci_conf_read(pc, tag, PCI_BAR(bar)); 360 pci_conf_write(pc, tag, PCI_BAR(bar), basebar); 361 362 if (sizebar == 0) 363 continue; 364 if (PCI_MAPREG_TYPE(sizebar) != PCI_MAPREG_TYPE_IO) 365 continue; 366 367 ok = ok && io_range_extend_by_bar(ric, bus, dev, fun, 368 PCI_BAR(bar), basebar, sizebar); 369 } 370 if (!ok) { 371 aprint_verbose("I/O range inference failed at PCI %d.%d.%d\n", 372 bus, dev, fun); 373 } 374 } 375 376 static bool 377 mmio_range_extend(struct range_infer_ctx *ric, const pci_alloc_t *pal) 378 { 379 if (ric->ric_mmio_bottom > pal->pal_addr) 380 ric->ric_mmio_bottom = pal->pal_addr; 381 if (ric->ric_mmio_top < pal->pal_addr + pal->pal_size) 382 ric->ric_mmio_top = pal->pal_addr + pal->pal_size; 383 384 return pci_alloc_linkdup(&ric->ric_pals, pal); 385 } 386 387 static bool 388 mmio_range_extend_by_bar(struct range_infer_ctx *ric, int bus, int dev, int fun, 389 int ofs, pcireg_t curbar, pcireg_t sizebar) 390 { 391 int type; 392 bool prefetchable; 393 pci_alloc_reg_t *r; 394 pci_alloc_t pal = { 395 .pal_flags = 0 396 , .pal_space = PCI_ALLOC_SPACE_MEM 397 , .pal_type = PCI_ALLOC_REGTYPE_BAR 398 , .pal_reg = {{ 399 .r_mask = ~(pcireg_t)0 400 }} 401 }; 402 403 r = &pal.pal_reg[0]; 404 405 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun); 406 r->r_ofs = ofs; 407 r->r_val = curbar; 408 409 pal.pal_addr = PCI_MAPREG_MEM_ADDR(curbar); 410 411 type = PCI_MAPREG_MEM_TYPE(curbar); 412 prefetchable = PCI_MAPREG_MEM_PREFETCHABLE(curbar); 413 414 if (prefetchable) 415 pal.pal_flags |= PCI_ALLOC_F_PREFETCHABLE; 416 417 switch (type) { 418 case PCI_MAPREG_MEM_TYPE_32BIT: 419 pal.pal_size = PCI_MAPREG_MEM_SIZE(sizebar); 420 break; 421 case PCI_MAPREG_MEM_TYPE_64BIT: 422 pal.pal_size = PCI_MAPREG_MEM64_SIZE(sizebar); 423 break; 424 case PCI_MAPREG_MEM_TYPE_32BIT_1M: 425 default: 426 aprint_debug("%s: ignored memory type %d at %d.%d.%d\n", 427 __func__, type, bus, dev, fun); 428 return false; 429 } 430 431 aprint_debug("%s: %d.%d.%d base at %" PRIx64 " size %" PRIx64 "\n", 432 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size); 433 434 return (pal.pal_size == 0) || mmio_range_extend(ric, &pal); 435 } 436 437 static bool 438 mmio_range_extend_by_vga_enable(struct range_infer_ctx *ric, 439 int bus, int dev, int fun, pcireg_t csr, pcireg_t bcr) 440 { 441 pci_alloc_reg_t *r; 442 pci_alloc_t tpal = { 443 .pal_flags = PCI_ALLOC_F_PREFETCHABLE /* XXX a guess */ 444 , .pal_space = PCI_ALLOC_SPACE_MEM 445 , .pal_type = PCI_ALLOC_REGTYPE_VGA_EN 446 , .pal_reg = {{ 447 .r_ofs = PCI_COMMAND_STATUS_REG 448 , .r_mask = PCI_COMMAND_MEM_ENABLE 449 }, { 450 .r_ofs = PCI_BRIDGE_CONTROL_REG 451 , .r_mask = 452 PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT 453 }} 454 }, pal; 455 456 aprint_debug("%s: %d.%d.%d enter\n", __func__, bus, dev, fun); 457 458 if ((csr & PCI_COMMAND_MEM_ENABLE) == 0 || 459 (bcr & (PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT)) == 0) { 460 aprint_debug("%s: %d.%d.%d memory or VGA disabled\n", 461 __func__, bus, dev, fun); 462 return true; 463 } 464 465 r = &tpal.pal_reg[0]; 466 tpal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun); 467 r[0].r_val = csr; 468 r[1].r_val = bcr; 469 470 pal = tpal; 471 472 pal.pal_addr = 0xa0000; 473 pal.pal_size = 0xbffff - 0xa0000 + 1; 474 475 return mmio_range_extend(ric, &pal); 476 } 477 478 static bool 479 mmio_range_extend_by_win(struct range_infer_ctx *ric, 480 int bus, int dev, int fun, int ofs, pcireg_t mem) 481 { 482 const int onemeg = 1024 * 1024; 483 pcireg_t baser, limitr; 484 pci_alloc_reg_t *r; 485 pci_alloc_t pal = { 486 .pal_flags = 0 487 , .pal_space = PCI_ALLOC_SPACE_MEM 488 , .pal_type = PCI_ALLOC_REGTYPE_WIN 489 , .pal_reg = {{ 490 .r_mask = ~(pcireg_t)0 491 }} 492 }; 493 494 r = &pal.pal_reg[0]; 495 496 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun); 497 r->r_ofs = ofs; 498 r->r_val = mem; 499 500 baser = (mem >> PCI_BRIDGE_MEMORY_BASE_SHIFT) & 501 PCI_BRIDGE_MEMORY_BASE_MASK; 502 limitr = (mem >> PCI_BRIDGE_MEMORY_LIMIT_SHIFT) & 503 PCI_BRIDGE_MEMORY_LIMIT_MASK; 504 505 /* XXX check with the PCI standard */ 506 if (baser > limitr || limitr == 0) 507 return true; 508 509 pal.pal_addr = baser * onemeg; 510 pal.pal_size = (limitr - baser + 1) * onemeg; 511 512 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n", 513 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size); 514 515 return mmio_range_extend(ric, &pal); 516 } 517 518 static bool 519 mmio_range_extend_by_prememwin(struct range_infer_ctx *ric, 520 int bus, int dev, int fun, int ofs, pcireg_t mem, 521 int hibaseofs, pcireg_t hibase, 522 int hilimitofs, pcireg_t hilimit) 523 { 524 const int onemeg = 1024 * 1024; 525 uint64_t baser, limitr; 526 pci_alloc_reg_t *r; 527 pci_alloc_t pal = { 528 .pal_flags = PCI_ALLOC_F_PREFETCHABLE 529 , .pal_space = PCI_ALLOC_SPACE_MEM 530 , .pal_type = PCI_ALLOC_REGTYPE_WIN 531 , .pal_reg = {{ 532 .r_mask = ~(pcireg_t)0 533 }} 534 }; 535 536 r = &pal.pal_reg[0]; 537 538 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun); 539 r[0].r_ofs = ofs; 540 r[0].r_val = mem; 541 542 baser = (mem >> PCI_BRIDGE_PREFETCHMEM_BASE_SHIFT) & 543 PCI_BRIDGE_PREFETCHMEM_BASE_MASK; 544 limitr = (mem >> PCI_BRIDGE_PREFETCHMEM_LIMIT_SHIFT) & 545 PCI_BRIDGE_PREFETCHMEM_LIMIT_MASK; 546 547 if (PCI_BRIDGE_PREFETCHMEM_64BITS(mem)) { 548 r[1].r_mask = r[2].r_mask = ~(pcireg_t)0; 549 r[1].r_ofs = hibaseofs; 550 r[1].r_val = hibase; 551 r[2].r_ofs = hilimitofs; 552 r[2].r_val = hilimit; 553 554 baser |= hibase << 12; 555 limitr |= hibase << 12; 556 } 557 558 /* XXX check with the PCI standard */ 559 if (baser > limitr || limitr == 0) 560 return true; 561 562 pal.pal_addr = baser * onemeg; 563 pal.pal_size = (limitr - baser + 1) * onemeg; 564 565 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n", 566 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size); 567 568 return mmio_range_extend(ric, &pal); 569 } 570 571 static bool 572 mmio_range_extend_by_cbwin(struct range_infer_ctx *ric, 573 int bus, int dev, int fun, int ofs, pcireg_t base, pcireg_t limit, 574 bool prefetchable) 575 { 576 pci_alloc_reg_t *r; 577 pci_alloc_t pal = { 578 .pal_flags = 0 579 , .pal_space = PCI_ALLOC_SPACE_MEM 580 , .pal_type = PCI_ALLOC_REGTYPE_CBWIN 581 , .pal_reg = {{ 582 .r_mask = ~(pcireg_t)0 583 }, { 584 .r_mask = ~(pcireg_t)0 585 }} 586 }; 587 588 r = &pal.pal_reg[0]; 589 590 if (prefetchable) 591 pal.pal_flags |= PCI_ALLOC_F_PREFETCHABLE; 592 593 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun); 594 r[0].r_ofs = ofs; 595 r[0].r_val = base; 596 r[1].r_ofs = ofs + 4; 597 r[1].r_val = limit; 598 599 if (base > limit) 600 return true; 601 602 if (limit == 0) 603 return true; 604 605 pal.pal_addr = base; 606 pal.pal_size = limit - base + 4096; 607 608 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n", 609 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size); 610 611 return mmio_range_extend(ric, &pal); 612 } 613 614 static void 615 mmio_range_infer(pci_chipset_tag_t pc, pcitag_t tag, void *ctx) 616 { 617 struct range_infer_ctx *ric = ctx; 618 pcireg_t bcr, bhlcr, limit, mem, premem, hiprebase, hiprelimit; 619 int bar, bus, dev, fun, hdrtype, nbar; 620 bool ok = true; 621 622 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); 623 624 hdrtype = PCI_HDRTYPE_TYPE(bhlcr); 625 626 pci_decompose_tag(pc, tag, &bus, &dev, &fun); 627 628 switch (hdrtype) { 629 case PCI_HDRTYPE_PPB: 630 nbar = 2; 631 /* Extract memory windows */ 632 ok = ok && mmio_range_extend_by_win(ric, bus, dev, fun, 633 PCI_BRIDGE_MEMORY_REG, 634 pci_conf_read(pc, tag, PCI_BRIDGE_MEMORY_REG)); 635 premem = pci_conf_read(pc, tag, PCI_BRIDGE_PREFETCHMEM_REG); 636 if (PCI_BRIDGE_PREFETCHMEM_64BITS(premem)) { 637 aprint_debug("%s: 64-bit prefetchable memory window " 638 "at %d.%d.%d\n", __func__, bus, dev, fun); 639 hiprebase = pci_conf_read(pc, tag, 640 PCI_BRIDGE_PREFETCHBASE32_REG); 641 hiprelimit = pci_conf_read(pc, tag, 642 PCI_BRIDGE_PREFETCHLIMIT32_REG); 643 } else 644 hiprebase = hiprelimit = 0; 645 ok = ok && 646 mmio_range_extend_by_prememwin(ric, bus, dev, fun, 647 PCI_BRIDGE_PREFETCHMEM_REG, premem, 648 PCI_BRIDGE_PREFETCHBASE32_REG, hiprebase, 649 PCI_BRIDGE_PREFETCHLIMIT32_REG, hiprelimit) && 650 mmio_range_extend_by_vga_enable(ric, bus, dev, fun, 651 pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG), 652 pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG)); 653 break; 654 case PCI_HDRTYPE_PCB: 655 /* Extract memory windows */ 656 bcr = pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG); 657 mem = pci_conf_read(pc, tag, PCI_CB_MEMBASE0); 658 limit = pci_conf_read(pc, tag, PCI_CB_MEMLIMIT0); 659 ok = ok && mmio_range_extend_by_cbwin(ric, bus, dev, fun, 660 PCI_CB_MEMBASE0, mem, limit, 661 (bcr & CB_BCR_PREFETCH_MEMWIN0) != 0); 662 mem = pci_conf_read(pc, tag, PCI_CB_MEMBASE1); 663 limit = pci_conf_read(pc, tag, PCI_CB_MEMLIMIT1); 664 ok = ok && mmio_range_extend_by_cbwin(ric, bus, dev, fun, 665 PCI_CB_MEMBASE1, mem, limit, 666 (bcr & CB_BCR_PREFETCH_MEMWIN1) != 0); 667 nbar = 1; 668 break; 669 case PCI_HDRTYPE_DEVICE: 670 nbar = 6; 671 break; 672 default: 673 aprint_debug("%s: unknown header type %d at %d.%d.%d\n", 674 __func__, hdrtype, bus, dev, fun); 675 return; 676 } 677 678 for (bar = 0; bar < nbar; bar++) { 679 pcireg_t basebar, sizebar; 680 681 basebar = pci_conf_read(pc, tag, PCI_BAR(bar)); 682 pci_conf_write(pc, tag, PCI_BAR(bar), 0xffffffff); 683 sizebar = pci_conf_read(pc, tag, PCI_BAR(bar)); 684 pci_conf_write(pc, tag, PCI_BAR(bar), basebar); 685 686 if (sizebar == 0) 687 continue; 688 if (PCI_MAPREG_TYPE(sizebar) != PCI_MAPREG_TYPE_MEM) 689 continue; 690 691 ok = ok && mmio_range_extend_by_bar(ric, bus, dev, fun, 692 PCI_BAR(bar), basebar, sizebar); 693 } 694 if (!ok) { 695 aprint_verbose("MMIO range inference failed at PCI %d.%d.%d\n", 696 bus, dev, fun); 697 } 698 } 699 700 static const char * 701 pci_alloc_regtype_string(const pci_alloc_regtype_t t) 702 { 703 switch (t) { 704 case PCI_ALLOC_REGTYPE_BAR: 705 return "bar"; 706 case PCI_ALLOC_REGTYPE_WIN: 707 case PCI_ALLOC_REGTYPE_CBWIN: 708 return "window"; 709 case PCI_ALLOC_REGTYPE_VGA_EN: 710 return "vga-enable"; 711 default: 712 return "<unknown>"; 713 } 714 } 715 716 static void 717 pci_alloc_print(pci_chipset_tag_t pc, const pci_alloc_t *pal) 718 { 719 int bus, dev, fun; 720 const pci_alloc_reg_t *r; 721 722 pci_decompose_tag(pc, pal->pal_tag, &bus, &dev, &fun); 723 r = &pal->pal_reg[0]; 724 725 aprint_normal("%s range [0x%08" PRIx64 ", 0x%08" PRIx64 ")" 726 " at %d.%d.%d %s%s 0x%02x\n", 727 (pal->pal_space == PCI_ALLOC_SPACE_IO) ? "IO" : "MMIO", 728 pal->pal_addr, pal->pal_addr + pal->pal_size, 729 bus, dev, fun, 730 (pal->pal_flags & PCI_ALLOC_F_PREFETCHABLE) ? "prefetchable " : "", 731 pci_alloc_regtype_string(pal->pal_type), 732 r->r_ofs); 733 } 734 735 prop_dictionary_t pci_rsrc_dict = NULL; 736 737 static bool 738 pci_range_record(pci_chipset_tag_t pc, prop_array_t rsvns, 739 pci_alloc_list_t *pals, pci_alloc_space_t space) 740 { 741 int bus, dev, fun, i; 742 prop_array_t regs; 743 prop_dictionary_t reg; 744 const pci_alloc_t *pal; 745 const pci_alloc_reg_t *r; 746 prop_dictionary_t rsvn; 747 748 TAILQ_FOREACH(pal, pals, pal_link) { 749 bool ok = true; 750 751 r = &pal->pal_reg[0]; 752 753 if (pal->pal_space != space) 754 continue; 755 756 if ((rsvn = prop_dictionary_create()) == NULL) 757 return false; 758 759 if ((regs = prop_array_create()) == NULL) { 760 prop_object_release(rsvn); 761 return false; 762 } 763 764 if (!prop_dictionary_set(rsvn, "regs", regs)) { 765 prop_object_release(rsvn); 766 prop_object_release(regs); 767 return false; 768 } 769 770 for (i = 0; i < __arraycount(pal->pal_reg); i++) { 771 r = &pal->pal_reg[i]; 772 773 if (r->r_mask == 0) 774 break; 775 776 ok = (reg = prop_dictionary_create()) != NULL; 777 if (!ok) 778 break; 779 780 ok = prop_dictionary_set_uint16(reg, "offset", 781 r->r_ofs) && 782 prop_dictionary_set_uint32(reg, "val", r->r_val) && 783 prop_dictionary_set_uint32(reg, "mask", 784 r->r_mask) && prop_array_add(regs, reg); 785 if (!ok) { 786 prop_object_release(reg); 787 break; 788 } 789 } 790 791 pci_decompose_tag(pc, pal->pal_tag, &bus, &dev, &fun); 792 793 ok = ok && 794 prop_dictionary_set_cstring_nocopy(rsvn, "type", 795 pci_alloc_regtype_string(pal->pal_type)) && 796 prop_dictionary_set_uint64(rsvn, "address", 797 pal->pal_addr) && 798 prop_dictionary_set_uint64(rsvn, "size", pal->pal_size) && 799 prop_dictionary_set_uint8(rsvn, "bus", bus) && 800 prop_dictionary_set_uint8(rsvn, "device", dev) && 801 prop_dictionary_set_uint8(rsvn, "function", fun) && 802 prop_array_add(rsvns, rsvn); 803 prop_object_release(rsvn); 804 if (!ok) 805 return false; 806 } 807 return true; 808 } 809 810 prop_dictionary_t 811 pci_rsrc_filter(prop_dictionary_t rsrcs0, 812 bool (*predicate)(void *, prop_dictionary_t), void *arg) 813 { 814 int i, space; 815 prop_dictionary_t rsrcs; 816 prop_array_t rsvns; 817 ppath_t *op, *p; 818 819 if ((rsrcs = prop_dictionary_copy(rsrcs0)) == NULL) 820 return NULL; 821 822 for (space = 0; space < 2; space++) { 823 op = p = ppath_create(); 824 p = ppath_push_key(p, (space == 0) ? "memory" : "io"); 825 p = ppath_push_key(p, "bios-reservations"); 826 if (p == NULL) { 827 ppath_release(op); 828 return NULL; 829 } 830 if ((rsvns = ppath_lookup(rsrcs0, p)) == NULL) { 831 printf("%s: reservations not found\n", __func__); 832 ppath_release(p); 833 return NULL; 834 } 835 for (i = prop_array_count(rsvns); --i >= 0; ) { 836 prop_dictionary_t rsvn; 837 838 if ((p = ppath_push_idx(p, i)) == NULL) { 839 printf("%s: ppath_push_idx\n", __func__); 840 ppath_release(op); 841 prop_object_release(rsrcs); 842 return NULL; 843 } 844 845 rsvn = ppath_lookup(rsrcs0, p); 846 847 KASSERT(rsvn != NULL); 848 849 if (!(*predicate)(arg, rsvn)) { 850 ppath_copydel_object((prop_object_t)rsrcs0, 851 (prop_object_t *)&rsrcs, p); 852 } 853 854 if ((p = ppath_pop(p, NULL)) == NULL) { 855 printf("%s: ppath_pop\n", __func__); 856 ppath_release(p); 857 prop_object_release(rsrcs); 858 return NULL; 859 } 860 } 861 ppath_release(op); 862 } 863 return rsrcs; 864 } 865 866 void 867 pci_ranges_infer(pci_chipset_tag_t pc, int minbus, int maxbus, 868 bus_addr_t *iobasep, bus_size_t *iosizep, 869 bus_addr_t *membasep, bus_size_t *memsizep) 870 { 871 prop_dictionary_t iodict = NULL, memdict = NULL; 872 prop_array_t iorsvns, memrsvns; 873 struct range_infer_ctx ric = { 874 .ric_io_bottom = ~((bus_addr_t)0) 875 , .ric_io_top = 0 876 , .ric_mmio_bottom = ~((bus_addr_t)0) 877 , .ric_mmio_top = 0 878 , .ric_pals = TAILQ_HEAD_INITIALIZER(ric.ric_pals) 879 }; 880 const pci_alloc_t *pal; 881 882 ric.ric_pc = pc; 883 pci_device_foreach_min(pc, minbus, maxbus, mmio_range_infer, &ric); 884 pci_device_foreach_min(pc, minbus, maxbus, io_range_infer, &ric); 885 if (membasep != NULL) 886 *membasep = ric.ric_mmio_bottom; 887 if (memsizep != NULL) 888 *memsizep = ric.ric_mmio_top - ric.ric_mmio_bottom; 889 if (iobasep != NULL) 890 *iobasep = ric.ric_io_bottom; 891 if (iosizep != NULL) 892 *iosizep = ric.ric_io_top - ric.ric_io_bottom; 893 aprint_verbose("%s: inferred %" PRIuMAX 894 " bytes of memory-mapped PCI space at 0x%" PRIxMAX "\n", __func__, 895 (uintmax_t)(ric.ric_mmio_top - ric.ric_mmio_bottom), 896 (uintmax_t)ric.ric_mmio_bottom); 897 aprint_verbose("%s: inferred %" PRIuMAX 898 " bytes of PCI I/O space at 0x%" PRIxMAX "\n", __func__, 899 (uintmax_t)(ric.ric_io_top - ric.ric_io_bottom), 900 (uintmax_t)ric.ric_io_bottom); 901 TAILQ_FOREACH(pal, &ric.ric_pals, pal_link) 902 pci_alloc_print(pc, pal); 903 904 if ((memdict = prop_dictionary_create()) == NULL) { 905 aprint_error("%s: could not create PCI MMIO " 906 "resources dictionary\n", __func__); 907 } else if ((memrsvns = prop_array_create()) == NULL) { 908 aprint_error("%s: could not create PCI BIOS memory " 909 "reservations array\n", __func__); 910 } else if (!prop_dictionary_set(memdict, "bios-reservations", 911 memrsvns)) { 912 aprint_error("%s: could not record PCI BIOS memory " 913 "reservations array\n", __func__); 914 } else if (!pci_range_record(pc, memrsvns, &ric.ric_pals, 915 PCI_ALLOC_SPACE_MEM)) { 916 aprint_error("%s: could not record PCI BIOS memory " 917 "reservations\n", __func__); 918 } else if (!prop_dictionary_set_uint64(memdict, 919 "start", ric.ric_mmio_bottom) || 920 !prop_dictionary_set_uint64(memdict, "size", 921 ric.ric_mmio_top - ric.ric_mmio_bottom)) { 922 aprint_error("%s: could not record PCI memory min & max\n", 923 __func__); 924 } else if ((iodict = prop_dictionary_create()) == NULL) { 925 aprint_error("%s: could not create PCI I/O " 926 "resources dictionary\n", __func__); 927 } else if ((iorsvns = prop_array_create()) == NULL) { 928 aprint_error("%s: could not create PCI BIOS I/O " 929 "reservations array\n", __func__); 930 } else if (!prop_dictionary_set(iodict, "bios-reservations", 931 iorsvns)) { 932 aprint_error("%s: could not record PCI BIOS I/O " 933 "reservations array\n", __func__); 934 } else if (!pci_range_record(pc, iorsvns, &ric.ric_pals, 935 PCI_ALLOC_SPACE_IO)) { 936 aprint_error("%s: could not record PCI BIOS I/O " 937 "reservations\n", __func__); 938 } else if (!prop_dictionary_set_uint64(iodict, 939 "start", ric.ric_io_bottom) || 940 !prop_dictionary_set_uint64(iodict, "size", 941 ric.ric_io_top - ric.ric_io_bottom)) { 942 aprint_error("%s: could not record PCI I/O min & max\n", 943 __func__); 944 } else if ((pci_rsrc_dict = prop_dictionary_create()) == NULL) { 945 aprint_error("%s: could not create PCI resources dictionary\n", 946 __func__); 947 } else if (!prop_dictionary_set(pci_rsrc_dict, "memory", memdict) || 948 !prop_dictionary_set(pci_rsrc_dict, "io", iodict)) { 949 aprint_error("%s: could not record PCI memory- or I/O-" 950 "resources dictionary\n", __func__); 951 prop_object_release(pci_rsrc_dict); 952 pci_rsrc_dict = NULL; 953 } 954 955 if (iodict != NULL) 956 prop_object_release(iodict); 957 if (memdict != NULL) 958 prop_object_release(memdict); 959 /* XXX release iorsvns, memrsvns */ 960 } 961 962 static bool 963 pcibus_rsvn_predicate(void *arg, prop_dictionary_t rsvn) 964 { 965 struct pcibus_attach_args *pba = arg; 966 uint8_t bus; 967 968 if (!prop_dictionary_get_uint8(rsvn, "bus", &bus)) 969 return false; 970 971 return pba->pba_bus <= bus && bus <= pba->pba_sub; 972 } 973 974 static bool 975 pci_rsvn_predicate(void *arg, prop_dictionary_t rsvn) 976 { 977 struct pci_attach_args *pa = arg; 978 uint8_t bus, device, function; 979 bool rc; 980 981 rc = prop_dictionary_get_uint8(rsvn, "bus", &bus) && 982 prop_dictionary_get_uint8(rsvn, "device", &device) && 983 prop_dictionary_get_uint8(rsvn, "function", &function); 984 985 if (!rc) 986 return false; 987 988 return pa->pa_bus == bus && pa->pa_device == device && 989 pa->pa_function == function; 990 } 991 992 void 993 device_pci_props_register(device_t dev, void *aux) 994 { 995 cfdata_t cf; 996 prop_dictionary_t dict; 997 998 cf = (device_parent(dev) != NULL) ? device_cfdata(dev) : NULL; 999 #if 0 1000 aprint_normal_dev(dev, "is%s a pci, parent %p, cf %p, ifattr %s\n", 1001 device_is_a(dev, "pci") ? "" : " not", 1002 device_parent(dev), 1003 cf, 1004 cf != NULL ? cfdata_ifattr(cf) : ""); 1005 #endif 1006 if (pci_rsrc_dict == NULL) 1007 return; 1008 1009 if (!device_is_a(dev, "pci") && 1010 (cf == NULL || strcmp(cfdata_ifattr(cf), "pci") != 0)) 1011 return; 1012 1013 dict = pci_rsrc_filter(pci_rsrc_dict, 1014 device_is_a(dev, "pci") ? &pcibus_rsvn_predicate 1015 : &pci_rsvn_predicate, aux); 1016 if (dict == NULL) 1017 return; 1018 (void)prop_dictionary_set(device_properties(dev), 1019 "pci-resources", dict); 1020 } 1021