/* * cpqhp_set_irq * * @bus_num: bus number of PCI device * @dev_num: device number of PCI device * @slot: pointer to u8 where slot number will be returned
*/ int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
{ int rc = 0;
/* 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 * Control Register
*/
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"); return 0;
} else { /* * XXX: Code whose debug printout indicated * recursion to buses underneath bridges might be * necessary was removed because it never did * any recursion.
*/
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 * * Reads configuration for all slots in a PCI bus and saves info. * * Note: For non-hot plug buses, the slot # saved is the device # * * returns 0 if success
*/ 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) return 1;
/* If multi-function device, set max_functions to 8 */ if (header_type & PCI_HEADER_TYPE_MFD)
max_functions = 8; else
max_functions = 1;
function = 0;
do {
DevError = 0; if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { /* Recurse the subordinate bus * get the subordinate bus number
*/
rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); if (rc) { return rc;
} else {
sub_bus = (int) secondary_bus;
/* Save secondary bus cfg spc * with this recursive call.
*/
rc = cpqhp_save_config(ctrl, sub_bus, 0); if (rc) return rc;
ctrl->pci_bus->number = busnumber;
}
}
index = 0;
new_slot = cpqhp_slot_find(busnumber, device, index++); while (new_slot &&
(new_slot->function != (u8) function))
new_slot = cpqhp_slot_find(busnumber, device, index++);
if (!new_slot) { /* Setup slot structure. */
new_slot = cpqhp_slot_create(busnumber); if (new_slot == NULL) return 1;
}
/* this loop skips to the next present function * reading in Class Code and Header type.
*/ 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 */
return 0;
}
/* * cpqhp_save_slot_config * * Saves configuration info for all PCI devices in a given slot * including subordinate buses. * * returns 0 if success
*/ 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 * reading in the Class Code and the Header type.
*/ 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++;
}
}
}
return 0;
}
/* * cpqhp_save_base_addr_length * * Saves the length of all base address registers for the * specified slot. this is for hot plug REPLACE * * returns 0 if success
*/ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func)
{
u8 cloop;
u8 header_type;
u8 secondary_bus;
u8 type; int sub_bus;
u32 temp_register;
u32 base;
u32 rc; struct pci_func *next; int index = 0; struct pci_bus *pci_bus = ctrl->pci_bus; unsignedint devfn;
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. The two could be rolled together Figure out * IO and memory base lengths
*/ 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 * set base = amount of IO space * 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 = amount of IO space * requested
*/
base = base & 0xFFFFFFFE;
base = (~base) + 1;
type = 1;
} else { /* memory base * base = amount of memory * space requested
*/
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++);
}
return(0);
}
/* * cpqhp_save_used_resources * * Stores used resource information for existing boards. this is * for boards that were in the system when this driver was loaded. * this function is for hot plug ADD * * returns 0 if success
*/ int cpqhp_save_used_resources(struct controller *ctrl, struct pci_func *func)
{
u8 cloop;
u8 header_type;
u8 secondary_bus;
u8 temp_byte;
u8 b_base;
u8 b_length;
u16 command;
u16 save_command;
u16 w_base;
u16 w_length;
u32 temp_register;
u32 save_base;
u32 base; int index = 0; struct pci_resource *mem_node; struct pci_resource *p_mem_node; struct pci_resource *io_node; struct pci_resource *bus_node; struct pci_bus *pci_bus = ctrl->pci_bus; unsignedint devfn;
/* If this register is implemented */ if (base) { if (((base & 0x03L) == 0x01)
&& (save_command & 0x01)) { /* IO base * set temp_register = amount * of IO space requested
*/
temp_register = base & 0xFFFFFFFE;
temp_register = (~temp_register) + 1;
io_node = kmalloc(sizeof(*io_node),
GFP_KERNEL); if (!io_node) return -ENOMEM;
/* If this register is implemented */ if (base) { if (((base & 0x03L) == 0x01)
&& (save_command & 0x01)) { /* IO base * set temp_register = amount * of IO space requested
*/
temp_register = base & 0xFFFFFFFE;
temp_register = (~temp_register) + 1;
io_node = kmalloc(sizeof(*io_node),
GFP_KERNEL); if (!io_node) return -ENOMEM;
mem_node->next = func->mem_head;
func->mem_head = mem_node;
} else return(1);
}
} /* End of base register loop */
}
/* find the next device in this slot */
func = cpqhp_slot_find(func->bus, func->device, index++);
}
return 0;
}
/* * cpqhp_configure_board * * Copies saved configuration information to one slot. * this is called recursively for bridge devices. * this is for hot plug REPLACE! * * returns 0 if success
*/ int cpqhp_configure_board(struct controller *ctrl, struct pci_func *func)
{ int cloop;
u8 header_type;
u8 secondary_bus; int sub_bus; struct pci_func *next;
u32 temp;
u32 rc; int index = 0; struct pci_bus *pci_bus = ctrl->pci_bus; unsignedint devfn;
/* Start at the top of config space so that the control * registers are programmed last
*/ 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 * they are the same. If not, the board is different.
*/
/* * cpqhp_valid_replace * * this function checks to see if a board is the same as the * one it is replacing. this check will detect if the device's * vendor or device id's are the same * * returns 0 if the board is the same nonzero otherwise
*/ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func)
{
u8 cloop;
u8 header_type;
u8 secondary_bus;
u8 type;
u32 temp_register = 0;
u32 base;
u32 rc; struct pci_func *next; int index = 0; struct pci_bus *pci_bus = ctrl->pci_bus; unsignedint devfn;
/* 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 * bus registers in the bridge to respond to accesses * for its subordinate bus(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 * filled in, ignore the difference because * they just have an old rev of the firmware
*/ 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 * set base = amount of IO * space 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;
}
/* 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 * we don't know how to do it
*/ return(DEVICE_TYPE_NOT_SUPPORTED);
}
/* Get the next function */
func = cpqhp_slot_find(func->bus, func->device, index++);
}
return 0;
}
/* * cpqhp_find_available_resources * * Finds available memory, IO, and IRQ resources for programming * devices which may be added to the system * this function is for hot plug ADD! * * returns 0 if success
*/ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start)
{
u8 temp;
u8 populated_slot;
u8 bridged_slot; void __iomem *one_slot; void __iomem *rom_resource_table; struct pci_func *func = NULL; int i = 10, index;
u32 temp_dword, rc; struct pci_resource *mem_node; struct pci_resource *p_mem_node; struct pci_resource *io_node; struct pci_resource *bus_node;
/* 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 prefetchable memory base, and * the base + length isn't greater than 0xFFFF
*/
temp_dword = pre_mem_base + pre_mem_length; if ((pre_mem_base) && (temp_dword < 0x10000)) {
p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL); if (!p_mem_node) return -ENOMEM;
/* If we've got a valid bus number, use it * The second condition is to ignore bus numbers on * populated slots that don't have PCI-PCI bridges
*/ 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 * hot plug add
*/
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));
return rc;
}
/* * cpqhp_return_board_resources * * this routine returns all resources allocated to a board to * the available pool. * * returns 0 if success
*/ int cpqhp_return_board_resources(struct pci_func *func, struct resource_lists *resources)
{ int rc = 0; struct pci_resource *node; struct pci_resource *t_node;
dbg("%s\n", __func__);
/* * cpqhp_destroy_resource_list * * Puts node back in the resource list pointed to by head
*/ void cpqhp_destroy_resource_list(struct resource_lists *resources)
{ struct pci_resource *res, *tres;
res = resources->io_head;
resources->io_head = NULL;
while (res) {
tres = res;
res = res->next;
kfree(tres);
}
res = resources->mem_head;
resources->mem_head = NULL;
while (res) {
tres = res;
res = res->next;
kfree(tres);
}
res = resources->p_mem_head;
resources->p_mem_head = NULL;
while (res) {
tres = res;
res = res->next;
kfree(tres);
}
res = resources->bus_head;
resources->bus_head = NULL;
while (res) {
tres = res;
res = res->next;
kfree(tres);
}
}
/* * cpqhp_destroy_board_resources * * Puts node back in the resource list pointed to by head
*/ void cpqhp_destroy_board_resources(struct pci_func *func)
{ struct pci_resource *res, *tres;
res = func->io_head;
func->io_head = NULL;
while (res) {
tres = res;
res = res->next;
kfree(tres);
}
res = func->mem_head;
func->mem_head = NULL;
while (res) {
tres = res;
res = res->next;
kfree(tres);
}
res = func->p_mem_head;
func->p_mem_head = NULL;
while (res) {
tres = res;
res = res->next;
kfree(tres);
}
res = func->bus_head;
func->bus_head = NULL;
while (res) {
tres = res;
res = res->next;
kfree(tres);
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet)
¤
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.