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