Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e368fa0 authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by Len Brown
Browse files

ipmi: add PNP discovery (ACPI namespace via PNPACPI)



This allows ipmi_si_intf.c to claim IPMI devices described in the ACPI
namespace.  Using PNP makes it simpler to parse the IRQ/IO/memory resources
of the device.

We look at any SPMI tables before looking for devices in the namespace.

This is based on ipmi_pci_probe().

Signed-off-by: default avatarBjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: default avatarMyron Stowe <myron.stowe@hp.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 18a3e0bf
Loading
Loading
Loading
Loading
+104 −0
Original line number Original line Diff line number Diff line
@@ -64,6 +64,7 @@
#include <linux/dmi.h>
#include <linux/dmi.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/ctype.h>
#include <linux/pnp.h>


#ifdef CONFIG_PPC_OF
#ifdef CONFIG_PPC_OF
#include <linux/of_device.h>
#include <linux/of_device.h>
@@ -2023,6 +2024,103 @@ static __devinit void spmi_find_bmc(void)
		try_init_spmi(spmi);
		try_init_spmi(spmi);
	}
	}
}
}

static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
				    const struct pnp_device_id *dev_id)
{
	struct acpi_device *acpi_dev;
	struct smi_info *info;
	acpi_handle handle;
	acpi_status status;
	unsigned long long tmp;

	acpi_dev = pnp_acpi_device(dev);
	if (!acpi_dev)
		return -ENODEV;

	info = kzalloc(sizeof(*info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	info->addr_source = "ACPI";

	handle = acpi_dev->handle;

	/* _IFT tells us the interface type: KCS, BT, etc */
	status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
	if (ACPI_FAILURE(status))
		goto err_free;

	switch (tmp) {
	case 1:
		info->si_type = SI_KCS;
		break;
	case 2:
		info->si_type = SI_SMIC;
		break;
	case 3:
		info->si_type = SI_BT;
		break;
	default:
		dev_info(&dev->dev, "unknown interface type %lld\n", tmp);
		goto err_free;
	}

	if (pnp_port_valid(dev, 0)) {
		info->io_setup = port_setup;
		info->io.addr_type = IPMI_IO_ADDR_SPACE;
		info->io.addr_data = pnp_port_start(dev, 0);
	} else if (pnp_mem_valid(dev, 0)) {
		info->io_setup = mem_setup;
		info->io.addr_type = IPMI_MEM_ADDR_SPACE;
		info->io.addr_data = pnp_mem_start(dev, 0);
	} else {
		dev_err(&dev->dev, "no I/O or memory address\n");
		goto err_free;
	}

	info->io.regspacing = DEFAULT_REGSPACING;
	info->io.regsize = DEFAULT_REGSPACING;
	info->io.regshift = 0;

	/* If _GPE exists, use it; otherwise use standard interrupts */
	status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
	if (ACPI_SUCCESS(status)) {
		info->irq = tmp;
		info->irq_setup = acpi_gpe_irq_setup;
	} else if (pnp_irq_valid(dev, 0)) {
		info->irq = pnp_irq(dev, 0);
		info->irq_setup = std_irq_setup;
	}

	info->dev = &acpi_dev->dev;
	pnp_set_drvdata(dev, info);

	return try_smi_init(info);

err_free:
	kfree(info);
	return -EINVAL;
}

static void __devexit ipmi_pnp_remove(struct pnp_dev *dev)
{
	struct smi_info *info = pnp_get_drvdata(dev);

	cleanup_one_si(info);
}

static const struct pnp_device_id pnp_dev_table[] = {
	{"IPI0001", 0},
	{"", 0},
};

static struct pnp_driver ipmi_pnp_driver = {
	.name		= DEVICE_NAME,
	.probe		= ipmi_pnp_probe,
	.remove		= __devexit_p(ipmi_pnp_remove),
	.id_table	= pnp_dev_table,
};
#endif
#endif


#ifdef CONFIG_DMI
#ifdef CONFIG_DMI
@@ -3106,6 +3204,9 @@ static __devinit int init_ipmi_si(void)
#ifdef CONFIG_ACPI
#ifdef CONFIG_ACPI
	spmi_find_bmc();
	spmi_find_bmc();
#endif
#endif
#ifdef CONFIG_PNP
	pnp_register_driver(&ipmi_pnp_driver);
#endif


#ifdef CONFIG_PCI
#ifdef CONFIG_PCI
	rv = pci_register_driver(&ipmi_pci_driver);
	rv = pci_register_driver(&ipmi_pci_driver);
@@ -3229,6 +3330,9 @@ static __exit void cleanup_ipmi_si(void)
#ifdef CONFIG_PCI
#ifdef CONFIG_PCI
	pci_unregister_driver(&ipmi_pci_driver);
	pci_unregister_driver(&ipmi_pci_driver);
#endif
#endif
#ifdef CONFIG_PNP
	pnp_unregister_driver(&ipmi_pnp_driver);
#endif


#ifdef CONFIG_PPC_OF
#ifdef CONFIG_PPC_OF
	of_unregister_platform_driver(&ipmi_of_platform_driver);
	of_unregister_platform_driver(&ipmi_of_platform_driver);