summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/ipmi/kcs_bmc.c23
-rw-r--r--drivers/char/ipmi/kcs_bmc.h27
-rw-r--r--drivers/char/ipmi/kcs_bmc_aspeed.c17
-rw-r--r--drivers/char/ipmi/kcs_bmc_cdev_ipmi.c39
-rw-r--r--drivers/char/ipmi/kcs_bmc_client.h27
-rw-r--r--drivers/char/ipmi/kcs_bmc_device.h19
-rw-r--r--drivers/char/ipmi/kcs_bmc_npcm7xx.c17
7 files changed, 117 insertions, 52 deletions
diff --git a/drivers/char/ipmi/kcs_bmc.c b/drivers/char/ipmi/kcs_bmc.c
index 07bb6747f29a..c347cf6f9337 100644
--- a/drivers/char/ipmi/kcs_bmc.c
+++ b/drivers/char/ipmi/kcs_bmc.c
@@ -1,46 +1,52 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015-2018, Intel Corporation.
+ * Copyright (c) 2021, IBM Corp.
*/
#include <linux/module.h>
#include "kcs_bmc.h"
+/* Implement both the device and client interfaces here */
+#include "kcs_bmc_device.h"
+#include "kcs_bmc_client.h"
+
+/* Consumer data access */
+
u8 kcs_bmc_read_data(struct kcs_bmc *kcs_bmc)
{
- return kcs_bmc->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
+ return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
}
EXPORT_SYMBOL(kcs_bmc_read_data);
void kcs_bmc_write_data(struct kcs_bmc *kcs_bmc, u8 data)
{
- kcs_bmc->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
+ kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
}
EXPORT_SYMBOL(kcs_bmc_write_data);
u8 kcs_bmc_read_status(struct kcs_bmc *kcs_bmc)
{
- return kcs_bmc->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
+ return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
}
EXPORT_SYMBOL(kcs_bmc_read_status);
void kcs_bmc_write_status(struct kcs_bmc *kcs_bmc, u8 data)
{
- kcs_bmc->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
+ kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
}
EXPORT_SYMBOL(kcs_bmc_write_status);
void kcs_bmc_update_status(struct kcs_bmc *kcs_bmc, u8 mask, u8 val)
{
- kcs_bmc->io_updateb(kcs_bmc, kcs_bmc->ioreg.str, mask, val);
+ kcs_bmc->ops->io_updateb(kcs_bmc, kcs_bmc->ioreg.str, mask, val);
}
EXPORT_SYMBOL(kcs_bmc_update_status);
-int kcs_bmc_ipmi_event(struct kcs_bmc *kcs_bmc);
-int kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc)
+irqreturn_t kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc)
{
- return kcs_bmc_ipmi_event(kcs_bmc);
+ return kcs_bmc->client.ops->event(&kcs_bmc->client);
}
EXPORT_SYMBOL(kcs_bmc_handle_event);
@@ -62,4 +68,5 @@ EXPORT_SYMBOL(kcs_bmc_remove_device);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");
diff --git a/drivers/char/ipmi/kcs_bmc.h b/drivers/char/ipmi/kcs_bmc.h
index f3ed89e7da98..f42843d240ed 100644
--- a/drivers/char/ipmi/kcs_bmc.h
+++ b/drivers/char/ipmi/kcs_bmc.h
@@ -8,6 +8,12 @@
#include <linux/miscdevice.h>
+#include "kcs_bmc_client.h"
+
+#define KCS_BMC_STR_OBF BIT(0)
+#define KCS_BMC_STR_IBF BIT(1)
+#define KCS_BMC_STR_CMD_DAT BIT(3)
+
/* Different phases of the KCS BMC module.
* KCS_PHASE_IDLE:
* BMC should not be expecting nor sending any data.
@@ -66,19 +72,21 @@ struct kcs_ioreg {
u32 str;
};
+struct kcs_bmc_device_ops;
+
struct kcs_bmc {
struct device *dev;
+ const struct kcs_bmc_device_ops *ops;
+
+ struct kcs_bmc_client client;
+
spinlock_t lock;
u32 channel;
int running;
- /* Setup by BMC KCS controller driver */
struct kcs_ioreg ioreg;
- u8 (*io_inputb)(struct kcs_bmc *kcs_bmc, u32 reg);
- void (*io_outputb)(struct kcs_bmc *kcs_bmc, u32 reg, u8 b);
- void (*io_updateb)(struct kcs_bmc *kcs_bmc, u32 reg, u8 mask, u8 val);
enum kcs_phases phase;
enum kcs_errors error;
@@ -97,15 +105,4 @@ struct kcs_bmc {
struct miscdevice miscdev;
};
-
-int kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc);
-int kcs_bmc_add_device(struct kcs_bmc *kcs_bmc);
-void kcs_bmc_remove_device(struct kcs_bmc *kcs_bmc);
-
-u8 kcs_bmc_read_data(struct kcs_bmc *kcs_bmc);
-void kcs_bmc_write_data(struct kcs_bmc *kcs_bmc, u8 data);
-u8 kcs_bmc_read_status(struct kcs_bmc *kcs_bmc);
-void kcs_bmc_write_status(struct kcs_bmc *kcs_bmc, u8 data);
-void kcs_bmc_update_status(struct kcs_bmc *kcs_bmc, u8 mask, u8 val);
-
#endif /* __KCS_BMC_H__ */
diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
index b07cbc423dd5..fdfba745302a 100644
--- a/drivers/char/ipmi/kcs_bmc_aspeed.c
+++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
@@ -21,7 +21,7 @@
#include <linux/slab.h>
#include <linux/timer.h>
-#include "kcs_bmc.h"
+#include "kcs_bmc_device.h"
#define DEVICE_NAME "ast-kcs-bmc"
@@ -220,14 +220,17 @@ static void aspeed_kcs_enable_channel(struct kcs_bmc *kcs_bmc, bool enable)
}
}
+static const struct kcs_bmc_device_ops aspeed_kcs_ops = {
+ .io_inputb = aspeed_kcs_inb,
+ .io_outputb = aspeed_kcs_outb,
+ .io_updateb = aspeed_kcs_updateb,
+};
+
static irqreturn_t aspeed_kcs_irq(int irq, void *arg)
{
struct kcs_bmc *kcs_bmc = arg;
- if (!kcs_bmc_handle_event(kcs_bmc))
- return IRQ_HANDLED;
-
- return IRQ_NONE;
+ return kcs_bmc_handle_event(kcs_bmc);
}
static int aspeed_kcs_config_irq(struct kcs_bmc *kcs_bmc,
@@ -364,9 +367,7 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
kcs_bmc->dev = &pdev->dev;
kcs_bmc->channel = channel;
kcs_bmc->ioreg = ast_kcs_bmc_ioregs[channel - 1];
- kcs_bmc->io_inputb = aspeed_kcs_inb;
- kcs_bmc->io_outputb = aspeed_kcs_outb;
- kcs_bmc->io_updateb = aspeed_kcs_updateb;
+ kcs_bmc->ops = &aspeed_kcs_ops;
priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
if (IS_ERR(priv->map)) {
diff --git a/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c b/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
index 5060643bf530..476ad6d541d5 100644
--- a/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
+++ b/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
@@ -22,7 +22,6 @@
#define KCS_ZERO_DATA 0
-
/* IPMI 2.0 - Table 9-1, KCS Interface Status Register Bits */
#define KCS_STATUS_STATE(state) (state << 6)
#define KCS_STATUS_STATE_MASK GENMASK(7, 6)
@@ -179,12 +178,19 @@ static void kcs_bmc_ipmi_handle_cmd(struct kcs_bmc *kcs_bmc)
}
}
-int kcs_bmc_ipmi_event(struct kcs_bmc *kcs_bmc);
-int kcs_bmc_ipmi_event(struct kcs_bmc *kcs_bmc)
+static inline struct kcs_bmc *client_to_kcs_bmc(struct kcs_bmc_client *client)
+{
+ return container_of(client, struct kcs_bmc, client);
+}
+
+static irqreturn_t kcs_bmc_ipmi_event(struct kcs_bmc_client *client)
{
+ struct kcs_bmc *kcs_bmc;
unsigned long flags;
- int ret = -ENODATA;
u8 status;
+ int ret;
+
+ kcs_bmc = client_to_kcs_bmc(client);
spin_lock_irqsave(&kcs_bmc->lock, flags);
@@ -197,23 +203,28 @@ int kcs_bmc_ipmi_event(struct kcs_bmc *kcs_bmc)
else
kcs_bmc_ipmi_handle_data(kcs_bmc);
- ret = 0;
+ ret = IRQ_HANDLED;
+ } else {
+ ret = IRQ_NONE;
}
spin_unlock_irqrestore(&kcs_bmc->lock, flags);
return ret;
}
-EXPORT_SYMBOL(kcs_bmc_ipmi_event);
-static inline struct kcs_bmc *to_kcs_bmc(struct file *filp)
+static const struct kcs_bmc_client_ops kcs_bmc_ipmi_client_ops = {
+ .event = kcs_bmc_ipmi_event,
+};
+
+static inline struct kcs_bmc *file_to_kcs_bmc(struct file *filp)
{
return container_of(filp->private_data, struct kcs_bmc, miscdev);
}
static int kcs_bmc_ipmi_open(struct inode *inode, struct file *filp)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
+ struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
int ret = 0;
spin_lock_irq(&kcs_bmc->lock);
@@ -228,7 +239,7 @@ static int kcs_bmc_ipmi_open(struct inode *inode, struct file *filp)
static __poll_t kcs_bmc_ipmi_poll(struct file *filp, poll_table *wait)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
+ struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
__poll_t mask = 0;
poll_wait(filp, &kcs_bmc->queue, wait);
@@ -244,7 +255,7 @@ static __poll_t kcs_bmc_ipmi_poll(struct file *filp, poll_table *wait)
static ssize_t kcs_bmc_ipmi_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
+ struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
bool data_avail;
size_t data_len;
ssize_t ret;
@@ -306,7 +317,7 @@ out_unlock:
static ssize_t kcs_bmc_ipmi_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
+ struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
ssize_t ret;
/* a minimum response size '3' : netfn + cmd + ccode */
@@ -342,7 +353,7 @@ out_unlock:
static long kcs_bmc_ipmi_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
+ struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
long ret = 0;
spin_lock_irq(&kcs_bmc->lock);
@@ -372,7 +383,7 @@ static long kcs_bmc_ipmi_ioctl(struct file *filp, unsigned int cmd,
static int kcs_bmc_ipmi_release(struct inode *inode, struct file *filp)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
+ struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
spin_lock_irq(&kcs_bmc->lock);
kcs_bmc->running = 0;
@@ -401,6 +412,8 @@ int kcs_bmc_ipmi_add_device(struct kcs_bmc *kcs_bmc)
mutex_init(&kcs_bmc->mutex);
init_waitqueue_head(&kcs_bmc->queue);
+ kcs_bmc->client.dev = kcs_bmc;
+ kcs_bmc->client.ops = &kcs_bmc_ipmi_client_ops;
kcs_bmc->data_in = devm_kmalloc(kcs_bmc->dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
kcs_bmc->data_out = devm_kmalloc(kcs_bmc->dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
kcs_bmc->kbuffer = devm_kmalloc(kcs_bmc->dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
diff --git a/drivers/char/ipmi/kcs_bmc_client.h b/drivers/char/ipmi/kcs_bmc_client.h
new file mode 100644
index 000000000000..dad8774aebce
--- /dev/null
+++ b/drivers/char/ipmi/kcs_bmc_client.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2021, IBM Corp. */
+
+#ifndef __KCS_BMC_CONSUMER_H__
+#define __KCS_BMC_CONSUMER_H__
+
+#include <linux/irqreturn.h>
+
+struct kcs_bmc;
+struct kcs_bmc_client_ops;
+
+struct kcs_bmc_client {
+ const struct kcs_bmc_client_ops *ops;
+
+ struct kcs_bmc *dev;
+};
+
+struct kcs_bmc_client_ops {
+ irqreturn_t (*event)(struct kcs_bmc_client *client);
+};
+
+u8 kcs_bmc_read_data(struct kcs_bmc *kcs_bmc);
+void kcs_bmc_write_data(struct kcs_bmc *kcs_bmc, u8 data);
+u8 kcs_bmc_read_status(struct kcs_bmc *kcs_bmc);
+void kcs_bmc_write_status(struct kcs_bmc *kcs_bmc, u8 data);
+void kcs_bmc_update_status(struct kcs_bmc *kcs_bmc, u8 mask, u8 val);
+#endif
diff --git a/drivers/char/ipmi/kcs_bmc_device.h b/drivers/char/ipmi/kcs_bmc_device.h
new file mode 100644
index 000000000000..dd8bf1307ad2
--- /dev/null
+++ b/drivers/char/ipmi/kcs_bmc_device.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2021, IBM Corp. */
+
+#ifndef __KCS_BMC_DEVICE_H__
+#define __KCS_BMC_DEVICE_H__
+
+#include "kcs_bmc.h"
+
+struct kcs_bmc_device_ops {
+ u8 (*io_inputb)(struct kcs_bmc *kcs_bmc, u32 reg);
+ void (*io_outputb)(struct kcs_bmc *kcs_bmc, u32 reg, u8 b);
+ void (*io_updateb)(struct kcs_bmc *kcs_bmc, u32 reg, u8 mask, u8 b);
+};
+
+irqreturn_t kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc);
+int kcs_bmc_add_device(struct kcs_bmc *kcs_bmc);
+void kcs_bmc_remove_device(struct kcs_bmc *kcs_bmc);
+
+#endif
diff --git a/drivers/char/ipmi/kcs_bmc_npcm7xx.c b/drivers/char/ipmi/kcs_bmc_npcm7xx.c
index e06250285113..ebb691af28c5 100644
--- a/drivers/char/ipmi/kcs_bmc_npcm7xx.c
+++ b/drivers/char/ipmi/kcs_bmc_npcm7xx.c
@@ -17,7 +17,7 @@
#include <linux/regmap.h>
#include <linux/slab.h>
-#include "kcs_bmc.h"
+#include "kcs_bmc_device.h"
#define DEVICE_NAME "npcm-kcs-bmc"
#define KCS_CHANNEL_MAX 3
@@ -128,10 +128,7 @@ static irqreturn_t npcm7xx_kcs_irq(int irq, void *arg)
{
struct kcs_bmc *kcs_bmc = arg;
- if (!kcs_bmc_handle_event(kcs_bmc))
- return IRQ_HANDLED;
-
- return IRQ_NONE;
+ return kcs_bmc_handle_event(kcs_bmc);
}
static int npcm7xx_kcs_config_irq(struct kcs_bmc *kcs_bmc,
@@ -148,6 +145,12 @@ static int npcm7xx_kcs_config_irq(struct kcs_bmc *kcs_bmc,
dev_name(dev), kcs_bmc);
}
+static const struct kcs_bmc_device_ops npcm7xx_kcs_ops = {
+ .io_inputb = npcm7xx_kcs_inb,
+ .io_outputb = npcm7xx_kcs_outb,
+ .io_updateb = npcm7xx_kcs_updateb,
+};
+
static int npcm7xx_kcs_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -179,9 +182,7 @@ static int npcm7xx_kcs_probe(struct platform_device *pdev)
kcs_bmc->ioreg.idr = priv->reg->dib;
kcs_bmc->ioreg.odr = priv->reg->dob;
kcs_bmc->ioreg.str = priv->reg->sts;
- kcs_bmc->io_inputb = npcm7xx_kcs_inb;
- kcs_bmc->io_outputb = npcm7xx_kcs_outb;
- kcs_bmc->io_updateb = npcm7xx_kcs_updateb;
+ kcs_bmc->ops = &npcm7xx_kcs_ops;
platform_set_drvdata(pdev, priv);