forked from Minki/linux
d73236383e
This is required for SSIF to work.
There was no way to know if the interface being added was SI
or SSIF from the platform data, but that was required so the
i2c-addr is only added for SSIF interfaces. So add a field
for that.
Also rework the logic a bit so that ipmi-type is not set
for SSIF interfaces, as it is not necessary for that.
Fixes: 3cd83bac48
("ipmi: Consolidate the adding of platform devices")
Reported-by: Kamlakant Patel <kamlakantp@marvell.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: stable@vger.kernel.org # 5.1
125 lines
2.7 KiB
C
125 lines
2.7 KiB
C
// 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 = 0, 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->iftype == IPMI_PLAT_IF_SI) {
|
|
if (p->type == SI_BT)
|
|
size = 3;
|
|
else if (p->type != SI_TYPE_INVALID)
|
|
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);
|
|
} else if (p->iftype == IPMI_PLAT_IF_SSIF) {
|
|
pr[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", p->addr);
|
|
}
|
|
|
|
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);
|