Exemple #1
0
static int acpi_processor_get_lpi_info(struct acpi_processor *pr)
{
	int ret, i;
	acpi_status status;
	acpi_handle handle = pr->handle, pr_ahandle;
	struct acpi_device *d = NULL;
	struct acpi_lpi_states_array info[2], *tmp, *prev, *curr;

	if (!osc_pc_lpi_support_confirmed)
		return -EOPNOTSUPP;

	if (!acpi_has_method(handle, "_LPI"))
		return -EINVAL;

	flat_state_cnt = 0;
	prev = &info[0];
	curr = &info[1];
	handle = pr->handle;
	ret = acpi_processor_evaluate_lpi(handle, prev);
	if (ret)
		return ret;
	flatten_lpi_states(pr, prev, NULL);

	status = acpi_get_parent(handle, &pr_ahandle);
	while (ACPI_SUCCESS(status)) {
		acpi_bus_get_device(pr_ahandle, &d);
		handle = pr_ahandle;

		if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID))
			break;

		/* can be optional ? */
		if (!acpi_has_method(handle, "_LPI"))
			break;

		ret = acpi_processor_evaluate_lpi(handle, curr);
		if (ret)
			break;

		/* flatten all the LPI states in this level of hierarchy */
		flatten_lpi_states(pr, curr, prev);

		tmp = prev, prev = curr, curr = tmp;

		status = acpi_get_parent(handle, &pr_ahandle);
	}

	pr->power.count = flat_state_cnt;
	/* reset the index after flattening */
	for (i = 0; i < pr->power.count; i++)
		pr->power.lpi_states[i].index = i;

	/* Tell driver that _LPI is supported. */
	pr->flags.has_lpi = 1;
	pr->flags.power = 1;

	return 0;
}
static
int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
{
	acpi_handle phandle;
	struct acpi_device *pdev;


	if (acpi_get_parent(handle, &phandle)) {
		return -ENODEV;
	}

	if (acpi_bus_get_device(phandle, &pdev)) {
		return -ENODEV;
	}

	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
		return -ENODEV;
	}

	if (processor_cntl_external() && acpi_driver_data(*device))
		processor_notify_external(acpi_driver_data(*device),
			PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD);

	return 0;
}
static
int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
{
	acpi_handle phandle;
	struct acpi_device *pdev;
	struct acpi_processor *pr;

	ACPI_FUNCTION_TRACE("acpi_processor_device_add");

	if (acpi_get_parent(handle, &phandle)) {
		return_VALUE(-ENODEV);
	}

	if (acpi_bus_get_device(phandle, &pdev)) {
		return_VALUE(-ENODEV);
	}

	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
		return_VALUE(-ENODEV);
	}

	acpi_bus_start(*device);

	pr = acpi_driver_data(*device);
	if (!pr)
		return_VALUE(-ENODEV);

	if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
		kobject_hotplug(&(*device)->kobj, KOBJ_ONLINE);
	}
	return_VALUE(0);
}
/* pci_get_hp_params
 *
 * @dev - the pci_dev for which we want parameters
 * @hpp - allocated by the caller
 */
int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
{
	acpi_status status;
	acpi_handle handle, phandle;
	struct pci_bus *pbus;

	handle = NULL;
	for (pbus = dev->bus; pbus; pbus = pbus->parent) {
		handle = acpi_pci_get_bridge_handle(pbus);
		if (handle)
			break;
	}

	/*
	 * _HPP settings apply to all child buses, until another _HPP is
	 * encountered. If we don't find an _HPP for the input pci dev,
	 * look for it in the parent device scope since that would apply to
	 * this pci dev.
	 */
	while (handle) {
		status = acpi_run_hpx(handle, hpp);
		if (ACPI_SUCCESS(status))
			return 0;
		status = acpi_run_hpp(handle, hpp);
		if (ACPI_SUCCESS(status))
			return 0;
		if (acpi_is_root_bridge(handle))
			break;
		status = acpi_get_parent(handle, &phandle);
		if (ACPI_FAILURE(status))
			break;
		handle = phandle;
	}
	return -ENODEV;
}
static int
container_device_add(struct acpi_device **device, acpi_handle handle)
{
	acpi_handle phandle;
	struct acpi_device *pdev;
	int result;

	ACPI_FUNCTION_TRACE("container_device_add");

	if (acpi_get_parent(handle, &phandle)) {
		return_VALUE(-ENODEV);
	}

	if (acpi_bus_get_device(phandle, &pdev)) {
		return_VALUE(-ENODEV);
	}

	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
		return_VALUE(-ENODEV);
	}

	result = acpi_bus_scan(*device);

	return_VALUE(result);
}
static
int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
{
	acpi_handle phandle;
	struct acpi_device *pdev;
	struct acpi_processor *pr;


	if (acpi_get_parent(handle, &phandle)) {
		return -ENODEV;
	}

	if (acpi_bus_get_device(phandle, &pdev)) {
		return -ENODEV;
	}

	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
		return -ENODEV;
	}

	acpi_bus_start(*device);

	pr = acpi_driver_data(*device);
	if (!pr)
		return -ENODEV;

	if ((pr->id >= 0) && (pr->id < nr_cpu_ids)) {
		kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
	}
	return 0;
}
Exemple #7
0
static
int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
{
	acpi_handle phandle;
	struct acpi_device *pdev;
	struct acpi_processor *pr;


	if (acpi_get_parent(handle, &phandle)) {
		return -ENODEV;
	}

	if (acpi_bus_get_device(phandle, &pdev)) {
		return -ENODEV;
	}

	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
		return -ENODEV;
	}

	acpi_bus_start(*device);

	pr = acpi_driver_data(*device);
	if (!pr)
		return -ENODEV;

	if (processor_cntl_external())
		processor_notify_external(pr,
			PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD);

	if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
		kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
	}
	return 0;
}
int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
{
	acpi_status status;
	acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
	struct pci_dev *pdev = dev;
	u8 *path_name;
	/*
	 * Per PCI firmware specification, we should run the ACPI _OSC
	 * method to get control of hotplug hardware before using it.
	 * If an _OSC is missing, we look for an OSHP to do the same thing.
	 * To handle different BIOS behavior, we look for _OSC and OSHP
	 * within the scope of the hotplug controller and its parents, upto
	 * the host bridge under which this controller exists.
	 */
	while (!handle) {
		/*
		 * This hotplug controller was not listed in the ACPI name
		 * space at all. Try to get acpi handle of parent pci bus.
		 */
		if (!pdev || !pdev->bus->parent)
			break;
		dbg("Could not find %s in acpi namespace, trying parent\n",
				pci_name(pdev));
		if (!pdev->bus->parent->self)
			/* Parent must be a host bridge */
			handle = acpi_get_pci_rootbridge_handle(
					pci_domain_nr(pdev->bus->parent),
					pdev->bus->parent->number);
		else
			handle = DEVICE_ACPI_HANDLE(
					&(pdev->bus->parent->self->dev));
		pdev = pdev->bus->parent->self;
	}

	while (handle) {
		path_name = acpi_path_name(handle);
		dbg("Trying to get hotplug control for %s \n", path_name);
		status = pci_osc_control_set(handle,
				OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
		if (status == AE_NOT_FOUND)
			status = acpi_run_oshp(handle);
		if (ACPI_SUCCESS(status)) {
			dbg("Gained control for hotplug HW for pci %s (%s)\n",
				pci_name(dev), path_name);
			return 0;
		}
		if (is_root_bridge(handle))
			break;
		chandle = handle;
		status = acpi_get_parent(chandle, &handle);
		if (ACPI_FAILURE(status))
			break;
	}

	err("Cannot get control of hotplug hardware for pci %s\n",
			pci_name(dev));
	return -1;
}
static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
{
	acpi_status status;
	acpi_handle child_handle;
	acpi_handle parent_handle;
	acpi_handle next_child_handle;
	acpi_handle dummy;
	u32 level;

	ACPI_FUNCTION_TRACE(ns_delete_subtree);

	parent_handle = start_handle;
	child_handle = NULL;
	level = 1;

	while (level > 0) {

		

		status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle,
					      child_handle, &next_child_handle);

		child_handle = next_child_handle;

		

		if (ACPI_SUCCESS(status)) {

			

			if (ACPI_SUCCESS
			    (acpi_get_next_object
			     (ACPI_TYPE_ANY, child_handle, NULL, &dummy))) {
				level++;
				parent_handle = child_handle;
				child_handle = NULL;
			}
		} else {
			level--;

			

			acpi_ns_delete_children(child_handle);

			child_handle = parent_handle;
			status = acpi_get_parent(parent_handle, &parent_handle);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
			}
		}
	}

	

	acpi_ns_remove_node(child_handle);
	return_ACPI_STATUS(AE_OK);
}
Exemple #10
0
/* 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;
		}
	}
}
Exemple #11
0
static acpi_status __init
zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
{
	acpi_handle handle, parent;
	acpi_status status;
	struct acpi_device_info *info;
	u64 lba_hpa, sba_hpa, length;
	int match;

	status = hp_acpi_csr_space(obj, &lba_hpa, &length);
	if (ACPI_FAILURE(status))
		return AE_OK; /* keep looking for another bridge */

	/* Look for an enclosing IOC scope and find its CSR space */
	handle = obj;
	do {
		status = acpi_get_object_info(handle, &info);
		if (ACPI_SUCCESS(status) && (info->valid & ACPI_VALID_HID)) {
			/* TBD check _CID also */
			match = (strcmp(info->hardware_id.string, "HWP0001") == 0);
			kfree(info);
			if (match) {
				status = hp_acpi_csr_space(handle, &sba_hpa, &length);
				if (ACPI_SUCCESS(status))
					break;
				else {
					printk(KERN_ERR PFX "Detected HP ZX1 "
					       "AGP LBA but no IOC.\n");
					return AE_OK;
				}
			}
		}

		status = acpi_get_parent(handle, &parent);
		handle = parent;
	} while (ACPI_SUCCESS(status));

	if (ACPI_FAILURE(status))
		return AE_OK;	/* found no enclosing IOC */

	if (hp_zx1_setup(sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa))
		return AE_OK;

#ifdef CONFIG_DEBUG_PRINTK
	printk(KERN_INFO PFX "Detected HP ZX1 %s AGP chipset "
		"(ioc=%llx, lba=%llx)\n", (char *)context,
		sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa);
#else
	;
#endif

	hp_zx1_gart_found = 1;
	return AE_CTRL_TERMINATE; /* we only support one bridge; quit looking */
}
Exemple #12
0
/**
 * acpi_pcihp_check_ejectable - check if handle is ejectable ACPI PCI slot
 * @pbus: the PCI bus of the PCI slot corresponding to 'handle'
 * @handle: ACPI handle to check
 *
 * Return 1 if handle is ejectable PCI slot, 0 otherwise.
 */
int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle)
{
	acpi_handle bridge_handle, parent_handle;

	bridge_handle = acpi_pci_get_bridge_handle(pbus);
	if (!bridge_handle)
		return 0;
	if ((ACPI_FAILURE(acpi_get_parent(handle, &parent_handle))))
		return 0;
	if (bridge_handle != parent_handle)
		return 0;
	return pcihp_is_ejectable(handle);
}
Exemple #13
0
static acpi_status __init
zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
{
	acpi_handle handle, parent;
	acpi_status status;
	struct acpi_buffer buffer;
	struct acpi_device_info *info;
	u64 lba_hpa, sba_hpa, length;
	int match;

	status = hp_acpi_csr_space(obj, &lba_hpa, &length);
	if (ACPI_FAILURE(status))
		return AE_OK; /* keep looking for another bridge */

	/* Look for an enclosing IOC scope and find its CSR space */
	handle = obj;
	do {
		buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
		status = acpi_get_object_info(handle, &buffer);
		if (ACPI_SUCCESS(status)) {
			/* TBD check _CID also */
			info = buffer.pointer;
			info->hardware_id.value[sizeof(info->hardware_id)-1] = '\0';
			match = (strcmp(info->hardware_id.value, "HWP0001") == 0);
			kfree(info);
			if (match) {
				status = hp_acpi_csr_space(handle, &sba_hpa, &length);
				if (ACPI_SUCCESS(status))
					break;
				else {
					printk(KERN_ERR PFX "Detected HP ZX1 "
					       "AGP LBA but no IOC.\n");
					return AE_OK;
				}
			}
		}

		status = acpi_get_parent(handle, &parent);
		handle = parent;
	} while (ACPI_SUCCESS(status));

	if (hp_zx1_setup(sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa))
		return AE_OK;

	printk(KERN_INFO PFX "Detected HP ZX1 %s AGP chipset "
		"(ioc=%llx, lba=%llx)\n", (char *)context,
		sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa);

	hp_zx1_gart_found = 1;
	return AE_CTRL_TERMINATE; /* we only support one bridge; quit looking */
}
Exemple #14
0
static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
{
	struct acpi_device *adev = pdata->adev;
	struct device *dev = pdata->dev;
	u32 property;
	acpi_handle handle;
	acpi_status status;
	unsigned long long data;
	int cca;
	int ret;

	/* Obtain the system clock setting */
	ret = device_property_read_u32(dev, XGBE_ACPI_DMA_FREQ, &property);
	if (ret) {
		dev_err(dev, "unable to obtain %s property\n",
			XGBE_ACPI_DMA_FREQ);
		return ret;
	}
	pdata->sysclk_rate = property;

	/* Obtain the PTP clock setting */
	ret = device_property_read_u32(dev, XGBE_ACPI_PTP_FREQ, &property);
	if (ret) {
		dev_err(dev, "unable to obtain %s property\n",
			XGBE_ACPI_PTP_FREQ);
		return ret;
	}
	pdata->ptpclk_rate = property;

	/* Retrieve the device cache coherency value */
	handle = adev->handle;
	do {
		status = acpi_evaluate_integer(handle, "_CCA", NULL, &data);
		if (!ACPI_FAILURE(status)) {
			cca = data;
			break;
		}

		status = acpi_get_parent(handle, &handle);
	} while (!ACPI_FAILURE(status));

	if (ACPI_FAILURE(status)) {
		dev_err(dev, "error obtaining acpi coherency value\n");
		return -EINVAL;
	}
	pdata->coherent = !!cca;

	return 0;
}
Exemple #15
0
static acpi_status __init
zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
{
	acpi_handle handle, parent;
	acpi_status status;
	struct acpi_device_info *info;
	u64 lba_hpa, sba_hpa, length;
	int match;

	status = hp_acpi_csr_space(obj, &lba_hpa, &length);
	if (ACPI_FAILURE(status))
		return AE_OK; 

	
	handle = obj;
	do {
		status = acpi_get_object_info(handle, &info);
		if (ACPI_SUCCESS(status)) {
			
			info->hardware_id.string[sizeof(info->hardware_id.length)-1] = '\0';
			match = (strcmp(info->hardware_id.string, "HWP0001") == 0);
			kfree(info);
			if (match) {
				status = hp_acpi_csr_space(handle, &sba_hpa, &length);
				if (ACPI_SUCCESS(status))
					break;
				else {
					printk(KERN_ERR PFX "Detected HP ZX1 "
					       "AGP LBA but no IOC.\n");
					return AE_OK;
				}
			}
		}

		status = acpi_get_parent(handle, &parent);
		handle = parent;
	} while (ACPI_SUCCESS(status));

	if (hp_zx1_setup(sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa))
		return AE_OK;

	printk(KERN_INFO PFX "Detected HP ZX1 %s AGP chipset "
		"(ioc=%llx, lba=%llx)\n", (char *)context,
		sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa);

	hp_zx1_gart_found = 1;
	return AE_CTRL_TERMINATE; 
}
Exemple #16
0
int acpi_get_pxm(acpi_handle h)
{
	unsigned long long pxm;
	acpi_status status;
	acpi_handle handle;
	acpi_handle phandle = h;

	do {
		handle = phandle;
		status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
		if (ACPI_SUCCESS(status))
			return pxm;
		status = acpi_get_parent(handle, &phandle);
	} while (ACPI_SUCCESS(status));
	return -1;
}
Exemple #17
0
static int
acpi_memory_get_device(acpi_handle handle,
		       struct acpi_memory_device **mem_device)
{
	acpi_status status;
	acpi_handle phandle;
	struct acpi_device *device = NULL;
	struct acpi_device *pdevice = NULL;

	ACPI_FUNCTION_TRACE("acpi_memory_get_device");

	if (!acpi_bus_get_device(handle, &device) && device)
		goto end;

	status = acpi_get_parent(handle, &phandle);
	if (ACPI_FAILURE(status)) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error in acpi_get_parent\n"));
		return_VALUE(-EINVAL);
	}

	/* Get the parent device */
	status = acpi_bus_get_device(phandle, &pdevice);
	if (ACPI_FAILURE(status)) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "Error in acpi_bus_get_device\n"));
		return_VALUE(-EINVAL);
	}

	/*
	 * Now add the notified device.  This creates the acpi_device
	 * and invokes .add function
	 */
	status = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
	if (ACPI_FAILURE(status)) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error in acpi_bus_add\n"));
		return_VALUE(-EINVAL);
	}

      end:
	*mem_device = acpi_driver_data(device);
	if (!(*mem_device)) {
		printk(KERN_ERR "\n driver data not found");
		return_VALUE(-ENODEV);
	}

	return_VALUE(0);
}
static
int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
{
	acpi_handle phandle;
	struct acpi_device *pdev;

	if (acpi_get_parent(handle, &phandle))
		return -ENODEV;

	if (acpi_bus_get_device(phandle, &pdev))
		return -ENODEV;

	if (acpi_bus_scan(handle))
		return -ENODEV;

	return 0;
}
Exemple #19
0
static acpi_status
acpi_hw_build_pci_list(acpi_handle root_pci_device,
		       acpi_handle pci_region,
		       struct acpi_pci_device **return_list_head)
{
	acpi_handle current_device;
	acpi_handle parent_device;
	acpi_status status;
	struct acpi_pci_device *list_element;
	struct acpi_pci_device *list_head = NULL;

	/*
	 * Ascend namespace branch until the root_pci_device is reached, building
	 * a list of device nodes. Loop will exit when either the PCI device is
	 * found, or the root of the namespace is reached.
	 */
	current_device = pci_region;
	while (1) {
		status = acpi_get_parent(current_device, &parent_device);
		if (ACPI_FAILURE(status)) {
			return (status);
		}

		/* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */

		if (parent_device == root_pci_device) {
			*return_list_head = list_head;
			return (AE_OK);
		}

		list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
		if (!list_element) {
			return (AE_NO_MEMORY);
		}

		/* Put new element at the head of the list */

		list_element->next = list_head;
		list_element->device = parent_device;
		list_head = list_element;

		current_device = parent_device;
	}
}
static
int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
{
	acpi_handle phandle;
	struct acpi_device *pdev;

	if (acpi_get_parent(handle, &phandle)) {
		return -ENODEV;
	}

	if (acpi_bus_get_device(phandle, &pdev)) {
		return -ENODEV;
	}

	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
		return -ENODEV;
	}

	return 0;
}
Exemple #21
0
/* acpi_get_hp_params_from_firmware
 *
 * @bus - the pci_bus of the bus on which the device is newly added
 * @hpp - allocated by the caller
 */
acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
        struct hotplug_params *hpp)
{
    acpi_status status = AE_NOT_FOUND;
    acpi_handle handle, phandle;
    struct pci_bus *pbus = bus;
    struct pci_dev *pdev;

    do {
        pdev = pbus->self;
        if (!pdev) {
            handle = acpi_get_pci_rootbridge_handle(
                pci_domain_nr(pbus), pbus->number);
            break;
        }
        handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
        pbus = pbus->parent;
    } while (!handle);

    /*
     * _HPP settings apply to all child buses, until another _HPP is
     * encountered. If we don't find an _HPP for the input pci dev,
     * look for it in the parent device scope since that would apply to
     * this pci dev. If we don't find any _HPP, use hardcoded defaults
     */
    while (handle) {
        status = acpi_run_hpx(handle, hpp);
        if (ACPI_SUCCESS(status))
            break;
        status = acpi_run_hpp(handle, hpp);
        if (ACPI_SUCCESS(status))
            break;
        if (acpi_root_bridge(handle))
            break;
        status = acpi_get_parent(handle, &phandle);
        if (ACPI_FAILURE(status))
            break;
        handle = phandle;
    }
    return status;
}
Exemple #22
0
static int container_device_add(struct acpi_device **device, acpi_handle handle)
{
	acpi_handle phandle;
	struct acpi_device *pdev;
	int result;

	if (acpi_get_parent(handle, &phandle)) {
		return -ENODEV;
	}

	if (acpi_bus_get_device(phandle, &pdev)) {
		return -ENODEV;
	}

	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
		return -ENODEV;
	}

	result = acpi_bus_start(*device);

	return result;
}
Exemple #23
0
/**
 * acpi_get_hp_hw_control_from_firmware
 * @dev: the pci_dev of the bridge that has a hotplug controller
 *
 * Attempt to take hotplug control from firmware.
 */
int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev)
{
	const struct pci_host_bridge *host;
	const struct acpi_pci_root *root;
	acpi_status status;
	acpi_handle chandle, handle;
	struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };

	/*
	 * If there's no ACPI host bridge (i.e., ACPI support is compiled
	 * into the kernel but the hardware platform doesn't support ACPI),
	 * there's nothing to do here.
	 */
	host = pci_find_host_bridge(pdev->bus);
	root = acpi_pci_find_root(ACPI_HANDLE(&host->dev));
	if (!root)
		return 0;

	/*
	 * If _OSC exists, it determines whether we're allowed to manage
	 * the SHPC.  We executed it while enumerating the host bridge.
	 */
	if (root->osc_support_set) {
		if (host->native_shpc_hotplug)
			return 0;
		return -ENODEV;
	}

	/*
	 * In the absence of _OSC, we're always allowed to manage the SHPC.
	 * However, if an OSHP method is present, we must execute it so the
	 * firmware can transfer control to the OS, e.g., direct interrupts
	 * to the OS instead of to the firmware.
	 *
	 * N.B. The PCI Firmware Spec (r3.2, sec 4.8) does not endorse
	 * searching up the ACPI hierarchy, so the loops below are suspect.
	 */
	handle = ACPI_HANDLE(&pdev->dev);
	if (!handle) {
		/*
		 * This hotplug controller was not listed in the ACPI name
		 * space at all. Try to get ACPI handle of parent PCI bus.
		 */
		struct pci_bus *pbus;
		for (pbus = pdev->bus; pbus; pbus = pbus->parent) {
			handle = acpi_pci_get_bridge_handle(pbus);
			if (handle)
				break;
		}
	}

	while (handle) {
		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
		pci_info(pdev, "Requesting control of SHPC hotplug via OSHP (%s)\n",
			 (char *)string.pointer);
		status = acpi_run_oshp(handle);
		if (ACPI_SUCCESS(status))
			goto got_one;
		if (acpi_is_root_bridge(handle))
			break;
		chandle = handle;
		status = acpi_get_parent(chandle, &handle);
		if (ACPI_FAILURE(status))
			break;
	}

	pci_info(pdev, "Cannot get control of SHPC hotplug\n");
	kfree(string.pointer);
	return -ENODEV;
got_one:
	pci_info(pdev, "Gained control of SHPC hotplug (%s)\n",
		 (char *)string.pointer);
	kfree(string.pointer);
	return 0;
}
Exemple #24
0
static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
{
    acpi_status status;
    acpi_handle child_handle;
    acpi_handle parent_handle;
    acpi_handle next_child_handle;
    acpi_handle dummy;
    u32 level;

    ACPI_FUNCTION_TRACE(ns_delete_subtree);

    parent_handle = start_handle;
    child_handle = NULL;
    level = 1;

    /*
     * Traverse the tree of objects until we bubble back up
     * to where we started.
     */
    while (level > 0) {

        /* Attempt to get the next object in this scope */

        status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle,
                          child_handle, &next_child_handle);

        child_handle = next_child_handle;

        /* Did we get a new object? */

        if (ACPI_SUCCESS(status)) {

            /* Check if this object has any children */

            if (ACPI_SUCCESS
                (acpi_get_next_object
                 (ACPI_TYPE_ANY, child_handle, NULL, &dummy))) {
                /*
                 * There is at least one child of this object,
                 * visit the object
                 */
                level++;
                parent_handle = child_handle;
                child_handle = NULL;
            }
        } else {
            /*
             * No more children in this object, go back up to
             * the object's parent
             */
            level--;

            /* Delete all children now */

            acpi_ns_delete_children(child_handle);

            child_handle = parent_handle;
            status = acpi_get_parent(parent_handle, &parent_handle);
            if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
            }
        }
    }

    /* Now delete the starting object, and we are done */

    acpi_ns_delete_node(child_handle);

    return_ACPI_STATUS(AE_OK);
}
Exemple #25
0
void
bm_print_object (
	acpi_handle		handle)
{
	acpi_buffer		buffer;
	acpi_handle		parent;
	acpi_object_type	type;

	buffer.length = 256;
	buffer.pointer = acpi_os_callocate(buffer.length);
	if (!buffer.pointer) {
		return;
	}

	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
	acpi_get_parent(handle, &parent);
	acpi_get_type(handle, &type);

	/*
	 * TBD: Hack to get around scope identification problem.
	 */
	if (type == ACPI_TYPE_ANY) {
		if (ACPI_SUCCESS(acpi_get_next_object(ACPI_TYPE_ANY,
			handle, 0, NULL))) {
			type = INTERNAL_TYPE_SCOPE;
		}
	}

	switch (type)
	 {
	case INTERNAL_TYPE_SCOPE:
		acpi_os_printf("SCOPE: ");
		break;
	case ACPI_TYPE_INTEGER:
		acpi_os_printf("SIMPLE (number): ");
		break;
	case ACPI_TYPE_STRING:
		acpi_os_printf("SIMPLE (string): ");
		break;
	case ACPI_TYPE_BUFFER:
		acpi_os_printf("SIMPLE (buffer): ");
		break;
	case ACPI_TYPE_PACKAGE:
		acpi_os_printf("SIMPLE (package): ");
		break;
	case ACPI_TYPE_FIELD_UNIT:
		acpi_os_printf("FIELD UNIT: ");
		break;
	case ACPI_TYPE_DEVICE:
		acpi_os_printf("DEVICE: ");
		break;
	case ACPI_TYPE_EVENT:
		acpi_os_printf("EVENT: ");
		break;
	case ACPI_TYPE_METHOD:
		acpi_os_printf("CONTROL METHOD: ");
		break;
	case ACPI_TYPE_MUTEX:
		acpi_os_printf("MUTEX: ");
		break;
	case ACPI_TYPE_REGION:
		acpi_os_printf("OPERATION REGION: ");
		break;
	case ACPI_TYPE_POWER:
		acpi_os_printf("POWER RESOURCE: ");
		break;
	case ACPI_TYPE_PROCESSOR:
		acpi_os_printf("PROCESSOR: ");
		break;
	case ACPI_TYPE_THERMAL:
		acpi_os_printf("THERMAL ZONE: ");
		break;
	case ACPI_TYPE_BUFFER_FIELD:
		acpi_os_printf("BUFFER FIELD: ");
		break;
	case ACPI_TYPE_DDB_HANDLE:
		acpi_os_printf("DDB HANDLE: ");
		break;
	default:
		acpi_os_printf("OTHER (%d): ", type);
		break;
	}

	acpi_os_printf("Object[%p][%s] parent[%p].\n", handle, (char*)buffer.pointer, parent);

	acpi_os_free(buffer.pointer);
}
Exemple #26
0
acpi_status
bm_enumerate_namespace (void)
{
	acpi_status		status = AE_OK;
	acpi_handle             parent_handle = ACPI_ROOT_OBJECT;
	acpi_handle             child_handle = NULL;
	BM_NODE			*parent = NULL;
	BM_NODE			*child = NULL;
	acpi_object_type        acpi_type = 0;
	u32                     level = 1;

	FUNCTION_TRACE("bm_enumerate_namespace");

	parent = node_list.nodes[0];

	/*
	 * Enumerate ACPI Namespace:
	 * -------------------------
	 * Parse through the ACPI namespace, identify all 'devices',
	 * and create a new entry for each in our collection.
	 */
	while (level > 0) {

		/*
		 * Get the next object at this level.
		 */
		status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, child_handle, &child_handle);
		if (ACPI_SUCCESS(status)) {
			/*
			 * TBD: This is a hack to get around the problem
			 *       identifying scope objects.  Scopes
			 *       somehow need to be uniquely identified.
			 */
			status = acpi_get_type(child_handle, &acpi_type);
			if (ACPI_SUCCESS(status) && (acpi_type == ACPI_TYPE_ANY)) {
				status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL);
				if (ACPI_SUCCESS(status)) {
					acpi_type = INTERNAL_TYPE_SCOPE;
				}
			}

			/*
			 * Device?
			 * -------
			 * If this object is a 'device', insert into the
			 * ACPI Bus Manager's local hierarchy and search
			 * the object's scope for any child devices (a
			 * depth-first search).
			 */
			switch (acpi_type) {
			case INTERNAL_TYPE_SCOPE:
			case ACPI_TYPE_DEVICE:
			case ACPI_TYPE_PROCESSOR:
			case ACPI_TYPE_THERMAL:
			case ACPI_TYPE_POWER:
				status = bm_add_namespace_device(child_handle, acpi_type, parent, &child);
				if (ACPI_SUCCESS(status)) {
					status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL);
					if (ACPI_SUCCESS(status)) {
						level++;
						parent_handle = child_handle;
						child_handle = 0;
						parent = child;
					}
				}
				break;
			}
		}

		/*
		 * Scope Exhausted:
		 * ----------------
		 * No more children in this object's scope, Go back up
		 * in the namespace tree to the object's parent.
		 */
		else {
			level--;
			child_handle = parent_handle;
			acpi_get_parent(parent_handle,
				&parent_handle);

			if (parent) {
				parent = parent->parent;
			}
			else {
				return_ACPI_STATUS(AE_NULL_ENTRY);
			}
		}
	}

	return_ACPI_STATUS(AE_OK);
}
static int xen_add_device(struct device *dev)
{
	int r;
	struct pci_dev *pci_dev = to_pci_dev(dev);
#ifdef CONFIG_PCI_IOV
	struct pci_dev *physfn = pci_dev->physfn;
#endif

	if (pci_seg_supported) {
		struct physdev_pci_device_add add = {
			.seg = pci_domain_nr(pci_dev->bus),
			.bus = pci_dev->bus->number,
			.devfn = pci_dev->devfn
		};
#ifdef CONFIG_ACPI
		acpi_handle handle;
#endif

#ifdef CONFIG_PCI_IOV
		if (pci_dev->is_virtfn) {
			add.flags = XEN_PCI_DEV_VIRTFN;
			add.physfn.bus = physfn->bus->number;
			add.physfn.devfn = physfn->devfn;
		} else
#endif
		if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn))
			add.flags = XEN_PCI_DEV_EXTFN;

#ifdef CONFIG_ACPI
		handle = DEVICE_ACPI_HANDLE(&pci_dev->dev);
		if (!handle)
			handle = DEVICE_ACPI_HANDLE(pci_dev->bus->bridge);
#ifdef CONFIG_PCI_IOV
		if (!handle && pci_dev->is_virtfn)
			handle = DEVICE_ACPI_HANDLE(physfn->bus->bridge);
#endif
		if (handle) {
			acpi_status status;

			do {
				unsigned long long pxm;

				status = acpi_evaluate_integer(handle, "_PXM",
							       NULL, &pxm);
				if (ACPI_SUCCESS(status)) {
					add.optarr[0] = pxm;
					add.flags |= XEN_PCI_DEV_PXM;
					break;
				}
				status = acpi_get_parent(handle, &handle);
			} while (ACPI_SUCCESS(status));
		}
#endif /* CONFIG_ACPI */

		r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, &add);
		if (r != -ENOSYS)
			return r;
		pci_seg_supported = false;
	}

	if (pci_domain_nr(pci_dev->bus))
		r = -ENOSYS;
#ifdef CONFIG_PCI_IOV
	else if (pci_dev->is_virtfn) {
		struct physdev_manage_pci_ext manage_pci_ext = {
			.bus		= pci_dev->bus->number,
			.devfn		= pci_dev->devfn,
			.is_virtfn 	= 1,
			.physfn.bus	= physfn->bus->number,
			.physfn.devfn	= physfn->devfn,
		};

		r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
			&manage_pci_ext);
	}
#endif
	else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
		struct physdev_manage_pci_ext manage_pci_ext = {
			.bus		= pci_dev->bus->number,
			.devfn		= pci_dev->devfn,
			.is_extfn	= 1,
		};

		r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
			&manage_pci_ext);
	} else {
		struct physdev_manage_pci manage_pci = {
			.bus	= pci_dev->bus->number,
			.devfn	= pci_dev->devfn,
		};

		r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add,
			&manage_pci);
	}

	return r;
}

static int xen_remove_device(struct device *dev)
{
	int r;
	struct pci_dev *pci_dev = to_pci_dev(dev);

	if (pci_seg_supported) {
		struct physdev_pci_device device = {
			.seg = pci_domain_nr(pci_dev->bus),
			.bus = pci_dev->bus->number,
			.devfn = pci_dev->devfn
		};

		r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove,
					  &device);
	} else if (pci_domain_nr(pci_dev->bus))
		r = -ENOSYS;
	else {
		struct physdev_manage_pci manage_pci = {
			.bus = pci_dev->bus->number,
			.devfn = pci_dev->devfn
		};

		r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
					  &manage_pci);
	}

	return r;
}

static int xen_pci_notifier(struct notifier_block *nb,
			    unsigned long action, void *data)
{
	struct device *dev = data;
	int r = 0;

	switch (action) {
	case BUS_NOTIFY_ADD_DEVICE:
		r = xen_add_device(dev);
		break;
	case BUS_NOTIFY_DEL_DEVICE:
		r = xen_remove_device(dev);
		break;
	default:
		return NOTIFY_DONE;
	}
	if (r)
		dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail!\n",
			action == BUS_NOTIFY_ADD_DEVICE ? "add" :
			(action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?"));
	return NOTIFY_OK;
}

static struct notifier_block device_nb = {
	.notifier_call = xen_pci_notifier,
};

static int __init register_xen_pci_notifier(void)
{
	if (!xen_initial_domain())
		return 0;

	return bus_register_notifier(&pci_bus_type, &device_nb);
}

arch_initcall(register_xen_pci_notifier);