blob: 1a3975a0ea59c8e73e159ed3317049f20cda88f9 [file] [log] [blame]
/*
2005.11 yhlu add let the real sb to use small unitid
*/
// only for sb ht chain
static void enumerate_ht_chain(void)
{
#if HT_CHAIN_UNITID_BASE != 0
/* 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 */
/* Assumption the HT chain that is bus 0 has the HT I/O Hub on it.
* On most boards this just happens. If a cpu has multiple
* non Coherent links the appropriate bus registers for the
* links needs to be programed to point at bus 0.
*/
unsigned next_unitid, last_unitid;
unsigned temp_unitid;
unsigned not_use_count;
#if HT_CHAIN_END_UNITID_BASE < HT_CHAIN_UNITID_BASE
//let't record the device of last ht device, So we can set the Unitid to HT_CHAIN_END_UNITID_BASE
unsigned real_last_unitid;
uint8_t real_last_pos;
int ht_dev_num = 0; // except host_bridge
#endif
next_unitid = HT_CHAIN_UNITID_BASE;
do {
uint32_t id;
uint8_t hdr_type, pos;
last_unitid = next_unitid;
id = pci_read_config32(PCI_DEV(0,0,0), PCI_VENDOR_ID);
/* If the chain is enumerated quit */
if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
(((id >> 16) & 0xffff) == 0xffff) ||
(((id >> 16) & 0xffff) == 0x0000))
{
break;
}
hdr_type = pci_read_config8(PCI_DEV(0,0,0), PCI_HEADER_TYPE);
pos = 0;
hdr_type &= 0x7f;
if ((hdr_type == PCI_HEADER_TYPE_NORMAL) ||
(hdr_type == PCI_HEADER_TYPE_BRIDGE))
{
pos = pci_read_config8(PCI_DEV(0,0,0), PCI_CAPABILITY_LIST);
}
while(pos != 0) {
uint8_t cap;
cap = pci_read_config8(PCI_DEV(0,0,0), pos + PCI_CAP_LIST_ID);
if (cap == PCI_CAP_ID_HT) {
uint16_t flags;
/* Read and write and reread flags so the link
* direction bit is valid.
*/
flags = pci_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS);
pci_write_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS, flags);
flags = pci_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS);
if ((flags >> 13) == 0) {
unsigned count;
unsigned ctrl, ctrl_off;
flags &= ~0x1f;
count = (flags >> 5) & 0x1f;
not_use_count = 0;
temp_unitid = next_unitid;
#if HT_CHAIN_END_UNITID_BASE < HT_CHAIN_UNITID_BASE
if ( (count + next_unitid) >= 0x20) {
temp_unitid = HT_CHAIN_END_UNITID_BASE;
not_use_count = 1;
}
real_last_unitid = temp_unitid;
real_last_pos = pos;
ht_dev_num++;
#endif
flags |= temp_unitid & 0x1f;
if(!not_use_count)
next_unitid += count;
/* Test for end of chain */
ctrl_off = ((flags >> 10) & 1)?
PCI_HT_CAP_SLAVE_CTRL1 : PCI_HT_CAP_SLAVE_CTRL0;
ctrl = pci_read_config16(PCI_DEV(0,0,0), pos + ctrl_off);
/* Is this the end of the hypertransport chain.
* or has the link failed?
*/
if (ctrl & ((1 << 6)|(1 << 4))) {
next_unitid = 0x20;
}
pci_write_config16(PCI_DEV(0, 0, 0), pos + PCI_CAP_FLAGS, flags);
break;
}
}
pos = pci_read_config8(PCI_DEV(0, 0, 0), pos + PCI_CAP_LIST_NEXT);
}
} while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
#if HT_CHAIN_END_UNITID_BASE < HT_CHAIN_UNITID_BASE
if((ht_dev_num>1) && (real_last_unitid != HT_CHAIN_END_UNITID_BASE)) {
uint16_t flags;
flags = pci_read_config16(PCI_DEV(0,real_last_unitid,0), real_last_pos + PCI_CAP_FLAGS);
flags &= ~0x1f;
flags |= HT_CHAIN_END_UNITID_BASE & 0x1f;
pci_write_config16(PCI_DEV(0, real_last_unitid, 0), real_last_pos + PCI_CAP_FLAGS, flags);
}
#endif
#endif
}