/* TODO: Change code to take advantage of driver model more */ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */ acpi_handle chandle, /* current node */ struct acpi_pci_id **id, int *is_bridge, u8 * bus_number) { acpi_handle handle; struct acpi_pci_id *pci_id = *id; acpi_status status; unsigned long temp; acpi_object_type type; u8 tu8; acpi_get_parent(chandle, &handle); if (handle != rhandle) { acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge, bus_number); status = acpi_get_type(handle, &type); if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE)) return; status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &temp); if (ACPI_SUCCESS(status)) { pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp)); pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp)); if (*is_bridge) pci_id->bus = *bus_number; /* any nicer way to get bus number of bridge ? */ status = acpi_os_read_pci_configuration(pci_id, 0x0e, &tu8, 8); if (ACPI_SUCCESS(status) && ((tu8 & 0x7f) == 1 || (tu8 & 0x7f) == 2)) { status = acpi_os_read_pci_configuration(pci_id, 0x18, &tu8, 8); if (!ACPI_SUCCESS(status)) { /* Certainly broken... FIX ME */ return; } *is_bridge = 1; pci_id->bus = tu8; status = acpi_os_read_pci_configuration(pci_id, 0x19, &tu8, 8); if (ACPI_SUCCESS(status)) { *bus_number = tu8; } } else *is_bridge = 0; } } }
acpi_status acpi_ev_pci_config_region_setup(acpi_handle handle, u32 function, void *handler_context, void **region_context) { acpi_status status = AE_OK; acpi_integer pci_value; struct acpi_pci_id *pci_id = *region_context; union acpi_operand_object *handler_obj; struct acpi_namespace_node *parent_node; struct acpi_namespace_node *pci_root_node; union acpi_operand_object *region_obj = (union acpi_operand_object *)handle; struct acpi_device_id object_hID; ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); handler_obj = region_obj->region.handler; if (!handler_obj) { /* * No installed handler. This shouldn't happen because the dispatch * routine checks before we get here, but we check again just in case. */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Attempting to init a region %p, with no handler\n", region_obj)); return_ACPI_STATUS(AE_NOT_EXIST); } *region_context = NULL; if (function == ACPI_REGION_DEACTIVATE) { if (pci_id) { ACPI_FREE(pci_id); } return_ACPI_STATUS(status); } parent_node = acpi_ns_get_parent_node(region_obj->region.node); /* * Get the _SEG and _BBN values from the device upon which the handler * is installed. * * We need to get the _SEG and _BBN objects relative to the PCI BUS device. * This is the device the handler has been registered to handle. */ /* * If the address_space.Node is still pointing to the root, we need * to scan upward for a PCI Root bridge and re-associate the op_region * handlers with that device. */ if (handler_obj->address_space.node == acpi_gbl_root_node) { /* Start search from the parent object */ pci_root_node = parent_node; while (pci_root_node != acpi_gbl_root_node) { status = acpi_ut_execute_HID(pci_root_node, &object_hID); if (ACPI_SUCCESS(status)) { /* * Got a valid _HID string, check if this is a PCI root. * New for ACPI 3.0: check for a PCI Express root also. */ if (! (ACPI_STRNCMP (object_hID.value, PCI_ROOT_HID_STRING, sizeof(PCI_ROOT_HID_STRING)) || !(ACPI_STRNCMP (object_hID.value, PCI_EXPRESS_ROOT_HID_STRING, sizeof(PCI_EXPRESS_ROOT_HID_STRING))))) { /* Install a handler for this PCI root bridge */ status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); if (ACPI_FAILURE(status)) { if (status == AE_SAME_HANDLER) { /* * It is OK if the handler is already installed on the root * bridge. Still need to return a context object for the * new PCI_Config operation region, however. */ status = AE_OK; } else { ACPI_EXCEPTION((AE_INFO, status, "Could not install PciConfig handler for Root Bridge %4.4s", acpi_ut_get_node_name (pci_root_node))); } } break; } } pci_root_node = acpi_ns_get_parent_node(pci_root_node); } /* PCI root bridge not found, use namespace root node */ } else { pci_root_node = handler_obj->address_space.node; } /* * If this region is now initialized, we are done. * (install_address_space_handler could have initialized it) */ if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { return_ACPI_STATUS(AE_OK); } /* Region is still not initialized. Create a new context */ pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id)); if (!pci_id) { return_ACPI_STATUS(AE_NO_MEMORY); } /* * For PCI_Config space access, we need the segment, bus, * device and function numbers. Acquire them here. */ /* * Get the PCI device and function numbers from the _ADR object * contained in the parent's scope. */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, parent_node, &pci_value); /* * The default is zero, and since the allocation above zeroed * the data, just do nothing on failure. */ if (ACPI_SUCCESS(status)) { pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value)); pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value)); } /* The PCI segment number comes from the _SEG method */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG, pci_root_node, &pci_value); if (ACPI_SUCCESS(status)) { pci_id->segment = ACPI_LOWORD(pci_value); } /* The PCI bus number comes from the _BBN method */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN, pci_root_node, &pci_value); if (ACPI_SUCCESS(status)) { pci_id->bus = ACPI_LOWORD(pci_value); } /* Complete this device's pci_id */ acpi_os_derive_pci_id(pci_root_node, region_obj->region.node, &pci_id); *region_context = pci_id; return_ACPI_STATUS(AE_OK); }
static ACPI_STATUS AcpiHwGetPciDeviceInfo ( ACPI_PCI_ID *PciId, ACPI_HANDLE PciDevice, UINT16 *BusNumber, BOOLEAN *IsBridge) { ACPI_STATUS Status; ACPI_OBJECT_TYPE ObjectType; UINT64 ReturnValue; UINT64 PciValue; /* We only care about objects of type Device */ Status = AcpiGetType (PciDevice, &ObjectType); if (ACPI_FAILURE (Status)) { return (Status); } if (ObjectType != ACPI_TYPE_DEVICE) { return (AE_OK); } /* We need an _ADR. Ignore device if not present */ Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, PciDevice, &ReturnValue); if (ACPI_FAILURE (Status)) { return (AE_OK); } /* * From _ADR, get the PCI Device and Function and * update the PCI ID. */ PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue)); PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue)); /* * If the previous device was a bridge, use the previous * device bus number */ if (*IsBridge) { PciId->Bus = *BusNumber; } /* * Get the bus numbers from PCI Config space: * * First, get the PCI HeaderType */ *IsBridge = FALSE; Status = AcpiOsReadPciConfiguration (PciId, PCI_CFG_HEADER_TYPE_REG, &PciValue, 8); if (ACPI_FAILURE (Status)) { return (Status); } /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */ PciValue &= PCI_HEADER_TYPE_MASK; if ((PciValue != PCI_TYPE_BRIDGE) && (PciValue != PCI_TYPE_CARDBUS_BRIDGE)) { return (AE_OK); } /* Bridge: Get the Primary BusNumber */ Status = AcpiOsReadPciConfiguration (PciId, PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8); if (ACPI_FAILURE (Status)) { return (Status); } *IsBridge = TRUE; PciId->Bus = (UINT16) PciValue; /* Bridge: Get the Secondary BusNumber */ Status = AcpiOsReadPciConfiguration (PciId, PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8); if (ACPI_FAILURE (Status)) { return (Status); } *BusNumber = (UINT16) PciValue; return (AE_OK); }
ACPI_STATUS AcpiEvPciConfigRegionSetup ( ACPI_HANDLE Handle, UINT32 Function, void *HandlerContext, void **RegionContext) { ACPI_STATUS Status = AE_OK; UINT64 PciValue; ACPI_PCI_ID *PciId = *RegionContext; ACPI_OPERAND_OBJECT *HandlerObj; ACPI_NAMESPACE_NODE *ParentNode; ACPI_NAMESPACE_NODE *PciRootNode; ACPI_NAMESPACE_NODE *PciDeviceNode; ACPI_OPERAND_OBJECT *RegionObj = (ACPI_OPERAND_OBJECT *) Handle; ACPI_FUNCTION_TRACE (EvPciConfigRegionSetup); HandlerObj = RegionObj->Region.Handler; if (!HandlerObj) { /* * No installed handler. This shouldn't happen because the dispatch * routine checks before we get here, but we check again just in case. */ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Attempting to init a region %p, with no handler\n", RegionObj)); return_ACPI_STATUS (AE_NOT_EXIST); } *RegionContext = NULL; if (Function == ACPI_REGION_DEACTIVATE) { if (PciId) { ACPI_FREE (PciId); } return_ACPI_STATUS (Status); } ParentNode = RegionObj->Region.Node->Parent; /* * Get the _SEG and _BBN values from the device upon which the handler * is installed. * * We need to get the _SEG and _BBN objects relative to the PCI BUS device. * This is the device the handler has been registered to handle. */ /* * If the AddressSpace.Node is still pointing to the root, we need * to scan upward for a PCI Root bridge and re-associate the OpRegion * handlers with that device. */ if (HandlerObj->AddressSpace.Node == AcpiGbl_RootNode) { /* Start search from the parent object */ PciRootNode = ParentNode; while (PciRootNode != AcpiGbl_RootNode) { /* Get the _HID/_CID in order to detect a RootBridge */ if (AcpiEvIsPciRootBridge (PciRootNode)) { /* Install a handler for this PCI root bridge */ Status = AcpiInstallAddressSpaceHandler ( (ACPI_HANDLE) PciRootNode, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); if (ACPI_FAILURE (Status)) { if (Status == AE_SAME_HANDLER) { /* * It is OK if the handler is already installed on the * root bridge. Still need to return a context object * for the new PCI_Config operation region, however. */ Status = AE_OK; } else { ACPI_EXCEPTION ((AE_INFO, Status, "Could not install PciConfig handler " "for Root Bridge %4.4s", AcpiUtGetNodeName (PciRootNode))); } } break; } PciRootNode = PciRootNode->Parent; } /* PCI root bridge not found, use namespace root node */ } else { PciRootNode = HandlerObj->AddressSpace.Node; } /* * If this region is now initialized, we are done. * (InstallAddressSpaceHandler could have initialized it) */ if (RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE) { return_ACPI_STATUS (AE_OK); } /* Region is still not initialized. Create a new context */ PciId = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_PCI_ID)); if (!PciId) { return_ACPI_STATUS (AE_NO_MEMORY); } /* * For PCI_Config space access, we need the segment, bus, device and * function numbers. Acquire them here. * * Find the parent device object. (This allows the operation region to be * within a subscope under the device, such as a control method.) */ PciDeviceNode = RegionObj->Region.Node; while (PciDeviceNode && (PciDeviceNode->Type != ACPI_TYPE_DEVICE)) { PciDeviceNode = PciDeviceNode->Parent; } if (!PciDeviceNode) { ACPI_FREE (PciId); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } /* * Get the PCI device and function numbers from the _ADR object * contained in the parent's scope. */ Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, PciDeviceNode, &PciValue); /* * The default is zero, and since the allocation above zeroed the data, * just do nothing on failure. */ if (ACPI_SUCCESS (Status)) { PciId->Device = ACPI_HIWORD (ACPI_LODWORD (PciValue)); PciId->Function = ACPI_LOWORD (ACPI_LODWORD (PciValue)); } /* The PCI segment number comes from the _SEG method */ Status = AcpiUtEvaluateNumericObject (METHOD_NAME__SEG, PciRootNode, &PciValue); if (ACPI_SUCCESS (Status)) { PciId->Segment = ACPI_LOWORD (PciValue); } /* The PCI bus number comes from the _BBN method */ Status = AcpiUtEvaluateNumericObject (METHOD_NAME__BBN, PciRootNode, &PciValue); if (ACPI_SUCCESS (Status)) { PciId->Bus = ACPI_LOWORD (PciValue); } /* Complete/update the PCI ID for this device */ Status = AcpiHwDerivePciId (PciId, PciRootNode, RegionObj->Region.Node); if (ACPI_FAILURE (Status)) { ACPI_FREE (PciId); return_ACPI_STATUS (Status); } *RegionContext = PciId; return_ACPI_STATUS (AE_OK); }
static acpi_status acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id, acpi_handle pci_device, u16 *bus_number, u8 *is_bridge) { acpi_status status; acpi_object_type object_type; u64 return_value; u64 pci_value; /* We only care about objects of type Device */ status = acpi_get_type(pci_device, &object_type); if (ACPI_FAILURE(status)) { return (status); } if (object_type != ACPI_TYPE_DEVICE) { return (AE_OK); } /* We need an _ADR. Ignore device if not present */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device, &return_value); if (ACPI_FAILURE(status)) { return (AE_OK); } /* * From _ADR, get the PCI Device and Function and * update the PCI ID. */ pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value)); pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value)); /* * If the previous device was a bridge, use the previous * device bus number */ if (*is_bridge) { pci_id->bus = *bus_number; } /* * Get the bus numbers from PCI Config space: * * First, get the PCI header_type */ *is_bridge = FALSE; status = acpi_os_read_pci_configuration(pci_id, PCI_CFG_HEADER_TYPE_REG, &pci_value, 8); if (ACPI_FAILURE(status)) { return (status); } /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */ pci_value &= PCI_HEADER_TYPE_MASK; if ((pci_value != PCI_TYPE_BRIDGE) && (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) { return (AE_OK); } /* Bridge: Get the Primary bus_number */ status = acpi_os_read_pci_configuration(pci_id, PCI_CFG_PRIMARY_BUS_NUMBER_REG, &pci_value, 8); if (ACPI_FAILURE(status)) { return (status); } *is_bridge = TRUE; pci_id->bus = (u16)pci_value; /* Bridge: Get the Secondary bus_number */ status = acpi_os_read_pci_configuration(pci_id, PCI_CFG_SECONDARY_BUS_NUMBER_REG, &pci_value, 8); if (ACPI_FAILURE(status)) { return (status); } *bus_number = (u16)pci_value; return (AE_OK); }
ACPI_STATUS AcpiEvPciConfigRegionSetup ( ACPI_HANDLE Handle, UINT32 Function, void *HandlerContext, void **RegionContext) { ACPI_STATUS Status = AE_OK; ACPI_INTEGER Temp; ACPI_PCI_ID *PciId = *RegionContext; ACPI_OPERAND_OBJECT *HandlerObj; ACPI_NAMESPACE_NODE *Node; ACPI_OPERAND_OBJECT *RegionObj = (ACPI_OPERAND_OBJECT *) Handle; ACPI_DEVICE_ID ObjectHID; ACPI_FUNCTION_TRACE ("EvPciConfigRegionSetup"); HandlerObj = RegionObj->Region.AddrHandler; if (!HandlerObj) { /* * No installed handler. This shouldn't happen because the dispatch * routine checks before we get here, but we check again just in case. */ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Attempting to init a region %p, with no handler\n", RegionObj)); return_ACPI_STATUS (AE_NOT_EXIST); } if (Function == ACPI_REGION_DEACTIVATE) { if (PciId) { ACPI_MEM_FREE (PciId); *RegionContext = NULL; } return_ACPI_STATUS (Status); } /* Create a new context */ PciId = ACPI_MEM_CALLOCATE (sizeof (ACPI_PCI_ID)); if (!PciId) { return_ACPI_STATUS (AE_NO_MEMORY); } /* * For PCI Config space access, we have to pass the segment, bus, * device and function numbers. This routine must acquire those. */ /* * First get device and function numbers from the _ADR object * in the parent's scope. */ Node = AcpiNsGetParentNode (RegionObj->Region.Node); /* Evaluate the _ADR object */ Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, Node, &Temp); /* * The default is zero, and since the allocation above zeroed * the data, just do nothing on failure. */ if (ACPI_SUCCESS (Status)) { PciId->Device = ACPI_HIWORD (ACPI_LODWORD (Temp)); PciId->Function = ACPI_LOWORD (ACPI_LODWORD (Temp)); } /* * Get the _SEG and _BBN values from the device upon which the handler * is installed. * * We need to get the _SEG and _BBN objects relative to the PCI BUS device. * This is the device the handler has been registered to handle. */ /* * If the AddrHandler.Node is still pointing to the root, we need * to scan upward for a PCI Root bridge and re-associate the OpRegion * handlers with that device. */ if (HandlerObj->AddrHandler.Node == AcpiGbl_RootNode) { /* * Node is currently the parent object */ while (Node != AcpiGbl_RootNode) { Status = AcpiUtExecute_HID (Node, &ObjectHID); if (ACPI_SUCCESS (Status)) { /* Got a valid _HID, check if this is a PCI root */ if (!(ACPI_STRNCMP (ObjectHID.Buffer, PCI_ROOT_HID_STRING, sizeof (PCI_ROOT_HID_STRING)))) { /* Install a handler for this PCI root bridge */ Status = AcpiInstallAddressSpaceHandler ((ACPI_HANDLE) Node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); if (ACPI_FAILURE (Status)) { ACPI_REPORT_ERROR (("Could not install PciConfig handler for %4.4s, %s\n", Node->Name.Ascii, AcpiFormatException (Status))); } break; } } Node = AcpiNsGetParentNode (Node); } } else { Node = HandlerObj->AddrHandler.Node; } /* * The PCI segment number comes from the _SEG method */ Status = AcpiUtEvaluateNumericObject (METHOD_NAME__SEG, Node, &Temp); if (ACPI_SUCCESS (Status)) { PciId->Segment = ACPI_LOWORD (Temp); } /* * The PCI bus number comes from the _BBN method */ Status = AcpiUtEvaluateNumericObject (METHOD_NAME__BBN, Node, &Temp); if (ACPI_SUCCESS (Status)) { PciId->Bus = ACPI_LOWORD (Temp); } /* * Complete this device's PciId */ AcpiOsDerivePciId (Node, RegionObj->Region.Node, &PciId); *RegionContext = PciId; return_ACPI_STATUS (AE_OK); }