acpiphp_glue.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,579 行 · 第 1/3 页
C
1,579 行
} return 0;}/** * acpiphp_check_bridge - re-enumerate devices * * Iterate over all slots under this bridge and make sure that if a * card is present they are enabled, and if not they are disabled. */static int acpiphp_check_bridge(struct acpiphp_bridge *bridge){ struct acpiphp_slot *slot; int retval = 0; int enabled, disabled; enabled = disabled = 0; for (slot = bridge->slots; slot; slot = slot->next) { unsigned int status = get_slot_status(slot); if (slot->flags & SLOT_ENABLED) { if (status == ACPI_STA_ALL) continue; retval = acpiphp_disable_slot(slot); if (retval) { err("Error occurred in disabling\n"); goto err_exit; } else { acpiphp_eject_slot(slot); } disabled++; } else { if (status != ACPI_STA_ALL) continue; retval = acpiphp_enable_slot(slot); if (retval) { err("Error occurred in enabling\n"); goto err_exit; } enabled++; } } dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled); err_exit: return retval;}static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge){ u16 pci_cmd, pci_bctl; struct pci_dev *cdev; /* Program hpp values for this device */ if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) return; pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, bridge->hpp.cache_line_size); pci_write_config_byte(dev, PCI_LATENCY_TIMER, bridge->hpp.latency_timer); pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); if (bridge->hpp.enable_serr) pci_cmd |= PCI_COMMAND_SERR; else pci_cmd &= ~PCI_COMMAND_SERR; if (bridge->hpp.enable_perr) pci_cmd |= PCI_COMMAND_PARITY; else pci_cmd &= ~PCI_COMMAND_PARITY; pci_write_config_word(dev, PCI_COMMAND, pci_cmd); /* Program bridge control value and child devices */ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, bridge->hpp.latency_timer); pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); if (bridge->hpp.enable_serr) pci_bctl |= PCI_BRIDGE_CTL_SERR; else pci_bctl &= ~PCI_BRIDGE_CTL_SERR; if (bridge->hpp.enable_perr) pci_bctl |= PCI_BRIDGE_CTL_PARITY; else pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); if (dev->subordinate) { list_for_each_entry(cdev, &dev->subordinate->devices, bus_list) program_hpp(cdev, bridge); } }}static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus){ struct acpiphp_bridge bridge; struct pci_dev *dev; memset(&bridge, 0, sizeof(bridge)); bridge.handle = handle; bridge.pci_dev = bus->self; decode_hpp(&bridge); list_for_each_entry(dev, &bus->devices, bus_list) program_hpp(dev, &bridge);}/* * Remove devices for which we could not assign resources, call * arch specific code to fix-up the bus */static void acpiphp_sanitize_bus(struct pci_bus *bus){ struct pci_dev *dev; int i; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; list_for_each_entry(dev, &bus->devices, bus_list) { for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { struct resource *res = &dev->resource[i]; if ((res->flags & type_mask) && !res->start && res->end) { /* Could not assign a required resources * for this device, remove it */ pci_remove_bus_device(dev); break; } } }}/* Program resources in newly inserted bridge */static int acpiphp_configure_bridge (acpi_handle handle){ struct acpi_pci_id pci_id; struct pci_bus *bus; if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) { err("cannot get PCI domain and bus number for bridge\n"); return -EINVAL; } bus = pci_find_bus(pci_id.segment, pci_id.bus); if (!bus) { err("cannot find bus %d:%d\n", pci_id.segment, pci_id.bus); return -EINVAL; } pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); acpiphp_sanitize_bus(bus); acpiphp_set_hpp_values(handle, bus); pci_enable_bridges(bus); acpiphp_configure_ioapics(handle); return 0;}static void handle_bridge_insertion(acpi_handle handle, u32 type){ struct acpi_device *device, *pdevice; acpi_handle phandle; if ((type != ACPI_NOTIFY_BUS_CHECK) && (type != ACPI_NOTIFY_DEVICE_CHECK)) { err("unexpected notification type %d\n", type); return; } acpi_get_parent(handle, &phandle); if (acpi_bus_get_device(phandle, &pdevice)) { dbg("no parent device, assuming NULL\n"); pdevice = NULL; } if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { err("cannot add bridge to acpi list\n"); return; } if (!acpiphp_configure_bridge(handle) && !acpi_bus_start(device)) add_bridge(handle); else err("cannot configure and start bridge\n");}/* * ACPI event handlers *//** * handle_hotplug_event_bridge - handle ACPI event on bridges * * @handle: Notify()'ed acpi_handle * @type: Notify code * @context: pointer to acpiphp_bridge structure * * handles ACPI event notification on {host,p2p} bridges * */static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context){ struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; struct acpi_device *device; if (acpi_bus_get_device(handle, &device)) { /* This bridge must have just been physically inserted */ handle_bridge_insertion(handle, type); return; } bridge = acpiphp_handle_to_bridge(handle); if (!bridge) { err("cannot get bridge info\n"); return; } acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); acpiphp_check_bridge(bridge); break; case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); acpiphp_check_bridge(bridge); break; case ACPI_NOTIFY_DEVICE_WAKE: /* wake event */ dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); break; case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: printk(KERN_ERR "Device %s cannot be configured due" " to a frequency mismatch\n", objname); break; case ACPI_NOTIFY_BUS_MODE_MISMATCH: printk(KERN_ERR "Device %s cannot be configured due" " to a bus mode mismatch\n", objname); break; case ACPI_NOTIFY_POWER_FAULT: printk(KERN_ERR "Device %s has suffered a power fault\n", objname); break; default: warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); break; }}/** * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) * * @handle: Notify()'ed acpi_handle * @type: Notify code * @context: pointer to acpiphp_func structure * * handles ACPI event notification on slots * */void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context){ struct acpiphp_func *func; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); func = (struct acpiphp_func *)context; switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); acpiphp_enable_slot(func->slot); break; case ACPI_NOTIFY_DEVICE_CHECK: /* device check : re-enumerate from parent bus */ dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); acpiphp_check_bridge(func->slot->bridge); break; case ACPI_NOTIFY_DEVICE_WAKE: /* wake event */ dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); break; case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); if (!(acpiphp_disable_slot(func->slot))) acpiphp_eject_slot(func->slot); break; default: warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); break; }}static acpi_statusfind_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv){ int *count = (int *)context; if (acpi_root_bridge(handle)) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge, NULL); (*count)++; } return AE_OK ;}static struct acpi_pci_driver acpi_pci_hp_driver = { .add = add_bridge, .remove = remove_bridge,};/** * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures * */int __init acpiphp_glue_init(void){ int num = 0; acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_root_bridges, &num, NULL); if (num <= 0) return -1; else acpi_pci_register_driver(&acpi_pci_hp_driver); return 0;}/** * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures * * This function frees all data allocated in acpiphp_glue_init() */void __exit acpiphp_glue_exit(void){ acpi_pci_unregister_driver(&acpi_pci_hp_driver);}/** * acpiphp_get_num_slots - count number of slots in a system */int __init acpiphp_get_num_slots(void){ struct list_head *node; struct acpiphp_bridge *bridge; int num_slots; num_slots = 0; list_for_each (node, &bridge_list) { bridge = (struct acpiphp_bridge *)node; dbg("Bus %04x:%02x has %d slot%s\n", pci_domain_nr(bridge->pci_bus), bridge->pci_bus->number, bridge->nr_slots, bridge->nr_slots == 1 ? "" : "s"); num_slots += bridge->nr_slots; } dbg("Total %d slots\n", num_slots); return num_slots;}#if 0/** * acpiphp_for_each_slot - call function for each slot * @fn: callback function * @data: context to be passed to callback function * */static int acpiphp_for_each_slot(acpiphp_callback fn, void *data){ struct list_head *node; struct acpiphp_bridge *bridge; struct acpiphp_slot *slot; int retval = 0; list_for_each (node, &bridge_list) { bridge = (struct acpiphp_bridge *)node; for (slot = bridge->slots; slot; slot = slot->next) { retval = fn(slot, data); if (!retval) goto err_exit; } } err_exit: return retval;}#endif/** * acpiphp_enable_slot - power on slot */int acpiphp_enable_slot(struct acpiphp_slot *slot){ int retval; mutex_lock(&slot->crit_sect); /* wake up all functions */ retval = power_on_slot(slot); if (retval) goto err_exit; if (get_slot_status(slot) == ACPI_STA_ALL) /* configure all functions */ retval = enable_device(slot); err_exit: mutex_unlock(&slot->crit_sect); return retval;}/** * acpiphp_disable_slot - power off slot */int acpiphp_disable_slot(struct acpiphp_slot *slot){ int retval = 0; mutex_lock(&slot->crit_sect); /* unconfigure all functions */ retval = disable_device(slot); if (retval) goto err_exit; /* power off all functions */ retval = power_off_slot(slot); if (retval) goto err_exit; err_exit: mutex_unlock(&slot->crit_sect); return retval;}/* * slot enabled: 1 * slot disabled: 0 */u8 acpiphp_get_power_status(struct acpiphp_slot *slot){ return (slot->flags & SLOT_POWEREDON);}/* * latch closed: 1 * latch open: 0 */u8 acpiphp_get_latch_status(struct acpiphp_slot *slot){ unsigned int sta; sta = get_slot_status(slot); return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;}/* * adapter presence : 1 * absence : 0 */u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot){ unsigned int sta; sta = get_slot_status(slot); return (sta == 0) ? 0 : 1;}/* * pci address (seg/bus/dev) */u32 acpiphp_get_address(struct acpiphp_slot *slot){ u32 address; struct pci_bus *pci_bus = slot->bridge->pci_bus; address = (pci_domain_nr(pci_bus) << 16) | (pci_bus->number << 8) | slot->device; return address;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?