1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * LDT Fabric Initialization File: ldtinit.c 5 * 6 ********************************************************************* 7 * 8 * Copyright 2001,2002,2003 9 * Broadcom Corporation. All rights reserved. 10 * 11 * This software is furnished under license and may be used and 12 * copied only in accordance with the following terms and 13 * conditions. Subject to these conditions, you may download, 14 * copy, install, use, modify and distribute modified or unmodified 15 * copies of this software in source and/or binary form. No title 16 * or ownership is transferred hereby. 17 * 18 * 1) Any source code used, modified or distributed must reproduce 19 * and retain this copyright notice and list of conditions 20 * as they appear in the source file. 21 * 22 * 2) No right is granted to use any trade name, trademark, or 23 * logo of Broadcom Corporation. The "Broadcom Corporation" 24 * name may not be used to endorse or promote products derived 25 * from this software without the prior written permission of 26 * Broadcom Corporation. 27 * 28 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 29 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 30 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 31 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 32 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 33 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 35 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 36 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 37 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 38 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 39 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 40 * THE POSSIBILITY OF SUCH DAMAGE. 41 ********************************************************************* */ 42 43#if CFG_LDT 44/* 45 * ldtinit.c: generic LDT fabric initialization and capability 46 * management. 47 */ 48 49#include "lib_types.h" 50#include "lib_printf.h" 51#include "cfe_timer.h" 52 53#include "pcivar.h" 54#include "pci_internal.h" 55#include "pcireg.h" 56#include "ldtreg.h" 57 58/* Write-to-clear bit masks */ 59 60#if CFG_LDT_REV_017 /* XXX not really the right test */ 61#define LDT_LINKCTRL_WC (LDT_LINKCTRL_CRCERROR_MASK) 62#else 63#define LDT_LINKCTRL_WC (LDT_LINKCTRL_LINKFAIL | LDT_LINKCTRL_CRCERROR_MASK) 64#endif 65 66 67/* LDT global variables. */ 68 69/* It is sometimes necessary to restrict links to less than their 70 advertised capabilities. For link frequencies, this is done by 71 adjusting capability registers at the root of the chain. For link 72 widths, adjustments of the corresponding capabilities are not 73 currently provided. */ 74 75static unsigned int max_width = LDT_WIDTH_32; /* capability-encoded */ 76 77void 78ldt_set_max_width (unsigned int width_cap) 79{ 80 max_width = width_cap; 81} 82 83 84/* LDT capability lookup. */ 85 86unsigned 87pci_find_ldt_cap (pcitag_t tag, int secondary) 88{ 89 pcireg_t cpr; 90 pcireg_t cr; 91 int offset, prev; 92 int type; 93 94 cpr = pci_conf_read(tag, PCI_CAPLISTPTR_REG); 95 offset = PCI_CAPLIST_PTR(cpr) &~ 0x3; 96 prev = 0; 97 98 while (offset != 0 && offset != prev) { 99 cr = pci_conf_read(tag, offset); 100 if (PCI_CAPLIST_CAP(cr) == PCI_CAP_LDT) { 101 type = LDT_COMMAND_TYPE(cr); 102 if (secondary && type == LDT_COMMAND_TYPE_HOST) 103 return offset; 104 if (!secondary && type == LDT_COMMAND_TYPE_SLAVE) 105 return offset; 106 } 107 prev = offset; 108 offset = PCI_CAPLIST_NEXT(cr) &~ 0x3; 109 } 110 return 0; 111} 112 113 114/* LDT utility functions, mostly for capabilities. */ 115 116static pcireg_t 117ldt_get_link(pcitag_t tag, int offset, int index) 118{ 119 return pci_conf_read(tag, offset + LDT_LINKn_OFF(index)); 120} 121 122static void 123ldt_set_link(pcitag_t tag, int offset, int index, pcireg_t lr) 124{ 125 pci_conf_write(tag, offset + LDT_LINKn_OFF(index), lr); 126} 127 128#if (LDT_DEBUG != 0) 129static void 130ldt_show_cap(pcitag_t tag, int offset, int secondary) 131{ 132 printf(" Cmd %08x", pci_conf_read(tag, offset)); 133 offset += 4; 134 printf(" Lnk0 %08x", pci_conf_read(tag, offset)); 135 offset += 4; 136 if (!secondary) { 137 printf(" Lnk1 %08x", pci_conf_read(tag, offset)); 138 offset += 4; 139 } 140 printf(" Freq0 %08x", pci_conf_read(tag, offset)); 141 offset += 4; 142 if (!secondary) { 143 printf(" Freq1 %08x", pci_conf_read(tag, offset)); 144 offset += 4; 145 } 146 printf("\n"); 147} 148#else 149static void 150ldt_show_cap(pcitag_t tag, int offset, int secondary) 151{ 152} 153#endif 154 155 156/* LDT bus initialization and sizing. */ 157 158/* We expect the entire chain to be ready at approximately the same 159 time, but we add some delay here for possible node-to-node 160 differences. 161 162 Empirically, neither InitDone nor LinkFail is reported for an 163 unconnected link. Thus we do not expect the outgoing link of a 164 terminating tunnel node to become ready. 165 166 Also, CRC errors are observed to occur with InitDone, so link 167 errors do not necessarily force LinkFail. 168*/ 169 170static int 171ldt_wait_ready (pcitag_t tag, int offset, int index) 172{ 173 volatile int count; 174 volatile pcireg_t lr; 175 int linkerr; 176 177 linkerr = 0; 178 count = 0x10000; /* empirical */ 179 do { 180 if (--count == 0) 181 return 1; 182 lr = ldt_get_link(tag, offset, index); 183 if ((lr & (LDT_LINKCTRL_LINKFAIL | LDT_LINKCTRL_CRCERROR_MASK)) != 0) 184 linkerr = 1; 185 } while ((lr & (LDT_LINKCTRL_INITDONE | LDT_LINKCTRL_LINKFAIL)) == 0); 186 187 return linkerr; 188} 189 190static void 191ldt_end_chain (pcitag_t tag, int offset, int index) 192{ 193 pcireg_t lr, t; 194 195 lr = ldt_get_link(tag, offset, index); 196 lr |= LDT_LINKCTRL_EOC; 197 ldt_set_link(tag, offset, index, lr); 198 lr |= LDT_LINKCTRL_TXOFF; 199 ldt_set_link(tag, offset, index, lr); 200 t = ldt_get_link(tag, offset, index); /* push */ 201} 202 203 204static uint16_t 205ldt_freq_cap (pcitag_t tag, int offset, int index) 206{ 207 pcireg_t cmd, cr; 208 uint16_t freq_cap; 209 210 cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 211 if (LDT_COMMAND_TYPE(cmd) == LDT_COMMAND_TYPE_HOST) { 212 cr = pci_conf_read(tag, offset + LDT_FREQ_OFF); 213 if (LDT_REVISION_ID(cr) == LDT_REV_017) { 214 /* REV 0.17 has restricted support for setting 215 frequencies. We assume that this is the host bridge in 216 pseudo-1.0x mode, in which case the desired maximum 217 frequency was left in the LDT_FREQ register and all 218 lower frequencies are supported. */ 219 freq_cap = (1 << (LDT_LINKFREQ(cr) + 1)) - 1; 220 } else { 221 freq_cap = LDT_LINKFREQ_CAP(cr); 222 } 223 } else { 224 cr = pci_conf_read(tag, offset + LDT_FREQ0_OFF); 225 if (LDT_REVISION_ID(cr) == LDT_REV_017) { 226 /* REV 0.17 has restricted support for setting frequencies. 227 This is not the host bridge. What to do? XXX */ 228 freq_cap = (1 << LDT_FREQ_200); 229 } else { 230 cr = pci_conf_read(tag, offset + LDT_FREQn_OFF(index)); 231 freq_cap = LDT_LINKFREQ_CAP(cr); 232 } 233 } 234 return freq_cap; 235} 236 237static uint8_t 238ldt_max_freq (uint16_t freq_cap) 239{ 240 unsigned ldt_freq; 241 242 /* Consider only standardized frequencies. */ 243 freq_cap &= 0x3F; /* XXX make symbolic */ 244 245 /* 200 MHz (encoded as 1 << 0) is required for all devices */ 246 freq_cap |= (1 << LDT_FREQ_200); 247 248 ldt_freq = 0; 249 250 while (freq_cap != 1) { 251 ldt_freq++; 252 freq_cap >>= 1; 253 } 254 255 return (ldt_freq >= LDT_FREQ_200 && ldt_freq <= LDT_FREQ_1000) ? 256 ldt_freq : LDT_FREQ_200; 257} 258 259static void 260ldt_set_freq (pcitag_t tag, int offset, int index, uint8_t freq) 261{ 262 pcireg_t cmd, cr; 263 264 cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 265 if (LDT_COMMAND_TYPE(cmd) == LDT_COMMAND_TYPE_HOST) { 266 cr = pci_conf_read(tag, offset + LDT_FREQ_OFF); 267 cr &=~ LDT_LINKFREQ_MASK; 268 cr |= (freq << LDT_LINKFREQ_SHIFT); 269 pci_conf_write(tag, offset + LDT_FREQ_OFF, cr); 270 } else { 271 cr = pci_conf_read(tag, offset + LDT_FREQn_OFF(index)); 272 cr &=~ LDT_LINKFREQ_MASK; 273 cr |= (freq << LDT_LINKFREQ_SHIFT); 274 pci_conf_write(tag, offset + LDT_FREQn_OFF(index), cr); 275 } 276#if (LDT_DEBUG != 0) 277 pci_tagprintf(tag, "set link %d freq = %02x\n", index, freq); 278#endif 279} 280 281 282static uint16_t 283ldt_set_link_freq (pcitag_t tag, int offset, int link, 284 pcitag_t prev_tag, int prev_offset, int prev_link, 285 uint16_t prev_cap) 286{ 287 uint16_t link_cap, freq_cap_in, freq_cap_out; 288 uint8_t ldt_freq; 289 290 /* Find common frequency for upstream link. */ 291 freq_cap_out = ldt_freq_cap(prev_tag, prev_offset, prev_link); 292 freq_cap_in = ldt_freq_cap(tag, offset, link); 293 link_cap = freq_cap_in & freq_cap_out & prev_cap; 294 ldt_freq = ldt_max_freq(link_cap); 295 296#if (LDT_DEBUG > 1) 297 pci_tagprintf(tag, "set freq %02x\n", ldt_freq); 298#endif 299 /* Set up frequency registers, next warm reset installs. */ 300 ldt_set_freq(prev_tag, prev_offset, prev_link, ldt_freq); 301 ldt_set_freq(tag, offset, link, ldt_freq); 302 303 return link_cap; 304} 305 306 307/* A link width capability is represented as a pair of hex digits, 308 (width_out, width_in), with widths encoded per LDT_WIDTH_*. This 309 matches the WIDTH and MAX_WIDTH fields used in LINKCFG fields. */ 310 311#define G_LINK_WIDTH_IN(cap) (((cap) >> 0) & 0x7) 312#define V_LINK_WIDTH_IN(v) (((v) & 0x7) << 0) 313#define G_LINK_WIDTH_OUT(cap) (((cap) >> 4) & 0x7) 314#define V_LINK_WIDTH_OUT(v) (((v) & 0x7) << 4) 315 316static unsigned int 317ldt_link_width(uint8_t width_cap) 318{ 319 static const uint8_t bit_width[8] = {8, 16, 0, 32, 2, 4, 0, 0}; 320 321 return bit_width[width_cap & 0x7]; 322} 323 324static uint8_t 325ldt_max_width(uint8_t width1, uint8_t width2) 326{ 327 /* Find the maximum width supported by both ends of the link. */ 328 uint8_t width; 329 330 if (width1 == width2) 331 width = width1; 332 else { 333 unsigned int bits1, bits2; 334 335 bits1 = ldt_link_width(width1); 336 bits2 = ldt_link_width(width2); 337 switch ((bits1 < bits2) ? bits1 : bits2) { 338 case 8: width = LDT_WIDTH_8; break; 339 case 16: width = LDT_WIDTH_16; break; 340 case 32: width = LDT_WIDTH_32; break; 341 case 2: width = LDT_WIDTH_2; break; 342 case 4: width = LDT_WIDTH_4; break; 343 default: width = LDT_WIDTH_DISC; break; 344 } 345 } 346 return width; 347} 348 349static unsigned int 350ldt_set_link_width (pcitag_t tag, int offset, int link, 351 pcitag_t prev_tag, int prev_offset, int prev_link) 352{ 353 pcireg_t lcl_attr, rem_attr; 354 uint8_t width_up, width_down; 355 356 lcl_attr = ldt_get_link(tag, offset, link); 357 rem_attr = ldt_get_link(prev_tag, prev_offset, prev_link); 358 359 width_down = ldt_max_width(LDT_LINKCFG_MAX_WIDTH_OUT(rem_attr), 360 LDT_LINKCFG_MAX_WIDTH_IN(lcl_attr)); 361 width_up = ldt_max_width(LDT_LINKCFG_MAX_WIDTH_OUT(lcl_attr), 362 LDT_LINKCFG_MAX_WIDTH_IN(rem_attr)); 363 364 if (ldt_link_width(width_down) > ldt_link_width(max_width)) 365 width_down = max_width; 366 if (ldt_link_width(width_up) > ldt_link_width(max_width)) 367 width_up = max_width; 368 369 rem_attr &= ~LDT_LINKCFG_WIDTH_MASK; 370 rem_attr |= (((V_LINK_WIDTH_IN(width_up) | V_LINK_WIDTH_OUT(width_down))) 371 << LDT_LINKCFG_WIDTH_SHIFT); 372 ldt_set_link(prev_tag, prev_offset, prev_link, rem_attr); 373 374 375 lcl_attr &= ~LDT_LINKCFG_WIDTH_MASK; 376 lcl_attr |= (((V_LINK_WIDTH_IN(width_down) | V_LINK_WIDTH_OUT(width_up))) 377 << LDT_LINKCFG_WIDTH_SHIFT); 378 ldt_set_link(tag, offset, link, lcl_attr); 379 380 return 0; 381} 382 383 384/* LDT fabric initialization. See LDT Spec, Section 13.3. */ 385static int 386ldt_fabric_init (pcitag_t br_tag, int br_offset, 387 int port, int bus, pci_flags_t flags) 388{ 389 int next_free_id; 390 pcitag_t prev_tag, tag; 391 int offset, prev_offset; 392 int link, prev_link; 393 uint16_t prev_cap; 394 pcireg_t cmd, lr, id, t; 395 int double_ended; 396 int linkerr; 397 398 prev_tag = br_tag; prev_offset = br_offset; prev_link = 0; 399 /* Since there is no direct peer-to-peer traffic, there is no 400 point in configuring a downstream link with more capability 401 than the current one. */ 402 prev_cap = ldt_freq_cap(br_tag, br_offset, 0); 403 404 /* For various reasons, including some chips that advertise link 405 frequencies they can't support, the system can cap the maximum 406 link frequency. Currently, the desired maximum frequency is 407 left in the LDT_FREQ register of the the bridge at the root of 408 the chain. */ 409 cmd = pci_conf_read(br_tag, br_offset + LDT_COMMAND_CAP_OFF); 410#ifndef _SB14XX_ 411 if (LDT_COMMAND_TYPE(cmd) == LDT_COMMAND_TYPE_HOST) { 412 pcireg_t cr = pci_conf_read(br_tag, br_offset + LDT_FREQ_OFF); 413 prev_cap &= (1 << (LDT_LINKFREQ(cr) + 1)) - 1; 414 } 415#else 416 /* XXX 1.05 parts need a different mechanism for this. */ 417#endif 418 419 next_free_id = 1; 420 double_ended = 0; 421 422#if (LDT_DEBUG != 0) 423 printf("Link sizing for bus %d, bridge freq cap %04x\n", 424 bus, ldt_freq_cap(br_tag, br_offset, 0)); 425#endif 426 for (;;) { 427 428 tag = pci_make_tag(port, bus, 0, 0); 429 430 id = pci_conf_read(tag, PCI_ID_REG); 431#if (LDT_DEBUG > 1) 432 pci_tagprintf(tag, "ldt_fabric_init: id register %08x\n", id); 433#endif 434 if (PCI_VENDOR(id) == 0xFFFF) { 435 /* The incoming link had InitDone set, but we got an NXA 436 trying to read the vendor id. Either the reverse link 437 is broken or we have found an LDT-Lite node. For now, 438 assume the latter. Since an LDT-Lite device cannot be 439 a tunnel, assume the chain terminates here. */ 440 pci_tagprintf(tag, "assumed LDT-LITE device (virtual unit %d)\n", 441 next_free_id); 442 break; 443 } 444 445 offset = pci_find_ldt_cap(tag, LDT_PRIMARY); 446 if (offset == 0) { 447 /* There is no primary interface; we must have found a host. */ 448 offset = pci_find_ldt_cap(tag, LDT_SECONDARY); 449 if (offset != 0) { 450 lr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 451 lr |= LDT_COMMAND_DOUBLE_ENDED; 452 pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, lr); 453 double_ended = 1; 454 cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 455 link = LDT_COMMAND_MASTER_HOST(cmd); /* Upstream link index */ 456 457 prev_cap = ldt_set_link_freq(tag, offset, link, 458 prev_tag, prev_offset, prev_link, 459 prev_cap); 460 (void)ldt_set_link_width(tag, offset, link, 461 prev_tag, prev_offset, prev_link); 462 } 463 break; 464 } 465 466 /* Otherwise, we have the primary interface. */ 467 468 /* Rewrite the old value to set master host bit. */ 469 cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 470 pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cmd); 471 cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); /* push */ 472 473 id = pci_conf_read(tag, PCI_ID_REG); 474 475 /* Update the unit id, gingerly. */ 476 cmd &= ~LDT_COMMAND_UNIT_ID_MASK; 477 cmd |= (next_free_id << LDT_COMMAND_UNIT_ID_SHIFT); 478#if (LDT_DEBUG != 0) 479 pci_tagprintf(tag, "ldt_fabric_init: set unit id %d\n", next_free_id); 480#endif 481 if (!pci_conf_write_acked(tag, offset + LDT_COMMAND_CAP_OFF, cmd)) { 482 pci_tagprintf(tag, "no ack of id update to %d\n", next_free_id); 483 } 484 485 /* The unit id just changed. Update the tag */ 486 tag = pci_make_tag(port, bus, next_free_id, 0); 487 t = pci_conf_read(tag, PCI_ID_REG); 488 if (t != id) { 489 pci_tagprintf(tag, "id mismatch: old %08x, new %08x\n", id, t); 490 } 491 492 next_free_id += LDT_COMMAND_UNIT_COUNT(cmd); 493 494 link = LDT_COMMAND_MASTER_HOST(cmd); /* Upstream link index */ 495 496 /* LDT Rev 0.17 does not support frequency updates. */ 497 if ((flags & PCI_FLG_LDT_REV_017) == 0) { 498 prev_cap = ldt_set_link_freq(tag, offset, link, 499 prev_tag, prev_offset, prev_link, 500 prev_cap); 501 (void)ldt_set_link_width(tag, offset, link, 502 prev_tag, prev_offset, prev_link); 503 } 504 505 link ^= 1; /* Downstream */ 506 linkerr = ldt_wait_ready(tag, offset, link); 507 lr = ldt_get_link(tag, offset, link); 508 ldt_set_link(tag, offset, link, lr | LDT_LINKCTRL_WC); 509 510#if (LDT_DEBUG != 0) 511 pci_tagprintf(tag, "node: up %d down %d:\n", link ^ 1, link); 512#endif 513 ldt_show_cap(tag, offset, LDT_PRIMARY); 514 515 if (linkerr || next_free_id > 0x1F) { 516 /* No downstream link or too many devices, set end of chain */ 517 ldt_end_chain(tag, offset, link); 518 break; 519 } 520 521 prev_tag = tag; prev_offset = offset; prev_link = link; 522 } 523 524 return double_ended; 525} 526 527 528static int 529ldt_fabric_reinit (int port, int bus) 530{ 531 int next_free_id; 532 pcitag_t tag; 533 int offset; 534 int link; 535 pcireg_t cmd, lr, id, t; 536 int linkerr; 537 538 next_free_id = 1; 539 540#if (LDT_DEBUG != 0) 541 printf("Link resizing for bus %d\n", bus); 542#endif 543 for (;;) { 544 545 tag = pci_make_tag(port, bus, 0, 0); 546 547 id = pci_conf_read(tag, PCI_ID_REG); 548 if (PCI_VENDOR(id) == 0xFFFF) { 549 /* Per the init pass, assume this indicates a link to an 550 LDT-Lite node, and the chain terminates here. */ 551 break; 552 } 553 554 offset = pci_find_ldt_cap(tag, LDT_PRIMARY); 555 if (offset == 0) { 556 /* There is no primary interface; we must have found a host. */ 557 offset = pci_find_ldt_cap(tag, LDT_SECONDARY); 558 if (offset != 0) { 559 lr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 560 lr |= LDT_COMMAND_DOUBLE_ENDED; 561 pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, lr); 562 } 563 break; 564 } 565 566 /* Otherwise, we have the primary interface. */ 567 568 /* Rewrite the old value to set master host bit. */ 569 cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 570 pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cmd); 571 cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 572 573 id = pci_conf_read(tag, PCI_ID_REG); 574 575 /* (Re)update the unit id. See above. */ 576 cmd &= ~LDT_COMMAND_UNIT_ID_MASK; 577 cmd |= (next_free_id << LDT_COMMAND_UNIT_ID_SHIFT); 578 if (!pci_conf_write_acked(tag, offset + LDT_COMMAND_CAP_OFF, cmd)) { 579 pci_tagprintf(tag, "no ack of id update to %d\n", next_free_id); 580 } 581 582 /* The unit id just changed. Update the tag */ 583 tag = pci_make_tag(port, bus, next_free_id, 0); 584 t = pci_conf_read(tag, PCI_ID_REG); /* for good measure */ 585 if (t != id) { 586 pci_tagprintf(tag, "id mismatch: old %08x, new %08x\n", id, t); 587 } 588 589 next_free_id += LDT_COMMAND_UNIT_COUNT(cmd); 590 591 link = LDT_COMMAND_MASTER_HOST(cmd); /* Upstream link index */ 592 link ^= 1; /* Downstream */ 593 594 linkerr = ldt_wait_ready(tag, offset, link); 595 596 lr = ldt_get_link(tag, offset, link); 597 ldt_set_link(tag, offset, link, lr | LDT_LINKCTRL_WC); 598#if (LDT_DEBUG > 1) 599 pci_tagprintf(tag, "node: up %d down %d:\n", link ^ 1, link); 600 ldt_show_cap(tag, offset, LDT_PRIMARY); 601#endif 602 if (linkerr || next_free_id > 0x1F) { 603 /* No downstream link or too many devices, set end of chain */ 604 ldt_end_chain(tag, offset, link); 605 break; 606 } 607 } 608 return next_free_id - 1; 609} 610 611 612/* LDT link reset (warm or cold as set up by caller) */ 613 614void 615ldt_link_reset (pcitag_t tag, int delay) 616{ 617 pcireg_t brctl; 618 619 /* This code is necessary for doing a warm reset as part of the HT 620 1.0x link sizing. Cold resets may be useful for LDT buses 621 behind bridges (none of which yet exist) but seem to be a bad 622 idea for the SB-1250 LDT bus in pass 1 parts. */ 623 624 /* Attempt a Secondary Bus Reset. */ 625 brctl = pci_conf_read(tag, PPB_BRCTL_INTERRUPT_REG); 626 brctl |= PPB_BRCTL_SECONDARY_RESET; 627 pci_conf_write(tag, PPB_BRCTL_INTERRUPT_REG, brctl); 628 629 brctl = pci_conf_read(tag, PPB_BRCTL_INTERRUPT_REG); 630 if ((brctl & PPB_BRCTL_SECONDARY_RESET) != 0) { 631 int i; 632 /* Bit can be written, assume soft reset is implemented. */ 633 brctl &=~ PPB_BRCTL_SECONDARY_RESET; 634 pci_conf_write(tag, PPB_BRCTL_INTERRUPT_REG, brctl); 635 636 /* Add some delay (duration is a guess) */ 637 for (i = 0; i < delay; i++) 638 (void)pci_conf_read(tag, PPB_BRCTL_INTERRUPT_REG); 639 /* Alternatively, wait for LinkFail or InitDone. */ 640 } 641} 642 643 644/* LDT bridge and fabric initialization for a secondary chain */ 645 646int 647ldt_chain_init (pcitag_t tag, int port, int bus, pci_flags_t flags) 648{ 649 int offset; 650 int double_ended; 651 int linkerr; 652 pcireg_t cr, lr; 653 int ndev, no_probe; 654 655#if 0 656 /* This code may be necessary for LDT buses behind bridges (none 657 of which yet exist) but seems to be a bad idea for the SB-1250 658 LDT bus in pass 1 parts. Note that if we do reset, we must 659 delay to give any attached devices a chance to (re)initialize 660 per the PCI spec. */ 661 662 /* Attempt a Secondary Bus Reset. */ 663 ldt_link_reset(tag, 100); 664#endif /* 0 */ 665 666 /* To avoid a chip erratum, we must prevent Type 0 configuration 667 probes that get NXAs on a double hosted chain. */ 668 no_probe = 0; 669 670 offset = pci_find_ldt_cap(tag, LDT_SECONDARY); 671 if (offset != 0) { 672 linkerr = ldt_wait_ready(tag, offset, 0); 673 674#if (LDT_DEBUG > 1) 675 pci_tagprintf(tag, "bridge secondary:\n"); 676 ldt_show_cap(tag, offset, LDT_SECONDARY); 677#endif 678 if (linkerr) { 679 pci_tagprintf(tag, "secondary bad or never ready\n"); 680 ldt_end_chain(tag, offset, 0); 681 } else { 682 lr = ldt_get_link(tag, offset, 0); 683 if ((lr & LDT_LINKCTRL_INITDONE) != 0) 684 double_ended = ldt_fabric_init(tag, offset, port, bus, flags); 685 else { 686 ldt_end_chain(tag, offset, 0); 687 double_ended = 0; 688 } 689 cr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 690 if (double_ended) 691 cr |= LDT_COMMAND_DOUBLE_ENDED; 692 else 693 cr &=~ LDT_COMMAND_DOUBLE_ENDED; 694 pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cr); 695 696 /* Rev 0.17 does not support dynamic link resizing. */ 697 if ((flags & PCI_FLG_LDT_REV_017) == 0) { 698 /* Issue a warm reset to update link frequencies. */ 699#if (LDT_DEBUG > 1) 700 pci_tagprintf(tag, "warm reset, bus %d\n", bus); 701#endif 702 cr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 703 cr |= LDT_COMMAND_WARM_RESET; 704 pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cr); 705 cr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 706 ldt_link_reset(tag, 100); 707 ldt_wait_ready(tag, offset, 0); 708 709 /* After reset, let secondary devices reinitialize. */ 710 cfe_sleep(CFE_HZ/2); 711 712 ndev = ldt_fabric_reinit(port, bus); 713 714 if (double_ended) { 715 cr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); 716 cr |= LDT_COMMAND_DOUBLE_ENDED; 717 pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cr); 718 719 /* Bug workaround -- don't scan simple dual-hosted chain */ 720 if (ndev == 0) 721 no_probe = 1; 722 } 723 } 724 } 725 } 726 727 return no_probe; 728} 729#endif /* CFG_LDT */ 730