Commit d4e7ac68 authored by Andrew Jeffery's avatar Andrew Jeffery Committed by Corey Minyard
Browse files

ipmi: kcs_bmc: Strip private client data from struct kcs_bmc



Move all client-private data out of `struct kcs_bmc` into the KCS client
implementation.

With this change the KCS BMC core code now only concerns itself with
abstract `struct kcs_bmc` and `struct kcs_bmc_client` types, achieving
expected separation of concerns. Further, the change clears the path for
implementation of alternative userspace interfaces.

The chardev data-structures are rearranged in the same manner applied to
the KCS device driver data-structures in an earlier patch - `struct
kcs_bmc_client` is embedded in the client's private data and we exploit
container_of() to translate as required.

Finally, now that it is free of client data, `struct kcs_bmc` is renamed
to `struct kcs_bmc_device` to contrast `struct kcs_bmc_client`.

Signed-off-by: default avatarAndrew Jeffery <andrew@aj.id.au>
Reviewed-by: default avatarZev Weiss <zweiss@equinix.com>
Message-Id: <20210608104757.582199-8-andrew@aj.id.au>
Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
parent faae6e39
Loading
Loading
Loading
Loading
+59 −11
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 * Copyright (c) 2021, IBM Corp.
 */

#include <linux/device.h>
#include <linux/module.h>

#include "kcs_bmc.h"
@@ -14,51 +15,98 @@

/* Consumer data access */

u8 kcs_bmc_read_data(struct kcs_bmc *kcs_bmc)
u8 kcs_bmc_read_data(struct kcs_bmc_device *kcs_bmc)
{
	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)
void kcs_bmc_write_data(struct kcs_bmc_device *kcs_bmc, u8 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)
u8 kcs_bmc_read_status(struct kcs_bmc_device *kcs_bmc)
{
	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)
void kcs_bmc_write_status(struct kcs_bmc_device *kcs_bmc, u8 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)
void kcs_bmc_update_status(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 val)
{
	kcs_bmc->ops->io_updateb(kcs_bmc, kcs_bmc->ioreg.str, mask, val);
}
EXPORT_SYMBOL(kcs_bmc_update_status);

irqreturn_t kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc)
irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc)
{
	return kcs_bmc->client.ops->event(&kcs_bmc->client);
	struct kcs_bmc_client *client;
	irqreturn_t rc;

	spin_lock(&kcs_bmc->lock);
	client = kcs_bmc->client;
	if (client) {
		rc = client->ops->event(client);
	} else {
		u8 status;

		status = kcs_bmc_read_status(kcs_bmc);
		if (status & KCS_BMC_STR_IBF) {
			/* Ack the event by reading the data */
			kcs_bmc_read_data(kcs_bmc);
			rc = IRQ_HANDLED;
		} else {
			rc = IRQ_NONE;
		}
	}
	spin_unlock(&kcs_bmc->lock);

	return rc;
}
EXPORT_SYMBOL(kcs_bmc_handle_event);

int kcs_bmc_ipmi_add_device(struct kcs_bmc *kcs_bmc);
int kcs_bmc_add_device(struct kcs_bmc *kcs_bmc)
int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
{
	int rc;

	spin_lock_irq(&kcs_bmc->lock);
	if (kcs_bmc->client) {
		rc = -EBUSY;
	} else {
		kcs_bmc->client = client;
		rc = 0;
	}
	spin_unlock_irq(&kcs_bmc->lock);

	return rc;
}
EXPORT_SYMBOL(kcs_bmc_enable_device);

void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
{
	spin_lock_irq(&kcs_bmc->lock);
	if (client == kcs_bmc->client)
		kcs_bmc->client = NULL;
	spin_unlock_irq(&kcs_bmc->lock);
}
EXPORT_SYMBOL(kcs_bmc_disable_device);

int kcs_bmc_ipmi_add_device(struct kcs_bmc_device *kcs_bmc);
int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc)
{
	return kcs_bmc_ipmi_add_device(kcs_bmc);
}
EXPORT_SYMBOL(kcs_bmc_add_device);

int kcs_bmc_ipmi_remove_device(struct kcs_bmc *kcs_bmc);
void kcs_bmc_remove_device(struct kcs_bmc *kcs_bmc)
int kcs_bmc_ipmi_remove_device(struct kcs_bmc_device *kcs_bmc);
void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc)
{
	if (kcs_bmc_ipmi_remove_device(kcs_bmc))
		pr_warn("Failed to remove device for KCS channel %d\n",
+9 −74
Original line number Diff line number Diff line
@@ -6,61 +6,12 @@
#ifndef __KCS_BMC_H__
#define __KCS_BMC_H__

#include <linux/miscdevice.h>

#include "kcs_bmc_client.h"
#include <linux/list.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.
 *  KCS_PHASE_WRITE_START:
 *            BMC is receiving a WRITE_START command from system software.
 *  KCS_PHASE_WRITE_DATA:
 *            BMC is receiving a data byte from system software.
 *  KCS_PHASE_WRITE_END_CMD:
 *            BMC is waiting a last data byte from system software.
 *  KCS_PHASE_WRITE_DONE:
 *            BMC has received the whole request from system software.
 *  KCS_PHASE_WAIT_READ:
 *            BMC is waiting the response from the upper IPMI service.
 *  KCS_PHASE_READ:
 *            BMC is transferring the response to system software.
 *  KCS_PHASE_ABORT_ERROR1:
 *            BMC is waiting error status request from system software.
 *  KCS_PHASE_ABORT_ERROR2:
 *            BMC is waiting for idle status afer error from system software.
 *  KCS_PHASE_ERROR:
 *            BMC has detected a protocol violation at the interface level.
 */
enum kcs_phases {
	KCS_PHASE_IDLE,

	KCS_PHASE_WRITE_START,
	KCS_PHASE_WRITE_DATA,
	KCS_PHASE_WRITE_END_CMD,
	KCS_PHASE_WRITE_DONE,

	KCS_PHASE_WAIT_READ,
	KCS_PHASE_READ,

	KCS_PHASE_ABORT_ERROR1,
	KCS_PHASE_ABORT_ERROR2,
	KCS_PHASE_ERROR
};

/* IPMI 2.0 - Table 9-4, KCS Interface Status Codes */
enum kcs_errors {
	KCS_NO_ERROR                = 0x00,
	KCS_ABORTED_BY_COMMAND      = 0x01,
	KCS_ILLEGAL_CONTROL_CODE    = 0x02,
	KCS_LENGTH_ERROR            = 0x06,
	KCS_UNSPECIFIED_ERROR       = 0xFF
};

/* IPMI 2.0 - 9.5, KCS Interface Registers
 * @idr: Input Data Register
 * @odr: Output Data Register
@@ -73,36 +24,20 @@ struct kcs_ioreg {
};

struct kcs_bmc_device_ops;
struct kcs_bmc_client;

struct kcs_bmc {
	struct device *dev;

	const struct kcs_bmc_device_ops *ops;

	struct kcs_bmc_client client;

	spinlock_t lock;
struct kcs_bmc_device {
	struct list_head entry;

	struct device *dev;
	u32 channel;
	int running;

	struct kcs_ioreg ioreg;

	enum kcs_phases phase;
	enum kcs_errors error;

	wait_queue_head_t queue;
	bool data_in_avail;
	int  data_in_idx;
	u8  *data_in;

	int  data_out_idx;
	int  data_out_len;
	u8  *data_out;

	struct mutex mutex;
	u8 *kbuffer;
	const struct kcs_bmc_device_ops *ops;

	struct miscdevice miscdev;
	spinlock_t lock;
	struct kcs_bmc_client *client;
};

#endif /* __KCS_BMC_H__ */
+11 −11
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@
#define LPC_STR4             0x11C

struct aspeed_kcs_bmc {
	struct kcs_bmc kcs_bmc;
	struct kcs_bmc_device kcs_bmc;

	struct regmap *map;
};
@@ -71,12 +71,12 @@ struct aspeed_kcs_of_ops {
	int (*get_io_address)(struct platform_device *pdev);
};

static inline struct aspeed_kcs_bmc *to_aspeed_kcs_bmc(struct kcs_bmc *kcs_bmc)
static inline struct aspeed_kcs_bmc *to_aspeed_kcs_bmc(struct kcs_bmc_device *kcs_bmc)
{
	return container_of(kcs_bmc, struct aspeed_kcs_bmc, kcs_bmc);
}

static u8 aspeed_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
static u8 aspeed_kcs_inb(struct kcs_bmc_device *kcs_bmc, u32 reg)
{
	struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
	u32 val = 0;
@@ -88,7 +88,7 @@ static u8 aspeed_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
	return rc == 0 ? (u8) val : 0;
}

static void aspeed_kcs_outb(struct kcs_bmc *kcs_bmc, u32 reg, u8 data)
static void aspeed_kcs_outb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 data)
{
	struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
	int rc;
@@ -97,7 +97,7 @@ static void aspeed_kcs_outb(struct kcs_bmc *kcs_bmc, u32 reg, u8 data)
	WARN(rc != 0, "regmap_write() failed: %d\n", rc);
}

static void aspeed_kcs_updateb(struct kcs_bmc *kcs_bmc, u32 reg, u8 mask, u8 val)
static void aspeed_kcs_updateb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 mask, u8 val)
{
	struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
	int rc;
@@ -119,7 +119,7 @@ static void aspeed_kcs_updateb(struct kcs_bmc *kcs_bmc, u32 reg, u8 mask, u8 val
 *     C. KCS4
 *        D / C : CA4h / CA5h
 */
static void aspeed_kcs_set_address(struct kcs_bmc *kcs_bmc, u16 addr)
static void aspeed_kcs_set_address(struct kcs_bmc_device *kcs_bmc, u16 addr)
{
	struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);

@@ -153,7 +153,7 @@ static void aspeed_kcs_set_address(struct kcs_bmc *kcs_bmc, u16 addr)
	}
}

static void aspeed_kcs_enable_channel(struct kcs_bmc *kcs_bmc, bool enable)
static void aspeed_kcs_enable_channel(struct kcs_bmc_device *kcs_bmc, bool enable)
{
	struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);

@@ -228,12 +228,12 @@ static const struct kcs_bmc_device_ops aspeed_kcs_ops = {

static irqreturn_t aspeed_kcs_irq(int irq, void *arg)
{
	struct kcs_bmc *kcs_bmc = arg;
	struct kcs_bmc_device *kcs_bmc = arg;

	return kcs_bmc_handle_event(kcs_bmc);
}

static int aspeed_kcs_config_irq(struct kcs_bmc *kcs_bmc,
static int aspeed_kcs_config_irq(struct kcs_bmc_device *kcs_bmc,
			struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
@@ -335,8 +335,8 @@ static int aspeed_kcs_of_v2_get_io_address(struct platform_device *pdev)
static int aspeed_kcs_probe(struct platform_device *pdev)
{
	const struct aspeed_kcs_of_ops *ops;
	struct kcs_bmc_device *kcs_bmc;
	struct aspeed_kcs_bmc *priv;
	struct kcs_bmc *kcs_bmc;
	struct device_node *np;
	int rc, channel, addr;

@@ -399,7 +399,7 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
static int aspeed_kcs_remove(struct platform_device *pdev)
{
	struct aspeed_kcs_bmc *priv = platform_get_drvdata(pdev);
	struct kcs_bmc *kcs_bmc = &priv->kcs_bmc;
	struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc;

	kcs_bmc_remove_device(kcs_bmc);

+257 −171

File changed.

Preview size limit exceeded, changes collapsed.

+13 −11
Original line number Diff line number Diff line
@@ -6,22 +6,24 @@

#include <linux/irqreturn.h>

struct kcs_bmc;
struct kcs_bmc_client_ops;
#include "kcs_bmc.h"

struct kcs_bmc_client_ops {
	irqreturn_t (*event)(struct kcs_bmc_client *client);
};

struct kcs_bmc_client {
	const struct kcs_bmc_client_ops *ops;

	struct kcs_bmc *dev;
	struct kcs_bmc_device *dev;
};

struct kcs_bmc_client_ops {
	irqreturn_t (*event)(struct kcs_bmc_client *client);
};
int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client);
void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, 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);
u8 kcs_bmc_read_data(struct kcs_bmc_device *kcs_bmc);
void kcs_bmc_write_data(struct kcs_bmc_device *kcs_bmc, u8 data);
u8 kcs_bmc_read_status(struct kcs_bmc_device *kcs_bmc);
void kcs_bmc_write_status(struct kcs_bmc_device *kcs_bmc, u8 data);
void kcs_bmc_update_status(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 val);
#endif
Loading