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;
}
Exemple #2
0
void get_hp_hw_control_from_firmware(struct pci_dev *dev)
{
	/*
	 * OSHP is an optional ACPI firmware control method. If present,
	 * we need to run it to inform BIOS that we will control SHPC
	 * hardware from now on.
	 */
	acpi_handle handle = DEVICE_ACPI_HANDLE(&(dev->dev));
	if (!handle)
		return;
	acpi_run_oshp(handle);
}
Exemple #3
0
static int acpi_add_slot_to_php_slots(
	struct acpi_bridge	*ab,
	int				bus_num,
	acpi_handle		handle,
	u32				adr,
	u32				sun
	)
{
	struct acpi_php_slot	*aps;
	static long	samesun = -1;

	aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);
	if (!aps) {
		err ("acpi_shpchprm: alloc for aps fail\n");
		return -1;
	}
	memset(aps, 0, sizeof(struct acpi_php_slot));

	aps->handle = handle;
	aps->bus = bus_num;
	aps->dev = (adr >> 16) & 0xffff;
	aps->fun = adr & 0xffff;
	aps->sun = sun;

	aps->next = ab->slots;	/* cling to the bridge */
	aps->bridge = ab;
	ab->slots = aps;

	ab->scanned += 1;
	if (!ab->_hpp)
		acpi_get__hpp(ab);

	acpi_run_oshp(ab);

	if (sun != samesun) {
		info("acpi_shpchprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", aps->sun, ab->seg, 
			aps->bus, aps->dev, aps->fun);
		samesun = sun;
	}
	return 0;
}
Exemple #4
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;
}