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