/* set the Edge Level Control Register (ELCR) */
temp_word = inb(0x4d0);
temp_word |= inb(0x4d1) << 8;
temp_word |= 0x01 << irq_num;
/* This should only be for x86 as it sets the Edge Level *ControlRegister
*/
outb((u8)(temp_word & 0xFF), 0x4d0);
outb((u8)((temp_word & 0xFF00) >> 8), 0x4d1);
rc = 0;
}
return rc;
}
staticint PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 *dev_num)
{
u16 tdevice;
u32 work; int ret = -1;
ctrl->pci_bus->number = bus_num;
for (tdevice = 0; tdevice < 0xFF; tdevice++) { /* Scan for access first */ if (!pci_bus_read_dev_vendor_id(ctrl->pci_bus, tdevice, &work, 0)) continue;
ret = pci_bus_read_config_dword(ctrl->pci_bus, tdevice, PCI_CLASS_REVISION, &work); if (ret) continue;
dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); /* Yep we got one. Not a bridge ? */ if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) {
*dev_num = tdevice;
dbg("found it !\n"); return0;
} else { /* *XXX:Codewhosedebugprintoutindicated *recursiontobusesunderneathbridgesmightbe *necessarywasremovedbecauseitneverdid *anyrecursion.
*/
ret = 0;
pr_warn("missing feature: bridge scan recursion not implemented\n");
}
}
/* More PCI configuration routines; this time centered around hotplug *controller
*/
/* *cpqhp_save_config * *ReadsconfigurationforallslotsinaPCIbusandsavesinfo. * *Note:Fornon-hotplugbuses,theslot#savedisthedevice# * *returns0ifsuccess
*/ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
{ long rc;
u8 class_code;
u8 header_type;
u32 ID;
u8 secondary_bus; struct pci_func *new_slot; int sub_bus; int FirstSupported; int LastSupported; int max_functions; int function;
u8 DevError; int device = 0; int cloop = 0; int stop_it; int index;
u16 devfn;
/* Save PCI configuration space for all devices in supported slots */
ctrl->pci_bus->number = busnumber; for (device = FirstSupported; device <= LastSupported; device++) {
ID = 0xFFFFFFFF;
rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
if (ID == 0xFFFFFFFF) { if (is_hot_plug) { /* Setup slot structure with entry for empty *slot
*/
new_slot = cpqhp_slot_create(busnumber); if (new_slot == NULL) return1;
/* this loop skips to the next present function *readinginClassCodeandHeadertype.
*/ while ((function < max_functions) && (!stop_it)) {
rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); if (ID == 0xFFFFFFFF) {
function++; continue;
}
rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); if (rc) return rc;
} while (function < max_functions);
} /* End of FOR loop */
return0;
}
/* *cpqhp_save_slot_config * *SavesconfigurationinfoforallPCIdevicesinagivenslot *includingsubordinatebuses. * *returns0ifsuccess
*/ int cpqhp_save_slot_config(struct controller *ctrl, struct pci_func *new_slot)
{ long rc;
u8 class_code;
u8 header_type;
u32 ID;
u8 secondary_bus; int sub_bus; int max_functions; int function = 0; int cloop; int stop_it;
while (function < max_functions) { if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { /* Recurse the subordinate bus */
pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
sub_bus = (int) secondary_bus;
/* Save the config headers for the secondary *bus.
*/
rc = cpqhp_save_config(ctrl, sub_bus, 0); if (rc) return(rc);
ctrl->pci_bus->number = new_slot->bus;
/* this loop skips to the next present function *readingintheClassCodeandtheHeadertype.
*/ while ((function < max_functions) && (!stop_it)) {
pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
if (ID == 0xFFFFFFFF)
function++; else {
pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
stop_it++;
}
}
while (next != NULL) {
rc = cpqhp_save_base_addr_length(ctrl, next); if (rc) return rc;
next = next->next;
}
pci_bus->number = func->bus;
/* FIXME: this loop is duplicated in the non-bridge *case.ThetwocouldberolledtogetherFigureout *IOandmemorybaselengths
*/ for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
temp_register = 0xFFFFFFFF;
pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
pci_bus_read_config_dword(pci_bus, devfn, cloop, &base); /* If this register is implemented */ if (base) { if (base & 0x01L) { /* IO base *setbase=amountofIOspace *requested
*/
base = base & 0xFFFFFFFE;
base = (~base) + 1;
type = 1;
} else { /* memory base */
base = base & 0xFFFFFFF0;
base = (~base) + 1;
type = 0;
}
} else {
base = 0x0L;
type = 0;
}
/* Save information in slot structure */
func->base_length[(cloop - 0x10) >> 2] =
base;
func->base_type[(cloop - 0x10) >> 2] = type;
} /* End of base register loop */
} elseif ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) { /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
temp_register = 0xFFFFFFFF;
pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
/* If this register is implemented */ if (base) { if (base & 0x01L) { /* IO base *base=amountofIOspace *requested
*/
base = base & 0xFFFFFFFE;
base = (~base) + 1;
type = 1;
} else { /* memory base *base=amountofmemory *spacerequested
*/
base = base & 0xFFFFFFF0;
base = (~base) + 1;
type = 0;
}
} else {
base = 0x0L;
type = 0;
}
/* Save information in slot structure */
func->base_length[(cloop - 0x10) >> 2] = base;
func->base_type[(cloop - 0x10) >> 2] = type;
} /* End of base register loop */
} else { /* Some other unknown header type */
}
/* find the next device in this slot */
func = cpqhp_slot_find(func->bus, func->device, index++);
}
/* Start at the top of config space so that the control *registersareprogrammedlast
*/ for (cloop = 0x3C; cloop > 0; cloop -= 4)
pci_bus_write_config_dword(pci_bus, devfn, cloop, func->config_space[cloop >> 2]);
/* If this is a bridge device, restore subordinate devices */ if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
sub_bus = (int) secondary_bus;
next = cpqhp_slot_list[sub_bus];
while (next != NULL) {
rc = cpqhp_configure_board(ctrl, next); if (rc) return rc;
next = next->next;
}
} else {
/* Check all the base Address Registers to make sure *theyarethesame.Ifnot,theboardisdifferent.
*/
/* No adapter present */ if (temp_register == 0xFFFFFFFF) return(NO_ADAPTER_PRESENT);
if (temp_register != func->config_space[0]) return(ADAPTER_NOT_SAME);
/* Check for same revision number and class code */
pci_bus_read_config_dword(pci_bus, devfn, PCI_CLASS_REVISION, &temp_register);
/* Adapter not the same */ if (temp_register != func->config_space[0x08 >> 2]) return(ADAPTER_NOT_SAME);
/* Check for Bridge */
pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { /* In order to continue checking, we must program the *busregistersinthebridgetorespondtoaccesses *foritssubordinatebus(es)
*/
while (next != NULL) {
rc = cpqhp_valid_replace(ctrl, next); if (rc) return rc;
next = next->next;
}
} /* Check to see if it is a standard config header */ elseif ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) { /* Check subsystem vendor and ID */
pci_bus_read_config_dword(pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
if (temp_register != func->config_space[0x2C >> 2]) { /* If it's a SMART-2 and the register isn't *filledin,ignorethedifferencebecause *theyjusthaveanoldrevofthefirmware
*/ if (!((func->config_space[0] == 0xAE100E11)
&& (temp_register == 0x00L))) return(ADAPTER_NOT_SAME);
} /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
temp_register = 0xFFFFFFFF;
pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
/* If this register is implemented */ if (base) { if (base & 0x01L) { /* IO base *setbase=amountofIO *spacerequested
*/
base = base & 0xFFFFFFFE;
base = (~base) + 1;
type = 1;
} else { /* memory base */
base = base & 0xFFFFFFF0;
base = (~base) + 1;
type = 0;
}
} else {
base = 0x0L;
type = 0;
}
/* Check information in slot structure */ if (func->base_length[(cloop - 0x10) >> 2] != base) return(ADAPTER_NOT_SAME);
if (func->base_type[(cloop - 0x10) >> 2] != type) return(ADAPTER_NOT_SAME);
} /* End of base register loop */
} /* End of (type 0 config space) else */ else { /* this is not a type 0 or 1 config space header so *wedon'tknowhowtodoit
*/ return(DEVICE_TYPE_NOT_SUPPORTED);
}
/* Get the next function */
func = cpqhp_slot_find(func->bus, func->device, index++);
}
/* If this entry isn't for our controller's bus, ignore it */ if (primary_bus != ctrl->bus) {
i--;
one_slot += sizeof(struct slot_rt); continue;
} /* find out if this entry is for an occupied slot */
ctrl->pci_bus->number = primary_bus;
pci_bus_read_config_dword(ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
dbg("temp_D_word = %x\n", temp_dword);
if (temp_dword != 0xFFFFFFFF) {
index = 0;
func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0);
/* If we can't find a match, skip this table entry */ if (!func) {
i--;
one_slot += sizeof(struct slot_rt); continue;
} /* this may not work and shouldn't be used */ if (secondary_bus != primary_bus)
bridged_slot = 1; else
bridged_slot = 0;
/* If we've got a valid bus number, use it *Thesecondconditionistoignorebusnumberson *populatedslotsthatdon'thavePCI-PCIbridges
*/ if (secondary_bus && (secondary_bus != primary_bus)) {
bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL); if (!bus_node) return -ENOMEM;
/* If all of the following fail, we don't have any resources for *hotplugadd
*/
rc = 1;
rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.