blob: 2ecc0d0d601b3651f8804880703b569bcd66d1af [file] [log] [blame]
Myles Watsond61ada62008-10-02 19:20:22 +00001/*
Stefan Reinauer7ce8c542005-12-02 21:52:30 +00002 2005.11 yhlu add let the real sb to use small unitid
3*/
4// only for sb ht chain
5static void enumerate_ht_chain(void)
Eric Biederman05f26fc2003-06-11 21:55:00 +00006{
Stefan Reinauer08670622009-06-30 15:17:49 +00007#if CONFIG_HT_CHAIN_UNITID_BASE != 0
8/* CONFIG_HT_CHAIN_UNITID_BASE could be 0 (only one ht device in the ht chain), if so, don't need to go through the chain */
Stefan Reinauer7ce8c542005-12-02 21:52:30 +00009
Eric Biederman05f26fc2003-06-11 21:55:00 +000010 /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it.
11 * On most boards this just happens. If a cpu has multiple
12 * non Coherent links the appropriate bus registers for the
13 * links needs to be programed to point at bus 0.
14 */
Eric Biederman9b4336c2003-07-19 04:28:22 +000015 unsigned next_unitid, last_unitid;
Yinghai Lu18c70d72007-09-14 14:58:33 +000016 device_t dev;
Stefan Reinauer08670622009-06-30 15:17:49 +000017#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
18 //let't record the device of last ht device, So we can set the Unitid to CONFIG_HT_CHAIN_END_UNITID_BASE
Stefan Reinauer328a6942011-10-13 17:04:02 -070019 unsigned real_last_unitid = 0;
20 uint8_t real_last_pos = 0;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +000021 int ht_dev_num = 0; // except host_bridge
Yinghai Lu18c70d72007-09-14 14:58:33 +000022 uint8_t end_used = 0;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +000023#endif
arch import user (historical)98d0d302005-07-06 17:13:46 +000024
Yinghai Lu18c70d72007-09-14 14:58:33 +000025 dev = PCI_DEV(0,0,0);
Stefan Reinauer08670622009-06-30 15:17:49 +000026 next_unitid = CONFIG_HT_CHAIN_UNITID_BASE;
Eric Biederman05f26fc2003-06-11 21:55:00 +000027 do {
28 uint32_t id;
29 uint8_t hdr_type, pos;
30 last_unitid = next_unitid;
31
Yinghai Lu18c70d72007-09-14 14:58:33 +000032 id = pci_read_config32(dev, PCI_VENDOR_ID);
Eric Biederman05f26fc2003-06-11 21:55:00 +000033 /* If the chain is enumerated quit */
34 if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000035 (((id >> 16) & 0xffff) == 0xffff) ||
36 (((id >> 16) & 0xffff) == 0x0000))
37 {
Eric Biederman05f26fc2003-06-11 21:55:00 +000038 break;
39 }
arch import user (historical)98d0d302005-07-06 17:13:46 +000040
Yinghai Lu18c70d72007-09-14 14:58:33 +000041 hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
Eric Biederman05f26fc2003-06-11 21:55:00 +000042 pos = 0;
43 hdr_type &= 0x7f;
44
45 if ((hdr_type == PCI_HEADER_TYPE_NORMAL) ||
Myles Watsond61ada62008-10-02 19:20:22 +000046 (hdr_type == PCI_HEADER_TYPE_BRIDGE))
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000047 {
Yinghai Lu18c70d72007-09-14 14:58:33 +000048 pos = pci_read_config8(dev, PCI_CAPABILITY_LIST);
Eric Biederman05f26fc2003-06-11 21:55:00 +000049 }
50 while(pos != 0) {
51 uint8_t cap;
Yinghai Lu18c70d72007-09-14 14:58:33 +000052 cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID);
Eric Biederman05f26fc2003-06-11 21:55:00 +000053 if (cap == PCI_CAP_ID_HT) {
54 uint16_t flags;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000055 /* Read and write and reread flags so the link
56 * direction bit is valid.
57 */
Yinghai Lu18c70d72007-09-14 14:58:33 +000058 flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
59 pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
60 flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
Eric Biederman05f26fc2003-06-11 21:55:00 +000061 if ((flags >> 13) == 0) {
62 unsigned count;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000063 unsigned ctrl, ctrl_off;
Yinghai Lu18c70d72007-09-14 14:58:33 +000064 device_t devx;
arch import user (historical)98d0d302005-07-06 17:13:46 +000065
Stefan Reinauer08670622009-06-30 15:17:49 +000066#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
Yinghai Lu18c70d72007-09-14 14:58:33 +000067 if(next_unitid>=0x18) { // don't get mask out by k8, at this time BSP, RT is not enabled, it will response from 0x18,0--0x1f.
68 if(!end_used) {
Stefan Reinauer08670622009-06-30 15:17:49 +000069 next_unitid = CONFIG_HT_CHAIN_END_UNITID_BASE;
Yinghai Lu18c70d72007-09-14 14:58:33 +000070 end_used = 1;
71 } else {
72 goto out;
73 }
Myles Watsond61ada62008-10-02 19:20:22 +000074 }
Yinghai Lu18c70d72007-09-14 14:58:33 +000075 real_last_unitid = next_unitid;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +000076 real_last_pos = pos;
Yinghai Lu00a018f2007-04-06 21:06:44 +000077 ht_dev_num++;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +000078#endif
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000079
Yinghai Lu18c70d72007-09-14 14:58:33 +000080 flags &= ~0x1f;
81 flags |= next_unitid & 0x1f;
82 count = (flags >> 5) & 0x1f;
83
84 devx = PCI_DEV(0, next_unitid, 0);
85 pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
86
87 next_unitid += count;
88
89 flags = pci_read_config16(devx, pos + PCI_CAP_FLAGS);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000090 /* Test for end of chain */
91 ctrl_off = ((flags >> 10) & 1)?
Yinghai Lu18c70d72007-09-14 14:58:33 +000092 PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1; // another end
93
94 do {
95 ctrl = pci_read_config16(devx, pos + ctrl_off);
96 /* Is this the end of the hypertransport chain? */
97 if (ctrl & (1 << 6)) {
98 goto out;
99 }
100
101 if (ctrl & ((1 << 4) | (1 << 8))) {
102 /*
103 * Either the link has failed, or we have
104 * a CRC error.
105 * Sometimes this can happen due to link
106 * retrain, so lets knock it down and see
107 * if its transient
108 */
109 ctrl |= ((1 << 4) | (1 <<8)); // Link fail + Crc
110 pci_write_config16(devx, pos + ctrl_off, ctrl);
111 ctrl = pci_read_config16(devx, pos + ctrl_off);
112 if (ctrl & ((1 << 4) | (1 << 8))) {
113 // can not clear the error
114 break;
115 }
116 }
117 } while((ctrl & (1 << 5)) == 0);
Myles Watsond61ada62008-10-02 19:20:22 +0000118
Eric Biederman05f26fc2003-06-11 21:55:00 +0000119 break;
120 }
121 }
Yinghai Lu18c70d72007-09-14 14:58:33 +0000122 pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
Eric Biederman05f26fc2003-06-11 21:55:00 +0000123 }
Yinghai Lu18c70d72007-09-14 14:58:33 +0000124 } while(last_unitid != next_unitid);
Yinghai Lu00a018f2007-04-06 21:06:44 +0000125
Yinghai Lu18c70d72007-09-14 14:58:33 +0000126out:
127 ;
128
Stefan Reinauer08670622009-06-30 15:17:49 +0000129#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
130 if((ht_dev_num>1) && (real_last_unitid != CONFIG_HT_CHAIN_END_UNITID_BASE) && !end_used) {
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000131 uint16_t flags;
Yinghai Lu18c70d72007-09-14 14:58:33 +0000132 dev = PCI_DEV(0,real_last_unitid, 0);
Myles Watsond61ada62008-10-02 19:20:22 +0000133 flags = pci_read_config16(dev, real_last_pos + PCI_CAP_FLAGS);
134 flags &= ~0x1f;
Stefan Reinauer08670622009-06-30 15:17:49 +0000135 flags |= CONFIG_HT_CHAIN_END_UNITID_BASE & 0x1f;
Yinghai Lu18c70d72007-09-14 14:58:33 +0000136 pci_write_config16(dev, real_last_pos + PCI_CAP_FLAGS, flags);
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000137 }
138#endif
arch import user (historical)98d0d302005-07-06 17:13:46 +0000139
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000140#endif
141
Eric Biederman05f26fc2003-06-11 21:55:00 +0000142}
Eric Biederman5cd81732004-03-11 15:01:31 +0000143