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