[RFC v1 1/4] ipmi_bmc: framework for BT IPMI on BMCs
Brendan Higgins
brendanhiggins at google.com
Fri Aug 11 11:06:32 AEST 2017
On Thu, Aug 10, 2017 at 6:58 AM, Corey Minyard <minyard at acm.org> wrote:
> On 08/07/2017 10:52 PM, Brendan Higgins wrote:
>>
>> From: Benjamin Fair <benjaminfair at google.com>
>>
>> This patch introduces a framework for writing IPMI drivers which run on
>> a Board Management Controller. It is similar in function to OpenIPMI.
>> The framework handles registering devices and routing messages.
>
>
> Ok, I think I understand this. I have a few nitpicky comments inline. The
> RCU usage
> looks correct, and the basic design seems sound.
Sweet
>
> This piece of code takes a communication interface, called a bus, and
> muxes/demuxes
> messages on that bus to various users, called devices. The name "devices"
> confused
> me for a bit, because I was thinking they were physical devices, what Linux
> would
> call a device. I don't have a good suggestion for another name, though.
We could maybe do "*_interface" instead of "*_bus" and "*_handler" instead
of "*_device"; admittedly, it is not the best name ever: handler has some
connotations.
>
>
>
> I assume you would create one of these per bus for handling multiple busses,
> which
> you will obviously need to do in the future when IPMB comes.
Yep, that is the intention. I was planning on adding support to use the device
infrastructure so that multiple busses could be declared using device tree, etc.
I do not have that now, but I thought that was a lot of work and I would want
to get general buy-in before doing that. We just did enough to make code
that achieves feature parity to what we have now and the core of the new
proposed features.
>
> I can see two big problems with the way the "match_request" is done:
> * If multiple users want to handle the same request, only one of them will
> get it
> and they will not know they have conflicted.
> * Doing this for userland interfaces will be hard.
> The other way to do this is for each user to register for each request type
> and
> manage it all in this code, which is kind of messy to use, but avoids the
> above problems.
Right, we considered this; however, I thought this is best because we also
want to handle routing of OEM messages; I suppose we could register a
type for OEM messages and then have a secondary set of handlers there;
this would have some drawbacks though, the default handler interface would
become a lot more complicated.
On the other hand, now that I am thinking about it; having a common kernel
interface for OEM messages could be really useful; this has definitely
caused us some grief.
>
> In thinking about the bigger picture here, you will need something like this
> for every
> communication interface the BMC supports: the system interface, LAN, IPMB,
> ICMB
> (let's hope not), and serial/modem interfaces (let's hope not, too, but
> people really
> use these in the field). Maybe ICMB and serial aren't on your radar, but
> I'd expect
> LAN is pretty important, and you have already mentioned IPMB.
Right, we are thinking about IPMB right now; I agree that the other stuff should
be considered, but we don't really have a need for it now.
My hope would be to make a similar interface for IPMB.
>
> If you are thinking you will have a separate one of these for LAN in
> userspace, I
> would say just do it all in userspace. For LAN you will have something that
> has
> to mux/demux all the messages from the LAN interface to the various users,
> the
> same code could sit on top of the current BT interface (and IPMB, etc.).
So right now we do have handlers for a lot of basic commands in user space;
this is why I have the default device file interface. However, it is incomplete
and I am starting to look at commands that make more sense being
implemented in the kernel.
I have kind of danced around your point so far, for LAN, as far as I know we
only support a REST interface right now; we should have the option of the
LAN interface, but I don't think anyone has really tackled that yet.
Basically, the way I see this now is sort of a mirror of what is done
on the host
side, we will have a kernel and a userland interface and then we will evolve it
as necessary.
In any case, I think there is probably a lot of room for additional discussion
here.
>
> I guess I'm trying to figure out how you expect all this work out in the
> end. What
> you have now is a message mux/demux that can only have on thing underneath
> it and one thing above it, which obviously isn't very useful. Are you
> thinking you
> can have other in-kernel things that can handle specific messages? I'm
> having
> a hard time imagining that's the case. Or are you thinking that you will
Yes, I as I mentioned above, having handlers in the kernel is a prime motivator
for this. I have been working on an interface for doing flash updates over IPMI.
IPMI is not really a great way to do this in terms of performance or
the interface
it provides; however, IPMI is great in the sense that all platforms
have it, so I
want to have alternative backends for this flash interface and provide an IPMI
OEM command implementation as a lowest common denominator option. I
have some other examples, but i think this is one of the most interesting.
> create
> a userland interface to create a bus and then when a LAN connection comes
> in you create one of these BMC contexts and route the LAN traffic through
> this
> code? That's kind of clever, but I'm wondering if there would be better
> ways
> to do this than this design.
Well, I think that is up for discussion; my main goal here is starting a
conversation.
As far as this being a complete design; I do not consider what I have
presented as being complete. I mentioned some things above that I would like
to add and some people have already chimed in asking for some changes.
I just wanted to get some feedback before I went *too* far.
>
> -corey
>
>> Signed-off-by: Benjamin Fair <benjaminfair at google.com>
>> Signed-off-by: Brendan Higgins <brendanhiggins at google.com>
>> ---
>> drivers/char/ipmi_bmc/Makefile | 1 +
>> drivers/char/ipmi_bmc/ipmi_bmc.c | 294
>> +++++++++++++++++++++++++++++++++++++++
>> include/linux/ipmi_bmc.h | 184 ++++++++++++++++++++++++
>> 3 files changed, 479 insertions(+)
>> create mode 100644 drivers/char/ipmi_bmc/ipmi_bmc.c
>>
>> diff --git a/drivers/char/ipmi_bmc/Makefile
>> b/drivers/char/ipmi_bmc/Makefile
>> index 8bff32b55c24..9c7cd48d899f 100644
>> --- a/drivers/char/ipmi_bmc/Makefile
>> +++ b/drivers/char/ipmi_bmc/Makefile
>> @@ -2,5 +2,6 @@
>> # Makefile for the ipmi bmc drivers.
>> #
>> +obj-$(CONFIG_IPMI_BMC) += ipmi_bmc.o
>> obj-$(CONFIG_IPMI_BMC_BT_I2C) += ipmi_bmc_bt_i2c.o
>> obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += ipmi_bmc_bt_aspeed.o
>> diff --git a/drivers/char/ipmi_bmc/ipmi_bmc.c
>> b/drivers/char/ipmi_bmc/ipmi_bmc.c
>> new file mode 100644
>> index 000000000000..c1324ac9a83c
>> --- /dev/null
>> +++ b/drivers/char/ipmi_bmc/ipmi_bmc.c
>
>
> This is not really a BMC, it's a BMC message router, or something like that.
How about ipmi_bmc_core.c or ipmi_slave_core.c ?
>
>
>> @@ -0,0 +1,294 @@
>> +/*
>> + * Copyright 2017 Google Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/errno.h>
>> +#include <linux/export.h>
>> +#include <linux/init.h>
>> +#include <linux/ipmi_bmc.h>
>> +#include <linux/list.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/rculist.h>
>> +#include <linux/rcupdate.h>
>> +
>> +#define PFX "IPMI BMC core: "
>> +
>> +struct ipmi_bmc_ctx *ipmi_bmc_get_global_ctx()
>> +{
>> + static struct ipmi_bmc_ctx global_ctx;
>> +
>> + return &global_ctx;
>> +}
>> +
>> +int ipmi_bmc_send_response(struct ipmi_bmc_ctx *ctx,
>> + struct bt_msg *bt_response)
>> +{
>> + struct ipmi_bmc_bus *bus;
>> + int ret = -ENODEV;
>> +
>> + rcu_read_lock();
>> + bus = rcu_dereference(ctx->bus);
>> +
>> + if (bus)
>> + ret = bus->send_response(bus, bt_response);
>> +
>> + rcu_read_unlock();
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_send_response);
>> +
>> +bool ipmi_bmc_is_response_open(struct ipmi_bmc_ctx *ctx)
>> +{
>> + struct ipmi_bmc_bus *bus;
>> + bool ret = false;
>> +
>> + rcu_read_lock();
>> + bus = rcu_dereference(ctx->bus);
>> +
>> + if (bus)
>> + ret = bus->is_response_open(bus);
>> +
>> + rcu_read_unlock();
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_is_response_open);
>> +
>> +int ipmi_bmc_register_device(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_device *device_in)
>> +{
>> + struct ipmi_bmc_device *device;
>> +
>> + mutex_lock(&ctx->drivers_mutex);
>> + /* Make sure it hasn't already been registered. */
>> + list_for_each_entry(device, &ctx->devices, link) {
>> + if (device == device_in) {
>> + mutex_unlock(&ctx->drivers_mutex);
>> + return -EINVAL;
>> + }
>> + }
>> +
>> + list_add_rcu(&device_in->link, &ctx->devices);
>> + mutex_unlock(&ctx->drivers_mutex);
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_register_device);
>> +
>> +int ipmi_bmc_unregister_device(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_device *device_in)
>> +{
>> + struct ipmi_bmc_device *device;
>> + bool found = false;
>> +
>> + mutex_lock(&ctx->drivers_mutex);
>> + /* Make sure it is currently registered. */
>> + list_for_each_entry(device, &ctx->devices, link) {
>> + if (device == device_in) {
>> + found = true;
>> + break;
>> + }
>> + }
>> + if (!found) {
>> + mutex_unlock(&ctx->drivers_mutex);
>> + return -ENXIO;
>> + }
>> +
>> + list_del_rcu(&device_in->link);
>> + mutex_unlock(&ctx->drivers_mutex);
>> + synchronize_rcu();
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_unregister_device);
>> +
>> +int ipmi_bmc_register_default_device(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_device *device)
>> +{
>> + int ret;
>> +
>> + mutex_lock(&ctx->drivers_mutex);
>> + if (!ctx->default_device) {
>> + ctx->default_device = device;
>> + ret = 0;
>> + } else {
>> + ret = -EBUSY;
>> + }
>> + mutex_unlock(&ctx->drivers_mutex);
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_register_default_device);
>> +
>> +int ipmi_bmc_unregister_default_device(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_device *device)
>> +{
>> + int ret;
>> +
>> + mutex_lock(&ctx->drivers_mutex);
>> + if (ctx->default_device == device) {
>> + ctx->default_device = NULL;
>> + ret = 0;
>> + } else {
>> + ret = -ENXIO;
>> + }
>> + mutex_unlock(&ctx->drivers_mutex);
>> + synchronize_rcu();
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_unregister_default_device);
>> +
>> +static u8 errno_to_ccode(int errno)
>> +{
>> + switch (errno) {
>> + case EBUSY:
>> + return 0xC0; /* Node Busy */
>> + case EINVAL:
>> + return 0xC1; /* Invalid Command */
>> + case ETIMEDOUT:
>> + return 0xC3; /* Timeout while processing command */
>> + case ENOMEM:
>> + return 0xC4; /* Out of space */
>> + default:
>> + return 0xFF; /* Unspecified error */
>
>
> Instead of the hard-coded constants, you can use
> include/uapi/linux/ipmi_msgdefs.h
> and add things there as needed. You probably knew that, but these numbers
> should
> all be the same. Same for other constant that might apply.
Noted.
>
>
>> + }
>> +}
>> +
>> +static void ipmi_bmc_send_error_response(struct ipmi_bmc_ctx *ctx,
>> + struct bt_msg *bt_request,
>> + u8 ccode)
>> +{
>> + struct bt_msg error_response;
>> + int ret;
>> +
>> + /* Payload contains 1 byte for completion code */
>> + error_response.len = bt_msg_payload_to_len(1);
>> + error_response.netfn_lun = bt_request->netfn_lun |
>> + IPMI_NETFN_LUN_RESPONSE_MASK;
>> + error_response.seq = bt_request->seq;
>> + error_response.cmd = bt_request->cmd;
>> + error_response.payload[0] = ccode;
>> +
>> + /*
>> + * TODO(benjaminfair): Retry sending the response if it fails. The
>> error
>> + * response might fail to send if another response is in progress.
>> In
>> + * that case, the request will timeout rather than getting a more
>> + * specific completion code. This should buffer up responses and
>> send
>> + * them when it can. Device drivers will generally handle error
>> + * reporting themselves; this code is only a fallback when that's
>> not
>> + * available or when the drivers themselves fail.
>> + */
>> + ret = ipmi_bmc_send_response(ctx, &error_response);
>> + if (ret)
>> + pr_warn(PFX "Failed to reply with completion code %u:
>> ipmi_bmc_send_response returned %d\n",
>> + (u32) ccode, ret);
>> +}
>> +
>> +void ipmi_bmc_handle_request(struct ipmi_bmc_ctx *ctx,
>> + struct bt_msg *bt_request)
>> +{
>> + struct ipmi_bmc_device *default_device;
>> + struct ipmi_bmc_device *device;
>> + int ret = -EINVAL;
>> +
>> + rcu_read_lock();
>> + list_for_each_entry_rcu(device, &ctx->devices, link) {
>> + if (device->match_request(device, bt_request)) {
>> + ret = device->handle_request(device, bt_request);
>> + goto out;
>> + }
>> + }
>> +
>> + /* No specific handler found. Use default handler instead */
>> + default_device = rcu_dereference(ctx->default_device);
>> + if (default_device)
>> + ret = default_device->handle_request(default_device,
>> + bt_request);
>> +
>> +out:
>> + rcu_read_unlock();
>> + if (ret)
>> + ipmi_bmc_send_error_response(ctx, bt_request,
>> + errno_to_ccode(-ret));
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_handle_request);
>> +
>> +void ipmi_bmc_signal_response_open(struct ipmi_bmc_ctx *ctx)
>> +{
>> + struct ipmi_bmc_device *default_device;
>> + struct ipmi_bmc_device *device;
>> +
>> + rcu_read_lock();
>> + list_for_each_entry_rcu(device, &ctx->devices, link) {
>> + device->signal_response_open(device);
>> + }
>> +
>> + default_device = rcu_dereference(ctx->default_device);
>> + if (default_device)
>> + default_device->signal_response_open(default_device);
>> +
>> + rcu_read_unlock();
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_signal_response_open);
>> +
>> +int ipmi_bmc_register_bus(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_bus *bus_in)
>> +{
>> + int ret;
>> +
>> + mutex_lock(&ctx->drivers_mutex);
>> + if (!ctx->bus) {
>> + ctx->bus = bus_in;
>> + ret = 0;
>> + } else {
>> + ret = -EBUSY;
>> + }
>> + mutex_unlock(&ctx->drivers_mutex);
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_register_bus);
>> +
>> +int ipmi_bmc_unregister_bus(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_bus *bus_in)
>> +{
>> + int ret;
>> +
>> + mutex_lock(&ctx->drivers_mutex);
>> + /* Tried to unregister when another bus is registered */
>> + if (ctx->bus == bus_in) {
>> + ctx->bus = NULL;
>> + ret = 0;
>> + } else {
>> + ret = -ENXIO;
>> + }
>> + mutex_unlock(&ctx->drivers_mutex);
>> + synchronize_rcu();
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(ipmi_bmc_unregister_bus);
>> +
>> +static int __init ipmi_bmc_init(void)
>> +{
>> + struct ipmi_bmc_ctx *ctx = ipmi_bmc_get_global_ctx();
>> +
>> + mutex_init(&ctx->drivers_mutex);
>> + INIT_LIST_HEAD(&ctx->devices);
>> + return 0;
>> +}
>> +module_init(ipmi_bmc_init);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Benjamin Fair <benjaminfair at google.com>");
>> +MODULE_DESCRIPTION("Core IPMI driver for the BMC side");
>> diff --git a/include/linux/ipmi_bmc.h b/include/linux/ipmi_bmc.h
>> index d0885c0bf190..2b494a79ec14 100644
>> --- a/include/linux/ipmi_bmc.h
>> +++ b/include/linux/ipmi_bmc.h
>> @@ -20,6 +20,13 @@
>> #include <linux/types.h>
>> #define BT_MSG_PAYLOAD_LEN_MAX 252
>> +#define BT_MSG_SEQ_MAX 255
>> +
>> +/*
>> + * The bit in this mask is set in the netfn_lun field of an IPMI message
>> to
>> + * indicate that it is a response.
>> + */
>> +#define IPMI_NETFN_LUN_RESPONSE_MASK (1 << 2)
>> /**
>> * struct bt_msg - Block Transfer IPMI message.
>> @@ -42,6 +49,84 @@ struct bt_msg {
>> u8 payload[BT_MSG_PAYLOAD_LEN_MAX];
>> } __packed;
>> +/**
>> + * struct ipmi_bmc_device - Device driver that wants to receive ipmi
>> requests.
>> + * @link: Used to make a linked list of devices.
>> + * @match_request: Used to determine whether a request can be handled by
>> this
>> + * device. Note that the matchers are checked in an
>> arbitrary
>> + * order.
>> + * @handle_request: Called when a request is received for this device.
>> + * @signal_response_open: Called when a response is done being sent and
>> another
>> + * device can send a message. Make sure to check
>> that the
>> + * bus isn't busy even after this is called,
>> because all
>> + * devices receive this call and another one may
>> have
>> + * already submitted a new response.
>> + *
>> + * This collection of callback functions represents an upper-level
>> handler of
>> + * IPMI requests.
>> + *
>> + * Note that the callbacks may be called from an interrupt context.
>> + */
>> +struct ipmi_bmc_device {
>> + struct list_head link;
>> +
>> + bool (*match_request)(struct ipmi_bmc_device *device,
>> + struct bt_msg *bt_request);
>> + int (*handle_request)(struct ipmi_bmc_device *device,
>> + struct bt_msg *bt_request);
>> + void (*signal_response_open)(struct ipmi_bmc_device *device);
>> +};
>> +
>> +/**
>> + * struct ipmi_bmc_bus - Bus driver that exchanges messages with the
>> host.
>> + * @send_response: Submits the given response to be sent to the host. May
>> return
>> + * -EBUSY if a response is already in progress, in which
>> case
>> + * the caller should wait for the response_open()
>> callback to be
>> + * called.
>> + * @is_response_open: Determines whether a response can currently be
>> sent. Note
>> + * that &ipmi_bmc_bus->send_response() may still fail
>> with
>> + * -EBUSY even after this returns true.
>> + *
>> + * This collection of callback functions represents a lower-level driver
>> which
>> + * acts as a connection to the host.
>> + */
>> +struct ipmi_bmc_bus {
>> + int (*send_response)(struct ipmi_bmc_bus *bus,
>> + struct bt_msg *bt_response);
>> + bool (*is_response_open)(struct ipmi_bmc_bus *bus);
>> +};
>> +
>> +/**
>> + * struct ipmi_bmc_ctx - Context object used to interact with the IPMI
>> BMC
>> + * core driver.
>> + * @bus: Pointer to the bus which is currently registered, or NULL for
>> none.
>> + * @default_device: Pointer to a device which will receive messages that
>> match
>> + * no other devices, or NULL if none is registered.
>> + * @devices: List of devices which are currently registered, besides the
>> default
>> + * device.
>> + * @drivers_mutex: Mutex which protects against concurrent editing of the
>> + * bus driver, default device driver, and devices list.
>> + *
>> + * This struct should only be modified by the IPMI BMC core code and not
>> by bus
>> + * or device drivers.
>> + */
>> +struct ipmi_bmc_ctx {
>> + struct ipmi_bmc_bus __rcu *bus;
>> + struct ipmi_bmc_device __rcu *default_device;
>> + struct list_head devices;
>> + struct mutex drivers_mutex;
>
>
> Since it does all it does, "drivers_mutex" IMHO is too specific a name.
Makes sense.
>
>
>> +};
>> +
>> +/**
>> + * ipmi_bmc_get_global_ctx() - Get a pointer to the global ctx.
>> + *
>> + * This function gets a reference to the global ctx object which is used
>> by
>> + * bus and device drivers to interact with the IPMI BMC core driver.
>> + *
>> + * Return: Pointer to the global ctx object.
>> + */
>> +struct ipmi_bmc_ctx *ipmi_bmc_get_global_ctx(void);
>> +
>> /**
>> * bt_msg_len() - Determine the total length of a Block Transfer
>> message.
>> * @bt_msg: Pointer to the message.
>> @@ -73,4 +158,103 @@ static inline u8 bt_msg_payload_to_len(u8
>> payload_len)
>> return payload_len + 3;
>> }
>> +/**
>> + * ipmi_bmc_send_response() - Send an IPMI response on the current bus.
>> + * @bt_response: The response message to send.
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ipmi_bmc_send_response(struct ipmi_bmc_ctx *ctx,
>> + struct bt_msg *bt_response);
>> +/**
>> + * ipmi_bmc_is_response_open() - Check whether we can currently send a
>> new
>> + * response.
>> + *
>> + * Note that even if this function returns true, ipmi_bmc_send_response()
>> may
>> + * still fail with -EBUSY if a response is submitted in the time between
>> the two
>> + * calls.
>> + *
>> + * Return: true if we can send a new response, false if one is already in
>> + * progress.
>> + */
>> +bool ipmi_bmc_is_response_open(struct ipmi_bmc_ctx *ctx);
>> +/**
>> + * ipmi_bmc_register_device() - Register a new device driver.
>> + * @device: Pointer to the struct which represents this device,
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ipmi_bmc_register_device(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_device *device);
>> +/**
>> + * ipmi_bmc_unregister_device() - Unregister an existing device driver.
>> + * @device: Pointer to the struct which represents the existing device.
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ipmi_bmc_unregister_device(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_device *device);
>> +/**
>> + * ipmi_bmc_register_default_device() - Register a new default device
>> driver.
>> + * @device: Pointer to the struct which represents this device,
>> + *
>> + * Make this device the default device. If none of the other devices
>> match on a
>> + * particular message, this device will receive it instead. Note that
>> only one
>> + * default device may be registered at a time.
>> + *
>> + * This functionalisty is currently used to allow messages which aren't
>> directly
>> + * handled by the kernel to be sent to userspace and handled there.
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ipmi_bmc_register_default_device(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_device *device);
>> +/**
>> + * ipmi_bmc_unregister_default_device() - Unregister the existing default
>> device
>> + * driver.
>> + * @device: Pointer to the struct which represents the existing device.
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ipmi_bmc_unregister_default_device(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_device *device);
>> +/**
>> + * ipmi_bmc_handle_request() - Handle a new request that was received.
>> + * @bt_request: The request that was received.
>> + *
>> + * This is called by the bus driver when it receives a new request
>> message.
>> + *
>> + * Note that it may be called from an interrupt context.
>> + */
>> +void ipmi_bmc_handle_request(struct ipmi_bmc_ctx *ctx,
>> + struct bt_msg *bt_request);
>> +/**
>> + * ipmi_bmc_signal_response_open() - Notify the upper layer that a
>> response can
>> + * be sent.
>> + *
>> + * This is called by the bus driver after it finishes sending a response
>> and is
>> + * ready to begin sending another one.
>> + */
>> +void ipmi_bmc_signal_response_open(struct ipmi_bmc_ctx *ctx);
>> +/**
>> + * ipmi_bmc_register_bus() - Register a new bus driver.
>> + * @bus: Pointer to the struct which represents this bus.
>> + *
>> + * Register a bus driver to handle communication with the host.
>> + *
>> + * Only one bus driver can be registered at any time.
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ipmi_bmc_register_bus(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_bus *bus);
>> +/**
>> + * ipmi_bmc_unregister_bus() - Unregister an existing bus driver.
>> + * @bus: Pointer to the struct which represents the existing bus.
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ipmi_bmc_unregister_bus(struct ipmi_bmc_ctx *ctx,
>> + struct ipmi_bmc_bus *bus);
>> +
>> #endif /* __LINUX_IPMI_BMC_H */
>
>
>
Thanks!
More information about the openbmc
mailing list