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

Commit 3cd83bac authored by Corey Minyard's avatar Corey Minyard
Browse files

ipmi: Consolidate the adding of platform devices



It was being done in two different places now that hard-coded devices
use platform devices, and it's about to be three with hotmod switching
to platform devices.  So put the code in one place.

This required some rework on some interfaces to make the type space
clean.

Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
parent f6296bdc
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -18,6 +18,10 @@ menuconfig IPMI_HANDLER
	 If unsure, say N.

config IPMI_DMI_DECODE
       select IPMI_PLAT_DATA
       bool

config IPMI_PLAT_DATA
       bool

if IPMI_HANDLER
@@ -56,6 +60,7 @@ config IPMI_DEVICE_INTERFACE

config IPMI_SI
       tristate 'IPMI System Interface handler'
       select IPMI_PLAT_DATA
       help
         Provides a driver for System Interfaces (KCS, SMIC, BT).
	 Currently, only KCS and SMIC are supported.  If
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
obj-$(CONFIG_IPMI_SI) += ipmi_si.o
obj-$(CONFIG_IPMI_DMI_DECODE) += ipmi_dmi.o
obj-$(CONFIG_IPMI_PLAT_DATA) += ipmi_plat_data.o
obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o
obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o
obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
+33 −106
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/property.h>
#include "ipmi_si_sm.h"
#include "ipmi_dmi.h"
#include "ipmi_plat_data.h"

#define IPMI_DMI_TYPE_KCS	0x01
#define IPMI_DMI_TYPE_SMIC	0x02
@@ -22,7 +23,7 @@

struct ipmi_dmi_info {
	enum si_type si_type;
	u32 flags;
	unsigned int space; /* addr space for si, intf# for ssif */
	unsigned long addr;
	u8 slave_addr;
	struct ipmi_dmi_info *next;
@@ -33,133 +34,60 @@ static struct ipmi_dmi_info *ipmi_dmi_infos;
static int ipmi_dmi_nr __initdata;

static void __init dmi_add_platform_ipmi(unsigned long base_addr,
					 u32 flags,
					 unsigned int space,
					 u8 slave_addr,
					 int irq,
					 int offset,
					 int type)
{
	struct platform_device *pdev;
	struct resource r[4];
	unsigned int num_r = 1, size;
	struct property_entry p[5];
	unsigned int pidx = 0;
	char *name;
	int rv;
	enum si_type si_type;
	const char *name;
	struct ipmi_dmi_info *info;
	struct ipmi_plat_data p;

	memset(p, 0, sizeof(p));
	memset(&p, 0, sizeof(p));

	name = "dmi-ipmi-si";
	switch (type) {
	case IPMI_DMI_TYPE_SSIF:
		name = "dmi-ipmi-ssif";
		offset = 1;
		size = 1;
		si_type = SI_TYPE_INVALID;
		p.type = SI_TYPE_INVALID;
		break;
	case IPMI_DMI_TYPE_BT:
		size = 3;
		si_type = SI_BT;
		p.type = SI_BT;
		break;
	case IPMI_DMI_TYPE_KCS:
		size = 2;
		si_type = SI_KCS;
		p.type = SI_KCS;
		break;
	case IPMI_DMI_TYPE_SMIC:
		size = 2;
		si_type = SI_SMIC;
		p.type = SI_SMIC;
		break;
	default:
		pr_err("Invalid IPMI type: %d\n", type);
		return;
	}

	if (si_type != SI_TYPE_INVALID)
		p[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", si_type);

	p[pidx++] = PROPERTY_ENTRY_U8("slave-addr", slave_addr);
	p[pidx++] = PROPERTY_ENTRY_U8("addr-source", SI_SMBIOS);
	memset(&p, 0, sizeof(p));
	p.addr = base_addr;
	p.space = space;
	p.regspacing = offset;
	p.irq = irq;
	p.slave_addr = slave_addr;
	p.addr_source = SI_SMBIOS;

	info = kmalloc(sizeof(*info), GFP_KERNEL);
	if (!info) {
		pr_warn("Could not allocate dmi info\n");
	} else {
		info->si_type = si_type;
		info->flags = flags;
		info->si_type = p.type;
		info->space = space;
		info->addr = base_addr;
		info->slave_addr = slave_addr;
		info->next = ipmi_dmi_infos;
		ipmi_dmi_infos = info;
	}

	pdev = platform_device_alloc(name, ipmi_dmi_nr);
	if (!pdev) {
		pr_err("Error allocation IPMI platform device\n");
		return;
	}

	if (type == IPMI_DMI_TYPE_SSIF) {
		p[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", base_addr);
		goto add_properties;
	}

	memset(r, 0, sizeof(r));

	r[0].start = base_addr;
	r[0].end = r[0].start + offset - 1;
	r[0].name = "IPMI Address 1";
	r[0].flags = flags;

	if (size > 1) {
		r[1].start = r[0].start + offset;
		r[1].end = r[1].start + offset - 1;
		r[1].name = "IPMI Address 2";
		r[1].flags = flags;
		num_r++;
	}

	if (size > 2) {
		r[2].start = r[1].start + offset;
		r[2].end = r[2].start + offset - 1;
		r[2].name = "IPMI Address 3";
		r[2].flags = flags;
		num_r++;
	}

	if (irq) {
		r[num_r].start = irq;
		r[num_r].end = irq;
		r[num_r].name = "IPMI IRQ";
		r[num_r].flags = IORESOURCE_IRQ;
		num_r++;
	}

	rv = platform_device_add_resources(pdev, r, num_r);
	if (rv) {
		dev_err(&pdev->dev, "Unable to add resources: %d\n", rv);
		goto err;
	}

add_properties:
	rv = platform_device_add_properties(pdev, p);
	if (rv) {
		dev_err(&pdev->dev, "Unable to add properties: %d\n", rv);
		goto err;
	}

	rv = platform_device_add(pdev);
	if (rv) {
		dev_err(&pdev->dev, "Unable to add device: %d\n", rv);
		goto err;
	}

	if (ipmi_platform_add(name, ipmi_dmi_nr, &p))
		ipmi_dmi_nr++;
	return;

err:
	platform_device_put(pdev);
}

/*
@@ -169,14 +97,14 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
 * This function allows an ACPI-specified IPMI device to look up the
 * slave address from the DMI table.
 */
int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags,
int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space,
			    unsigned long base_addr)
{
	struct ipmi_dmi_info *info = ipmi_dmi_infos;

	while (info) {
		if (info->si_type == si_type &&
		    info->flags == flags &&
		    info->space == space &&
		    info->addr == base_addr)
			return info->slave_addr;
		info = info->next;
@@ -198,11 +126,11 @@ EXPORT_SYMBOL(ipmi_dmi_get_slave_addr);
static void __init dmi_decode_ipmi(const struct dmi_header *dm)
{
	const u8 *data = (const u8 *) dm;
	u32             flags = IORESOURCE_IO;
	int space = IPMI_IO_ADDR_SPACE;
	unsigned long base_addr;
	u8 len = dm->length;
	u8 slave_addr;
	int             irq = 0, offset;
	int irq = 0, offset = 0;
	int type;

	if (len < DMI_IPMI_MIN_LENGTH)
@@ -218,8 +146,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
	}
	if (len >= DMI_IPMI_VER2_LENGTH) {
		if (type == IPMI_DMI_TYPE_SSIF) {
			offset = 0;
			flags = 0;
			space = 0; /* Match I2C interface 0. */
			base_addr = data[DMI_IPMI_ADDR] >> 1;
			if (base_addr == 0) {
				/*
@@ -236,7 +163,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
				base_addr &= DMI_IPMI_IO_MASK;
			} else {
				/* Memory */
				flags = IORESOURCE_MEM;
				space = IPMI_MEM_ADDR_SPACE;
			}

			/*
@@ -280,7 +207,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
		offset = 1;
	}

	dmi_add_platform_ipmi(base_addr, flags, slave_addr, irq,
	dmi_add_platform_ipmi(base_addr, space, slave_addr, irq,
			      offset, type);
}

+1 −1
Original line number Diff line number Diff line
@@ -4,6 +4,6 @@
 */

#ifdef CONFIG_IPMI_DMI_DECODE
int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags,
int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space,
			    unsigned long base_addr);
#endif
+121 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0+

/*
 * Add an IPMI platform device.
 */

#include <linux/platform_device.h>
#include "ipmi_plat_data.h"
#include "ipmi_si.h"

struct platform_device *ipmi_platform_add(const char *name, unsigned int inst,
					  struct ipmi_plat_data *p)
{
	struct platform_device *pdev;
	unsigned int num_r = 1, size, pidx = 0;
	struct resource r[4];
	struct property_entry pr[6];
	u32 flags;
	int rv;

	memset(pr, 0, sizeof(pr));
	memset(r, 0, sizeof(r));

	if (p->type == SI_BT)
		size = 3;
	else if (p->type == SI_TYPE_INVALID)
		size = 0;
	else
		size = 2;

	if (p->regsize == 0)
		p->regsize = DEFAULT_REGSIZE;
	if (p->regspacing == 0)
		p->regspacing = p->regsize;

	pr[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", p->type);
	if (p->slave_addr)
		pr[pidx++] = PROPERTY_ENTRY_U8("slave-addr", p->slave_addr);
	pr[pidx++] = PROPERTY_ENTRY_U8("addr-source", p->addr_source);
	if (p->regshift)
		pr[pidx++] = PROPERTY_ENTRY_U8("reg-shift", p->regshift);
	pr[pidx++] = PROPERTY_ENTRY_U8("reg-size", p->regsize);
	/* Last entry must be left NULL to terminate it. */

	pdev = platform_device_alloc(name, inst);
	if (!pdev) {
		pr_err("Error allocating IPMI platform device %s.%d\n",
		       name, inst);
		return NULL;
	}

	if (size == 0)
		/* An invalid or SSIF interface, no resources. */
		goto add_properties;

	/*
	 * Register spacing is derived from the resources in
	 * the IPMI platform code.
	 */

	if (p->space == IPMI_IO_ADDR_SPACE)
		flags = IORESOURCE_IO;
	else
		flags = IORESOURCE_MEM;

	r[0].start = p->addr;
	r[0].end = r[0].start + p->regsize - 1;
	r[0].name = "IPMI Address 1";
	r[0].flags = flags;

	if (size > 1) {
		r[1].start = r[0].start + p->regspacing;
		r[1].end = r[1].start + p->regsize - 1;
		r[1].name = "IPMI Address 2";
		r[1].flags = flags;
		num_r++;
	}

	if (size > 2) {
		r[2].start = r[1].start + p->regspacing;
		r[2].end = r[2].start + p->regsize - 1;
		r[2].name = "IPMI Address 3";
		r[2].flags = flags;
		num_r++;
	}

	if (p->irq) {
		r[num_r].start = p->irq;
		r[num_r].end = p->irq;
		r[num_r].name = "IPMI IRQ";
		r[num_r].flags = IORESOURCE_IRQ;
		num_r++;
	}

	rv = platform_device_add_resources(pdev, r, num_r);
	if (rv) {
		dev_err(&pdev->dev,
			"Unable to add hard-code resources: %d\n", rv);
		goto err;
	}
 add_properties:
	rv = platform_device_add_properties(pdev, pr);
	if (rv) {
		dev_err(&pdev->dev,
			"Unable to add hard-code properties: %d\n", rv);
		goto err;
	}

	rv = platform_device_add(pdev);
	if (rv) {
		dev_err(&pdev->dev,
			"Unable to add hard-code device: %d\n", rv);
		goto err;
	}
	return pdev;

err:
	platform_device_put(pdev);
	return NULL;
}
EXPORT_SYMBOL(ipmi_platform_add);
Loading