blob: a30c8f6a8dec2cdc19333ac18c395120be78dad0 [file] [log] [blame]
Eric Biederman0ac6b412003-09-02 17:16:48 +00001#include <bitops.h>
2#include <console/console.h>
3#include <device/device.h>
4#include <device/path.h>
5#include <device/pci.h>
Eric Biederman5cd81732004-03-11 15:01:31 +00006#include <device/pci_ids.h>
Eric Biedermanff0e8462003-09-04 03:00:54 +00007#include <device/hypertransport.h>
Eric Biederman0ac6b412003-09-02 17:16:48 +00008#include <part/hard_reset.h>
9#include <part/fallback_boot.h>
10
Yinghai Lu90b3e092005-01-26 22:00:20 +000011#define OPT_HT_LINK 0
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000012
arch import user (historical)ef03afa2005-07-06 17:15:30 +000013#if OPT_HT_LINK == 1
14#include "../northbridge/amd/amdk8/cpu_rev.c"
15#endif
16
Eric Biederman0ac6b412003-09-02 17:16:48 +000017static device_t ht_scan_get_devs(device_t *old_devices)
18{
19 device_t first, last;
20 first = *old_devices;
21 last = first;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000022 /* Extract the chain of devices to (first through last)
23 * for the next hypertransport device.
24 */
Eric Biederman03acab62004-10-14 21:25:53 +000025 while(last && last->sibling &&
26 (last->sibling->path.type == DEVICE_PATH_PCI) &&
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000027 (last->sibling->path.u.pci.devfn > last->path.u.pci.devfn))
28 {
Eric Biederman0ac6b412003-09-02 17:16:48 +000029 last = last->sibling;
30 }
31 if (first) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000032 device_t child;
33 /* Unlink the chain from the list of old devices */
Eric Biederman0ac6b412003-09-02 17:16:48 +000034 *old_devices = last->sibling;
35 last->sibling = 0;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000036
37 /* Now add the device to the list of devices on the bus.
38 */
39 /* Find the last child of our parent */
40 for(child = first->bus->children; child && child->sibling; ) {
41 child = child->sibling;
42 }
43 /* Place the chain on the list of children of their parent. */
44 if (child) {
45 child->sibling = first;
46 } else {
47 first->bus->children = first;
48 }
Eric Biederman0ac6b412003-09-02 17:16:48 +000049 }
50 return first;
51}
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000052
Yinghai Lu90b3e092005-01-26 22:00:20 +000053#if OPT_HT_LINK == 1
Eric Biederman5cd81732004-03-11 15:01:31 +000054static unsigned ht_read_freq_cap(device_t dev, unsigned pos)
55{
56 /* Handle bugs in valid hypertransport frequency reporting */
57 unsigned freq_cap;
58
59 freq_cap = pci_read_config16(dev, pos);
60 freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */
61
62 /* AMD 8131 Errata 48 */
63 if ((dev->vendor == PCI_VENDOR_ID_AMD) &&
64 (dev->device == PCI_DEVICE_ID_AMD_8131_PCIX)) {
65 freq_cap &= ~(1 << HT_FREQ_800Mhz);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000066 }
Eric Biederman5cd81732004-03-11 15:01:31 +000067 /* AMD 8151 Errata 23 */
68 if ((dev->vendor == PCI_VENDOR_ID_AMD) &&
69 (dev->device == PCI_DEVICE_ID_AMD_8151_SYSCTRL)) {
70 freq_cap &= ~(1 << HT_FREQ_800Mhz);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000071 }
Eric Biederman5cd81732004-03-11 15:01:31 +000072 /* AMD K8 Unsupported 1Ghz? */
73 if ((dev->vendor == PCI_VENDOR_ID_AMD) && (dev->device == 0x1100)) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000074#if K8_HT_FREQ_1G_SUPPORT == 1
arch import user (historical)ef03afa2005-07-06 17:15:30 +000075 if (is_cpu_pre_e0())
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000076#endif
77 {
Yinghai Lu90b3e092005-01-26 22:00:20 +000078 freq_cap &= ~(1 << HT_FREQ_1000Mhz);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000079 }
80
Eric Biederman5cd81732004-03-11 15:01:31 +000081 }
82 return freq_cap;
83}
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000084#endif
Eric Biederman0ac6b412003-09-02 17:16:48 +000085
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000086struct ht_link {
Eric Biederman0ac6b412003-09-02 17:16:48 +000087 struct device *dev;
88 unsigned pos;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000089 unsigned char ctrl_off, config_off, freq_off, freq_cap_off;
Eric Biederman0ac6b412003-09-02 17:16:48 +000090};
91
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000092static int ht_setup_link(struct ht_link *prev, device_t dev, unsigned pos)
Eric Biederman0ac6b412003-09-02 17:16:48 +000093{
94 static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
95 static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000096 struct ht_link cur[1];
Eric Biederman0ac6b412003-09-02 17:16:48 +000097 unsigned present_width_cap, upstream_width_cap;
98 unsigned present_freq_cap, upstream_freq_cap;
99 unsigned ln_present_width_in, ln_upstream_width_in;
100 unsigned ln_present_width_out, ln_upstream_width_out;
101 unsigned freq, old_freq;
102 unsigned present_width, upstream_width, old_width;
103 int reset_needed;
Yinghai Lu1f1085b2005-01-17 21:37:12 +0000104 int linkb_to_host;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000105
106 /* Set the hypertransport link width and frequency */
107 reset_needed = 0;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000108 /* See which side of the device our previous write to
109 * set the unitid came from.
110 */
111 cur->dev = dev;
112 cur->pos = pos;
113 linkb_to_host = (pci_read_config16(cur->dev, cur->pos + PCI_CAP_FLAGS) >> 10) & 1;
114 if (!linkb_to_host) {
115 cur->ctrl_off = PCI_HT_CAP_SLAVE_CTRL0;
116 cur->config_off = PCI_HT_CAP_SLAVE_WIDTH0;
117 cur->freq_off = PCI_HT_CAP_SLAVE_FREQ0;
118 cur->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP0;
119 }
120 else {
121 cur->ctrl_off = PCI_HT_CAP_SLAVE_CTRL1;
122 cur->config_off = PCI_HT_CAP_SLAVE_WIDTH1;
123 cur->freq_off = PCI_HT_CAP_SLAVE_FREQ1;
124 cur->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP1;
125 }
126#if OPT_HT_LINK == 1
Eric Biederman0ac6b412003-09-02 17:16:48 +0000127 /* Read the capabilities */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000128 present_freq_cap = ht_read_freq_cap(cur->dev, cur->pos + cur->freq_cap_off);
Eric Biederman5cd81732004-03-11 15:01:31 +0000129 upstream_freq_cap = ht_read_freq_cap(prev->dev, prev->pos + prev->freq_cap_off);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000130 present_width_cap = pci_read_config8(cur->dev, cur->pos + cur->config_off);
131 upstream_width_cap = pci_read_config8(prev->dev, prev->pos + prev->config_off);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000132
133 /* Calculate the highest useable frequency */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000134 freq = log2(present_freq_cap & upstream_freq_cap);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000135
136 /* Calculate the highest width */
137 ln_upstream_width_in = link_width_to_pow2[upstream_width_cap & 7];
138 ln_present_width_out = link_width_to_pow2[(present_width_cap >> 4) & 7];
139 if (ln_upstream_width_in > ln_present_width_out) {
140 ln_upstream_width_in = ln_present_width_out;
141 }
142 upstream_width = pow2_to_link_width[ln_upstream_width_in];
143 present_width = pow2_to_link_width[ln_upstream_width_in] << 4;
144
145 ln_upstream_width_out = link_width_to_pow2[(upstream_width_cap >> 4) & 7];
146 ln_present_width_in = link_width_to_pow2[present_width_cap & 7];
147 if (ln_upstream_width_out > ln_present_width_in) {
148 ln_upstream_width_out = ln_present_width_in;
149 }
150 upstream_width |= pow2_to_link_width[ln_upstream_width_out] << 4;
151 present_width |= pow2_to_link_width[ln_upstream_width_out];
152
153 /* Set the current device */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000154 old_freq = pci_read_config8(cur->dev, cur->pos + cur->freq_off);
155 old_freq &= 0x0f;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000156 if (freq != old_freq) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000157 unsigned new_freq;
158 pci_write_config8(cur->dev, cur->pos + cur->freq_off, freq);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000159 reset_needed = 1;
160 printk_spew("HyperT FreqP old %x new %x\n",old_freq,freq);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000161 new_freq = pci_read_config8(cur->dev, cur->pos + cur->freq_off);
162 new_freq &= 0x0f;
163 if (new_freq != freq) {
164 printk_err("%s Hypertransport frequency would not set wanted: %x got: %x\n",
165 dev_path(dev), freq, new_freq);
166 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000167 }
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000168 old_width = pci_read_config8(cur->dev, cur->pos + cur->config_off + 1);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000169 if (present_width != old_width) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000170 unsigned new_width;
171 pci_write_config8(cur->dev, cur->pos + cur->config_off + 1,
172 present_width);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000173 reset_needed = 1;
174 printk_spew("HyperT widthP old %x new %x\n",old_width, present_width);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000175 new_width = pci_read_config8(cur->dev, cur->pos + cur->config_off + 1);
176 if (new_width != present_width) {
177 printk_err("%s Hypertransport width would not set wanted: %x got: %x\n",
178 dev_path(dev), present_width, new_width);
179 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000180 }
181
182 /* Set the upstream device */
183 old_freq = pci_read_config8(prev->dev, prev->pos + prev->freq_off);
184 old_freq &= 0x0f;
185 if (freq != old_freq) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000186 unsigned new_freq;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000187 pci_write_config8(prev->dev, prev->pos + prev->freq_off, freq);
188 reset_needed = 1;
189 printk_spew("HyperT freqU old %x new %x\n", old_freq, freq);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000190 new_freq = pci_read_config8(prev->dev, prev->pos + prev->freq_off);
191 new_freq &= 0x0f;
192 if (new_freq != freq) {
193 printk_err("%s Hypertransport frequency would not set wanted: %x got: %x\n",
194 dev_path(prev->dev), freq, new_freq);
195 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000196 }
197 old_width = pci_read_config8(prev->dev, prev->pos + prev->config_off + 1);
198 if (upstream_width != old_width) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000199 unsigned new_width;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000200 pci_write_config8(prev->dev, prev->pos + prev->config_off + 1, upstream_width);
201 reset_needed = 1;
202 printk_spew("HyperT widthU old %x new %x\n", old_width, upstream_width);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000203 new_width = pci_read_config8(prev->dev, prev->pos + prev->config_off + 1);
204 if (new_width != upstream_width) {
205 printk_err("%s Hypertransport width would not set wanted: %x got: %x\n",
206 dev_path(prev->dev), upstream_width, new_width);
207 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000208 }
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000209#endif
Eric Biederman0ac6b412003-09-02 17:16:48 +0000210
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000211 /* Remember the current link as the previous link,
212 * But look at the other offsets.
213 */
214 prev->dev = cur->dev;
215 prev->pos = cur->pos;
216 if (cur->ctrl_off == PCI_HT_CAP_SLAVE_CTRL0) {
217 prev->ctrl_off = PCI_HT_CAP_SLAVE_CTRL1;
218 prev->config_off = PCI_HT_CAP_SLAVE_WIDTH1;
219 prev->freq_off = PCI_HT_CAP_SLAVE_FREQ1;
220 prev->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP1;
221 } else {
222 prev->ctrl_off = PCI_HT_CAP_SLAVE_CTRL0;
223 prev->config_off = PCI_HT_CAP_SLAVE_WIDTH0;
224 prev->freq_off = PCI_HT_CAP_SLAVE_FREQ0;
225 prev->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP0;
226 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000227
228 return reset_needed;
229
230}
231
232static unsigned ht_lookup_slave_capability(struct device *dev)
233{
234 unsigned pos;
235 pos = 0;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000236 do {
237 pos = pci_find_next_capability(dev, PCI_CAP_ID_HT, pos);
238 if (pos) {
Eric Biederman0ac6b412003-09-02 17:16:48 +0000239 unsigned flags;
240 flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000241 printk_spew("flags: 0x%04x\n", flags);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000242 if ((flags >> 13) == 0) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000243 /* Entry is a Slave secondary, success... */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000244 break;
245 }
246 }
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000247 } while(pos);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000248 return pos;
249}
250
251static void ht_collapse_early_enumeration(struct bus *bus)
252{
253 unsigned int devfn;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000254 struct ht_link prev;
255 unsigned ctrl;
256
257 /* Initialize the hypertransport enumeration state */
258 prev.dev = bus->dev;
259 prev.pos = bus->cap;
260 prev.ctrl_off = PCI_HT_CAP_HOST_CTRL;
261 prev.config_off = PCI_HT_CAP_HOST_WIDTH;
262 prev.freq_off = PCI_HT_CAP_HOST_FREQ;
263 prev.freq_cap_off = PCI_HT_CAP_HOST_FREQ_CAP;
264
265 /* Wait until the link initialization is complete */
266 do {
267 ctrl = pci_read_config16(prev.dev, prev.pos + prev.ctrl_off);
268 /* Is this the end of the hypertransport chain */
269 if (ctrl & (1 << 6)) {
270 return;
271 }
272 /* Has the link failed? */
273 if (ctrl & (1 << 4)) {
274 return;
275 }
276 } while((ctrl & (1 << 5)) == 0);
277
Eric Biederman0ac6b412003-09-02 17:16:48 +0000278
279 /* Spin through the devices and collapse any early
280 * hypertransport enumeration.
281 */
Yinghai Lu1f1085b2005-01-17 21:37:12 +0000282 for(devfn = PCI_DEVFN(1, 0); devfn <= 0xff; devfn += 8) {
Eric Biederman0ac6b412003-09-02 17:16:48 +0000283 struct device dummy;
284 uint32_t id;
285 unsigned pos, flags;
286 dummy.bus = bus;
287 dummy.path.type = DEVICE_PATH_PCI;
288 dummy.path.u.pci.devfn = devfn;
289 id = pci_read_config32(&dummy, PCI_VENDOR_ID);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000290 if ( (id == 0xffffffff) || (id == 0x00000000) ||
291 (id == 0x0000ffff) || (id == 0xffff0000)) {
Eric Biederman0ac6b412003-09-02 17:16:48 +0000292 continue;
293 }
294 dummy.vendor = id & 0xffff;
295 dummy.device = (id >> 16) & 0xffff;
296 dummy.hdr_type = pci_read_config8(&dummy, PCI_HEADER_TYPE);
297 pos = ht_lookup_slave_capability(&dummy);
298 if (!pos){
299 continue;
300 }
301
302 /* Clear the unitid */
303 flags = pci_read_config16(&dummy, pos + PCI_CAP_FLAGS);
304 flags &= ~0x1f;
305 pci_write_config16(&dummy, pos + PCI_CAP_FLAGS, flags);
306 printk_spew("Collapsing %s [%04x/%04x]\n",
307 dev_path(&dummy), dummy.vendor, dummy.device);
308 }
309}
310
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000311unsigned int hypertransport_scan_chain(struct bus *bus,
312 unsigned min_devfn, unsigned max_devfn, unsigned int max)
Eric Biederman0ac6b412003-09-02 17:16:48 +0000313{
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000314 unsigned next_unitid, last_unitid;
315 device_t old_devices, dev, func;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000316 unsigned min_unitid = 1;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000317 struct ht_link prev;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000318
319 /* Restore the hypertransport chain to it's unitialized state */
320 ht_collapse_early_enumeration(bus);
321
322 /* See which static device nodes I have */
323 old_devices = bus->children;
324 bus->children = 0;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000325
326 /* Initialize the hypertransport enumeration state */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000327 prev.dev = bus->dev;
328 prev.pos = bus->cap;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000329 prev.ctrl_off = PCI_HT_CAP_HOST_CTRL;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000330 prev.config_off = PCI_HT_CAP_HOST_WIDTH;
331 prev.freq_off = PCI_HT_CAP_HOST_FREQ;
332 prev.freq_cap_off = PCI_HT_CAP_HOST_FREQ_CAP;
333
334 /* If present assign unitid to a hypertransport chain */
335 last_unitid = min_unitid -1;
336 next_unitid = min_unitid;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000337 do {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000338 uint8_t pos;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000339 uint16_t flags;
340 unsigned count, static_count;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000341 unsigned ctrl;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000342
Eric Biederman0ac6b412003-09-02 17:16:48 +0000343 last_unitid = next_unitid;
344
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000345 /* Wait until the link initialization is complete */
346 do {
347 ctrl = pci_read_config16(prev.dev, prev.pos + prev.ctrl_off);
348 /* Is this the end of the hypertransport chain?
349 * Has the link failed?
350 * If so further scanning is pointless.
351 */
352 if (ctrl & ((1 << 6) | (1 << 4))) {
353 goto end_of_chain;
354 }
355 } while((ctrl & (1 << 5)) == 0);
356
357
358 /* Get and setup the device_structure */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000359 dev = ht_scan_get_devs(&old_devices);
360
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000361 /* See if a device is present and setup the
362 * device structure.
363 */
364 dev = pci_probe_dev(dev, bus, 0);
365 if (!dev || !dev->enabled) {
366 break;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000367 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000368
369 /* Find the hypertransport link capability */
370 pos = ht_lookup_slave_capability(dev);
371 if (pos == 0) {
Eric Biederman83b991a2003-10-11 06:20:25 +0000372 printk_err("%s Hypertransport link capability not found",
373 dev_path(dev));
Eric Biederman0ac6b412003-09-02 17:16:48 +0000374 break;
375 }
376
377 /* Update the Unitid of the current device */
378 flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000379
380 /* If the devices has a unitid set and is at devfn 0 we are done.
381 * This can happen with shadow hypertransport devices,
382 * or if we have reached the bottom of a
383 * hypertransport device chain.
384 */
385 if (flags & 0x1f) {
386 break;
387 }
388
Eric Biederman0ac6b412003-09-02 17:16:48 +0000389 flags &= ~0x1f; /* mask out base Unit ID */
arch import user (historical)98d0d302005-07-06 17:13:46 +0000390#if CK804_DEVN_BASE==0
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000391 if((dev->vendor == 0x10de) && (dev->device == 0x005e)) {
392 next_unitid = 0;
393 }
394 else {
arch import user (historical)98d0d302005-07-06 17:13:46 +0000395#endif
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000396 flags |= next_unitid & 0x1f;
397 pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
arch import user (historical)98d0d302005-07-06 17:13:46 +0000398#if CK804_DEVN_BASE==0
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000399 }
arch import user (historical)98d0d302005-07-06 17:13:46 +0000400#endif
Eric Biederman0ac6b412003-09-02 17:16:48 +0000401
402 /* Update the Unitd id in the device structure */
403 static_count = 1;
404 for(func = dev; func; func = func->sibling) {
405 func->path.u.pci.devfn += (next_unitid << 3);
406 static_count = (func->path.u.pci.devfn >> 3)
407 - (dev->path.u.pci.devfn >> 3) + 1;
408 }
409
410 /* Compute the number of unitids consumed */
411 count = (flags >> 5) & 0x1f; /* get unit count */
412 printk_spew("%s count: %04x static_count: %04x\n",
413 dev_path(dev), count, static_count);
414 if (count < static_count) {
415 count = static_count;
416 }
417
418 /* Update the Unitid of the next device */
419 next_unitid += count;
420
421 /* Setup the hypetransport link */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000422 bus->reset_needed |= ht_setup_link(&prev, dev, pos);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000423
424 printk_debug("%s [%04x/%04x] %s next_unitid: %04x\n",
425 dev_path(dev),
426 dev->vendor, dev->device,
Li-Ta Lo69c5a902004-04-29 20:08:54 +0000427 (dev->enabled? "enabled": "disabled"), next_unitid);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000428
arch import user (historical)98d0d302005-07-06 17:13:46 +0000429#if CK804_DEVN_BASE==0
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000430 if ((dev->vendor == 0x10de) && (dev->device == 0x005e)) {
431 break; // CK804 can not change unitid, so it only can be alone in the link
432 }
arch import user (historical)98d0d302005-07-06 17:13:46 +0000433#endif
Eric Biederman0ac6b412003-09-02 17:16:48 +0000434
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000435 } while((last_unitid != next_unitid) && (next_unitid <= (max_devfn >> 3)));
436 end_of_chain:
Yinghai Lu90b3e092005-01-26 22:00:20 +0000437#if OPT_HT_LINK == 1
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000438 if(bus->reset_needed) {
Eric Biederman0ac6b412003-09-02 17:16:48 +0000439 printk_info("HyperT reset needed\n");
Eric Biederman5cd81732004-03-11 15:01:31 +0000440 }
441 else {
442 printk_debug("HyperT reset not needed\n");
443 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000444#endif
Eric Biederman0ac6b412003-09-02 17:16:48 +0000445 if (next_unitid > 0x1f) {
446 next_unitid = 0x1f;
447 }
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000448
449 /* Die if any leftover Static devices are are found.
450 * There's probably a problem in the Config.lb.
451 */
452 if(old_devices) {
453 device_t left;
454 for(left = old_devices; left; left = left->sibling) {
455 printk_debug("%s\n", dev_path(left));
456 }
457 die("Left over static devices. Check your Config.lb\n");
458 }
459
460 /* Now that nothing is overlapping it is safe to scan the
461 * children.
462 */
463 max = pci_scan_bus(bus, 0x00, (next_unitid << 3)|7, max);
464 return max;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000465}
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000466
467/**
468 * @brief Scan a PCI bridge and the buses behind the bridge.
469 *
470 * Determine the existence of buses behind the bridge. Set up the bridge
471 * according to the result of the scan.
472 *
473 * This function is the default scan_bus() method for PCI bridge devices.
474 *
475 * @param dev pointer to the bridge device
476 * @param max the highest bus number assgined up to now
477 *
478 * @return The maximum bus number found, after scanning all subordinate busses
479 */
480unsigned int ht_scan_bridge(struct device *dev, unsigned int max)
481{
482 return do_pci_scan_bridge(dev, max, hypertransport_scan_chain);
483}
484
485
486/** Default device operations for hypertransport bridges */
487static struct pci_operations ht_bus_ops_pci = {
488 .set_subsystem = 0,
489};
490
491struct device_operations default_ht_ops_bus = {
492 .read_resources = pci_bus_read_resources,
493 .set_resources = pci_dev_set_resources,
494 .enable_resources = pci_bus_enable_resources,
495 .init = 0,
496 .scan_bus = ht_scan_bridge,
497 .enable = 0,
498 .reset_bus = pci_bus_reset,
499 .ops_pci = &ht_bus_ops_pci,
500};