Commit be37f259 authored by Jonathan Currier's avatar Jonathan Currier

Migrate transport, and other mechanism away from poll, and to epoll.

This will easy the transition to making transports compile time
optional.

NOTE: this commit if unfinished and should eventually be rebased &
squashed.

specifically, the shutdown code no longer works correctly.
parent 200e3736
......@@ -5,11 +5,11 @@
#include "backend.h"
#include "common.h"
#include "dbus.h"
#include "lpc.h"
#include "mboxd.h"
#include "protocol.h"
#include "windows.h"
#include "hiomapd-state.h"
int control_ping(struct mbox_context *context)
{
......
......@@ -202,7 +202,7 @@ static int control_dbus_get_u8(sd_bus *bus, const char *path,
sd_bus_message *reply, void *userdata,
sd_bus_error *ret_error)
{
struct mbox_context *context = userdata;
struct mbox_context *context = dctx_to_mctx((struct transport_dbus_context*)userdata);
uint8_t value;
assert(!strcmp(MBOX_DBUS_OBJECT, path));
......@@ -242,12 +242,12 @@ static const sd_bus_vtable mboxd_vtable[] = {
SD_BUS_VTABLE_END
};
int control_dbus_init(struct mbox_context *context)
int control_dbus_init(struct transport_dbus_context *dctx)
{
return sd_bus_add_object_vtable(context->bus, NULL,
return sd_bus_add_object_vtable(dctx->bus, NULL,
MBOX_DBUS_OBJECT,
MBOX_DBUS_CONTROL_IFACE,
mboxd_vtable, context);
mboxd_vtable, dctx);
}
#define __unused __attribute__((unused))
......
......@@ -294,20 +294,19 @@ static const sd_bus_vtable control_legacy_vtable[] = {
SD_BUS_VTABLE_END
};
int control_legacy_init(struct mbox_context *context)
int control_legacy_init(struct transport_dbus_context *dctx)
{
int rc;
rc = sd_bus_add_object_vtable(context->bus, NULL,
rc = sd_bus_add_object_vtable(dctx->bus, NULL,
MBOX_DBUS_LEGACY_OBJECT,
MBOX_DBUS_LEGACY_NAME,
control_legacy_vtable, context);
control_legacy_vtable, dctx);
if (rc < 0) {
MSG_ERR("Failed to register vtable: %s\n", strerror(-rc));
return rc;
}
return sd_bus_request_name(context->bus, MBOX_DBUS_LEGACY_NAME,
return sd_bus_request_name(dctx->bus, MBOX_DBUS_LEGACY_NAME,
SD_BUS_NAME_ALLOW_REPLACEMENT |
SD_BUS_NAME_REPLACE_EXISTING);
}
......
......@@ -25,22 +25,24 @@
#define MBOX_DBUS_LEGACY_NAME "org.openbmc.mboxd"
#define MBOX_DBUS_LEGACY_OBJECT "/org/openbmc/mboxd"
/* Command Args */
/* Resume */
#define RESUME_NUM_ARGS 1
#define RESUME_NOT_MODIFIED 0x00
#define RESUME_FLASH_MODIFIED 0x01
/* Response Args */
/* Status */
#define DAEMON_STATE_NUM_ARGS 1
#define DAEMON_STATE_ACTIVE 0x00 /* Daemon Active */
#define DAEMON_STATE_SUSPENDED 0x01 /* Daemon Suspended */
/* LPC State */
#define LPC_STATE_NUM_ARGS 1
#define LPC_STATE_INVALID 0x00 /* Invalid State */
#define LPC_STATE_FLASH 0x01 /* LPC Maps Flash Directly */
#define LPC_STATE_MEM 0x02 /* LPC Maps Memory */
#include "hiomapd-state.h"
struct transport_dbus_context {
struct ops_container w;
struct mbox_context *context;
sd_bus *bus;
int dbus_fd;
};
static inline struct mbox_context *dctx_to_mctx(struct transport_dbus_context *dctx)
{
return dctx->context;
}
static inline struct transport_dbus_context *
container_to_dctx(struct ops_container *container)
{
return container_of(container, struct transport_dbus_context, w);
}
#endif /* MBOX_DBUS_H */
#ifndef HIOMAPD_STATE_H
#define HIOMAPD_STATE_H
/* Command Args */
/* Resume */
#define RESUME_NUM_ARGS 1
#define RESUME_NOT_MODIFIED 0x00
#define RESUME_FLASH_MODIFIED 0x01
/* Response Args */
/* Status */
#define DAEMON_STATE_NUM_ARGS 1
#define DAEMON_STATE_ACTIVE 0x00 /* Daemon Active */
#define DAEMON_STATE_SUSPENDED 0x01 /* Daemon Suspended */
/* LPC State */
#define LPC_STATE_NUM_ARGS 1
#define LPC_STATE_INVALID 0x00 /* Invalid State */
#define LPC_STATE_FLASH 0x01 /* LPC Maps Flash Directly */
#define LPC_STATE_MEM 0x02 /* LPC Maps Memory */
#endif
......@@ -32,6 +32,10 @@
#define LPC_CTRL_PATH "/dev/aspeed-lpc-ctrl"
struct host_lpc_link_context {
int lpcfd;
};
int __lpc_dev_init(struct mbox_context *context, const char *path)
{
struct aspeed_lpc_ctrl_mapping map = {
......@@ -43,6 +47,13 @@ int __lpc_dev_init(struct mbox_context *context, const char *path)
.size = 0
};
int fd;
struct host_lpc_link_context *lctx = calloc(1,sizeof(*lctx));
if (!lctx) {
MSG_ERR("Couldn't allocate lpc link context\n");
return -ENOMEM;
}
context->host_link_ctx = lctx;
/* Open LPC Device */
MSG_DBG("Opening %s\n", path);
......@@ -53,7 +64,7 @@ int __lpc_dev_init(struct mbox_context *context, const char *path)
return -errno;
}
context->fds[LPC_CTRL_FD].fd = fd;
lctx->lpcfd = fd;
/* Find Size of Reserved Memory Region */
MSG_DBG("Getting buffer size...\n");
......@@ -86,10 +97,11 @@ int lpc_dev_init(struct mbox_context *context)
void lpc_dev_free(struct mbox_context *context)
{
struct host_lpc_link_context *lctx = context->host_link_ctx;
if (context->mem) {
munmap(context->mem, context->mem_size);
}
close(context->fds[LPC_CTRL_FD].fd);
close(lctx->lpcfd);
}
/*
......@@ -100,6 +112,7 @@ void lpc_dev_free(struct mbox_context *context)
*/
int lpc_map_flash(struct mbox_context *context)
{
struct host_lpc_link_context *lctx = context->host_link_ctx;
struct aspeed_lpc_ctrl_mapping map = {
.window_type = ASPEED_LPC_CTRL_WINDOW_FLASH,
.window_id = 0, /* Theres only one */
......@@ -126,7 +139,7 @@ int lpc_map_flash(struct mbox_context *context)
MSG_INFO("Assuming %dMB of flash: HOST LPC 0x%08x\n",
context->backend.flash_size >> 20, map.addr);
if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_MAP, &map)
if (ioctl(lctx->lpcfd, ASPEED_LPC_CTRL_IOCTL_MAP, &map)
== -1) {
MSG_ERR("Failed to point the LPC BUS at the actual flash: %s\n",
strerror(errno));
......@@ -150,6 +163,7 @@ int lpc_map_flash(struct mbox_context *context)
*/
int lpc_map_memory(struct mbox_context *context)
{
struct host_lpc_link_context *lctx = context->host_link_ctx;
struct aspeed_lpc_ctrl_mapping map = {
.window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
.window_id = 0, /* There's only one */
......@@ -167,7 +181,7 @@ int lpc_map_memory(struct mbox_context *context)
context->mem, context->mem_size);
MSG_INFO("LPC address 0x%.8x\n", map.addr);
if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_MAP,
if (ioctl(lctx->lpcfd, ASPEED_LPC_CTRL_IOCTL_MAP,
&map)) {
MSG_ERR("Failed to point the LPC BUS to memory: %s\n",
strerror(errno));
......
......@@ -24,17 +24,13 @@
#include <time.h>
#include <unistd.h>
#include <inttypes.h>
#include <systemd/sd-bus.h>
#include <sys/epoll.h>
#include "config.h"
#include "mboxd.h"
#include "common.h"
#include "dbus.h"
#include "control_dbus.h"
#include "backend.h"
#include "lpc.h"
#include "transport_mbox.h"
#include "transport_dbus.h"
#include "windows.h"
#include "vpnor/backend.h"
......@@ -57,133 +53,33 @@ const char* USAGE =
"\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n"
"\t-t | --trace\t\tFile to write trace data to (in blktrace format)\n\n";
static int dbus_init(struct mbox_context *context,
const struct transport_ops **ops)
{
int rc;
rc = sd_bus_default_system(&context->bus);
if (rc < 0) {
MSG_ERR("Failed to connect to the system bus: %s\n",
strerror(-rc));
return rc;
}
rc = control_legacy_init(context);
if (rc < 0) {
MSG_ERR("Failed to initialise legacy DBus interface: %s\n",
strerror(-rc));
return rc;
}
rc = control_dbus_init(context);
if (rc < 0) {
MSG_ERR("Failed to initialise DBus control interface: %s\n",
strerror(-rc));
return rc;
}
rc = transport_dbus_init(context, ops);
if (rc < 0) {
MSG_ERR("Failed to initialise DBus protocol interface: %s\n",
strerror(-rc));
return rc;
}
rc = sd_bus_request_name(context->bus, MBOX_DBUS_NAME,
SD_BUS_NAME_ALLOW_REPLACEMENT |
SD_BUS_NAME_REPLACE_EXISTING);
if (rc < 0) {
MSG_ERR("Failed to request DBus name: %s\n", strerror(-rc));
return rc;
}
rc = sd_bus_get_fd(context->bus);
if (rc < 0) {
MSG_ERR("Failed to get bus fd: %s\n", strerror(-rc));
return rc;
}
context->fds[DBUS_FD].fd = rc;
return 0;
}
static void dbus_free(struct mbox_context *context)
{
transport_dbus_free(context);
control_dbus_free(context);
control_legacy_free(context);
sd_bus_unref(context->bus);
}
static int poll_loop(struct mbox_context *context)
{
int rc = 0, i;
/* Set POLLIN on polling file descriptors */
for (i = 0; i < POLL_FDS; i++) {
context->fds[i].events = POLLIN;
}
while (1) {
rc = poll(context->fds, POLL_FDS, -1);
if (rc < 0) { /* Error */
MSG_ERR("Error from poll(): %s\n", strerror(errno));
break; /* This should mean we clean up nicely */
}
/* Event on Polled File Descriptor - Handle It */
if (context->fds[SIG_FD].revents & POLLIN) { /* Signal */
struct signalfd_siginfo info = { 0 };
rc = read(context->fds[SIG_FD].fd, (void *) &info,
sizeof(info));
if (rc != sizeof(info)) {
MSG_ERR("Error reading signal event: %s\n",
strerror(errno));
}
MSG_DBG("Received signal: %d\n", info.ssi_signo);
switch (info.ssi_signo) {
case SIGINT:
case SIGTERM:
MSG_INFO("Caught Signal - Exiting...\n");
context->terminate = true;
break;
case SIGHUP:
rc = protocol_reset(context);
if (rc < 0) {
MSG_ERR("Failed to reset on SIGHUP\n");
}
break;
default:
MSG_ERR("Unhandled Signal: %d\n",
info.ssi_signo);
break;
}
}
if (context->fds[DBUS_FD].revents & POLLIN) { /* DBUS */
while ((rc = sd_bus_process(context->bus, NULL)) > 0) {
MSG_DBG("DBUS Event\n");
}
if (rc < 0) {
MSG_ERR("Error handling DBUS event: %s\n",
strerror(-rc));
}
}
int count;
/* This is a low throughput api, 0x10 events is huge,
* one would probably be sufficent.*/
struct epoll_event evt[0x10] = { 0 };
struct ops_container *w;
while (true) {
count = epoll_wait(context->epollfd, evt, 0x10, -1);
if (count < 0)
{
MSG_ERR("Error from epoll_wait(): %s\n", strerror(errno));
continue;
}
for (i = 0; i < count; i++)
{
w = evt[i].data.ptr;
if (w[0].ops->event(w, evt + i) < 0)
MSG_ERR("Error in event dispatch\n");
}
if (context->terminate) {
break; /* This should mean we clean up nicely */
}
if (context->fds[MBOX_FD].revents & POLLIN) { /* MBOX */
MSG_DBG("MBOX Event\n");
rc = transport_mbox_dispatch(context);
if (rc < 0) {
MSG_ERR("Error handling MBOX event\n");
}
}
}
}
rc = protocol_reset(context);
if (rc < 0) {
......@@ -193,32 +89,6 @@ static int poll_loop(struct mbox_context *context)
return rc;
}
static int init_signals(struct mbox_context *context, sigset_t *set)
{
int rc;
/* Block SIGHUPs, SIGTERMs and SIGINTs */
sigemptyset(set);
sigaddset(set, SIGHUP);
sigaddset(set, SIGINT);
sigaddset(set, SIGTERM);
rc = sigprocmask(SIG_BLOCK, set, NULL);
if (rc < 0) {
MSG_ERR("Failed to set SIG_BLOCK mask %s\n", strerror(errno));
return rc;
}
/* Get Signal File Descriptor */
rc = signalfd(-1, set, SFD_NONBLOCK);
if (rc < 0) {
MSG_ERR("Failed to get signalfd %s\n", strerror(errno));
return rc;
}
context->fds[SIG_FD].fd = rc;
return 0;
}
static void usage(const char *name)
{
printf(USAGE, name);
......@@ -387,14 +257,20 @@ static int mboxd_backend_init(struct mbox_context *context)
return rc;
}
extern void *__start_ops_array;
extern void *__stop_ops_array;
static struct transport_ops **ops_array =
(struct transport_ops **)&__start_ops_array;
static size_t ops_array_size;
int main(int argc, char **argv)
{
const struct transport_ops *mbox_ops, *dbus_ops;
struct mbox_context *context;
bool have_transport_mbox;
char *name = argv[0];
sigset_t set;
int rc, i;
ops_array_size =
((struct transport_ops **)&__stop_ops_array) -
((struct transport_ops **)&__start_ops_array);
context = calloc(1, sizeof(*context));
if (!context) {
......@@ -408,17 +284,10 @@ int main(int argc, char **argv)
exit(0);
}
for (i = 0; i < TOTAL_FDS; i++) {
context->fds[i].fd = -1;
}
context->epollfd = epoll_create1(EPOLL_CLOEXEC);
MSG_INFO("Starting Daemon\n");
rc = init_signals(context, &set);
if (rc) {
goto cleanup_context;
}
rc = mboxd_backend_init(context);
if (rc) {
goto cleanup_context;
......@@ -429,16 +298,6 @@ int main(int argc, char **argv)
goto cleanup_backend;
}
rc = transport_mbox_init(context, &mbox_ops);
/* TODO: Think about whether we could use a less branch-y strategy */
have_transport_mbox = rc == 0;
if (!have_transport_mbox) {
/* Disable MBOX for poll()ing purposes */
context->fds[MBOX_FD].fd = -1;
MSG_DBG("Failed to initialise MBOX transport: %d\n", rc);
MSG_INFO("MBOX transport unavailable\n");
}
rc = lpc_dev_init(context);
if (rc) {
goto cleanup_mbox;
......@@ -450,10 +309,8 @@ int main(int argc, char **argv)
goto cleanup_lpc;
}
rc = dbus_init(context, &dbus_ops);
if (rc) {
goto cleanup_windows;
}
for (i = 0; i < ops_array_size; i++)
ops_array[i]->init(context, ops_array[i]);
/* Set the LPC bus mapping */
__protocol_reset(context);
......@@ -462,19 +319,6 @@ int main(int argc, char **argv)
context->bmc_events |= BMC_EVENT_DAEMON_READY;
context->bmc_events |= BMC_EVENT_PROTOCOL_RESET;
/* Alert on all supported transports, as required */
if (have_transport_mbox) {
rc = protocol_events_put(context, mbox_ops);
if (rc) {
goto cleanup;
}
}
rc = protocol_events_put(context, dbus_ops);
if (rc) {
goto cleanup;
}
MSG_INFO("Entering Polling Loop\n");
rc = poll_loop(context);
......@@ -484,23 +328,14 @@ int main(int argc, char **argv)
context->bmc_events &= ~BMC_EVENT_DAEMON_READY;
context->bmc_events |= BMC_EVENT_PROTOCOL_RESET;
/* Alert on all supported transports, as required */
if (have_transport_mbox) {
protocol_events_put(context, mbox_ops);
}
protocol_events_put(context, dbus_ops);
/* I think we can skip all transport that are not the active
* transport */
cleanup:
dbus_free(context);
cleanup_windows:
windows_free(context);
cleanup_lpc:
lpc_dev_free(context);
cleanup_mbox:
if (have_transport_mbox) {
transport_mbox_free(context);
}
protocol_free(context);
cleanup_backend:
backend_free(&context->backend);
......@@ -512,3 +347,109 @@ cleanup_context:
return rc;
}
/* Singal 'transport' */
struct signal_context {
struct mbox_context *context;
struct ops_container w;
int signal_fd;
};
static inline struct signal_context* container_to_sctx(struct ops_container *container)
{
return container_of(container, struct signal_context, w);
}
static int init_signals(struct mbox_context *context,
struct transport_ops *ops)
{
int rc;
sigset_t set;
struct signal_context *sctx = calloc(1, sizeof(*sctx));
if (!sctx) {
MSG_ERR("Failed to allocate signal context\n");
return -ENOMEM;
}
sctx->context = context;
sctx->w.ops = ops;
/* Block SIGHUPs, SIGTERMs and SIGINTs */
sigemptyset(&set);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGTERM);
rc = sigprocmask(SIG_BLOCK, &set, NULL);
if (rc < 0) {
MSG_ERR("Failed to set SIG_BLOCK mask %s\n", strerror(errno));
free(sctx);
return rc;
}
/* Get Signal File Descriptor */
rc = signalfd(-1, &set, SFD_NONBLOCK);
if (rc < 0) {
MSG_ERR("Failed to get signalfd %s\n", strerror(errno));
free(sctx);
return rc;
}
sctx->signal_fd = rc;
register_event_fd(sctx->signal_fd, context, &sctx->w);
return 0;
}
static int signal_event(struct ops_container *container,
struct epoll_event *evt)
{
struct signal_context *sctx = container_to_sctx(container);
struct mbox_context *context = sctx->context;
struct signalfd_siginfo info = { 0 };
int rc;
if (!(evt->events & EPOLLIN))
{
MSG_ERR("Signal event, but no event ready\n");
return -EINVAL;
}
rc = read(sctx->signal_fd, (void *) &info,
sizeof(info));
if (rc != sizeof(info)) {
MSG_ERR("Error reading signal event: %s\n",
strerror(errno));
return rc;
}
MSG_DBG("Received signal: %d\n", info.ssi_signo);
switch (info.ssi_signo) {
case SIGINT:
case SIGTERM:
MSG_INFO("Caught Signal - Exiting...\n");
context->terminate = true;
break;
case SIGHUP:
rc = protocol_reset(context);
if (rc < 0) {
MSG_ERR("Failed to reset on SIGHUP\n");
}
break;
default:
MSG_ERR("Unhandled Signal: %d\n",
info.ssi_signo);
break;
}
return 0;
}
DECLARE_TRANSPORT_OPS(signal) = {
.init = init_signals,
.event = signal_event,
.fini = 0,
.put_events = 0,
.set_events = 0,
.clear_events = 0,
};
......@@ -7,7 +7,6 @@
#include <assert.h>
#include <linux/blktrace_api.h>
#include <mtd/mtd-abi.h>
#include <systemd/sd-bus.h>
#include <poll.h>
#include <stdbool.h>
......@@ -45,13 +44,6 @@ enum api_version {
BMC_EVENT_FLASH_CTRL_LOST | \
BMC_EVENT_DAEMON_READY)
/* Put polled file descriptors first */
#define DBUS_FD 0
#define MBOX_FD 1
#define SIG_FD 2
#define POLL_FDS 3 /* Number of FDs we poll on */
#define LPC_CTRL_FD 3
#define TOTAL_FDS 4
#define MAPS_FLASH (1 << 0)
#define MAPS_MEM (1 << 1)
......@@ -73,7 +65,8 @@ enum mbox_state {
struct mbox_context {
enum api_version version;
const struct protocol_ops *protocol;
const struct transport_ops *transport;
//const struct transport_ops *transport;
struct ops_container *transport;
struct backend backend;
/* Commandline parameters */
......@@ -81,8 +74,7 @@ struct mbox_context {
/* System State */
enum mbox_state state;
struct pollfd fds[TOTAL_FDS];
sd_bus *bus;
int epollfd;
bool terminate;
uint8_t bmc_events;
uint8_t prev_seq;
......@@ -102,6 +94,10 @@ struct mbox_context {
uint32_t mem_size;
/* LPC Bus Base Address (bytes) */
uint32_t lpc_base;
/* In this implementation it's the context for
* the lpc.c file, the details of which are unneeded
* for the rest of the code */
void *host_link_ctx;
/* Tracing */
int blktracefd;
......
......@@ -36,11 +36,11 @@ static inline uint8_t protocol_get_bmc_event_mask(struct mbox_context *context)
* Return: 0 on success otherwise negative error code
*/
int protocol_events_put(struct mbox_context *context,
const struct transport_ops *ops)
struct ops_container *container)
{
const uint8_t mask = protocol_get_bmc_event_mask(context);
return ops->put_events(context, mask);
return container->ops->put_events(container, mask);
}
/*
......@@ -61,7 +61,7 @@ int protocol_events_set(struct mbox_context *context, uint8_t bmc_event)
*/
context->bmc_events |= bmc_event;
return context->transport->set_events(context, bmc_event, mask);
return context->transport->ops->set_events(context->transport, bmc_event, mask);
}
/*
......@@ -78,7 +78,7 @@ int protocol_events_clear(struct mbox_context *context, uint8_t bmc_event)
context->bmc_events &= ~bmc_event;
return context->transport->clear_events(context, bmc_event, mask);
return context->transport->ops->clear_events(context->transport, bmc_event, mask);
}
static int protocol_negotiate_version(struct mbox_context *context,
......
......@@ -6,6 +6,7 @@
struct mbox_context;
struct transport_ops;
struct ops_container;
/*
* The GET_MBOX_INFO command is special as it can change the interface based on
......@@ -126,7 +127,7 @@ int __protocol_reset(struct mbox_context *context);
int protocol_reset(struct mbox_context *context);
int protocol_events_put(struct mbox_context *context,
const struct transport_ops *ops);
struct ops_container *container);
int protocol_events_set(struct mbox_context *context, uint8_t bmc_event);
int protocol_events_clear(struct mbox_context *context, uint8_t bmc_event);
......
......@@ -5,13 +5,48 @@
#define TRANSPORT_H
struct mbox_context;
struct ops_container;
struct epoll_event;
struct transport_ops {
int (*put_events)(struct mbox_context *context, uint8_t mask);