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