blob: d27e66b5cf10c9a31e41ce40d5b74f5eba1eb6b1 [file] [log] [blame]
Stefan Reinauer7ce8c542005-12-02 21:52:30 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Uwe Hermannb80dbf02007-04-22 19:08:13 +00003 *
4 * Copyright (C) 2003-2004 Linux Networx
5 * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
6 * Copyright (C) 2004 David Hendricks <sc@flagen.com>
7 * Copyright (C) 2004 Li-Ta Lo <ollie@lanl.gov>
8 * Copyright (C) 2005-2006 Tyan
9 * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan)
10 * Copyright (C) 2005-2006 Stefan Reinauer <stepan@openbios.org>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; version 2 of the License.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Uwe Hermannb80dbf02007-04-22 19:08:13 +000024 */
Stefan Reinauer7ce8c542005-12-02 21:52:30 +000025
Ronald G. Minnich5079a0d2012-11-27 11:32:38 -080026#include <lib.h>
Eric Biederman0ac6b412003-09-02 17:16:48 +000027#include <console/console.h>
28#include <device/device.h>
29#include <device/path.h>
30#include <device/pci.h>
Eric Biederman5cd81732004-03-11 15:01:31 +000031#include <device/pci_ids.h>
Eric Biedermanff0e8462003-09-04 03:00:54 +000032#include <device/hypertransport.h>
Eric Biederman0ac6b412003-09-02 17:16:48 +000033
Kyösti Mälkkic3f6bb02015-02-03 12:18:02 +020034struct ht_link {
35 struct device *dev;
36 unsigned pos;
37 unsigned char ctrl_off, config_off, freq_off, freq_cap_off;
38};
arch import user (historical)ef03afa2005-07-06 17:15:30 +000039
Eric Biederman0ac6b412003-09-02 17:16:48 +000040static device_t ht_scan_get_devs(device_t *old_devices)
41{
42 device_t first, last;
Uwe Hermanne4870472010-11-04 23:23:47 +000043
Eric Biederman0ac6b412003-09-02 17:16:48 +000044 first = *old_devices;
45 last = first;
Uwe Hermanne4870472010-11-04 23:23:47 +000046
47 /*
48 * Extract the chain of devices to (first through last) for the next
49 * hypertransport device.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000050 */
Uwe Hermanne4870472010-11-04 23:23:47 +000051 while (last && last->sibling &&
52 (last->sibling->path.type == DEVICE_PATH_PCI) &&
53 (last->sibling->path.pci.devfn > last->path.pci.devfn))
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000054 {
Eric Biederman0ac6b412003-09-02 17:16:48 +000055 last = last->sibling;
56 }
Uwe Hermanne4870472010-11-04 23:23:47 +000057
Eric Biederman0ac6b412003-09-02 17:16:48 +000058 if (first) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000059 device_t child;
Uwe Hermanne4870472010-11-04 23:23:47 +000060
61 /* Unlink the chain from the list of old devices. */
Eric Biederman0ac6b412003-09-02 17:16:48 +000062 *old_devices = last->sibling;
63 last->sibling = 0;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000064
Uwe Hermanne4870472010-11-04 23:23:47 +000065 /* Now add the device to the list of devices on the bus. */
66 /* Find the last child of our parent. */
67 for (child = first->bus->children; child && child->sibling; )
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000068 child = child->sibling;
Uwe Hermanne4870472010-11-04 23:23:47 +000069
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000070 /* Place the chain on the list of children of their parent. */
Uwe Hermanne4870472010-11-04 23:23:47 +000071 if (child)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000072 child->sibling = first;
Uwe Hermanne4870472010-11-04 23:23:47 +000073 else
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000074 first->bus->children = first;
Eric Biederman0ac6b412003-09-02 17:16:48 +000075 }
76 return first;
77}
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000078
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000079static int ht_setup_link(struct ht_link *prev, device_t dev, unsigned pos)
Eric Biederman0ac6b412003-09-02 17:16:48 +000080{
Stefan Reinauer0dff6e32007-10-23 22:17:45 +000081 struct ht_link cur[1];
Yinghai Lu1f1085b2005-01-17 21:37:12 +000082 int linkb_to_host;
Eric Biederman0ac6b412003-09-02 17:16:48 +000083
Uwe Hermanne4870472010-11-04 23:23:47 +000084 /* Set the hypertransport link width and frequency. */
Kyösti Mälkkic3f6bb02015-02-03 12:18:02 +020085
Uwe Hermanne4870472010-11-04 23:23:47 +000086 /*
87 * See which side of the device our previous write to set the unitid
88 * came from.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000089 */
90 cur->dev = dev;
91 cur->pos = pos;
Uwe Hermanne4870472010-11-04 23:23:47 +000092 linkb_to_host =
93 (pci_read_config16(cur->dev, cur->pos + PCI_CAP_FLAGS) >> 10) & 1;
94
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000095 if (!linkb_to_host) {
96 cur->ctrl_off = PCI_HT_CAP_SLAVE_CTRL0;
97 cur->config_off = PCI_HT_CAP_SLAVE_WIDTH0;
98 cur->freq_off = PCI_HT_CAP_SLAVE_FREQ0;
99 cur->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP0;
Uwe Hermanne4870472010-11-04 23:23:47 +0000100 } else {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000101 cur->ctrl_off = PCI_HT_CAP_SLAVE_CTRL1;
102 cur->config_off = PCI_HT_CAP_SLAVE_WIDTH1;
103 cur->freq_off = PCI_HT_CAP_SLAVE_FREQ1;
104 cur->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP1;
105 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000106
Uwe Hermanne4870472010-11-04 23:23:47 +0000107 /*
108 * Remember the current link as the previous link, but look at the
109 * other offsets.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000110 */
111 prev->dev = cur->dev;
112 prev->pos = cur->pos;
113 if (cur->ctrl_off == PCI_HT_CAP_SLAVE_CTRL0) {
114 prev->ctrl_off = PCI_HT_CAP_SLAVE_CTRL1;
115 prev->config_off = PCI_HT_CAP_SLAVE_WIDTH1;
116 prev->freq_off = PCI_HT_CAP_SLAVE_FREQ1;
117 prev->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP1;
118 } else {
119 prev->ctrl_off = PCI_HT_CAP_SLAVE_CTRL0;
120 prev->config_off = PCI_HT_CAP_SLAVE_WIDTH0;
121 prev->freq_off = PCI_HT_CAP_SLAVE_FREQ0;
122 prev->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP0;
123 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000124
Kyösti Mälkkic3f6bb02015-02-03 12:18:02 +0200125 return 0;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000126}
127
128static unsigned ht_lookup_slave_capability(struct device *dev)
129{
130 unsigned pos;
Uwe Hermanne4870472010-11-04 23:23:47 +0000131
Eric Biederman0ac6b412003-09-02 17:16:48 +0000132 pos = 0;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000133 do {
134 pos = pci_find_next_capability(dev, PCI_CAP_ID_HT, pos);
135 if (pos) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000136 u16 flags;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000137 flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000138 printk(BIOS_SPEW, "flags: 0x%04x\n", flags);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000139 if ((flags >> 13) == 0) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000140 /* Entry is a slave secondary, success... */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000141 break;
142 }
143 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000144 } while (pos);
145
Eric Biederman0ac6b412003-09-02 17:16:48 +0000146 return pos;
147}
148
Uwe Hermanne4870472010-11-04 23:23:47 +0000149static void ht_collapse_early_enumeration(struct bus *bus,
150 unsigned offset_unitid)
Eric Biederman0ac6b412003-09-02 17:16:48 +0000151{
152 unsigned int devfn;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000153 struct ht_link prev;
Uwe Hermanne4870472010-11-04 23:23:47 +0000154 u16 ctrl;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000155
Uwe Hermanne4870472010-11-04 23:23:47 +0000156 /* Initialize the hypertransport enumeration state. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000157 prev.dev = bus->dev;
158 prev.pos = bus->cap;
159 prev.ctrl_off = PCI_HT_CAP_HOST_CTRL;
160 prev.config_off = PCI_HT_CAP_HOST_WIDTH;
161 prev.freq_off = PCI_HT_CAP_HOST_FREQ;
162 prev.freq_cap_off = PCI_HT_CAP_HOST_FREQ_CAP;
163
Uwe Hermanne4870472010-11-04 23:23:47 +0000164 /* Wait until the link initialization is complete. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000165 do {
166 ctrl = pci_read_config16(prev.dev, prev.pos + prev.ctrl_off);
Uwe Hermanne4870472010-11-04 23:23:47 +0000167
168 /* Is this the end of the hypertransport chain? */
169 if (ctrl & (1 << 6))
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000170 return;
Uwe Hermanne4870472010-11-04 23:23:47 +0000171
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000172 /* Has the link failed? */
173 if (ctrl & (1 << 4)) {
Stefan Reinauercf648c92006-04-11 19:23:57 +0000174 /*
Uwe Hermanne4870472010-11-04 23:23:47 +0000175 * Either the link has failed, or we have a CRC error.
176 * Sometimes this can happen due to link retrain, so
177 * lets knock it down and see if its transient.
Stefan Reinauercf648c92006-04-11 19:23:57 +0000178 */
Uwe Hermanne4870472010-11-04 23:23:47 +0000179 ctrl |= ((1 << 4) | (1 << 8)); /* Link fail + CRC */
180 pci_write_config16(prev.dev, prev.pos + prev.ctrl_off,
181 ctrl);
182 ctrl = pci_read_config16(prev.dev,
183 prev.pos + prev.ctrl_off);
Stefan Reinauercf648c92006-04-11 19:23:57 +0000184 if (ctrl & ((1 << 4) | (1 << 8))) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000185 printk(BIOS_ALERT, "Detected error on "
186 "Hypertransport link\n");
Stefan Reinauercf648c92006-04-11 19:23:57 +0000187 return;
188 }
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000189 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000190 } while ((ctrl & (1 << 5)) == 0);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000191
Uwe Hermanne4870472010-11-04 23:23:47 +0000192 /* Actually, only for one HT device HT chain, and unitid is 0. */
Patrick Georgie1667822012-05-05 15:29:32 +0200193#if !CONFIG_HT_CHAIN_UNITID_BASE
Uwe Hermanne4870472010-11-04 23:23:47 +0000194 if (offset_unitid)
195 return;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000196#endif
197
Uwe Hermanne4870472010-11-04 23:23:47 +0000198 /* Check if is already collapsed. */
199 if ((!offset_unitid) || (offset_unitid
200 && (!((CONFIG_HT_CHAIN_END_UNITID_BASE == 0)
201 && (CONFIG_HT_CHAIN_END_UNITID_BASE
202 < CONFIG_HT_CHAIN_UNITID_BASE))))) {
Eric Biederman0ac6b412003-09-02 17:16:48 +0000203
Eric Biederman0ac6b412003-09-02 17:16:48 +0000204 struct device dummy;
Uwe Hermanne4870472010-11-04 23:23:47 +0000205 u32 id;
206
207 dummy.bus = bus;
208 dummy.path.type = DEVICE_PATH_PCI;
209 dummy.path.pci.devfn = PCI_DEVFN(0, 0);
210
Eric Biederman0ac6b412003-09-02 17:16:48 +0000211 id = pci_read_config32(&dummy, PCI_VENDOR_ID);
Uwe Hermanne4870472010-11-04 23:23:47 +0000212 if (!((id == 0xffffffff) || (id == 0x00000000)
213 || (id == 0x0000ffff) || (id == 0xffff0000))) {
214 return;
215 }
216 }
217
218 /* Spin through the devices and collapse any early HT enumeration. */
219 for (devfn = PCI_DEVFN(1, 0); devfn <= 0xff; devfn += 8) {
220 struct device dummy;
221 u32 id;
222 unsigned pos, flags;
223
224 dummy.bus = bus;
225 dummy.path.type = DEVICE_PATH_PCI;
226 dummy.path.pci.devfn = devfn;
227
228 id = pci_read_config32(&dummy, PCI_VENDOR_ID);
229 if ((id == 0xffffffff) || (id == 0x00000000)
230 || (id == 0x0000ffff) || (id == 0xffff0000)) {
Eric Biederman0ac6b412003-09-02 17:16:48 +0000231 continue;
232 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000233
Eric Biederman0ac6b412003-09-02 17:16:48 +0000234 dummy.vendor = id & 0xffff;
235 dummy.device = (id >> 16) & 0xffff;
236 dummy.hdr_type = pci_read_config8(&dummy, PCI_HEADER_TYPE);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000237
Uwe Hermanne4870472010-11-04 23:23:47 +0000238 pos = ht_lookup_slave_capability(&dummy);
239 if (!pos)
240 continue;
241
242 /* Clear the unitid. */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000243 flags = pci_read_config16(&dummy, pos + PCI_CAP_FLAGS);
244 flags &= ~0x1f;
245 pci_write_config16(&dummy, pos + PCI_CAP_FLAGS, flags);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000246 printk(BIOS_SPEW, "Collapsing %s [%04x/%04x]\n",
Uwe Hermanne4870472010-11-04 23:23:47 +0000247 dev_path(&dummy), dummy.vendor, dummy.device);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000248 }
249}
250
Uwe Hermanne4870472010-11-04 23:23:47 +0000251unsigned int hypertransport_scan_chain(struct bus *bus, unsigned min_devfn,
252 unsigned max_devfn, unsigned int max,
253 unsigned *ht_unitid_base,
254 unsigned offset_unitid)
Eric Biederman0ac6b412003-09-02 17:16:48 +0000255{
Uwe Hermanne4870472010-11-04 23:23:47 +0000256 /*
257 * Even CONFIG_HT_CHAIN_UNITID_BASE == 0, we still can go through this
258 * function, because of end_of_chain check. Also, we need it to
259 * optimize link.
260 */
261 unsigned int next_unitid, last_unitid, min_unitid, max_unitid;
262 device_t old_devices, dev, func, last_func = 0;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000263 struct ht_link prev;
Stefan Reinauerbbdd8f42005-12-04 21:52:58 +0000264 int ht_dev_num = 0;
Uwe Hermanne4870472010-11-04 23:23:47 +0000265
266 min_unitid = (offset_unitid) ? CONFIG_HT_CHAIN_UNITID_BASE : 1;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000267
Stefan Reinauer08670622009-06-30 15:17:49 +0000268#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
Uwe Hermanne4870472010-11-04 23:23:47 +0000269 /*
270 * Let's record the device of last HT device, so we can set the unitid
271 * to CONFIG_HT_CHAIN_END_UNITID_BASE.
272 */
273 unsigned int real_last_unitid = 0, end_used = 0;
274 u8 real_last_pos = 0;
275 device_t real_last_dev = NULL;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000276#endif
Eric Biederman0ac6b412003-09-02 17:16:48 +0000277
Martin Roth63373ed2013-07-08 16:24:19 -0600278 /* Restore the hypertransport chain to it's uninitialized state. */
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000279 ht_collapse_early_enumeration(bus, offset_unitid);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000280
Uwe Hermanne4870472010-11-04 23:23:47 +0000281 /* See which static device nodes I have. */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000282 old_devices = bus->children;
283 bus->children = 0;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000284
Uwe Hermanne4870472010-11-04 23:23:47 +0000285 /* Initialize the hypertransport enumeration state. */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000286 prev.dev = bus->dev;
287 prev.pos = bus->cap;
Uwe Hermanne4870472010-11-04 23:23:47 +0000288
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000289 prev.ctrl_off = PCI_HT_CAP_HOST_CTRL;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000290 prev.config_off = PCI_HT_CAP_HOST_WIDTH;
291 prev.freq_off = PCI_HT_CAP_HOST_FREQ;
292 prev.freq_cap_off = PCI_HT_CAP_HOST_FREQ_CAP;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000293
Uwe Hermanne4870472010-11-04 23:23:47 +0000294 /* If present, assign unitid to a hypertransport chain. */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000295 last_unitid = min_unitid -1;
Yinghai Lu18c70d72007-09-14 14:58:33 +0000296 max_unitid = next_unitid = min_unitid;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000297 do {
Uwe Hermanne4870472010-11-04 23:23:47 +0000298 u8 pos;
299 u16 flags, ctrl;
300 unsigned int count, static_count;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000301
Eric Biederman0ac6b412003-09-02 17:16:48 +0000302 last_unitid = next_unitid;
303
Uwe Hermanne4870472010-11-04 23:23:47 +0000304 /* Wait until the link initialization is complete. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000305 do {
Uwe Hermanne4870472010-11-04 23:23:47 +0000306 ctrl = pci_read_config16(prev.dev,
307 prev.pos + prev.ctrl_off);
Stefan Reinauercf648c92006-04-11 19:23:57 +0000308
Uwe Hermanne4870472010-11-04 23:23:47 +0000309 /* End of chain? */
Stefan Reinauercf648c92006-04-11 19:23:57 +0000310 if (ctrl & (1 << 6))
Uwe Hermanne4870472010-11-04 23:23:47 +0000311 goto end_of_chain;
Stefan Reinauercf648c92006-04-11 19:23:57 +0000312
313 if (ctrl & ((1 << 4) | (1 << 8))) {
314 /*
Uwe Hermanne4870472010-11-04 23:23:47 +0000315 * Either the link has failed, or we have a CRC
316 * error. Sometimes this can happen due to link
317 * retrain, so lets knock it down and see if
318 * it's transient.
Stefan Reinauercf648c92006-04-11 19:23:57 +0000319 */
Uwe Hermanne4870472010-11-04 23:23:47 +0000320 ctrl |= ((1 << 4) | (1 <<8)); // Link fail + CRC
321 pci_write_config16(prev.dev,
322 prev.pos + prev.ctrl_off, ctrl);
323 ctrl = pci_read_config16(prev.dev,
324 prev.pos + prev.ctrl_off);
Stefan Reinauercf648c92006-04-11 19:23:57 +0000325 if (ctrl & ((1 << 4) | (1 << 8))) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000326 printk(BIOS_ALERT, "Detected error on "
327 "hypertransport link\n");
Stefan Reinauercf648c92006-04-11 19:23:57 +0000328 goto end_of_chain;
329 }
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000330 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000331 } while ((ctrl & (1 << 5)) == 0);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000332
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000333
Uwe Hermanne4870472010-11-04 23:23:47 +0000334 /* Get and setup the device_structure. */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000335 dev = ht_scan_get_devs(&old_devices);
336
Uwe Hermanne4870472010-11-04 23:23:47 +0000337 /* See if a device is present and setup the device structure. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000338 dev = pci_probe_dev(dev, bus, 0);
Uwe Hermanne4870472010-11-04 23:23:47 +0000339 if (!dev || !dev->enabled)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000340 break;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000341
Uwe Hermanne4870472010-11-04 23:23:47 +0000342 /* Find the hypertransport link capability. */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000343 pos = ht_lookup_slave_capability(dev);
344 if (pos == 0) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000345 printk(BIOS_ERR, "%s Hypertransport link capability "
346 "not found", dev_path(dev));
Eric Biederman0ac6b412003-09-02 17:16:48 +0000347 break;
348 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000349
Uwe Hermanne4870472010-11-04 23:23:47 +0000350 /* Update the unitid of the current device. */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000351 flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000352
Uwe Hermanne4870472010-11-04 23:23:47 +0000353 /*
Timothy Pearsond0c1dd02015-01-23 20:22:56 -0600354 * If the device has a unitid set and is at devfn 0 we are
Uwe Hermanne4870472010-11-04 23:23:47 +0000355 * done. This can happen with shadow hypertransport devices,
356 * or if we have reached the bottom of a HT device chain.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000357 */
Uwe Hermanne4870472010-11-04 23:23:47 +0000358 if (flags & 0x1f)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000359 break;
Yinghai Luecad5df2007-05-21 18:11:17 +0000360
Uwe Hermanne4870472010-11-04 23:23:47 +0000361 flags &= ~0x1f; /* Mask out base Unit ID. */
362
363 count = (flags >> 5) & 0x1f; /* Het unit count. */
364
Stefan Reinauer08670622009-06-30 15:17:49 +0000365#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
Uwe Hermanne4870472010-11-04 23:23:47 +0000366 if (offset_unitid) {
367 /* max_devfn will be (0x17<<3)|7 or (0x1f<<3)|7. */
368 if (next_unitid > (max_devfn >> 3)) {
369 if (!end_used) {
370 next_unitid =
371 CONFIG_HT_CHAIN_END_UNITID_BASE;
Yinghai Lu18c70d72007-09-14 14:58:33 +0000372 end_used = 1;
373 } else {
Stefan Reinauer0dff6e32007-10-23 22:17:45 +0000374 goto end_of_chain;
Yinghai Lu18c70d72007-09-14 14:58:33 +0000375 }
Yinghai Luecad5df2007-05-21 18:11:17 +0000376 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000377 }
Yinghai Luecad5df2007-05-21 18:11:17 +0000378#endif
379
Uwe Hermanne4870472010-11-04 23:23:47 +0000380 flags |= next_unitid & 0x1f;
381 pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000382
Uwe Hermanne4870472010-11-04 23:23:47 +0000383 /* Update the unitid in the device structure. */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000384 static_count = 1;
Uwe Hermanne4870472010-11-04 23:23:47 +0000385 for (func = dev; func; func = func->sibling) {
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000386 func->path.pci.devfn += (next_unitid << 3);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000387 static_count = (func->path.pci.devfn >> 3)
Uwe Hermanne4870472010-11-04 23:23:47 +0000388 - (dev->path.pci.devfn >> 3) + 1;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000389 last_func = func;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000390 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000391
Uwe Hermanne4870472010-11-04 23:23:47 +0000392 /* Compute the number of unitids consumed. */
393 printk(BIOS_SPEW, "%s count: %04x static_count: %04x\n",
394 dev_path(dev), count, static_count);
395 if (count < static_count)
396 count = static_count;
397
398 /* Update the unitid of the next device. */
Yinghai Lu18c70d72007-09-14 14:58:33 +0000399 ht_unitid_base[ht_dev_num] = next_unitid;
Stefan Reinauerbbdd8f42005-12-04 21:52:58 +0000400 ht_dev_num++;
Yinghai Luecad5df2007-05-21 18:11:17 +0000401
Stefan Reinauer08670622009-06-30 15:17:49 +0000402#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
Yinghai Lu18c70d72007-09-14 14:58:33 +0000403 if (offset_unitid) {
Uwe Hermanne4870472010-11-04 23:23:47 +0000404 real_last_pos = pos;
Yinghai Lu18c70d72007-09-14 14:58:33 +0000405 real_last_unitid = next_unitid;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000406 real_last_dev = dev;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000407 }
408#endif
Uwe Hermanne4870472010-11-04 23:23:47 +0000409 next_unitid += count;
410 if (next_unitid > max_unitid)
Yinghai Lu18c70d72007-09-14 14:58:33 +0000411 max_unitid = next_unitid;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000412
Martin Roth63373ed2013-07-08 16:24:19 -0600413 /* Setup the hypertransport link. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000414 bus->reset_needed |= ht_setup_link(&prev, dev, pos);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000415
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000416 printk(BIOS_DEBUG, "%s [%04x/%04x] %s next_unitid: %04x\n",
Uwe Hermanne4870472010-11-04 23:23:47 +0000417 dev_path(dev), dev->vendor, dev->device,
418 (dev->enabled? "enabled" : "disabled"), next_unitid);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000419
Yinghai Lu18c70d72007-09-14 14:58:33 +0000420 } while (last_unitid != next_unitid);
Uwe Hermanne4870472010-11-04 23:23:47 +0000421
422end_of_chain:
423
Stefan Reinauer08670622009-06-30 15:17:49 +0000424#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
Uwe Hermanne4870472010-11-04 23:23:47 +0000425 if (offset_unitid && (ht_dev_num > 1)
426 && (real_last_unitid != CONFIG_HT_CHAIN_END_UNITID_BASE)
427 && !end_used) {
428 u16 flags;
429 flags = pci_read_config16(real_last_dev,
430 real_last_pos + PCI_CAP_FLAGS);
431 flags &= ~0x1f;
432 flags |= CONFIG_HT_CHAIN_END_UNITID_BASE & 0x1f;
433 pci_write_config16(real_last_dev,
434 real_last_pos + PCI_CAP_FLAGS, flags);
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000435
Uwe Hermanne4870472010-11-04 23:23:47 +0000436 for (func = real_last_dev; func; func = func->sibling) {
437 func->path.pci.devfn -= ((real_last_unitid
438 - CONFIG_HT_CHAIN_END_UNITID_BASE) << 3);
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000439 last_func = func;
Uwe Hermanne4870472010-11-04 23:23:47 +0000440 }
Yinghai Luecad5df2007-05-21 18:11:17 +0000441
Uwe Hermanne4870472010-11-04 23:23:47 +0000442 /* Update last one. */
443 ht_unitid_base[ht_dev_num-1] = CONFIG_HT_CHAIN_END_UNITID_BASE;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000444
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000445 printk(BIOS_DEBUG, " unitid: %04x --> %04x\n",
Uwe Hermanne4870472010-11-04 23:23:47 +0000446 real_last_unitid, CONFIG_HT_CHAIN_END_UNITID_BASE);
447 }
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000448#endif
Yinghai Lu18c70d72007-09-14 14:58:33 +0000449 next_unitid = max_unitid;
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000450
Uwe Hermanne4870472010-11-04 23:23:47 +0000451 if (next_unitid > 0x20)
Yinghai Lu18c70d72007-09-14 14:58:33 +0000452 next_unitid = 0x20;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000453
Uwe Hermanne4870472010-11-04 23:23:47 +0000454 if ((bus->secondary == 0) && (next_unitid > 0x18))
455 next_unitid = 0x18; /* Avoid K8 on bus 0. */
456
457 /*
458 * Die if any leftover static devices are are found. There's probably
459 * a problem in devicetree.cb.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000460 */
Uwe Hermanne4870472010-11-04 23:23:47 +0000461 if (old_devices) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000462 device_t left;
Uwe Hermanne4870472010-11-04 23:23:47 +0000463 for (left = old_devices; left; left = left->sibling)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000464 printk(BIOS_DEBUG, "%s\n", dev_path(left));
Uwe Hermanne4870472010-11-04 23:23:47 +0000465
466 printk(BIOS_ERR, "HT: Leftover static devices. "
467 "Check your devicetree.cb\n");
468
469 /*
470 * Put back the leftover static device, and let pci_scan_bus()
471 * disable it.
472 */
473 if (last_func && !last_func->sibling)
Stefan Reinauer14e22772010-04-27 06:56:47 +0000474 last_func->sibling = old_devices;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000475 }
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000476
Uwe Hermanne4870472010-11-04 23:23:47 +0000477 /* Now that nothing is overlapping it is safe to scan the children. */
478 max = pci_scan_bus(bus, 0x00, ((next_unitid - 1) << 3) | 7, max);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000479 return max;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000480}
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000481
482/**
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000483 * Scan a PCI bridge and the buses behind the bridge.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000484 *
485 * Determine the existence of buses behind the bridge. Set up the bridge
486 * according to the result of the scan.
487 *
488 * This function is the default scan_bus() method for PCI bridge devices.
489 *
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000490 * @param bus TODO
491 * @param min_devfn TODO
492 * @param max_devfn TODO
Martin Roth63373ed2013-07-08 16:24:19 -0600493 * @param max The highest bus number assigned up to now.
Uwe Hermannc1ee4292010-10-17 19:01:48 +0000494 * @return The maximum bus number found, after scanning all subordinate busses.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000495 */
Myles Watson7943fe62009-10-30 02:08:07 +0000496static unsigned int hypertransport_scan_chain_x(struct bus *bus,
Uwe Hermanne4870472010-11-04 23:23:47 +0000497 unsigned int min_devfn, unsigned int max_devfn, unsigned int max)
Yinghai Lud4b278c2006-10-04 20:46:15 +0000498{
Uwe Hermanne4870472010-11-04 23:23:47 +0000499 unsigned int ht_unitid_base[4];
500 unsigned int offset_unitid = 1;
501 return hypertransport_scan_chain(bus, min_devfn, max_devfn, max,
502 ht_unitid_base, offset_unitid);
Yinghai Lud4b278c2006-10-04 20:46:15 +0000503}
504
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000505unsigned int ht_scan_bridge(struct device *dev, unsigned int max)
506{
Yinghai Lud4b278c2006-10-04 20:46:15 +0000507 return do_pci_scan_bridge(dev, max, hypertransport_scan_chain_x);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000508}
509
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000510/** Default device operations for hypertransport bridges */
511static struct pci_operations ht_bus_ops_pci = {
512 .set_subsystem = 0,
513};
514
515struct device_operations default_ht_ops_bus = {
516 .read_resources = pci_bus_read_resources,
517 .set_resources = pci_dev_set_resources,
518 .enable_resources = pci_bus_enable_resources,
Uwe Hermanne4870472010-11-04 23:23:47 +0000519 .init = 0,
520 .scan_bus = ht_scan_bridge,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000521 .enable = 0,
522 .reset_bus = pci_bus_reset,
523 .ops_pci = &ht_bus_ops_pci,
524};